2 ;; page.scm -- implement Page stuff.
4 ;; source file of the GNU LilyPond music typesetter
6 ;; (c) 2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 (define-module (scm page)
32 (define (annotate? layout)
33 (eq? #t (ly:output-def-lookup layout 'annotatespacing)))
36 (define page-module (current-module))
38 (define (make-page . args)
39 (apply ly:make-prob (append
43 (define page-property ly:prob-property)
44 (define (page-property? page sym)
45 (eq? #t (page-property page sym)))
47 (define (page? x) (ly:prob-type? x 'page))
49 (define page-set-property! ly:prob-set-property!)
56 (string->symbol (format "page-~a" j))
58 (page-property pg j))))
60 '(page-number prev lines force penalty configuration lines))
62 (define (page-system-numbers node)
63 (map (lambda (ps) (ly:prob-property ps 'number))
68 (define (annotate-page stencil layout)
70 ((topmargin (ly:output-def-lookup layout 'topmargin))
71 (vsize (ly:output-def-lookup layout 'vsize))
72 (bottommargin (ly:output-def-lookup layout 'bottommargin))
73 (add-stencil (lambda (y)
75 (ly:stencil-add stencil y))
79 (ly:stencil-translate-axis
80 (annotate-y-interval layout "vsize"
87 (ly:stencil-translate-axis
88 (annotate-y-interval layout "topmargin"
89 (cons (- topmargin) 0)
94 (ly:stencil-translate-axis
95 (annotate-y-interval layout "bottommargin"
96 (cons (- vsize) (- bottommargin vsize))
102 (define (annotate-space-left page-stencil layout bottom-edge)
104 ((arrow (annotate-y-interval layout
106 (cons (- bottom-edge) (car (ly:stencil-extent page-stencil Y)))
109 (set! arrow (ly:stencil-translate-axis arrow 8 X))
110 (ly:stencil-add page-stencil arrow)))
115 (define (page-headfoot layout scopes number
116 sym separation-symbol dir last?)
118 "Create a stencil including separating space."
120 (let* ((header-proc (ly:output-def-lookup layout sym))
121 (sep (ly:output-def-lookup layout separation-symbol))
122 (stencil (ly:make-stencil "" '(0 . 0) '(0 . 0)))
124 (if (procedure? header-proc)
125 (header-proc layout scopes number last?)
129 (if (and (number? sep)
130 (ly:stencil? head-stencil)
131 (not (ly:stencil-empty? head-stencil)))
135 (ly:stencil-combine-at-edge
136 stencil Y dir head-stencil
141 (if (annotate? layout)
144 (ly:stencil-translate-axis
145 (annotate-y-interval layout
146 (symbol->string separation-symbol)
147 (cons (min 0 (* dir sep))
150 (/ (ly:output-def-lookup layout 'linewidth) 2)
153 (ly:stencil-translate-axis
154 (annotate-y-interval layout
157 (- (min 0 (* dir sep))
158 (ly:output-def-lookup layout 'pagetopspace))
161 (+ 7 (interval-center (ly:stencil-extent head-stencil X))) X)
170 (define (page-header-or-footer page dir)
172 ((p-book (page-property page 'paper-book))
173 (layout (ly:paper-book-paper p-book))
174 (scopes (ly:paper-book-scopes p-book))
175 (lines (page-lines page))
176 (offsets (page-configuration page))
177 (number (page-page-number page))
178 (last? (page-property page 'is-last))
182 (page-headfoot layout scopes number
191 (define (page-footer page)
192 (page-header-or-footer page UP))
194 (define (page-header page)
195 (page-header-or-footer page DOWN))
197 (define (make-page-stencil page)
198 "Construct a stencil representing the page from LINES.
200 Offsets is a list of increasing numbers. They must be negated to
205 ((p-book (page-property page 'paper-book))
206 (layout (ly:paper-book-paper p-book))
207 (scopes (ly:paper-book-scopes p-book))
208 (lines (page-lines page))
209 (offsets (page-configuration page))
210 (number (page-page-number page))
211 (last? (page-property page 'is-last))
213 (topmargin (ly:output-def-lookup layout 'topmargin))
215 ;; TODO: naming vsize/hsize not analogous to TeX.
217 (vsize (ly:output-def-lookup layout 'vsize))
218 (hsize (ly:output-def-lookup layout 'hsize))
220 (system-xoffset (ly:output-def-lookup layout 'horizontalshift 0.0))
221 (system-separator-markup (ly:output-def-lookup layout 'systemSeparatorMarkup))
222 (system-separator-stencil (if (markup? system-separator-markup)
223 (interpret-markup layout
224 (layout-extract-page-properties layout)
225 system-separator-markup)
227 (lmargin (ly:output-def-lookup layout 'leftmargin))
228 (leftmargin (if lmargin
231 (ly:output-def-lookup layout 'linewidth)) 2)))
233 (rightmargin (ly:output-def-lookup layout 'rightmargin))
234 (bottom-edge (- vsize
235 (ly:output-def-lookup layout 'bottommargin)))
237 (head (page-header page))
239 (foot (page-footer page))
241 (head-height (if (ly:stencil? head)
242 (interval-length (ly:stencil-extent head Y))
245 (height-proc (ly:output-def-lookup layout 'page-music-height))
247 (page-stencil (ly:make-stencil '()
248 (cons leftmargin hsize)
249 (cons (- topmargin) 0)))
252 (add-to-page (lambda (stencil y)
254 (ly:stencil-add page-stencil
255 (ly:stencil-translate stencil
258 (- 0 head-height y topmargin))
262 (lambda (stencil-position)
263 (let* ((system (car stencil-position))
264 (stencil (paper-system-stencil system))
265 (y (cadr stencil-position))
266 (is-title (paper-system-title?
267 (car stencil-position))))
268 (add-to-page stencil y)
269 (if (and (ly:stencil? system-separator-stencil)
271 (not (paper-system-title? system))
272 (not (paper-system-title? last-system)))
274 system-separator-stencil
276 (car (paper-system-staff-extents last-system)))
278 (cdr (paper-system-staff-extents system))))))
279 (set! last-system system)
284 (if (annotate? layout)
286 (for-each (lambda (sys) (paper-system-annotate sys layout))
288 (paper-system-annotate-last (car (last-pair lines)) layout)))
293 "leftmargin " leftmargin "rightmargin " rightmargin
296 (set! page-stencil (ly:stencil-combine-at-edge
300 (not (ly:stencil-empty? head)))
302 (ly:make-stencil "" (cons 0 0) (cons 0 0)))
305 (map add-system (zip lines offsets))
307 (if (annotate? layout)
310 (annotate-space-left page-stencil layout
312 (if (ly:stencil? foot)
313 (interval-length (ly:stencil-extent foot Y))
318 (if (and (ly:stencil? foot)
319 (not (ly:stencil-empty? foot)))
323 (ly:stencil-translate
327 (- (car (ly:stencil-extent foot Y)))))))))
330 (ly:stencil-translate page-stencil (cons leftmargin 0)))
333 (if (annotate? layout)
334 (set! page-stencil (annotate-page layout page-stencil)))
341 (define (page-stencil page)
342 (if (not (ly:stencil? (page-property page 'stencil)))
344 ;; todo: make tweakable.
345 ;; via property + callbacks.
347 (page-set-property! page 'stencil (make-page-stencil page)))
348 (page-property page 'stencil))
350 (define (page-height page)
351 "Printable area for music and titles; matches default-page-make-stencil."
353 ((p-book (page-property page 'paper-book))
354 (layout (ly:paper-book-paper p-book))
355 (scopes (ly:paper-book-scopes p-book))
356 (number (page-page-number page))
357 (last? (page-property page 'is-last))
358 (h (- (ly:output-def-lookup layout 'vsize)
359 (ly:output-def-lookup layout 'topmargin)
360 (ly:output-def-lookup layout 'bottommargin)))
362 (head (page-headfoot layout scopes number 'make-header 'headsep UP last?))
363 (foot (page-headfoot layout scopes number 'make-footer 'footsep DOWN last?))
365 (- h (if (ly:stencil? head)
366 (interval-length (ly:stencil-extent head Y))
368 (if (ly:stencil? foot)
369 (interval-length (ly:stencil-extent foot Y))
372 ;; (display (list "\n available" available head foot))