]> git.donarmstrong.com Git - lilypond.git/blob - scm/framework-gnome.scm
* buildscripts/guile-gnome.sh: Build without gcc libtool version
[lilypond.git] / scm / framework-gnome.scm
1 ;;;; framework-gnome.scm --
2 ;;;;
3 ;;;;  source file of the GNU LilyPond music typesetter
4 ;;;; 
5 ;;;; (c)  2004 Jan Nieuwenhuizen <janneke@gnu.org>
6
7 ;;;; See output-gnome.scm for usage information.
8
9
10 (define-module (scm framework-gnome))
11
12 (use-modules (guile) (oop goops) (lily))
13
14 (use-modules
15  (srfi srfi-2)
16  (ice-9 regex)
17  (gnome gtk)
18  (gnome gtk gdk-event)
19  (gnome gw canvas))
20
21 (define-public (output-framework outputter book scopes fields basename)
22   (gnome-main book))
23
24 (define SCROLLBAR-SIZE 20)
25 (define BUTTON-HEIGHT 25)
26 (define PANELS-HEIGHT 80)
27
28 (define PIXELS-PER-UNIT 2)
29 (define OUTPUT-SCALE (* 2.5 PIXELS-PER-UNIT))
30 (define-public output-scale OUTPUT-SCALE)
31
32 (define (stderr string . rest)
33   (apply format (cons (current-error-port) (cons string rest)))
34   (force-output (current-error-port)))
35
36 (define (debugf string . rest)
37   (if #f
38       (stderr (cons string rest))))
39       
40 (define-class <gnome-outputter> ()
41   (page-stencils ;;#:init-value '#()
42    #:init-keyword #:page-stencils #:accessor page-stencils)
43   (window #:init-value (make <gtk-window> #:type 'toplevel) #:accessor window)
44   (scrolled #:init-value (make <gtk-scrolled-window>) #:accessor scrolled)
45   (canvas #:init-value #f #:accessor canvas)
46   (page-number #:init-value 0 #:accessor page-number)
47   (pixels-per-unit #:init-value PIXELS-PER-UNIT #:accessor pixels-per-unit)
48   (text-items #:init-value '() #:accessor text-items)
49   (grob #:init-value #f #:accessor grob)
50   (item-grobs #:init-value (make-hash-table 31) #:accessor item-grobs)
51   (window-width #:init-keyword #:window-width #:accessor window-width)
52   (window-height #:init-keyword #:window-height #:accessor window-height)
53   (canvas-width #:init-keyword #:canvas-width #:accessor canvas-width)
54   (canvas-height #:init-keyword #:canvas-height #:accessor canvas-height))
55
56 (define-method (initialize (go <gnome-outputter>))
57   (let* ((button (make <gtk-button> #:label "Exit"))
58          (next (make <gtk-button> #:label "Next"))
59          (prev (make <gtk-button> #:label "Previous"))
60          (vbox (make <gtk-vbox> #:homogeneous #f))
61          (hbox (make <gtk-hbox> #:homogeneous #f)))
62
63     (set-size-request (window go) (window-width go) (window-height go))
64     
65     (set-size-request (scrolled go) (window-width go) (- (window-height go)
66                                                          BUTTON-HEIGHT
67                                                          SCROLLBAR-SIZE))
68
69     (new-canvas go)
70
71     (add (window go) vbox)
72     (add vbox (scrolled go))
73     
74     (add (scrolled go) (canvas go))
75
76     ;; buttons
77     (add vbox hbox)
78     (set-size-request hbox (window-width go) BUTTON-HEIGHT)
79
80     ;; hmm?  These are broken when using <gnome-outputter>.
81     ;;(set-child-packing vbox hbox #f #f 0 'end)
82     ;;(set-child-packing hbox button #f #f 0 'end)
83     
84     (set-size-request button (quotient (window-width go) 2) BUTTON-HEIGHT)
85
86     
87     (add hbox next)
88     (add hbox prev)
89     (add hbox button)
90
91     ;; signals
92     (connect button 'clicked (lambda (b) (gtk-main-quit)))
93     (connect next 'clicked (lambda (b) (dump-page go (1+ (page-number go)))))
94     (connect prev 'clicked (lambda (b) (dump-page go (1- (page-number go)))))
95     (connect (window go) 'key-press-event
96              (lambda (w e) (key-press-event go w e)))
97     
98     (show-all (window go))))
99
100
101 (define (gnome-main book)
102   (let* ((book-paper (ly:paper-book-book-paper book))
103          (hsize (ly:output-def-lookup book-paper 'hsize))
104          (vsize (ly:output-def-lookup book-paper 'vsize))
105          (page-width (inexact->exact (ceiling (* OUTPUT-SCALE hsize))))
106          (page-height (inexact->exact (ceiling (* OUTPUT-SCALE vsize))))
107          ;;(page-width (inexact->exact (ceiling hsize)))
108          ;;(page-height (inexact->exact (ceiling vsize)))
109
110          (screen-width (gdk-screen-width))
111          (screen-height (gdk-screen-height))
112          (desktop-height (- screen-height PANELS-HEIGHT))
113
114          (go (make <gnome-outputter>
115                #:page-stencils (list->vector (ly:paper-book-pages book))
116                #:canvas-width page-width
117                #:canvas-height page-height
118                #:window-width
119                ;; huh, *2 -- pixels-per-unit?
120                (min (+ SCROLLBAR-SIZE (* page-width 2)) screen-width)
121                #:window-height
122                (min (+ BUTTON-HEIGHT SCROLLBAR-SIZE (* page-height 2))
123                     desktop-height))))
124
125     ;; ugh.  The GOOPS doc promises this is called automagically.
126     ;; possibly a goops 1.6.4 problem
127     (initialize go)
128
129     (map ly:pango-add-afm-decoder
130          '("lilypond-feta"
131            "lilypond-braces"
132            "lilypond-dyn"
133            "lilypond-parmesan"))
134
135     (dump-page go 0)
136
137     (gtk-main)))
138
139 (define (dump-page go number)
140   (if (or (not (page-stencils go))
141           (< number 0)
142           (>= number (vector-length (page-stencils go))))
143       (stderr "No such page: ~S\n" (1+ number))
144       
145       (let ((old-canvas (canvas go)))
146         (new-canvas go)
147         (set! (page-number go) number)
148         
149         ;; no destroy method for gnome-canvas-text yet.
150         ;;(map destroy (gtk-container-get-children main-canvas))
151         ;;(map destroy text-items)
152
153         (set! (text-items go) '())
154         (debugf "page-stencil ~S: ~S\n"
155                 (page-number go)                
156                 (vector-ref (page-stencils go) (page-number go)))
157         
158         (ly:interpret-stencil-expression 
159          ;; ;;(vector-ref (page-stencils go) (page-number go))
160          (ly:stencil-expr (vector-ref (page-stencils go) (page-number go)))
161          gnome-output-expression go '(0 . 0))
162
163         (if old-canvas (destroy old-canvas))
164         (add (scrolled go) (canvas go))
165         (show (canvas go)))))
166
167 (define x-editor #f)
168 (define (get-x-editor)
169   (if (not x-editor)
170       (set! x-editor (getenv "XEDITOR")))
171   x-editor)
172
173 (define ifs #f)
174 (define (get-ifs)
175   (if (not ifs)
176       (set! ifs (getenv "IFS")))
177   (if (not ifs)
178       (set! ifs "       "))
179   ifs)
180       
181 (define (spawn-editor location)
182   (let* ((file-name (car location))
183          (line (cadr location))
184          (column (caddr location))
185          (template (substring (get-x-editor) 0))
186          
187          ;; Adhere to %l %c %f?
188          (command
189           (regexp-substitute/global
190            #f "%l" (regexp-substitute/global
191                     #f "%c"
192                     (regexp-substitute/global
193                      #f "%f" template 'pre file-name 'post)
194                     'pre (number->string column)
195                     'post)
196            'pre (number->string line) 'post)))
197     
198     (debugf "spawning: ~s\n" command)
199     (if (= (primitive-fork) 0)
200         (let ((command-list (string-split command #\ )));; (get-ifs))))
201           (apply execlp command-list)
202           (primitive-exit)))))
203           
204 (define location-callback spawn-editor)
205
206 (define (get-location grob)
207   (and-let* ((p? (procedure? point-and-click))
208              (g grob)
209              (cause (ly:grob-property grob 'cause))
210              (music-origin (if (ly:music? cause)
211                                (ly:music-property cause 'origin)
212                                ;; How come #<unspecied> [and '()]
213                                ;; are #t? :-(
214                                #f)))
215             (if (ly:input-location? music-origin)
216                 (ly:input-location music-origin)
217                 #f)))
218
219 ;;;(define (item-event go grob item event)
220 (define (item-event go item event)
221   (case (gdk-event:type event)
222     ((enter-notify) (gobject-set-property item 'fill-color "red"))
223     ((leave-notify) (gobject-set-property item 'fill-color "black"))
224     ((button-press)
225      (let ((button (gdk-event-button:button event)))
226        (cond
227         ((= button 1)
228          (and-let* ((grob (hashq-ref (item-grobs go) item #f))
229                     (location (get-location grob)))
230                    (location-callback location)))
231         ((= button 2)
232
233          (and-let*
234           ((grob (hashq-ref (item-grobs go) item #f)))
235           
236           (let ((properties (ly:grob-properties grob))
237                 (basic-properties (ly:grob-basic-properties grob))
238                 (x (inexact->exact (gdk-event-button:x-root event)))
239                 (y (inexact->exact (gdk-event-button:y-root event))))
240                
241             (debugf "GROB: ~S\n" grob)
242             (debugf "PROPERTIES: ~S\n" properties)
243             (debugf "BASIC PROPERTIES: ~S\n" basic-properties)
244             
245             (let ((window (make <gtk-window>))
246                   (vbox (make <gtk-vbox>))
247                   (button (make <gtk-button> #:label "Ok")))
248               
249               (add window vbox)
250               (connect button 'clicked (lambda (b) (destroy window)))
251               
252               (for-each
253                (lambda (x)
254                  (let ((button (make <gtk-button>
255                                  #:xalign 0.0
256                                  #:label
257                                  (string-append
258                                   (symbol->string (car x))
259                                   ": "
260                                   (format #f "~S" (cdr x))))))
261                    (set-size-request button 150 BUTTON-HEIGHT)
262                    (add vbox button)))
263                properties)
264               (add vbox button)
265               
266               ;; FIXME: how to do window placement?
267               ;; - no effect:
268               (move window x y)
269               (show-all window)
270               ;; - shows actual movement:
271               (move window x y)
272               )))))))
273     
274     ((2button-press) (gobject-set-property item 'fill-color "green")))
275   #t)
276
277 (define (scale-canvas go factor)
278   (set! (pixels-per-unit go) (* (pixels-per-unit go) factor))
279   (set-pixels-per-unit (canvas go) (pixels-per-unit go))
280   (for-each
281    (lambda (x)
282      (let ((scale (gobject-get-property x 'scale))
283            (points (gobject-get-property x 'size-points)))
284        ;;(gobject-set-property x 'scale pixels-per-unit)
285        (gobject-set-property x 'size-points (* points factor))))
286      (text-items go)))
287
288 (define (key-press-event go item event)
289   (let ((keyval (gdk-event-key:keyval event))
290         (mods (gdk-event-key:modifiers event)))
291     (cond ((and (or (eq? keyval gdk:q)
292                     (eq? keyval gdk:w))
293                 (equal? mods '(control-mask modifier-mask)))
294            (gtk-main-quit))
295           ((and #t ;;(null? mods)
296                 (eq? keyval gdk:plus))
297            (scale-canvas go 2))
298           ((and #t ;; (null? mods)
299                 (eq? keyval gdk:minus))
300            (scale-canvas go 0.5))
301           ((or (eq? keyval gdk:Page-Up)
302                (eq? keyval gdk:BackSpace))
303            (dump-page go (1- (page-number go))))
304           ((or (eq? keyval gdk:Page-Down)
305                (eq? keyval gdk:space))
306            (dump-page go (1+ (page-number go)))))
307     #f))
308
309 (define (new-canvas go)
310   (set! (canvas go) (make <gnome-canvas>))
311   (set-size-request (canvas go) (window-width go) (window-height go))
312   (set-scroll-region (canvas go) 0 0 (canvas-width go) (canvas-height go))
313   (set-pixels-per-unit (canvas go) (pixels-per-unit go))
314   (make <gnome-canvas-rect>
315     #:parent (root (canvas go))
316     #:x2 (canvas-width go) #:y2 (canvas-height go)
317     #:fill-color "white"))
318
319 (define output-gnome-module #f)
320 (define (get-output-gnome-module go)
321   (if (not output-gnome-module)
322       (let ((m  (resolve-module '(scm output-gnome))))
323         (module-define! m 'canvas-root (lambda () (root (canvas go))))
324         (module-define! m 'output-scale output-scale)
325         (set! output-gnome-module m)))
326   output-gnome-module)
327
328 (define-public (gnome-output-expression go expr)
329   (let* ((m (get-output-gnome-module go))
330          (result (eval expr m)))
331     (cond
332      ((ly:grob? result) (set! (grob go) result))
333      ((is-a? result <gnome-canvas-item>)
334       
335       ;; AAARGH; grobs happen after stencils
336       ;; (connect result 'event (lambda (w e) (item-event go (grob go) w e)))
337       (connect result 'event (lambda (w e) (item-event go w e)))
338       (if (grob go)
339           (hashq-set! (item-grobs go) result (grob go)))
340       (set! (grob go) #f)
341       
342       (if (is-a? result <gnome-canvas-text>)
343           (set! (text-items go) (cons result (text-items go))))))))
344