]> git.donarmstrong.com Git - lilypond.git/blob - scm/output-gnome.scm
9a03791402941849bf5a1ea031adb66c62caf29a
[lilypond.git] / scm / output-gnome.scm
1 ;;;; output-gnome.scm -- implement GNOME canvas output
2 ;;;;
3 ;;;;  source file of the GNU LilyPond music typesetter
4 ;;;; 
5 ;;;; (c)  2004 Jan Nieuwenhuizen <janneke@gnu.org>
6
7 ;;; TODO:
8 ;;;
9 ;;;  * Figure out and fix font scaling and character placement
10 ;;;  * EC font package: add missing X font directories and AFMs
11 ;;;  * User-interface, keybindings
12 ;;;  * Implement missing stencil functions
13 ;;;  * Implement missing commands
14 ;;;  * More information in stencils, e.g., location and grob tag.
15 ;;;  * Embedded Lily:
16 ;;;    - allow GnomeCanvas or `toplevel' GtkWindow to be created
17 ;;;      outside of LilyPond
18 ;;;    - lilylib.
19 ;;;  * Release schedule and packaging of dependencies.  This hack
20 ;;;    depends on several CVS and TLA development sources.
21
22 ;;; You need:
23 ;;;
24 ;;;   * Rotty's g-wrap >= 1.9.3 (or TLA)
25 ;;;   * guile-gnome-platform >= 2.7.95 (or TLA)
26 ;;;   * pango >= 1.6.0
27 ;;;
28 ;;; See also: guile-gtk-general@gnu.org
29
30 ;;; Try it
31 ;;;
32 ;;;   [* Get cvs and tla]
33 ;;;
34 ;;;   * Install gnome/gtk and libffi development stuff
35 ;;;
36 ;;;   * Install pango, g-wrap and guile-gnome from CVS or arch: 
37 ;;;     see buildscripts/guile-gnome.sh
38 ;;;  
39 ;;;   * Build LilyPond with gui support: configure --enable-gui
40 ;;;
41 ;;;   * Supposing that LilyPond was built in ~/cvs/savannah/lilypond,
42 ;;;     tell fontconfig about the feta fonts dir and run fc-cache
43 "
44 cat > ~/.fonts.conf << EOF
45 <fontconfig>
46 <dir>~/cvs/savannah/lilypond/mf/out</dir>
47 <dir>/usr/share/texmf/fonts/type1/public/ec-fonts-mftraced</dir>
48 </fontconfig>
49 EOF
50 fc-cache
51 "
52 ;;;     or copy all your .pfa/.pfb's to ~/.fonts if your fontconfig
53 ;;;     already looks there for fonts.  Check if it works by doing:
54 "
55 fc-list | grep -i lily
56 "
57 ;;;
58 ;;;   * Setup environment
59 "
60 export GUILE_LOAD_PATH=$HOME/usr/pkg/g-wrap/share/guile/site:$HOME/usr/pkg/g-wrap/share/guile/site/g-wrap:$HOME/usr/pkg/guile-gnome/share/guile:$GUILE_LOAD_PATH
61 export LD_LIBRARY_PATH=$HOME/usr/pkg/pango/lib:$HOME/usr/pkg/g-wrap/lib:$HOME/usr/pkg/guile-gnome/lib:$LD_LIBRARY_PATH
62 export XEDITOR='/usr/bin/emacsclient --no-wait +%l:%c %f'
63 "
64 ;;;  * Also for GNOME point-and-click, you need to set XEDITOR and add
65 "
66 #(ly:set-point-and-click 'line-column)
67 "
68 ;;;    to your .ly.
69 ;;;
70 ;;;  * Run lily:
71 "
72 lilypond -fgnome input/simple-song.ly
73 "
74 ;;; point-and-click: (mouse-1) click on a graphical object;
75 ;;; grob-property-list: (mouse-3) click on a graphical object.
76
77 (debug-enable 'backtrace)
78
79 (define-module (scm output-gnome))
80 (define this-module (current-module))
81
82 (use-modules
83  (guile)
84  (ice-9 regex)
85  (srfi srfi-13)
86  (lily)
87  (gnome gtk)
88  (gnome gw canvas))
89
90 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
91 ;;; Wrappers from guile-gnome TLA
92 ;;; guile-gnome-devel@gnu.org--2004
93 ;;; http://arch.gna.org/guile-gnome/archive-2004
94 ;;;
95 ;;; janneke@gnu.org--2004-gnome
96 ;;; http://lilypond.org/~janneke/{arch}/2004-gnome
97 ;;;
98 (if (not (defined? '<gnome-canvas-path-def>))
99     (begin
100       (define-class <gnome-canvas-path-def> (<gobject>)
101         (closure #:init-value (gnome-canvas-path-def-new)
102                  #:init-keyword #:path-def
103                  #:getter get-def #:setter set-def))
104       
105       (define-method (moveto (this <gnome-canvas-path-def>) x y)
106         (gnome-canvas-path-def-moveto (get-def this) x y))
107       (define-method (curveto (this <gnome-canvas-path-def>) x1 y1 x2 y2 x3 y3)
108         (gnome-canvas-path-def-curveto (get-def this)  x1 y1 x2 y2 x3 y3))
109       (define-method (lineto (this <gnome-canvas-path-def>) x y)
110         (gnome-canvas-path-def-lineto (get-def this) x y))
111       (define-method (closepath (this <gnome-canvas-path-def>))
112         (gnome-canvas-path-def-closepath (get-def this)))
113       (define-method (reset (this <gnome-canvas-path-def>))
114         (gnome-canvas-path-def-reset (get-def this)))
115       
116       (define -set-path-def set-path-def)
117       (define -get-path-def get-path-def)
118       
119       (define-method (set-path-def (this <gnome-canvas-shape>)
120                                    (def <gnome-canvas-path-def>))
121         (-set-path-def this (get-def def)))
122       
123       (define-method (get-path-def (this <gnome-canvas-shape>))
124         (make <gnome-canvas-path-def> #:path-def (-get-path-def this)))))
125
126 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
127 ;;; globals
128
129 ;; junkme
130 (define system-origin '(0 . 0))
131
132 ;;; set by framework-gnome.scm
133 (define canvas-root #f)
134 (define output-scale #f)
135
136
137 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
138 ;; helper functions
139
140 (define (stderr string . rest)
141   (apply format (cons (current-error-port) (cons string rest)))
142   (force-output (current-error-port)))
143
144 (define (debugf string . rest)
145   (if #f
146       (apply stderr (cons string rest))))
147
148 (define (utf8 i)
149   (cond
150    ((< i #x80) (list (integer->char i)))
151    ((< i #x800) (map integer->char
152                      (list (+ #xc0 (quotient i #x40))
153                            (+ #x80 (modulo i #x40)))))
154    ((< i #x10000)
155     (let ((x (quotient i #x1000))
156           (y (modulo i #x1000)))
157       (map integer->char
158            (list (+ #xe0 x)
159                  (+ #x80 (quotient y #x40))
160                  (+ #x80 (modulo y #x40))))))
161    (else FIXME)))
162   
163 (define (char->utf8-string font char)
164   (list->string (utf8 (char->unicode-index font char))))
165   
166 (define (string->utf8-string font string)
167   (apply
168    string-append
169    (map (lambda (x) (char->utf8-string font x)) (string->list string))))
170
171 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
172 ;;; stencil outputters
173 ;;;
174
175 ;;; catch-all for missing stuff
176 ;;; comment this out to see find out what functions you miss :-)
177 (define (dummy . foo) #f)
178 (map (lambda (x) (module-define! this-module x dummy))
179      (append
180       (ly:all-stencil-expressions)
181       (ly:all-output-backend-commands)))
182
183 (define (beam width slope thick blot)
184   (define cursor '(0 . 0))
185   (define (rmoveto def x y)
186     (set! cursor (cons (+ x (car cursor)) (+ y (cdr cursor))))
187     (moveto def (car cursor) (cdr cursor)))
188   (define (rlineto def x y)
189     (set! cursor (cons (+ x (car cursor)) (+ y (cdr cursor))))
190     (lineto def (car cursor) (cdr cursor)))
191   (let* ((def (make <gnome-canvas-path-def>))
192          (bezier (make <gnome-canvas-bpath>
193                    #:parent (canvas-root)
194                    #:fill-color "black"
195                    #:outline-color "black"
196                    #:width-units blot
197                    #:join-style 'round))
198          (t (- thick blot))
199          (w (- width blot))
200          (h (* w slope)))
201     
202     (reset def)
203     (rmoveto def (/ blot 2) (/ t 2))
204     (rlineto def w (- h))
205     (rlineto def 0 (- t))
206     (rlineto def (- w) h)
207     (rlineto def 0 t)
208     (closepath def)
209     (set-path-def bezier def)
210     bezier))
211
212 (define (square-beam width slope thick blot)
213   (let*
214       ((def (make <gnome-canvas-path-def>))
215        (y (* (- width) slope))
216        (props (make <gnome-canvas-bpath>
217                    #:parent (canvas-root)
218                    #:fill-color "black"
219                    #:outline-color "black"
220                    #:width-units 0.0)))
221     
222     (reset def)
223     (moveto def 0 0)
224     (lineto def width y)
225     (lineto def width (- y thick))
226     (lineto def 0 (- thick))
227     (lineto def 0 0)
228     (closepath def)
229     (set-path-def props def)
230     props))
231     
232 ;; two beziers
233 (define (bezier-sandwich lst thick)
234   (let* ((def (make <gnome-canvas-path-def>))
235          (bezier (make <gnome-canvas-bpath>
236                    #:parent (canvas-root)
237                    #:fill-color "black"
238                    #:outline-color "black"
239                    #:width-units thick
240                    #:join-style 'round)))
241
242     (reset def)
243
244     ;; FIXME: LST is pre-mangled for direct ps stack usage
245     ;; cl cr r l  0 1 2 3 
246     ;; cr cl l r  4 5 6 7
247     
248      (moveto def (car (list-ref lst 3)) (- (cdr (list-ref lst 3))))
249      (curveto def (car (list-ref lst 0)) (- (cdr (list-ref lst 0)))
250              (car (list-ref lst 1)) (- (cdr (list-ref lst 1)))
251              (car (list-ref lst 2)) (- (cdr (list-ref lst 2))))
252
253      (lineto def (car (list-ref lst 7)) (- (cdr (list-ref lst 7))))
254      (curveto def (car (list-ref lst 4)) (- (cdr (list-ref lst 4)))
255              (car (list-ref lst 5)) (- (cdr (list-ref lst 5)))
256              (car (list-ref lst 6)) (- (cdr (list-ref lst 6))))
257      (lineto def (car (list-ref lst 3)) (- (cdr (list-ref lst 3))))
258
259     (closepath def)
260     (set-path-def bezier def)
261     bezier))
262
263 (define (char font i)
264   (text font (integer->char i)))
265
266 ;; FIXME: naming
267 (define (filledbox breapth width depth height)
268   (make <gnome-canvas-rect>
269     #:parent (canvas-root)
270     #:x1 (- breapth) #:y1 depth #:x2 width #:y2 (- height)
271     #:fill-color "black"
272     #:join-style 'miter))
273
274 (define (grob-cause grob)
275   grob)
276
277 ;; WTF is this in every backend?
278 (define (horizontal-line x1 x2 thickness)
279   (filledbox (- x1) (- x2 x1) (* .5 thickness) (* .5 thickness)))
280
281 (define (placebox x y expr)
282   (debugf "item: ~S\n" expr)
283   (let ((item expr))
284     ;;(if item
285     ;; FIXME ugly hack to skip #unspecified ...
286     (if (and item (not (eq? item (if #f #f))))
287         (begin
288           (move item
289                 (* output-scale (+ (car system-origin) x))
290                 (* output-scale (- (car system-origin) y)))
291           (affine-relative item output-scale 0 0 output-scale 0 0)
292           item)
293         #f)))
294
295 (define (dashed-line thick on off dx dy)
296   (draw-line thick 0 0 dx dy)) 
297
298 (define (draw-line thick fx fy tx ty)
299   (let*
300       ((def (make <gnome-canvas-path-def>))
301        (props (make <gnome-canvas-bpath>
302                    #:parent (canvas-root)
303                    #:fill-color "black"
304                    #:outline-color "black"
305                    #:width-units thick)))
306     
307     (reset def)
308     (moveto def fx (- fy))
309     (lineto def tx (- ty))
310     (set-path-def props def)
311     props))
312     
313
314 (define (list->offsets accum coords)
315   (if (null? coords)
316       accum
317       (cons (cons (car coords) (cadr coords))
318             (list->offsets accum (cddr coords))
319       )))
320
321 (define (polygon coords blotdiameter)
322   (let*
323       ((def (make <gnome-canvas-path-def>))
324        (props (make <gnome-canvas-bpath>
325                    #:parent (canvas-root)
326                    #:fill-color "black"
327                    #:outline-color "black"
328                    #:width-units blotdiameter))
329        (points (list->offsets '() coords))
330        (last-point (car (last-pair points))))
331
332     (reset def)
333     (moveto def (car last-point) (cdr last-point))
334     (for-each (lambda (x)
335                 (lineto def (car x) (cdr x))
336                 ) points)
337     (closepath def)
338     (set-path-def props def)
339     props))
340     
341
342 (define (round-filled-box breapth width depth height blot-diameter)
343   (let ((r (/ blot-diameter 2)))
344     (make <gnome-canvas-rect>
345       #:parent (canvas-root)
346       #:x1 (- r breapth) #:y1 (- depth r) #:x2 (- width r) #:y2 (- r height)
347       #:fill-color "black"
348       #:outline-color "black"
349       #:width-units blot-diameter
350       #:join-style 'round)))
351
352 (define (text font s)
353   (define (pango-font-name font)
354     (font-family font))
355   
356   (define (pango-font-size font)
357     (let* ((designsize (ly:font-design-size font))
358            (magnification (* (ly:font-magnification font)))
359            
360            ;;font-name: "GNU-LilyPond-feta-20"
361            ;;font-file-name: "feta20"
362            ;;pango-font-name: "lilypond-feta, regular 32"
363            ;;OPS:2.61
364            ;;scaling:29.7046771653543
365            ;;magnification:0.569055118110236
366            ;;design:20.0
367   
368            ;; ugh, experimental sizing
369            ;; where does factor ops come from?
370            ;; Hmm, design size: 26/20 
371            (ops 2.60)
372            
373            (scaling (* ops magnification designsize)))
374       (debugf "OPS:~S\n" ops)
375       (debugf "scaling:~S\n" scaling)
376       (debugf "magnification:~S\n" magnification)
377       (debugf "design:~S\n" designsize)
378       
379       scaling))
380
381   (let ((encoding (ly:font-encoding font)))
382     (make <gnome-canvas-text>
383       #:parent (canvas-root)
384       ;; ugh, experimental placement corections
385       ;; #:x 0.0 #:y 0.0
386       #:x 0.0 #:y (if (memq encoding '(fetaMusic fetaBraces)) 0.15 0.69)
387
388       #:anchor (if (memq encoding '(fetaMusic fetaBraces)) 'west 'south-west)
389       #:font (pango-font-name font)
390       #:size-points (pango-font-size font)
391       #:size-set #t
392       #:text (if (char? s)
393                  (char->utf8-string font s)
394                  (string->utf8-string font s)))))