]> git.donarmstrong.com Git - lilypond.git/blob - scm/define-markup-commands.scm
Issue 3479: Define \fermata markup command that heeds `direction'
[lilypond.git] / scm / define-markup-commands.scm
1 ;;;; This file is part of LilyPond, the GNU music typesetter.
2 ;;;;
3 ;;;; Copyright (C) 2000--2012  Han-Wen Nienhuys <hanwen@xs4all.nl>
4 ;;;;                  Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;;
6 ;;;; LilyPond is free software: you can redistribute it and/or modify
7 ;;;; it under the terms of the GNU General Public License as published by
8 ;;;; the Free Software Foundation, either version 3 of the License, or
9 ;;;; (at your option) any later version.
10 ;;;;
11 ;;;; LilyPond is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ;;;; GNU General Public License for more details.
15 ;;;;
16 ;;;; You should have received a copy of the GNU General Public License
17 ;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18
19 ;;;
20 ;;; Markup commands and markup-list commands definitions.
21 ;;;
22 ;;; Markup commands which are part of LilyPond, are defined
23 ;;; in the (lily) module, which is the current module in this file,
24 ;;; using the `define-markup-command' macro.
25 ;;;
26 ;;; Usage:
27 ;;;
28 ;;; (define-markup-command (command-name layout props args...)
29 ;;;   args-signature
30 ;;;   [ #:category category ]
31 ;;;   [ #:properties property-bindings ]
32 ;;;   documentation-string
33 ;;;   ..body..)
34 ;;;
35 ;;; with:
36 ;;;   command-name
37 ;;;     the name of the markup command
38 ;;;
39 ;;;   layout and props
40 ;;;     arguments that are automatically passed to the command when it
41 ;;;     is interpreted.
42 ;;;     `layout' is an output def, which properties can be accessed
43 ;;;     using `ly:output-def-lookup'.
44 ;;;     `props' is a list of property settings which can be accessed
45 ;;;     using `chain-assoc-get' (more on that below)
46 ;;;
47 ;;;   args...
48 ;;;     the command arguments.
49 ;;;     There is no limitation on the order of command arguments.
50 ;;;     However, markup functions taking a markup as their last
51 ;;;     argument are somewhat special as you can apply them to a
52 ;;;     markup list, and the result is a markup list where the
53 ;;;     markup function (with the specified leading arguments) has
54 ;;;     been applied to every element of the original markup list.
55 ;;;
56 ;;;     Since replicating the leading arguments for applying a
57 ;;;     markup function to a markup list is cheap mostly for
58 ;;;     Scheme arguments, you avoid performance pitfalls by just
59 ;;;     using Scheme arguments for the leading arguments of markup
60 ;;;     functions that take a markup as their last argument.
61 ;;;
62 ;;;   args-signature
63 ;;;     the arguments signature, i.e., a list of type predicates which
64 ;;;     are used to type check the arguments, and also to define the general
65 ;;;     argument types (markup, markup-list, scheme) that the command is
66 ;;;     expecting.
67 ;;;     For instance, if a command expects a number, then a markup, the
68 ;;;     signature would be: (number? markup?)
69 ;;;
70 ;;;   category
71 ;;;     for documentation purpose, builtin markup commands are grouped by
72 ;;;     category.  This can be any symbol.  When documentation is generated,
73 ;;;     the symbol is converted to a capitalized string, where hyphens are
74 ;;;     replaced by spaces.
75 ;;;
76 ;;;   property-bindings
77 ;;;     this is used both for documentation generation, and to ease
78 ;;;     programming the command itself.  It is list of
79 ;;;        (property-name default-value)
80 ;;;     or (property-name)
81 ;;;     elements.  Each property is looked-up in the `props' argument, and
82 ;;;     the symbol naming the property is bound to its value.
83 ;;;     When the property is not found in `props', then the symbol is bound
84 ;;;     to the given default value.  When no default value is given, #f is
85 ;;;     used instead.
86 ;;;     Thus, using the following property bindings:
87 ;;;       ((thickness 0.1)
88 ;;;        (font-size 0))
89 ;;;     is equivalent to writing:
90 ;;;       (let ((thickness (chain-assoc-get 'thickness props 0.1))
91 ;;;             (font-size (chain-assoc-get 'font-size props 0)))
92 ;;;         ..body..)
93 ;;;     When a command `B' internally calls an other command `A', it may
94 ;;;     desirable to see in `B' documentation all the properties and
95 ;;;     default values used by `A'.  In that case, add `A-markup' to the
96 ;;;     property-bindings of B.  (This is used when generating
97 ;;;     documentation, but won't create bindings.)
98 ;;;
99 ;;;   documentation-string
100 ;;;     the command documentation string (used to generate manuals)
101 ;;;
102 ;;;   body
103 ;;;     the command body.  The function is supposed to return a stencil.
104 ;;;
105 ;;; Each markup command definition shall have a documentation string
106 ;;; with description, syntax and example.
107
108 (use-modules (ice-9 regex))
109
110 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
111 ;; utility functions
112 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
113
114 (define-public empty-stencil (ly:make-stencil '()
115                                               empty-interval empty-interval))
116 (define-public point-stencil (ly:make-stencil "" '(0 . 0) '(0 . 0)))
117
118 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
119 ;; geometric shapes
120 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
121
122 (define-markup-command (draw-line layout props dest)
123   (number-pair?)
124   #:category graphic
125   #:properties ((thickness 1))
126   "
127 @cindex drawing lines within text
128
129 A simple line.
130 @lilypond[verbatim,quote]
131 \\markup {
132   \\draw-line #'(4 . 4)
133   \\override #'(thickness . 5)
134   \\draw-line #'(-3 . 0)
135 }
136 @end lilypond"
137   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
138                thickness))
139         (x (car dest))
140         (y (cdr dest)))
141     (make-line-stencil th 0 0 x y)))
142
143 (define-markup-command (draw-dashed-line layout props dest)
144   (number-pair?)
145   #:category graphic
146   #:properties ((thickness 1)
147                 (on 1)
148                 (off 1)
149                 (phase 0)
150                 (full-length #t))
151   "
152 @cindex drawing dashed lines within text
153
154 A dashed line.
155
156 If @code{full-length} is set to #t (default) the dashed-line extends to the
157 whole length given by @var{dest}, without white space at beginning or end.
158 @code{off} will then be altered to fit.
159 To insist on the given (or default) values of @code{on}, @code{off} use
160 @code{\\override #'(full-length . #f)}
161 Manual settings for @code{on},@code{off} and @code{phase} are possible.
162 @lilypond[verbatim,quote]
163 \\markup {
164   \\draw-dashed-line #'(5.1 . 2.3)
165   \\override #'(on . 0.3)
166   \\override #'(off . 0.5)
167   \\draw-dashed-line #'(5.1 . 2.3)
168 }
169 @end lilypond"
170   (let* ((line-thickness (ly:output-def-lookup layout 'line-thickness))
171          ;; Calculate the thickness to be used.
172          (th (* line-thickness thickness))
173          (half-thick (/ th 2))
174          ;; Get the extensions in x- and y-direction.
175          (x (car dest))
176          (y (cdr dest))
177          ;; Calculate the length of the dashed line.
178          (line-length (sqrt (+ (expt x 2) (expt y 2)))))
179
180     (if (and full-length (not (= (+ on off) 0)))
181         (begin
182           ;; Add double-thickness to avoid overlapping.
183           (set! off (+ (* 2 th) off))
184           (let* (;; Make a guess how often the off/on-pair should be printed
185                  ;; after the initial `on´.
186                  ;; Assume a minimum of 1 to avoid division by zero.
187                  (guess (max 1 (round (/ (- line-length on) (+ off on)))))
188                  ;; Not sure about the value or why corr is necessary at all,
189                  ;; but it seems to be necessary.
190                  (corr (if (= on 0)
191                            (/ line-thickness 10)
192                            0))
193                  ;; Calculate a new value for off to fit the
194                  ;; line-length.
195                  (new-off (/ (- line-length corr (* (1+ guess) on)) guess))
196                  )
197             (cond
198
199              ;; Settings for (= on 0). Resulting in a dotted line.
200
201              ;; If line-length isn't shorter than `th´, change the given
202              ;; value for `off´ to fit the line-length.
203              ((and (= on 0) (< th line-length))
204               (set! off new-off))
205
206              ;; If the line-length is shorter than `th´, it makes no
207              ;; sense to adjust `off´. The rounded edges of the lines
208              ;; would prevent any nice output.
209              ;; Do nothing.
210              ;; This will result in a single dot for very short lines.
211              ((and (= on 0) (>= th line-length))
212               #f)
213
214              ;; Settings for (not (= on 0)). Resulting in a dashed line.
215
216              ;; If line-length isn't shorter than one go of on-off-on,
217              ;; change the given value for `off´ to fit the line-length.
218              ((< (+ (* 2 on) off) line-length)
219               (set! off new-off))
220              ;; If the line-length is too short, but greater than
221              ;; (* 4 th) set on/off to (/ line-length 3)
222              ((< (* 4 th) line-length)
223               (set! on (/ line-length 3))
224               (set! off (/ line-length 3)))
225              ;; If the line-length is shorter than (* 4 th), it makes
226              ;; no sense trying to adjust on/off. The rounded edges of
227              ;; the lines would prevent any nice output.
228              ;; Simply set `on´ to line-length.
229              (else
230               (set! on line-length))))))
231
232     ;; If `on´ or `off´ is negative, or the sum of `on' and `off' equals zero a
233     ;; ghostscript-error occurs while calling
234     ;; (ly:make-stencil (list 'dashed-line th on off x y phase) x-ext y-ext)
235     ;; Better be paranoid.
236     (if (or (= (+ on off) 0)
237             (negative? on)
238             (negative? off))
239         (begin
240           (ly:warning "Can't print a line - setting on/off to default")
241           (set! on 1)
242           (set! off 1)))
243
244     ;; To give the lines produced by \draw-line and \draw-dashed-line the same
245     ;; length, half-thick has to be added to the stencil-extensions.
246     (ly:make-stencil
247      (list 'dashed-line th on off x y phase)
248      (interval-widen (ordered-cons 0 x) half-thick)
249      (interval-widen (ordered-cons 0 y) half-thick))))
250
251 (define-markup-command (draw-dotted-line layout props dest)
252   (number-pair?)
253   #:category graphic
254   #:properties ((thickness 1)
255                 (off 1)
256                 (phase 0))
257   "
258 @cindex drawing dotted lines within text
259
260 A dotted line.
261
262 The dotted-line always extends to the whole length given by @var{dest}, without
263 white space at beginning or end.
264 Manual settings for @code{off} are possible to get larger or smaller space
265 between the dots.
266 The given (or default) value of @code{off} will be altered to fit the
267 line-length.
268 @lilypond[verbatim,quote]
269 \\markup {
270   \\draw-dotted-line #'(5.1 . 2.3)
271   \\override #'(thickness . 2)
272   \\override #'(off . 0.2)
273   \\draw-dotted-line #'(5.1 . 2.3)
274 }
275 @end lilypond"
276
277   (let ((new-props (prepend-alist-chain 'on 0
278                                         (prepend-alist-chain 'full-length #t props))))
279
280     (interpret-markup layout
281                       new-props
282                       (markup #:draw-dashed-line dest))))
283
284 (define-markup-command (draw-hline layout props)
285   ()
286   #:category graphic
287   #:properties ((draw-line-markup)
288                 (line-width)
289                 (span-factor 1))
290   "
291 @cindex drawing a line across a page
292
293 Draws a line across a page, where the property @code{span-factor}
294 controls what fraction of the page is taken up.
295 @lilypond[verbatim,quote]
296 \\markup {
297   \\column {
298     \\draw-hline
299     \\override #'(span-factor . 1/3)
300     \\draw-hline
301   }
302 }
303 @end lilypond"
304   (interpret-markup layout
305                     props
306                     (markup #:draw-line (cons (* line-width
307                                                  span-factor)
308                                               0))))
309
310 (define-markup-command (draw-circle layout props radius thickness filled)
311   (number? number? boolean?)
312   #:category graphic
313   "
314 @cindex drawing circles within text
315
316 A circle of radius @var{radius} and thickness @var{thickness},
317 optionally filled.
318
319 @lilypond[verbatim,quote]
320 \\markup {
321   \\draw-circle #2 #0.5 ##f
322   \\hspace #2
323   \\draw-circle #2 #0 ##t
324 }
325 @end lilypond"
326   (make-circle-stencil radius thickness filled))
327
328 (define-markup-command (triangle layout props filled)
329   (boolean?)
330   #:category graphic
331   #:properties ((thickness 0.1)
332                 (font-size 0)
333                 (baseline-skip 2))
334   "
335 @cindex drawing triangles within text
336
337 A triangle, either filled or empty.
338
339 @lilypond[verbatim,quote]
340 \\markup {
341   \\triangle ##t
342   \\hspace #2
343   \\triangle ##f
344 }
345 @end lilypond"
346   (let ((ex (* (magstep font-size) 0.8 baseline-skip)))
347     (ly:make-stencil
348      `(polygon '(0.0 0.0
349                      ,ex 0.0
350                      ,(* 0.5 ex)
351                      ,(* 0.86 ex))
352                ,thickness
353                ,filled)
354      (cons 0 ex)
355      (cons 0 (* .86 ex)))))
356
357 (define-markup-command (circle layout props arg)
358   (markup?)
359   #:category graphic
360   #:properties ((thickness 1)
361                 (font-size 0)
362                 (circle-padding 0.2))
363   "
364 @cindex circling text
365
366 Draw a circle around @var{arg}.  Use @code{thickness},
367 @code{circle-padding} and @code{font-size} properties to determine line
368 thickness and padding around the markup.
369
370 @lilypond[verbatim,quote]
371 \\markup {
372   \\circle {
373     Hi
374   }
375 }
376 @end lilypond"
377   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
378                thickness))
379         (pad (* (magstep font-size) circle-padding))
380         (m (interpret-markup layout props arg)))
381     (circle-stencil m th pad)))
382
383 (define-markup-command (ellipse layout props arg)
384   (markup?)
385   #:category graphic
386   #:properties ((thickness 1)
387                 (font-size 0)
388                 (x-padding 0.2)
389                 (y-padding 0.2))
390   "
391 @cindex drawing ellipse around text
392
393 Draw an ellipse around @var{arg}.  Use @code{thickness},
394 @code{x-padding}, @code{y-padding} and @code{font-size} properties to determine
395 line thickness and padding around the markup.
396
397 @lilypond[verbatim,quote]
398 \\markup {
399   \\ellipse {
400     Hi
401   }
402 }
403 @end lilypond"
404   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
405                thickness))
406         (pad-x (* (magstep font-size) x-padding))
407         (pad-y (* (magstep font-size) y-padding))
408         (m (interpret-markup layout props arg)))
409     (ellipse-stencil m th pad-x pad-y)))
410
411 (define-markup-command (oval layout props arg)
412   (markup?)
413   #:category graphic
414   #:properties ((thickness 1)
415                 (font-size 0)
416                 (x-padding 0.75)
417                 (y-padding 0.75))
418   "
419 @cindex drawing oval around text
420
421 Draw a oval around @var{arg}.  Use @code{thickness},
422 @code{x-padding}, @code{x-padding} and @code{font-size} properties to determine
423 line thickness and padding around the markup.
424
425 @lilypond[verbatim,quote]
426 \\markup {
427   \\oval {
428     Hi
429   }
430 }
431 @end lilypond"
432   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
433                thickness))
434         (pad-x (* (magstep font-size) x-padding))
435         (pad-y (* (magstep font-size) y-padding))
436         (m (interpret-markup layout props arg)))
437     (oval-stencil m th pad-x pad-y)))
438
439 (define-markup-command (with-url layout props url arg)
440   (string? markup?)
441   #:category graphic
442   "
443 @cindex inserting URL links into text
444
445 Add a link to URL @var{url} around @var{arg}.  This only works in
446 the PDF backend.
447
448 @lilypond[verbatim,quote]
449 \\markup {
450   \\with-url #\"http://lilypond.org/\" {
451     LilyPond ... \\italic {
452       music notation for everyone
453     }
454   }
455 }
456 @end lilypond"
457   (let* ((stil (interpret-markup layout props arg))
458          (xextent (ly:stencil-extent stil X))
459          (yextent (ly:stencil-extent stil Y))
460          (old-expr (ly:stencil-expr stil))
461          (url-expr (list 'url-link url `(quote ,xextent) `(quote ,yextent))))
462
463     (ly:stencil-add (ly:make-stencil url-expr xextent yextent) stil)))
464
465 (define-markup-command (page-link layout props page-number arg)
466   (number? markup?)
467   #:category other
468   "
469 @cindex referencing page numbers in text
470
471 Add a link to the page @var{page-number} around @var{arg}.  This only works
472 in the PDF backend.
473
474 @lilypond[verbatim,quote]
475 \\markup {
476   \\page-link #2  { \\italic { This links to page 2... } }
477 }
478 @end lilypond"
479   (let* ((stil (interpret-markup layout props arg))
480          (xextent (ly:stencil-extent stil X))
481          (yextent (ly:stencil-extent stil Y))
482          (old-expr (ly:stencil-expr stil))
483          (link-expr (list 'page-link page-number `(quote ,xextent) `(quote ,yextent))))
484
485     (ly:stencil-add (ly:make-stencil link-expr xextent yextent) stil)))
486
487 (define-markup-command (with-link layout props label arg)
488   (symbol? markup?)
489   #:category other
490   "
491 @cindex referencing page labels in text
492
493 Add a link to the page holding label @var{label} around @var{arg}.  This
494 only works in the PDF backend.
495
496 @lilypond[verbatim,quote]
497 \\markup {
498   \\with-link #'label {
499     \\italic { This links to the page containing the label... }
500   }
501 }
502 @end lilypond"
503   (let* ((arg-stencil (interpret-markup layout props arg))
504          (x-ext (ly:stencil-extent arg-stencil X))
505          (y-ext (ly:stencil-extent arg-stencil Y)))
506     (ly:make-stencil
507      `(delay-stencil-evaluation
508        ,(delay (ly:stencil-expr
509                 (let* ((table (ly:output-def-lookup layout 'label-page-table))
510                        (page-number (if (list? table)
511                                         (assoc-get label table)
512                                         #f))
513                        (link-expr (list 'page-link page-number
514                                         `(quote ,x-ext) `(quote ,y-ext))))
515                   (ly:stencil-add (ly:make-stencil link-expr x-ext y-ext)
516                                   arg-stencil)))))
517      x-ext
518      y-ext)))
519
520
521 (define-markup-command (beam layout props width slope thickness)
522   (number? number? number?)
523   #:category graphic
524   "
525 @cindex drawing beams within text
526
527 Create a beam with the specified parameters.
528 @lilypond[verbatim,quote]
529 \\markup {
530   \\beam #5 #1 #2
531 }
532 @end lilypond"
533   (let* ((y (* slope width))
534          (yext (cons (min 0 y) (max 0 y)))
535          (half (/ thickness 2)))
536
537     (ly:make-stencil
538      `(polygon ',(list
539                   0 (/ thickness -2)
540                   width (+ (* width slope)  (/ thickness -2))
541                   width (+ (* width slope)  (/ thickness 2))
542                   0 (/ thickness 2))
543                ,(ly:output-def-lookup layout 'blot-diameter)
544                #t)
545      (cons 0 width)
546      (cons (+ (- half) (car yext))
547            (+ half (cdr yext))))))
548
549 (define-markup-command (underline layout props arg)
550   (markup?)
551   #:category font
552   #:properties ((thickness 1) (offset 2))
553   "
554 @cindex underlining text
555
556 Underline @var{arg}.  Looks at @code{thickness} to determine line
557 thickness, and @code{offset} to determine line y-offset.
558
559 @lilypond[verbatim,quote]
560 \\markup \\fill-line {
561   \\underline \"underlined\"
562   \\override #'(offset . 5)
563   \\override #'(thickness . 1)
564   \\underline \"underlined\"
565   \\override #'(offset . 1)
566   \\override #'(thickness . 5)
567   \\underline \"underlined\"
568 }
569 @end lilypond"
570   (let* ((thick (ly:output-def-lookup layout 'line-thickness))
571          (underline-thick (* thickness thick))
572          (markup (interpret-markup layout props arg))
573          (x1 (car (ly:stencil-extent markup X)))
574          (x2 (cdr (ly:stencil-extent markup X)))
575          (y (* thick (- offset)))
576          (line (make-line-stencil underline-thick x1 y x2 y)))
577     (ly:stencil-add markup line)))
578
579 (define-markup-command (box layout props arg)
580   (markup?)
581   #:category font
582   #:properties ((thickness 1)
583                 (font-size 0)
584                 (box-padding 0.2))
585   "
586 @cindex enclosing text within a box
587
588 Draw a box round @var{arg}.  Looks at @code{thickness},
589 @code{box-padding} and @code{font-size} properties to determine line
590 thickness and padding around the markup.
591
592 @lilypond[verbatim,quote]
593 \\markup {
594   \\override #'(box-padding . 0.5)
595   \\box
596   \\line { V. S. }
597 }
598 @end lilypond"
599   (let* ((th (* (ly:output-def-lookup layout 'line-thickness)
600                 thickness))
601          (pad (* (magstep font-size) box-padding))
602          (m (interpret-markup layout props arg)))
603     (box-stencil m th pad)))
604
605 (define-markup-command (filled-box layout props xext yext blot)
606   (number-pair? number-pair? number?)
607   #:category graphic
608   "
609 @cindex drawing solid boxes within text
610 @cindex drawing boxes with rounded corners
611
612 Draw a box with rounded corners of dimensions @var{xext} and
613 @var{yext}.  For example,
614 @verbatim
615 \\filled-box #'(-.3 . 1.8) #'(-.3 . 1.8) #0
616 @end verbatim
617 creates a box extending horizontally from -0.3 to 1.8 and
618 vertically from -0.3 up to 1.8, with corners formed from a
619 circle of diameter@tie{}0 (i.e., sharp corners).
620
621 @lilypond[verbatim,quote]
622 \\markup {
623   \\filled-box #'(0 . 4) #'(0 . 4) #0
624   \\filled-box #'(0 . 2) #'(-4 . 2) #0.4
625   \\filled-box #'(1 . 8) #'(0 . 7) #0.2
626   \\with-color #white
627   \\filled-box #'(-4.5 . -2.5) #'(3.5 . 5.5) #0.7
628 }
629 @end lilypond"
630   (ly:round-filled-box
631    xext yext blot))
632
633 (define-markup-command (rounded-box layout props arg)
634   (markup?)
635   #:category graphic
636   #:properties ((thickness 1)
637                 (corner-radius 1)
638                 (font-size 0)
639                 (box-padding 0.5))
640   "@cindex enclosing text in a box with rounded corners
641    @cindex drawing boxes with rounded corners around text
642 Draw a box with rounded corners around @var{arg}.  Looks at @code{thickness},
643 @code{box-padding} and @code{font-size} properties to determine line
644 thickness and padding around the markup; the @code{corner-radius} property
645 makes it possible to define another shape for the corners (default is 1).
646
647 @lilypond[quote,verbatim,relative=2]
648 c4^\\markup {
649   \\rounded-box {
650     Overtura
651   }
652 }
653 c,8. c16 c4 r
654 @end lilypond"
655   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
656                thickness))
657         (pad (* (magstep font-size) box-padding))
658         (m (interpret-markup layout props arg)))
659     (ly:stencil-add (rounded-box-stencil m th pad corner-radius)
660                     m)))
661
662 (define-markup-command (rotate layout props ang arg)
663   (number? markup?)
664   #:category align
665   "
666 @cindex rotating text
667
668 Rotate object with @var{ang} degrees around its center.
669
670 @lilypond[verbatim,quote]
671 \\markup {
672   default
673   \\hspace #2
674   \\rotate #45
675   \\line {
676     rotated 45°
677   }
678 }
679 @end lilypond"
680   (let* ((stil (interpret-markup layout props arg)))
681     (ly:stencil-rotate stil ang 0 0)))
682
683 (define-markup-command (whiteout layout props arg)
684   (markup?)
685   #:category other
686   "
687 @cindex adding a white background to text
688
689 Provide a white background for @var{arg}.
690
691 @lilypond[verbatim,quote]
692 \\markup {
693   \\combine
694     \\filled-box #'(-1 . 10) #'(-3 . 4) #1
695     \\whiteout whiteout
696 }
697 @end lilypond"
698   (stencil-whiteout (interpret-markup layout props arg)))
699
700 (define-markup-command (pad-markup layout props amount arg)
701   (number? markup?)
702   #:category align
703   "
704 @cindex padding text
705 @cindex putting space around text
706
707 Add space around a markup object.
708
709 @lilypond[verbatim,quote]
710 \\markup {
711   \\box {
712     default
713   }
714   \\hspace #2
715   \\box {
716     \\pad-markup #1 {
717       padded
718     }
719   }
720 }
721 @end lilypond"
722   (let*
723       ((stil (interpret-markup layout props arg))
724        (xext (ly:stencil-extent stil X))
725        (yext (ly:stencil-extent stil Y)))
726
727     (ly:make-stencil
728      (ly:stencil-expr stil)
729      (interval-widen xext amount)
730      (interval-widen yext amount))))
731
732 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
733 ;; space
734 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
735
736 (define-markup-command (strut layout props)
737   ()
738   #:category other
739   "
740 @cindex creating vertical spaces in text
741
742 Create a box of the same height as the space in the current font."
743   (let ((m (ly:text-interface::interpret-markup layout props " ")))
744     (ly:make-stencil (ly:stencil-expr m)
745                      '(0 . 0)
746                      (ly:stencil-extent m X)
747                      )))
748
749 (define-markup-command (hspace layout props amount)
750   (number?)
751   #:category align
752   "
753 @cindex creating horizontal spaces in text
754
755 Create an invisible object taking up horizontal space @var{amount}.
756
757 @lilypond[verbatim,quote]
758 \\markup {
759   one
760   \\hspace #2
761   two
762   \\hspace #8
763   three
764 }
765 @end lilypond"
766   (ly:make-stencil "" (cons 0 amount) empty-interval))
767
768 (define-markup-command (vspace layout props amount)
769   (number?)
770   #:category align
771   "
772 @cindex creating vertical spaces in text
773
774 Create an invisible object taking up vertical space
775 of @var{amount} multiplied by 3.
776
777 @lilypond[verbatim,quote]
778 \\markup {
779     \\center-column {
780     one
781     \\vspace #2
782     two
783     \\vspace #5
784     three
785   }
786 }
787 @end lilypond"
788   (let ((amount (* amount 3.0)))
789     (ly:make-stencil "" empty-interval (cons 0 amount))))
790
791
792 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
793 ;; importing graphics.
794 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
795
796 (define-markup-command (stencil layout props stil)
797   (ly:stencil?)
798   #:category other
799   "
800 @cindex importing stencils into text
801
802 Use a stencil as markup.
803
804 @lilypond[verbatim,quote]
805 \\markup {
806   \\stencil #(make-circle-stencil 2 0 #t)
807 }
808 @end lilypond"
809   stil)
810
811 (define bbox-regexp
812   (make-regexp "%%BoundingBox:[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)"))
813
814 (define (get-postscript-bbox string)
815   "Extract the bbox from STRING, or return #f if not present."
816   (let*
817       ((match (regexp-exec bbox-regexp string)))
818
819     (if match
820         (map (lambda (x)
821                (string->number (match:substring match x)))
822              (cdr (iota 5)))
823
824         #f)))
825
826 (define-markup-command (epsfile layout props axis size file-name)
827   (number? number? string?)
828   #:category graphic
829   "
830 @cindex inlining an Encapsulated PostScript image
831
832 Inline an EPS image.  The image is scaled along @var{axis} to
833 @var{size}.
834
835 @lilypond[verbatim,quote]
836 \\markup {
837   \\general-align #Y #DOWN {
838     \\epsfile #X #20 #\"context-example.eps\"
839     \\epsfile #Y #20 #\"context-example.eps\"
840   }
841 }
842 @end lilypond"
843   (if (ly:get-option 'safe)
844       (interpret-markup layout props "not allowed in safe")
845       (eps-file->stencil axis size file-name)
846       ))
847
848 (define-markup-command (postscript layout props str)
849   (string?)
850   #:category graphic
851   "
852 @cindex inserting PostScript directly into text
853 This inserts @var{str} directly into the output as a PostScript
854 command string.
855
856 @lilypond[verbatim,quote]
857 ringsps = #\"
858   0.15 setlinewidth
859   0.9 0.6 moveto
860   0.4 0.6 0.5 0 361 arc
861   stroke
862   1.0 0.6 0.5 0 361 arc
863   stroke
864   \"
865
866 rings = \\markup {
867   \\with-dimensions #'(-0.2 . 1.6) #'(0 . 1.2)
868   \\postscript #ringsps
869 }
870
871 \\relative c'' {
872   c2^\\rings
873   a2_\\rings
874 }
875 @end lilypond"
876   ;; FIXME
877   (ly:make-stencil
878    (list 'embedded-ps
879          (format #f "
880 gsave currentpoint translate
881 0.1 setlinewidth
882  ~a
883 grestore
884 "
885                  str))
886    '(0 . 0) '(0 . 0)))
887
888 (define-markup-command (path layout props thickness commands) (number? list?)
889   #:category graphic
890   #:properties ((line-cap-style 'round)
891                 (line-join-style 'round)
892                 (filled #f))
893   "
894 @cindex paths, drawing
895 @cindex drawing paths
896 Draws a path with line thickness @var{thickness} according to the
897 directions given in @var{commands}.  @var{commands} is a list of
898 lists where the @code{car} of each sublist is a drawing command and
899 the @code{cdr} comprises the associated arguments for each command.
900
901 Line-cap styles and line-join styles may be customized by
902 overriding the @code{line-cap-style} and @code{line-join-style}
903 properties, respectively.  Available line-cap styles are
904 @code{'butt}, @code{'round}, and @code{'square}.  Available
905 line-join styles are @code{'miter}, @code{'round}, and
906 @code{'bevel}.
907
908 The property @code{filled} specifies whether or not the path is
909 filled with color.
910
911 There are seven commands available to use in the list
912 @code{commands}: @code{moveto}, @code{rmoveto}, @code{lineto},
913 @code{rlineto}, @code{curveto}, @code{rcurveto}, and
914 @code{closepath}.  Note that the commands that begin with @emph{r}
915 are the relative variants of the other three commands.
916
917 The commands @code{moveto}, @code{rmoveto}, @code{lineto}, and
918 @code{rlineto} take 2 arguments; they are the X and Y coordinates
919 for the destination point.
920
921 The commands @code{curveto} and @code{rcurveto} create cubic
922 Bézier curves, and take 6 arguments; the first two are the X and Y
923 coordinates for the first control point, the second two are the X
924 and Y coordinates for the second control point, and the last two
925 are the X and Y coordinates for the destination point.
926
927 The @code{closepath} command takes zero arguments and closes the
928 current subpath in the active path.
929
930 Note that a sequence of commands @emph{must} begin with a
931 @code{moveto} or @code{rmoveto} to work with the SVG output.
932
933 @lilypond[verbatim,quote]
934 samplePath =
935   #'((moveto 0 0)
936      (lineto -1 1)
937      (lineto 1 1)
938      (lineto 1 -1)
939      (curveto -5 -5 -5 5 -1 0)
940      (closepath))
941
942 \\markup {
943   \\path #0.25 #samplePath
944 }
945 @end lilypond"
946   (let* ((half-thickness (/ thickness 2))
947          (current-point '(0 . 0))
948          (set-point (lambda (lst) (set! current-point lst)))
949          (relative? (lambda (x)
950                       (string-prefix? "r" (symbol->string (car x)))))
951          ;; For calculating extents, we want to modify the command
952          ;; list so that all coordinates are absolute.
953          (new-commands (map (lambda (x)
954                               (cond
955                                ;; for rmoveto, rlineto
956                                ((and (relative? x) (= 3 (length x)))
957                                 (let ((cp (cons
958                                            (+ (car current-point)
959                                               (second x))
960                                            (+ (cdr current-point)
961                                               (third x)))))
962                                   (set-point cp)
963                                   (list (car cp)
964                                         (cdr cp))))
965                                ;; for rcurveto
966                                ((and (relative? x) (= 7 (length x)))
967                                 (let* ((old-cp current-point)
968                                        (cp (cons
969                                             (+ (car old-cp)
970                                                (sixth x))
971                                             (+ (cdr old-cp)
972                                                (seventh x)))))
973                                   (set-point cp)
974                                   (list (+ (car old-cp) (second x))
975                                         (+ (cdr old-cp) (third x))
976                                         (+ (car old-cp) (fourth x))
977                                         (+ (cdr old-cp) (fifth x))
978                                         (car cp)
979                                         (cdr cp))))
980                                ;; for moveto, lineto
981                                ((= 3 (length x))
982                                 (set-point (cons (second x)
983                                                  (third x)))
984                                 (drop x 1))
985                                ;; for curveto
986                                ((= 7 (length x))
987                                 (set-point (cons (sixth x)
988                                                  (seventh x)))
989                                 (drop x 1))
990                                ;; keep closepath for filtering;
991                                ;; see `without-closepath'.
992                                (else x)))
993                             commands))
994          ;; path-min-max does not accept 0-arg lists,
995          ;; and since closepath does not affect extents, filter
996          ;; out those commands here.
997          (without-closepath (filter (lambda (x)
998                                       (not (equal? 'closepath (car x))))
999                                     new-commands))
1000          (extents (path-min-max
1001                    ;; set the origin to the first moveto
1002                    (list (list-ref (car without-closepath) 0)
1003                          (list-ref (car without-closepath) 1))
1004                    without-closepath))
1005          (X-extent (cons (list-ref extents 0) (list-ref extents 1)))
1006          (Y-extent (cons (list-ref extents 2) (list-ref extents 3)))
1007          (command-list (fold-right append '() commands)))
1008
1009     ;; account for line thickness
1010     (set! X-extent (interval-widen X-extent half-thickness))
1011     (set! Y-extent (interval-widen Y-extent half-thickness))
1012
1013     (ly:make-stencil
1014      `(path ,thickness `(,@',command-list)
1015             ',line-cap-style ',line-join-style ,filled)
1016      X-extent
1017      Y-extent)))
1018
1019 (define-markup-list-command (score-lines layout props score)
1020   (ly:score?)
1021   "
1022 This is the same as the @code{\\score} markup but delivers its
1023 systems as a list of lines.  This is not usually called directly by
1024 the user.  Instead, it is called when the parser encounters
1025 @code{\\score} in a context where only markup lists are allowed.  When
1026 used as the argument of a toplevel @code{\\markuplist}, the result can
1027 be split across pages."
1028   (let ((output (ly:score-embedded-format score layout)))
1029
1030     (if (ly:music-output? output)
1031         (map
1032          (lambda (paper-system)
1033            ;; shift such that the refpoint of the bottom staff of
1034            ;; the first system is the baseline of the score
1035            (ly:stencil-translate-axis
1036             (paper-system-stencil paper-system)
1037             (- (car (paper-system-staff-extents paper-system)))
1038             Y))
1039          (vector->list (ly:paper-score-paper-systems output)))
1040         (begin
1041           (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?"))
1042           '()))))
1043
1044 (define-markup-command (score layout props score)
1045   (ly:score?)
1046   #:category music
1047   #:properties ((baseline-skip))
1048   "
1049 @cindex inserting music into text
1050
1051 Inline an image of music.  The reference point (usually the middle
1052 staff line) of the lowest staff in the top system is placed on the
1053 baseline.
1054
1055 @lilypond[verbatim,quote]
1056 \\markup {
1057   \\score {
1058     \\new PianoStaff <<
1059       \\new Staff \\relative c' {
1060         \\key f \\major
1061         \\time 3/4
1062         \\mark \\markup { Allegro }
1063         f2\\p( a4)
1064         c2( a4)
1065         bes2( g'4)
1066         f8( e) e4 r
1067       }
1068       \\new Staff \\relative c {
1069         \\clef bass
1070         \\key f \\major
1071         \\time 3/4
1072         f8( a c a c a
1073         f c' es c es c)
1074         f,( bes d bes d bes)
1075         f( g bes g bes g)
1076       }
1077     >>
1078     \\layout {
1079       indent = 0.0\\cm
1080       \\context {
1081         \\Score
1082         \\override RehearsalMark
1083           #'break-align-symbols = #'(time-signature key-signature)
1084         \\override RehearsalMark
1085           #'self-alignment-X = #LEFT
1086       }
1087       \\context {
1088         \\Staff
1089         \\override TimeSignature
1090           #'break-align-anchor-alignment = #LEFT
1091       }
1092     }
1093   }
1094 }
1095 @end lilypond"
1096   (stack-stencils Y DOWN baseline-skip
1097                   (score-lines-markup-list layout props score)))
1098
1099 (define-markup-command (null layout props)
1100   ()
1101   #:category other
1102   "
1103 @cindex creating empty text objects
1104
1105 An empty markup with extents of a single point.
1106
1107 @lilypond[verbatim,quote]
1108 \\markup {
1109   \\null
1110 }
1111 @end lilypond"
1112   point-stencil)
1113
1114 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1115 ;; basic formatting.
1116 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1117
1118 (define-markup-command (simple layout props str)
1119   (string?)
1120   #:category font
1121   "
1122 @cindex simple text strings
1123
1124 A simple text string; @code{\\markup @{ foo @}} is equivalent with
1125 @code{\\markup @{ \\simple #\"foo\" @}}.
1126
1127 Note: for creating standard text markup or defining new markup commands,
1128 the use of @code{\\simple} is unnecessary.
1129
1130 @lilypond[verbatim,quote]
1131 \\markup {
1132   \\simple #\"simple\"
1133   \\simple #\"text\"
1134   \\simple #\"strings\"
1135 }
1136 @end lilypond"
1137   (interpret-markup layout props str))
1138
1139 (define-markup-command (tied-lyric layout props str)
1140   (string?)
1141   #:category music
1142   #:properties ((word-space))
1143   "
1144 @cindex simple text strings with tie characters
1145
1146 Like simple-markup, but use tie characters for @q{~} tilde symbols.
1147
1148 @lilypond[verbatim,quote]
1149 \\markup \\column {
1150   \\tied-lyric #\"Siam navi~all'onde~algenti Lasciate~in abbandono\"
1151   \\tied-lyric #\"Impetuosi venti I nostri~affetti sono\"
1152   \\tied-lyric #\"Ogni diletto~e scoglio Tutta la vita~e~un mar.\"
1153 }
1154 @end lilypond"
1155   (define (replace-ties tie str)
1156     (if (string-contains str "~")
1157         (let*
1158             ((half-space (/ word-space 2))
1159              (parts (string-split str #\~))
1160              (tie-str (markup #:hspace half-space
1161                               #:musicglyph tie
1162                               #:hspace half-space))
1163              (joined  (list-join parts tie-str)))
1164           (make-concat-markup joined))
1165         str))
1166
1167   (define short-tie-regexp (make-regexp "~[^.]~"))
1168   (define (match-short str) (regexp-exec short-tie-regexp str))
1169
1170   (define (replace-short str mkp)
1171     (let ((match (match-short str)))
1172       (if (not match)
1173           (make-concat-markup (list
1174                                mkp
1175                                (replace-ties "ties.lyric.default" str)))
1176           (let ((new-str (match:suffix match))
1177                 (new-mkp (make-concat-markup (list
1178                                               mkp
1179                                               (replace-ties "ties.lyric.default"
1180                                                             (match:prefix match))
1181                                               (replace-ties "ties.lyric.short"
1182                                                             (match:substring match))))))
1183             (replace-short new-str new-mkp)))))
1184
1185   (interpret-markup layout
1186                     props
1187                     (replace-short str (markup))))
1188
1189 (define-public empty-markup
1190   (make-simple-markup ""))
1191
1192 ;; helper for justifying lines.
1193 (define (get-fill-space word-count line-width word-space text-widths)
1194   "Calculate the necessary paddings between each two adjacent texts.
1195   The lengths of all texts are stored in @var{text-widths}.
1196   The normal formula for the padding between texts a and b is:
1197   padding = line-width/(word-count - 1) - (length(a) + length(b))/2
1198   The first and last padding have to be calculated specially using the
1199   whole length of the first or last text.
1200   All paddings are checked to be at least word-space, to ensure that
1201   no texts collide.
1202   Return a list of paddings."
1203   (cond
1204    ((null? text-widths) '())
1205
1206    ;; special case first padding
1207    ((= (length text-widths) word-count)
1208     (cons
1209      (- (- (/ line-width (1- word-count)) (car text-widths))
1210         (/ (car (cdr text-widths)) 2))
1211      (get-fill-space word-count line-width word-space (cdr text-widths))))
1212    ;; special case last padding
1213    ((= (length text-widths) 2)
1214     (list (- (/ line-width (1- word-count))
1215              (+ (/ (car text-widths) 2) (car (cdr text-widths)))) 0))
1216    (else
1217     (let ((default-padding
1218             (- (/ line-width (1- word-count))
1219                (/ (+ (car text-widths) (car (cdr text-widths))) 2))))
1220       (cons
1221        (if (> word-space default-padding)
1222            word-space
1223            default-padding)
1224        (get-fill-space word-count line-width word-space (cdr text-widths)))))))
1225
1226 (define-markup-command (fill-line layout props args)
1227   (markup-list?)
1228   #:category align
1229   #:properties ((text-direction RIGHT)
1230                 (word-space 0.6)
1231                 (line-width #f))
1232   "Put @var{markups} in a horizontal line of width @var{line-width}.
1233 The markups are spaced or flushed to fill the entire line.
1234 If there are no arguments, return an empty stencil.
1235
1236 @lilypond[verbatim,quote]
1237 \\markup {
1238   \\column {
1239     \\fill-line {
1240       Words evenly spaced across the page
1241     }
1242     \\null
1243     \\fill-line {
1244       \\line { Text markups }
1245       \\line {
1246         \\italic { evenly spaced }
1247       }
1248       \\line { across the page }
1249     }
1250   }
1251 }
1252 @end lilypond"
1253   (let* ((orig-stencils (interpret-markup-list layout props args))
1254          (stencils
1255           (map (lambda (stc)
1256                  (if (ly:stencil-empty? stc)
1257                      point-stencil
1258                      stc)) orig-stencils))
1259          (text-widths
1260           (map (lambda (stc)
1261                  (if (ly:stencil-empty? stc)
1262                      0.0
1263                      (interval-length (ly:stencil-extent stc X))))
1264                stencils))
1265          (text-width (apply + text-widths))
1266          (word-count (length stencils))
1267          (line-width (or line-width (ly:output-def-lookup layout 'line-width)))
1268          (fill-space
1269           (cond
1270            ((= word-count 1)
1271             (list
1272              (/ (- line-width text-width) 2)
1273              (/ (- line-width text-width) 2)))
1274            ((= word-count 2)
1275             (list
1276              (- line-width text-width)))
1277            (else
1278             (get-fill-space word-count line-width word-space text-widths))))
1279
1280          (line-contents (if (= word-count 1)
1281                             (list
1282                              point-stencil
1283                              (car stencils)
1284                              point-stencil)
1285                             stencils)))
1286
1287     (if (null? (remove ly:stencil-empty? orig-stencils))
1288         empty-stencil
1289         (begin
1290           (if (= text-direction LEFT)
1291               (set! line-contents (reverse line-contents)))
1292           (set! line-contents
1293                 (stack-stencils-padding-list
1294                  X RIGHT fill-space line-contents))
1295           (if (> word-count 1)
1296               ;; shift s.t. stencils align on the left edge, even if
1297               ;; first stencil had negative X-extent (e.g. center-column)
1298               ;; (if word-count = 1, X-extents are already normalized in
1299               ;; the definition of line-contents)
1300               (set! line-contents
1301                     (ly:stencil-translate-axis
1302                      line-contents
1303                      (- (car (ly:stencil-extent (car stencils) X)))
1304                      X)))
1305           line-contents))))
1306
1307 (define-markup-command (line layout props args)
1308   (markup-list?)
1309   #:category align
1310   #:properties ((word-space)
1311                 (text-direction RIGHT))
1312   "Put @var{args} in a horizontal line.  The property @code{word-space}
1313 determines the space between markups in @var{args}.
1314
1315 @lilypond[verbatim,quote]
1316 \\markup {
1317   \\line {
1318     one two three
1319   }
1320 }
1321 @end lilypond"
1322   (let ((stencils (interpret-markup-list layout props args)))
1323     (if (= text-direction LEFT)
1324         (set! stencils (reverse stencils)))
1325     (stack-stencil-line word-space stencils)))
1326
1327 (define-markup-command (concat layout props args)
1328   (markup-list?)
1329   #:category align
1330   "
1331 @cindex concatenating text
1332 @cindex ligatures in text
1333
1334 Concatenate @var{args} in a horizontal line, without spaces in between.
1335 Strings and simple markups are concatenated on the input level, allowing
1336 ligatures.  For example, @code{\\concat @{ \"f\" \\simple #\"i\" @}} is
1337 equivalent to @code{\"fi\"}.
1338
1339 @lilypond[verbatim,quote]
1340 \\markup {
1341   \\concat {
1342     one
1343     two
1344     three
1345   }
1346 }
1347 @end lilypond"
1348   (define (concat-string-args arg-list)
1349     (fold-right (lambda (arg result-list)
1350                   (let ((result (if (pair? result-list)
1351                                     (car result-list)
1352                                     '())))
1353                     (if (and (pair? arg) (eqv? (car arg) simple-markup))
1354                         (set! arg (cadr arg)))
1355                     (if (and (string? result) (string? arg))
1356                         (cons (string-append arg result) (cdr result-list))
1357                         (cons arg result-list))))
1358                 '()
1359                 arg-list))
1360
1361   (interpret-markup layout
1362                     (prepend-alist-chain 'word-space 0 props)
1363                     (make-line-markup
1364                      (make-override-lines-markup-list
1365                       (cons 'word-space
1366                             (chain-assoc-get 'word-space props))
1367                       (if (markup-command-list? args)
1368                           args
1369                           (concat-string-args args))))))
1370
1371 (define (wordwrap-stencils stencils
1372                            justify base-space line-width text-dir)
1373   "Perform simple wordwrap, return stencil of each line."
1374   (define space (if justify
1375                     ;; justify only stretches lines.
1376                     (* 0.7 base-space)
1377                     base-space))
1378   (define (stencil-space stencil line-start)
1379     (if (ly:stencil-empty? stencil X)
1380         0
1381         (cdr (ly:stencil-extent
1382               (ly:stencil-stack (if line-start
1383                                     empty-stencil
1384                                     point-stencil)
1385                                 X RIGHT stencil)
1386               X))))
1387   (define (take-list width space stencils
1388                      accumulator accumulated-width)
1389     "Return (head-list . tail) pair, with head-list fitting into width"
1390     (if (null? stencils)
1391         (cons accumulator stencils)
1392         (let* ((first (car stencils))
1393                (first-wid (stencil-space first (null? accumulator)))
1394                (newwid (+ (if (or (ly:stencil-empty? first Y)
1395                                   (ly:stencil-empty? first X))
1396                               0 space)
1397                           first-wid accumulated-width)))
1398           (if (or (null? accumulator)
1399                   (< newwid width))
1400               (take-list width space
1401                          (cdr stencils)
1402                          (cons first accumulator)
1403                          newwid)
1404               (cons accumulator stencils)))))
1405   (let loop ((lines '())
1406              (todo stencils))
1407     (let* ((line-break (take-list line-width space todo
1408                                   '() 0.0))
1409            (line-stencils (car line-break))
1410            (space-left (- line-width
1411                           (stencil-space
1412                            (stack-stencil-line 0 line-stencils)
1413                            #t)))
1414            (line-words (count (lambda (s) (not (or (ly:stencil-empty? s Y)
1415                                                    (ly:stencil-empty? s X))))
1416                               line-stencils))
1417            (line-word-space (cond ((not justify) space)
1418                                   ;; don't stretch last line of paragraph.
1419                                   ;; hmmm . bug - will overstretch the last line in some case.
1420                                   ((null? (cdr line-break))
1421                                    base-space)
1422                                   ((< line-words 2) space)
1423                                   (else (/ space-left (1- line-words)))))
1424            (line (stack-stencil-line line-word-space
1425                                      (if (= text-dir RIGHT)
1426                                          (reverse line-stencils)
1427                                          line-stencils))))
1428       (if (pair? (cdr line-break))
1429           (loop (cons line lines)
1430                 (cdr line-break))
1431           (begin
1432             (if (= text-dir LEFT)
1433                 (set! line
1434                       (ly:stencil-translate-axis
1435                        line
1436                        (- line-width (interval-end (ly:stencil-extent line X)))
1437                        X)))
1438             (reverse (cons line lines)))))))
1439
1440 (define-markup-list-command (wordwrap-internal layout props justify args)
1441   (boolean? markup-list?)
1442   #:properties ((line-width #f)
1443                 (word-space)
1444                 (text-direction RIGHT))
1445   "Internal markup list command used to define @code{\\justify} and @code{\\wordwrap}."
1446   (wordwrap-stencils (interpret-markup-list layout props args)
1447                      justify
1448                      word-space
1449                      (or line-width
1450                          (ly:output-def-lookup layout 'line-width))
1451                      text-direction))
1452
1453 (define-markup-command (justify layout props args)
1454   (markup-list?)
1455   #:category align
1456   #:properties ((baseline-skip)
1457                 wordwrap-internal-markup-list)
1458   "
1459 @cindex justifying text
1460
1461 Like @code{\\wordwrap}, but with lines stretched to justify the margins.
1462 Use @code{\\override #'(line-width . @var{X})} to set the line width;
1463 @var{X}@tie{}is the number of staff spaces.
1464
1465 @lilypond[verbatim,quote]
1466 \\markup {
1467   \\justify {
1468     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
1469     do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1470     Ut enim ad minim veniam, quis nostrud exercitation ullamco
1471     laboris nisi ut aliquip ex ea commodo consequat.
1472   }
1473 }
1474 @end lilypond"
1475   (stack-lines DOWN 0.0 baseline-skip
1476                (wordwrap-internal-markup-list layout props #t args)))
1477
1478 (define-markup-command (wordwrap layout props args)
1479   (markup-list?)
1480   #:category align
1481   #:properties ((baseline-skip)
1482                 wordwrap-internal-markup-list)
1483   "Simple wordwrap.  Use @code{\\override #'(line-width . @var{X})} to set
1484 the line width, where @var{X} is the number of staff spaces.
1485
1486 @lilypond[verbatim,quote]
1487 \\markup {
1488   \\wordwrap {
1489     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
1490     do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1491     Ut enim ad minim veniam, quis nostrud exercitation ullamco
1492     laboris nisi ut aliquip ex ea commodo consequat.
1493   }
1494 }
1495 @end lilypond"
1496   (stack-lines DOWN 0.0 baseline-skip
1497                (wordwrap-internal-markup-list layout props #f args)))
1498
1499 (define-markup-list-command (wordwrap-string-internal layout props justify arg)
1500   (boolean? string?)
1501   #:properties ((line-width)
1502                 (word-space)
1503                 (text-direction RIGHT))
1504   "Internal markup list command used to define @code{\\justify-string} and
1505 @code{\\wordwrap-string}."
1506   (let* ((para-strings (regexp-split
1507                         (string-regexp-substitute
1508                          "\r" "\n"
1509                          (string-regexp-substitute "\r\n" "\n" arg))
1510                         "\n[ \t\n]*\n[ \t\n]*"))
1511          (list-para-words (map (lambda (str)
1512                                  (regexp-split str "[ \t\n]+"))
1513                                para-strings))
1514          (para-lines (map (lambda (words)
1515                             (let* ((stencils
1516                                     (map (lambda (x)
1517                                            (interpret-markup layout props x))
1518                                          words)))
1519                               (wordwrap-stencils stencils
1520                                                  justify word-space
1521                                                  line-width text-direction)))
1522                           list-para-words)))
1523     (apply append para-lines)))
1524
1525 (define-markup-command (wordwrap-string layout props arg)
1526   (string?)
1527   #:category align
1528   #:properties ((baseline-skip)
1529                 wordwrap-string-internal-markup-list)
1530   "Wordwrap a string.  Paragraphs may be separated with double newlines.
1531
1532 @lilypond[verbatim,quote]
1533 \\markup {
1534   \\override #'(line-width . 40)
1535   \\wordwrap-string #\"Lorem ipsum dolor sit amet, consectetur
1536       adipisicing elit, sed do eiusmod tempor incididunt ut labore
1537       et dolore magna aliqua.
1538
1539
1540       Ut enim ad minim veniam, quis nostrud exercitation ullamco
1541       laboris nisi ut aliquip ex ea commodo consequat.
1542
1543
1544       Excepteur sint occaecat cupidatat non proident, sunt in culpa
1545       qui officia deserunt mollit anim id est laborum\"
1546 }
1547 @end lilypond"
1548   (stack-lines DOWN 0.0 baseline-skip
1549                (wordwrap-string-internal-markup-list layout props #f arg)))
1550
1551 (define-markup-command (justify-string layout props arg)
1552   (string?)
1553   #:category align
1554   #:properties ((baseline-skip)
1555                 wordwrap-string-internal-markup-list)
1556   "Justify a string.  Paragraphs may be separated with double newlines
1557
1558 @lilypond[verbatim,quote]
1559 \\markup {
1560   \\override #'(line-width . 40)
1561   \\justify-string #\"Lorem ipsum dolor sit amet, consectetur
1562       adipisicing elit, sed do eiusmod tempor incididunt ut labore
1563       et dolore magna aliqua.
1564
1565
1566       Ut enim ad minim veniam, quis nostrud exercitation ullamco
1567       laboris nisi ut aliquip ex ea commodo consequat.
1568
1569
1570       Excepteur sint occaecat cupidatat non proident, sunt in culpa
1571       qui officia deserunt mollit anim id est laborum\"
1572 }
1573 @end lilypond"
1574   (stack-lines DOWN 0.0 baseline-skip
1575                (wordwrap-string-internal-markup-list layout props #t arg)))
1576
1577 (define-markup-command (wordwrap-field layout props symbol)
1578   (symbol?)
1579   #:category align
1580   "Wordwrap the data which has been assigned to @var{symbol}.
1581
1582 @lilypond[verbatim,quote]
1583 \\header {
1584   title = \"My title\"
1585   myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing
1586     elit, sed do eiusmod tempor incididunt ut labore et dolore
1587     magna aliqua.  Ut enim ad minim veniam, quis nostrud
1588     exercitation ullamco laboris nisi ut aliquip ex ea commodo
1589     consequat.\"
1590 }
1591
1592 \\paper {
1593   bookTitleMarkup = \\markup {
1594     \\column {
1595       \\fill-line { \\fromproperty #'header:title }
1596       \\null
1597       \\wordwrap-field #'header:myText
1598     }
1599   }
1600 }
1601
1602 \\markup {
1603   \\null
1604 }
1605 @end lilypond"
1606   (let* ((m (chain-assoc-get symbol props)))
1607     (if (string? m)
1608         (wordwrap-string-markup layout props m)
1609         empty-stencil)))
1610
1611 (define-markup-command (justify-field layout props symbol)
1612   (symbol?)
1613   #:category align
1614   "Justify the data which has been assigned to @var{symbol}.
1615
1616 @lilypond[verbatim,quote]
1617 \\header {
1618   title = \"My title\"
1619   myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing
1620     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
1621     aliqua.  Ut enim ad minim veniam, quis nostrud exercitation ullamco
1622     laboris nisi ut aliquip ex ea commodo consequat.\"
1623 }
1624
1625 \\paper {
1626   bookTitleMarkup = \\markup {
1627     \\column {
1628       \\fill-line { \\fromproperty #'header:title }
1629       \\null
1630       \\justify-field #'header:myText
1631     }
1632   }
1633 }
1634
1635 \\markup {
1636   \\null
1637 }
1638 @end lilypond"
1639   (let* ((m (chain-assoc-get symbol props)))
1640     (if (string? m)
1641         (justify-string-markup layout props m)
1642         empty-stencil)))
1643
1644 (define-markup-command (combine layout props arg1 arg2)
1645   (markup? markup?)
1646   #:category align
1647   "
1648 @cindex merging text
1649
1650 Print two markups on top of each other.
1651
1652 Note: @code{\\combine} cannot take a list of markups enclosed in
1653 curly braces as an argument; the follow example will not compile:
1654
1655 @example
1656 \\combine @{ a list @}
1657 @end example
1658
1659 @lilypond[verbatim,quote]
1660 \\markup {
1661   \\fontsize #5
1662   \\override #'(thickness . 2)
1663   \\combine
1664     \\draw-line #'(0 . 4)
1665     \\arrow-head #Y #DOWN ##f
1666 }
1667 @end lilypond"
1668   (let* ((s1 (interpret-markup layout props arg1))
1669          (s2 (interpret-markup layout props arg2)))
1670     (ly:stencil-add s1 s2)))
1671
1672 ;;
1673 ;; TODO: should extract baseline-skip from each argument somehow..
1674 ;;
1675 (define-markup-command (column layout props args)
1676   (markup-list?)
1677   #:category align
1678   #:properties ((baseline-skip))
1679   "
1680 @cindex stacking text in a column
1681
1682 Stack the markups in @var{args} vertically.  The property
1683 @code{baseline-skip} determines the space between markups
1684 in @var{args}.
1685
1686 @lilypond[verbatim,quote]
1687 \\markup {
1688   \\column {
1689     one
1690     two
1691     three
1692   }
1693 }
1694 @end lilypond"
1695   (let ((arg-stencils (interpret-markup-list layout props args)))
1696     (stack-lines -1 0.0 baseline-skip arg-stencils)))
1697
1698 (define-markup-command (dir-column layout props args)
1699   (markup-list?)
1700   #:category align
1701   #:properties ((direction)
1702                 (baseline-skip))
1703   "
1704 @cindex changing direction of text columns
1705
1706 Make a column of @var{args}, going up or down, depending on the
1707 setting of the @code{direction} layout property.
1708
1709 @lilypond[verbatim,quote]
1710 \\markup {
1711   \\override #`(direction . ,UP) {
1712     \\dir-column {
1713       going up
1714     }
1715   }
1716   \\hspace #1
1717   \\dir-column {
1718     going down
1719   }
1720   \\hspace #1
1721   \\override #'(direction . 1) {
1722     \\dir-column {
1723       going up
1724     }
1725   }
1726 }
1727 @end lilypond"
1728   (stack-lines (if (number? direction) direction -1)
1729                0.0
1730                baseline-skip
1731                (interpret-markup-list layout props args)))
1732
1733 (define (general-column align-dir baseline mols)
1734   "Stack @var{mols} vertically, aligned to  @var{align-dir} horizontally."
1735
1736   (let* ((aligned-mols (map (lambda (x) (ly:stencil-aligned-to x X align-dir)) mols))
1737          (stacked-stencil (stack-lines -1 0.0 baseline aligned-mols))
1738          (stacked-extent (ly:stencil-extent stacked-stencil X)))
1739     (ly:stencil-translate-axis stacked-stencil (- (car stacked-extent)) X )))
1740
1741 (define-markup-command (center-column layout props args)
1742   (markup-list?)
1743   #:category align
1744   #:properties ((baseline-skip))
1745   "
1746 @cindex centering a column of text
1747
1748 Put @code{args} in a centered column.
1749
1750 @lilypond[verbatim,quote]
1751 \\markup {
1752   \\center-column {
1753     one
1754     two
1755     three
1756   }
1757 }
1758 @end lilypond"
1759   (general-column CENTER baseline-skip (interpret-markup-list layout props args)))
1760
1761 (define-markup-command (left-column layout props args)
1762   (markup-list?)
1763   #:category align
1764   #:properties ((baseline-skip))
1765   "
1766 @cindex text columns, left-aligned
1767
1768 Put @code{args} in a left-aligned column.
1769
1770 @lilypond[verbatim,quote]
1771 \\markup {
1772   \\left-column {
1773     one
1774     two
1775     three
1776   }
1777 }
1778 @end lilypond"
1779   (general-column LEFT baseline-skip (interpret-markup-list layout props args)))
1780
1781 (define-markup-command (right-column layout props args)
1782   (markup-list?)
1783   #:category align
1784   #:properties ((baseline-skip))
1785   "
1786 @cindex text columns, right-aligned
1787
1788 Put @code{args} in a right-aligned column.
1789
1790 @lilypond[verbatim,quote]
1791 \\markup {
1792   \\right-column {
1793     one
1794     two
1795     three
1796   }
1797 }
1798 @end lilypond"
1799   (general-column RIGHT baseline-skip (interpret-markup-list layout props args)))
1800
1801 (define-markup-command (vcenter layout props arg)
1802   (markup?)
1803   #:category align
1804   "
1805 @cindex vertically centering text
1806
1807 Align @code{arg} to its Y@tie{}center.
1808
1809 @lilypond[verbatim,quote]
1810 \\markup {
1811   one
1812   \\vcenter
1813   two
1814   three
1815 }
1816 @end lilypond"
1817   (let* ((mol (interpret-markup layout props arg)))
1818     (ly:stencil-aligned-to mol Y CENTER)))
1819
1820 (define-markup-command (center-align layout props arg)
1821   (markup?)
1822   #:category align
1823   "
1824 @cindex horizontally centering text
1825
1826 Align @code{arg} to its X@tie{}center.
1827
1828 @lilypond[verbatim,quote]
1829 \\markup {
1830   \\column {
1831     one
1832     \\center-align
1833     two
1834     three
1835   }
1836 }
1837 @end lilypond"
1838   (let* ((mol (interpret-markup layout props arg)))
1839     (ly:stencil-aligned-to mol X CENTER)))
1840
1841 (define-markup-command (right-align layout props arg)
1842   (markup?)
1843   #:category align
1844   "
1845 @cindex right aligning text
1846
1847 Align @var{arg} on its right edge.
1848
1849 @lilypond[verbatim,quote]
1850 \\markup {
1851   \\column {
1852     one
1853     \\right-align
1854     two
1855     three
1856   }
1857 }
1858 @end lilypond"
1859   (let* ((m (interpret-markup layout props arg)))
1860     (ly:stencil-aligned-to m X RIGHT)))
1861
1862 (define-markup-command (left-align layout props arg)
1863   (markup?)
1864   #:category align
1865   "
1866 @cindex left aligning text
1867
1868 Align @var{arg} on its left edge.
1869
1870 @lilypond[verbatim,quote]
1871 \\markup {
1872   \\column {
1873     one
1874     \\left-align
1875     two
1876     three
1877   }
1878 }
1879 @end lilypond"
1880   (let* ((m (interpret-markup layout props arg)))
1881     (ly:stencil-aligned-to m X LEFT)))
1882
1883 (define-markup-command (general-align layout props axis dir arg)
1884   (integer? number? markup?)
1885   #:category align
1886   "
1887 @cindex controlling general text alignment
1888
1889 Align @var{arg} in @var{axis} direction to the @var{dir} side.
1890
1891 @lilypond[verbatim,quote]
1892 \\markup {
1893   \\column {
1894     one
1895     \\general-align #X #LEFT
1896     two
1897     three
1898     \\null
1899     one
1900     \\general-align #X #CENTER
1901     two
1902     three
1903     \\null
1904     \\line {
1905       one
1906       \\general-align #Y #UP
1907       two
1908       three
1909     }
1910     \\null
1911     \\line {
1912       one
1913       \\general-align #Y #3.2
1914       two
1915       three
1916     }
1917   }
1918 }
1919 @end lilypond"
1920   (let* ((m (interpret-markup layout props arg)))
1921     (ly:stencil-aligned-to m axis dir)))
1922
1923 (define-markup-command (halign layout props dir arg)
1924   (number? markup?)
1925   #:category align
1926   "
1927 @cindex setting horizontal text alignment
1928
1929 Set horizontal alignment.  If @var{dir} is @w{@code{-1}}, then it is
1930 left-aligned, while @code{+1} is right.  Values in between interpolate
1931 alignment accordingly.
1932
1933 @lilypond[verbatim,quote]
1934 \\markup {
1935   \\column {
1936     one
1937     \\halign #LEFT
1938     two
1939     three
1940     \\null
1941     one
1942     \\halign #CENTER
1943     two
1944     three
1945     \\null
1946     one
1947     \\halign #RIGHT
1948     two
1949     three
1950     \\null
1951     one
1952     \\halign #-5
1953     two
1954     three
1955   }
1956 }
1957 @end lilypond"
1958   (let* ((m (interpret-markup layout props arg)))
1959     (ly:stencil-aligned-to m X dir)))
1960
1961 (define-markup-command (with-dimensions layout props x y arg)
1962   (number-pair? number-pair? markup?)
1963   #:category other
1964   "
1965 @cindex setting extent of text objects
1966
1967 Set the dimensions of @var{arg} to @var{x} and@tie{}@var{y}."
1968   (let* ((m (interpret-markup layout props arg)))
1969     (ly:make-stencil (ly:stencil-expr m) x y)))
1970
1971 (define-markup-command (pad-around layout props amount arg)
1972   (number? markup?)
1973   #:category align
1974   "Add padding @var{amount} all around @var{arg}.
1975
1976 @lilypond[verbatim,quote]
1977 \\markup {
1978   \\box {
1979     default
1980   }
1981   \\hspace #2
1982   \\box {
1983     \\pad-around #0.5 {
1984       padded
1985     }
1986   }
1987 }
1988 @end lilypond"
1989   (let* ((m (interpret-markup layout props arg))
1990          (x (ly:stencil-extent m X))
1991          (y (ly:stencil-extent m Y)))
1992     (ly:make-stencil (ly:stencil-expr m)
1993                      (interval-widen x amount)
1994                      (interval-widen y amount))))
1995
1996 (define-markup-command (pad-x layout props amount arg)
1997   (number? markup?)
1998   #:category align
1999   "
2000 @cindex padding text horizontally
2001
2002 Add padding @var{amount} around @var{arg} in the X@tie{}direction.
2003
2004 @lilypond[verbatim,quote]
2005 \\markup {
2006   \\box {
2007     default
2008   }
2009   \\hspace #4
2010   \\box {
2011     \\pad-x #2 {
2012       padded
2013     }
2014   }
2015 }
2016 @end lilypond"
2017   (let* ((m (interpret-markup layout props arg))
2018          (x (ly:stencil-extent m X))
2019          (y (ly:stencil-extent m Y)))
2020     (ly:make-stencil (ly:stencil-expr m)
2021                      (interval-widen x amount)
2022                      y)))
2023
2024 (define-markup-command (put-adjacent layout props axis dir arg1 arg2)
2025   (integer? ly:dir? markup? markup?)
2026   #:category align
2027   "Put @var{arg2} next to @var{arg1}, without moving @var{arg1}."
2028   (let ((m1 (interpret-markup layout props arg1))
2029         (m2 (interpret-markup layout props arg2)))
2030     (ly:stencil-combine-at-edge m1 axis dir m2 0.0)))
2031
2032 (define-markup-command (transparent layout props arg)
2033   (markup?)
2034   #:category other
2035   "Make @var{arg} transparent.
2036
2037 @lilypond[verbatim,quote]
2038 \\markup {
2039   \\transparent {
2040     invisible text
2041   }
2042 }
2043 @end lilypond"
2044   (let* ((m (interpret-markup layout props arg))
2045          (x (ly:stencil-extent m X))
2046          (y (ly:stencil-extent m Y)))
2047     (ly:make-stencil "" x y)))
2048
2049 (define-markup-command (pad-to-box layout props x-ext y-ext arg)
2050   (number-pair? number-pair? markup?)
2051   #:category align
2052   "Make @var{arg} take at least @var{x-ext}, @var{y-ext} space.
2053
2054 @lilypond[verbatim,quote]
2055 \\markup {
2056   \\box {
2057     default
2058   }
2059   \\hspace #4
2060   \\box {
2061     \\pad-to-box #'(0 . 10) #'(0 . 3) {
2062       padded
2063     }
2064   }
2065 }
2066 @end lilypond"
2067   (let* ((m (interpret-markup layout props arg))
2068          (x (ly:stencil-extent m X))
2069          (y (ly:stencil-extent m Y)))
2070     (ly:make-stencil (ly:stencil-expr m)
2071                      (interval-union x-ext x)
2072                      (interval-union y-ext y))))
2073
2074 (define-markup-command (hcenter-in layout props length arg)
2075   (number? markup?)
2076   #:category align
2077   "Center @var{arg} horizontally within a box of extending
2078 @var{length}/2 to the left and right.
2079
2080 @lilypond[quote,verbatim]
2081 \\new StaffGroup <<
2082   \\new Staff {
2083     \\set Staff.instrumentName = \\markup {
2084       \\hcenter-in #12
2085       Oboe
2086     }
2087     c''1
2088   }
2089   \\new Staff {
2090     \\set Staff.instrumentName = \\markup {
2091       \\hcenter-in #12
2092       Bassoon
2093     }
2094     \\clef tenor
2095     c'1
2096   }
2097 >>
2098 @end lilypond"
2099   (interpret-markup layout props
2100                     (make-pad-to-box-markup
2101                      (cons (/ length -2) (/ length 2))
2102                      '(0 . 0)
2103                      (make-center-align-markup arg))))
2104
2105 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2106 ;; property
2107 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2108
2109 (define-markup-command (property-recursive layout props symbol)
2110   (symbol?)
2111   #:category other
2112   "Print out a warning when a header field markup contains some recursive
2113 markup definition."
2114   (ly:warning "Recursive definition of property ~a detected!" symbol)
2115   empty-stencil)
2116
2117 (define-markup-command (fromproperty layout props symbol)
2118   (symbol?)
2119   #:category other
2120   "Read the @var{symbol} from property settings, and produce a stencil
2121 from the markup contained within.  If @var{symbol} is not defined, it
2122 returns an empty markup.
2123
2124 @lilypond[verbatim,quote]
2125 \\header {
2126   myTitle = \"myTitle\"
2127   title = \\markup {
2128     from
2129     \\italic
2130     \\fromproperty #'header:myTitle
2131   }
2132 }
2133 \\markup {
2134   \\null
2135 }
2136 @end lilypond"
2137   (let ((m (chain-assoc-get symbol props)))
2138     (if (markup? m)
2139         ;; prevent infinite loops by clearing the interpreted property:
2140         (interpret-markup layout (cons (list (cons symbol `(,property-recursive-markup ,symbol))) props) m)
2141         empty-stencil)))
2142
2143 (define-markup-command (on-the-fly layout props procedure arg)
2144   (procedure? markup?)
2145   #:category other
2146   "Apply the @var{procedure} markup command to @var{arg}.
2147 @var{procedure} should take a single argument."
2148   (let ((anonymous-with-signature (lambda (layout props arg) (procedure layout props arg))))
2149     (set-object-property! anonymous-with-signature
2150                           'markup-signature
2151                           (list markup?))
2152     (interpret-markup layout props (list anonymous-with-signature arg))))
2153
2154 (define-markup-command (footnote layout props mkup note)
2155   (markup? markup?)
2156   #:category other
2157   "Have footnote @var{note} act as an annotation to the markup @var{mkup}.
2158
2159 @lilypond[verbatim,quote]
2160 \\markup {
2161   \\auto-footnote a b
2162   \\override #'(padding . 0.2)
2163   \\auto-footnote c d
2164 }
2165 @end lilypond
2166 The footnote will not be annotated automatically."
2167   (ly:stencil-combine-at-edge
2168    (interpret-markup layout props mkup)
2169    X
2170    RIGHT
2171    (ly:make-stencil
2172     `(footnote (gensym "footnote") #f ,(interpret-markup layout props note))
2173     '(0 . 0)
2174     '(0 . 0))
2175    0.0))
2176
2177 (define-markup-command (auto-footnote layout props mkup note)
2178   (markup? markup?)
2179   #:category other
2180   #:properties ((raise 0.5)
2181                 (padding 0.0))
2182   "Have footnote @var{note} act as an annotation to the markup @var{mkup}.
2183
2184 @lilypond[verbatim,quote]
2185 \\markup {
2186   \\auto-footnote a b
2187   \\override #'(padding . 0.2)
2188   \\auto-footnote c d
2189 }
2190 @end lilypond
2191 The footnote will be annotated automatically."
2192   (let* ((markup-stencil (interpret-markup layout props mkup))
2193          (footnote-hash (gensym "footnote"))
2194          (stencil-seed 0)
2195          (gauge-stencil (interpret-markup
2196                          layout
2197                          props
2198                          ((ly:output-def-lookup
2199                            layout
2200                            'footnote-numbering-function)
2201                           stencil-seed)))
2202          (x-ext (ly:stencil-extent gauge-stencil X))
2203          (y-ext (ly:stencil-extent gauge-stencil Y))
2204          (footnote-number
2205           `(delay-stencil-evaluation
2206             ,(delay
2207                (ly:stencil-expr
2208                 (let* ((table
2209                         (ly:output-def-lookup layout
2210                                               'number-footnote-table))
2211                        (footnote-stencil (if (list? table)
2212                                              (assoc-get footnote-hash
2213                                                         table)
2214                                              empty-stencil))
2215                        (footnote-stencil (if (ly:stencil? footnote-stencil)
2216                                              footnote-stencil
2217                                              (begin
2218                                                (ly:programming-error
2219                                                 "Cannot find correct footnote for a markup object.")
2220                                                empty-stencil)))
2221                        (gap (- (interval-length x-ext)
2222                                (interval-length
2223                                 (ly:stencil-extent footnote-stencil X))))
2224                        (y-trans (- (+ (cdr y-ext)
2225                                       raise)
2226                                    (cdr (ly:stencil-extent footnote-stencil
2227                                                            Y)))))
2228                   (ly:stencil-translate footnote-stencil
2229                                         (cons gap y-trans)))))))
2230          (main-stencil (ly:stencil-combine-at-edge
2231                         markup-stencil
2232                         X
2233                         RIGHT
2234                         (ly:make-stencil footnote-number x-ext y-ext)
2235                         padding)))
2236     (ly:stencil-add
2237      main-stencil
2238      (ly:make-stencil
2239       `(footnote ,footnote-hash #t ,(interpret-markup layout props note))
2240       '(0 . 0)
2241       '(0 . 0)))))
2242
2243 (define-markup-command (override layout props new-prop arg)
2244   (pair? markup?)
2245   #:category other
2246   "
2247 @cindex overriding properties within text markup
2248
2249 Add the argument @var{new-prop} to the property list.  Properties
2250 may be any property supported by @rinternals{font-interface},
2251 @rinternals{text-interface} and
2252 @rinternals{instrument-specific-markup-interface}.
2253
2254 @lilypond[verbatim,quote]
2255 \\markup {
2256   \\line {
2257     \\column {
2258       default
2259       baseline-skip
2260     }
2261     \\hspace #2
2262     \\override #'(baseline-skip . 4) {
2263       \\column {
2264         increased
2265         baseline-skip
2266       }
2267     }
2268   }
2269 }
2270 @end lilypond"
2271   (interpret-markup layout (cons (list new-prop) props) arg))
2272
2273 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2274 ;; files
2275 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2276
2277 (define-markup-command (verbatim-file layout props name)
2278   (string?)
2279   #:category other
2280   "Read the contents of file @var{name}, and include it verbatim.
2281
2282 @lilypond[verbatim,quote]
2283 \\markup {
2284   \\verbatim-file #\"simple.ly\"
2285 }
2286 @end lilypond"
2287   (interpret-markup layout props
2288                     (if  (ly:get-option 'safe)
2289                          "verbatim-file disabled in safe mode"
2290                          (let* ((str (ly:gulp-file name))
2291                                 (lines (string-split str #\nl)))
2292                            (make-typewriter-markup
2293                             (make-column-markup lines))))))
2294
2295 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2296 ;; fonts.
2297 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2298
2299
2300 (define-markup-command (smaller layout props arg)
2301   (markup?)
2302   #:category font
2303   "Decrease the font size relative to the current setting.
2304
2305 @lilypond[verbatim,quote]
2306 \\markup {
2307   \\fontsize #3.5 {
2308     some large text
2309     \\hspace #2
2310     \\smaller {
2311       a bit smaller
2312     }
2313     \\hspace #2
2314     more large text
2315   }
2316 }
2317 @end lilypond"
2318   (interpret-markup layout props
2319                     `(,fontsize-markup -1 ,arg)))
2320
2321 (define-markup-command (larger layout props arg)
2322   (markup?)
2323   #:category font
2324   "Increase the font size relative to the current setting.
2325
2326 @lilypond[verbatim,quote]
2327 \\markup {
2328   default
2329   \\hspace #2
2330   \\larger
2331   larger
2332 }
2333 @end lilypond"
2334   (interpret-markup layout props
2335                     `(,fontsize-markup 1 ,arg)))
2336
2337 (define-markup-command (finger layout props arg)
2338   (markup?)
2339   #:category font
2340   "Set @var{arg} as small numbers.
2341
2342 @lilypond[verbatim,quote]
2343 \\markup {
2344   \\finger {
2345     1 2 3 4 5
2346   }
2347 }
2348 @end lilypond"
2349   (interpret-markup layout
2350                     (cons '((font-size . -5) (font-encoding . fetaText)) props)
2351                     arg))
2352
2353 (define-markup-command (abs-fontsize layout props size arg)
2354   (number? markup?)
2355   #:category font
2356   "Use @var{size} as the absolute font size to display @var{arg}.
2357 Adjusts @code{baseline-skip} and @code{word-space} accordingly.
2358
2359 @lilypond[verbatim,quote]
2360 \\markup {
2361   default text font size
2362   \\hspace #2
2363   \\abs-fontsize #16 { text font size 16 }
2364   \\hspace #2
2365   \\abs-fontsize #12 { text font size 12 }
2366 }
2367 @end lilypond"
2368   (let* ((ref-size (ly:output-def-lookup layout 'text-font-size 12))
2369          (text-props (list (ly:output-def-lookup layout 'text-font-defaults)))
2370          (ref-word-space (chain-assoc-get 'word-space text-props 0.6))
2371          (ref-baseline (chain-assoc-get 'baseline-skip text-props 3))
2372          (magnification (/ size ref-size)))
2373     (interpret-markup
2374      layout
2375      (cons
2376       `((baseline-skip . ,(* magnification ref-baseline))
2377         (word-space . ,(* magnification ref-word-space))
2378         (font-size . ,(magnification->font-size magnification)))
2379       props)
2380      arg)))
2381
2382 (define-markup-command (fontsize layout props increment arg)
2383   (number? markup?)
2384   #:category font
2385   #:properties ((font-size 0)
2386                 (word-space 1)
2387                 (baseline-skip 2))
2388   "Add @var{increment} to the font-size.  Adjusts @code{baseline-skip}
2389 accordingly.
2390
2391 @lilypond[verbatim,quote]
2392 \\markup {
2393   default
2394   \\hspace #2
2395   \\fontsize #-1.5
2396   smaller
2397 }
2398 @end lilypond"
2399   (interpret-markup
2400    layout
2401    (cons
2402     `((baseline-skip . ,(* baseline-skip (magstep increment)))
2403       (word-space . ,(* word-space (magstep increment)))
2404       (font-size . ,(+ font-size increment)))
2405     props)
2406    arg))
2407
2408 (define-markup-command (magnify layout props sz arg)
2409   (number? markup?)
2410   #:category font
2411   "
2412 @cindex magnifying text
2413
2414 Set the font magnification for its argument.  In the following
2415 example, the middle@tie{}A is 10% larger:
2416
2417 @example
2418 A \\magnify #1.1 @{ A @} A
2419 @end example
2420
2421 Note: Magnification only works if a font name is explicitly selected.
2422 Use @code{\\fontsize} otherwise.
2423
2424 @lilypond[verbatim,quote]
2425 \\markup {
2426   default
2427   \\hspace #2
2428   \\magnify #1.5 {
2429     50% larger
2430   }
2431 }
2432 @end lilypond"
2433   (interpret-markup
2434    layout
2435    (prepend-alist-chain 'font-size (magnification->font-size sz) props)
2436    arg))
2437
2438 (define-markup-command (bold layout props arg)
2439   (markup?)
2440   #:category font
2441   "Switch to bold font-series.
2442
2443 @lilypond[verbatim,quote]
2444 \\markup {
2445   default
2446   \\hspace #2
2447   \\bold
2448   bold
2449 }
2450 @end lilypond"
2451   (interpret-markup layout (prepend-alist-chain 'font-series 'bold props) arg))
2452
2453 (define-markup-command (sans layout props arg)
2454   (markup?)
2455   #:category font
2456   "Switch to the sans serif font family.
2457
2458 @lilypond[verbatim,quote]
2459 \\markup {
2460   default
2461   \\hspace #2
2462   \\sans {
2463     sans serif
2464   }
2465 }
2466 @end lilypond"
2467   (interpret-markup layout (prepend-alist-chain 'font-family 'sans props) arg))
2468
2469 (define-markup-command (number layout props arg)
2470   (markup?)
2471   #:category font
2472   "Set font family to @code{number}, which yields the font used for
2473 time signatures and fingerings.  This font contains numbers and
2474 some punctuation; it has no letters.
2475
2476 @lilypond[verbatim,quote]
2477 \\markup {
2478   \\number {
2479     0 1 2 3 4 5 6 7 8 9 . ,
2480   }
2481 }
2482 @end lilypond"
2483   (interpret-markup layout (prepend-alist-chain 'font-encoding 'fetaText props) arg))
2484
2485 (define-markup-command (roman layout props arg)
2486   (markup?)
2487   #:category font
2488   "Set font family to @code{roman}.
2489
2490 @lilypond[verbatim,quote]
2491 \\markup {
2492   \\sans \\bold {
2493     sans serif, bold
2494     \\hspace #2
2495     \\roman {
2496       text in roman font family
2497     }
2498     \\hspace #2
2499     return to sans
2500   }
2501 }
2502 @end lilypond"
2503   (interpret-markup layout (prepend-alist-chain 'font-family 'roman props) arg))
2504
2505 (define-markup-command (huge layout props arg)
2506   (markup?)
2507   #:category font
2508   "Set font size to +2.
2509
2510 @lilypond[verbatim,quote]
2511 \\markup {
2512   default
2513   \\hspace #2
2514   \\huge
2515   huge
2516 }
2517 @end lilypond"
2518   (interpret-markup layout (prepend-alist-chain 'font-size 2 props) arg))
2519
2520 (define-markup-command (large layout props arg)
2521   (markup?)
2522   #:category font
2523   "Set font size to +1.
2524
2525 @lilypond[verbatim,quote]
2526 \\markup {
2527   default
2528   \\hspace #2
2529   \\large
2530   large
2531 }
2532 @end lilypond"
2533   (interpret-markup layout (prepend-alist-chain 'font-size 1 props) arg))
2534
2535 (define-markup-command (normalsize layout props arg)
2536   (markup?)
2537   #:category font
2538   "Set font size to default.
2539
2540 @lilypond[verbatim,quote]
2541 \\markup {
2542   \\teeny {
2543     this is very small
2544     \\hspace #2
2545     \\normalsize {
2546       normal size
2547     }
2548     \\hspace #2
2549     teeny again
2550   }
2551 }
2552 @end lilypond"
2553   (interpret-markup layout (prepend-alist-chain 'font-size 0 props) arg))
2554
2555 (define-markup-command (small layout props arg)
2556   (markup?)
2557   #:category font
2558   "Set font size to -1.
2559
2560 @lilypond[verbatim,quote]
2561 \\markup {
2562   default
2563   \\hspace #2
2564   \\small
2565   small
2566 }
2567 @end lilypond"
2568   (interpret-markup layout (prepend-alist-chain 'font-size -1 props) arg))
2569
2570 (define-markup-command (tiny layout props arg)
2571   (markup?)
2572   #:category font
2573   "Set font size to -2.
2574
2575 @lilypond[verbatim,quote]
2576 \\markup {
2577   default
2578   \\hspace #2
2579   \\tiny
2580   tiny
2581 }
2582 @end lilypond"
2583   (interpret-markup layout (prepend-alist-chain 'font-size -2 props) arg))
2584
2585 (define-markup-command (teeny layout props arg)
2586   (markup?)
2587   #:category font
2588   "Set font size to -3.
2589
2590 @lilypond[verbatim,quote]
2591 \\markup {
2592   default
2593   \\hspace #2
2594   \\teeny
2595   teeny
2596 }
2597 @end lilypond"
2598   (interpret-markup layout (prepend-alist-chain 'font-size -3 props) arg))
2599
2600 (define-markup-command (fontCaps layout props arg)
2601   (markup?)
2602   #:category font
2603   "Set @code{font-shape} to @code{caps}
2604
2605 Note: @code{\\fontCaps} requires the installation and selection of
2606 fonts which support the @code{caps} font shape."
2607   (interpret-markup layout (prepend-alist-chain 'font-shape 'caps props) arg))
2608
2609 ;; Poor man's caps
2610 (define-markup-command (smallCaps layout props arg)
2611   (markup?)
2612   #:category font
2613   "Emit @var{arg} as small caps.
2614
2615 Note: @code{\\smallCaps} does not support accented characters.
2616
2617 @lilypond[verbatim,quote]
2618 \\markup {
2619   default
2620   \\hspace #2
2621   \\smallCaps {
2622     Text in small caps
2623   }
2624 }
2625 @end lilypond"
2626   (define (char-list->markup chars lower)
2627     (let ((final-string (string-upcase (reverse-list->string chars))))
2628       (if lower
2629           (markup #:fontsize -2 final-string)
2630           final-string)))
2631   (define (make-small-caps rest-chars currents current-is-lower prev-result)
2632     (if (null? rest-chars)
2633         (make-concat-markup
2634          (reverse! (cons (char-list->markup currents current-is-lower)
2635                          prev-result)))
2636         (let* ((ch (car rest-chars))
2637                (is-lower (char-lower-case? ch)))
2638           (if (or (and current-is-lower is-lower)
2639                   (and (not current-is-lower) (not is-lower)))
2640               (make-small-caps (cdr rest-chars)
2641                                (cons ch currents)
2642                                is-lower
2643                                prev-result)
2644               (make-small-caps (cdr rest-chars)
2645                                (list ch)
2646                                is-lower
2647                                (if (null? currents)
2648                                    prev-result
2649                                    (cons (char-list->markup
2650                                           currents current-is-lower)
2651                                          prev-result)))))))
2652   (interpret-markup layout props
2653                     (if (string? arg)
2654                         (make-small-caps (string->list arg) (list) #f (list))
2655                         arg)))
2656
2657 (define-markup-command (caps layout props arg)
2658   (markup?)
2659   #:category font
2660   "Copy of the @code{\\smallCaps} command.
2661
2662 @lilypond[verbatim,quote]
2663 \\markup {
2664   default
2665   \\hspace #2
2666   \\caps {
2667     Text in small caps
2668   }
2669 }
2670 @end lilypond"
2671   (interpret-markup layout props (make-smallCaps-markup arg)))
2672
2673 (define-markup-command (dynamic layout props arg)
2674   (markup?)
2675   #:category font
2676   "Use the dynamic font.  This font only contains @b{s}, @b{f}, @b{m},
2677 @b{z}, @b{p}, and @b{r}.  When producing phrases, like
2678 @q{pi@`{u}@tie{}@b{f}}, the normal words (like @q{pi@`{u}}) should be
2679 done in a different font.  The recommended font for this is bold and italic.
2680 @lilypond[verbatim,quote]
2681 \\markup {
2682   \\dynamic {
2683     sfzp
2684   }
2685 }
2686 @end lilypond"
2687   (interpret-markup
2688    layout (prepend-alist-chain 'font-encoding 'fetaText props) arg))
2689
2690 (define-markup-command (text layout props arg)
2691   (markup?)
2692   #:category font
2693   "Use a text font instead of music symbol or music alphabet font.
2694
2695 @lilypond[verbatim,quote]
2696 \\markup {
2697   \\number {
2698     1, 2,
2699     \\text {
2700       three, four,
2701     }
2702     5
2703   }
2704 }
2705 @end lilypond"
2706
2707   ;; ugh - latin1
2708   (interpret-markup layout (prepend-alist-chain 'font-encoding 'latin1 props)
2709                     arg))
2710
2711 (define-markup-command (italic layout props arg)
2712   (markup?)
2713   #:category font
2714   "Use italic @code{font-shape} for @var{arg}.
2715
2716 @lilypond[verbatim,quote]
2717 \\markup {
2718   default
2719   \\hspace #2
2720   \\italic
2721   italic
2722 }
2723 @end lilypond"
2724   (interpret-markup layout (prepend-alist-chain 'font-shape 'italic props) arg))
2725
2726 (define-markup-command (typewriter layout props arg)
2727   (markup?)
2728   #:category font
2729   "Use @code{font-family} typewriter for @var{arg}.
2730
2731 @lilypond[verbatim,quote]
2732 \\markup {
2733   default
2734   \\hspace #2
2735   \\typewriter
2736   typewriter
2737 }
2738 @end lilypond"
2739   (interpret-markup
2740    layout (prepend-alist-chain 'font-family 'typewriter props) arg))
2741
2742 (define-markup-command (upright layout props arg)
2743   (markup?)
2744   #:category font
2745   "Set @code{font-shape} to @code{upright}.  This is the opposite
2746 of @code{italic}.
2747
2748 @lilypond[verbatim,quote]
2749 \\markup {
2750   \\italic {
2751     italic text
2752     \\hspace #2
2753     \\upright {
2754       upright text
2755     }
2756     \\hspace #2
2757     italic again
2758   }
2759 }
2760 @end lilypond"
2761   (interpret-markup
2762    layout (prepend-alist-chain 'font-shape 'upright props) arg))
2763
2764 (define-markup-command (medium layout props arg)
2765   (markup?)
2766   #:category font
2767   "Switch to medium font-series (in contrast to bold).
2768
2769 @lilypond[verbatim,quote]
2770 \\markup {
2771   \\bold {
2772     some bold text
2773     \\hspace #2
2774     \\medium {
2775       medium font series
2776     }
2777     \\hspace #2
2778     bold again
2779   }
2780 }
2781 @end lilypond"
2782   (interpret-markup layout (prepend-alist-chain 'font-series 'medium props)
2783                     arg))
2784
2785 (define-markup-command (normal-text layout props arg)
2786   (markup?)
2787   #:category font
2788   "Set all font related properties (except the size) to get the default
2789 normal text font, no matter what font was used earlier.
2790
2791 @lilypond[verbatim,quote]
2792 \\markup {
2793   \\huge \\bold \\sans \\caps {
2794     huge bold sans caps
2795     \\hspace #2
2796     \\normal-text {
2797       huge normal
2798     }
2799     \\hspace #2
2800     as before
2801   }
2802 }
2803 @end lilypond"
2804   ;; ugh - latin1
2805   (interpret-markup layout
2806                     (cons '((font-family . roman) (font-shape . upright)
2807                             (font-series . medium) (font-encoding . latin1))
2808                           props)
2809                     arg))
2810
2811 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2812 ;; symbols.
2813 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2814
2815 (define-markup-command (musicglyph layout props glyph-name)
2816   (string?)
2817   #:category music
2818   "@var{glyph-name} is converted to a musical symbol; for example,
2819 @code{\\musicglyph #\"accidentals.natural\"} selects the natural sign from
2820 the music font.  See @ruser{The Feta font} for a complete listing of
2821 the possible glyphs.
2822
2823 @lilypond[verbatim,quote]
2824 \\markup {
2825   \\musicglyph #\"f\"
2826   \\musicglyph #\"rests.2\"
2827   \\musicglyph #\"clefs.G_change\"
2828 }
2829 @end lilypond"
2830   (let* ((font (ly:paper-get-font layout
2831                                   (cons '((font-encoding . fetaMusic)
2832                                           (font-name . #f))
2833
2834                                         props)))
2835          (glyph (ly:font-get-glyph font glyph-name)))
2836     (if (null? (ly:stencil-expr glyph))
2837         (ly:warning (_ "Cannot find glyph ~a") glyph-name))
2838
2839     glyph))
2840
2841 (define-markup-command (doublesharp layout props)
2842   ()
2843   #:category music
2844   "Draw a double sharp symbol.
2845
2846 @lilypond[verbatim,quote]
2847 \\markup {
2848   \\doublesharp
2849 }
2850 @end lilypond"
2851   (interpret-markup layout props (markup #:musicglyph (assoc-get 1 standard-alteration-glyph-name-alist ""))))
2852
2853 (define-markup-command (sesquisharp layout props)
2854   ()
2855   #:category music
2856   "Draw a 3/2 sharp symbol.
2857
2858 @lilypond[verbatim,quote]
2859 \\markup {
2860   \\sesquisharp
2861 }
2862 @end lilypond"
2863   (interpret-markup layout props (markup #:musicglyph (assoc-get 3/4 standard-alteration-glyph-name-alist ""))))
2864
2865 (define-markup-command (sharp layout props)
2866   ()
2867   #:category music
2868   "Draw a sharp symbol.
2869
2870 @lilypond[verbatim,quote]
2871 \\markup {
2872   \\sharp
2873 }
2874 @end lilypond"
2875   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/2 standard-alteration-glyph-name-alist ""))))
2876
2877 (define-markup-command (semisharp layout props)
2878   ()
2879   #:category music
2880   "Draw a semisharp symbol.
2881
2882 @lilypond[verbatim,quote]
2883 \\markup {
2884   \\semisharp
2885 }
2886 @end lilypond"
2887   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/4 standard-alteration-glyph-name-alist ""))))
2888
2889 (define-markup-command (natural layout props)
2890   ()
2891   #:category music
2892   "Draw a natural symbol.
2893
2894 @lilypond[verbatim,quote]
2895 \\markup {
2896   \\natural
2897 }
2898 @end lilypond"
2899   (interpret-markup layout props (markup #:musicglyph (assoc-get 0 standard-alteration-glyph-name-alist ""))))
2900
2901 (define-markup-command (semiflat layout props)
2902   ()
2903   #:category music
2904   "Draw a semiflat symbol.
2905
2906 @lilypond[verbatim,quote]
2907 \\markup {
2908   \\semiflat
2909 }
2910 @end lilypond"
2911   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/4 standard-alteration-glyph-name-alist ""))))
2912
2913 (define-markup-command (flat layout props)
2914   ()
2915   #:category music
2916   "Draw a flat symbol.
2917
2918 @lilypond[verbatim,quote]
2919 \\markup {
2920   \\flat
2921 }
2922 @end lilypond"
2923   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/2 standard-alteration-glyph-name-alist ""))))
2924
2925 (define-markup-command (sesquiflat layout props)
2926   ()
2927   #:category music
2928   "Draw a 3/2 flat symbol.
2929
2930 @lilypond[verbatim,quote]
2931 \\markup {
2932   \\sesquiflat
2933 }
2934 @end lilypond"
2935   (interpret-markup layout props (markup #:musicglyph (assoc-get -3/4 standard-alteration-glyph-name-alist ""))))
2936
2937 (define-markup-command (doubleflat layout props)
2938   ()
2939   #:category music
2940   "Draw a double flat symbol.
2941
2942 @lilypond[verbatim,quote]
2943 \\markup {
2944   \\doubleflat
2945 }
2946 @end lilypond"
2947   (interpret-markup layout props (markup #:musicglyph (assoc-get -1 standard-alteration-glyph-name-alist ""))))
2948
2949 (define-markup-command (with-color layout props color arg)
2950   (color? markup?)
2951   #:category other
2952   "
2953 @cindex coloring text
2954
2955 Draw @var{arg} in color specified by @var{color}.
2956
2957 @lilypond[verbatim,quote]
2958 \\markup {
2959   \\with-color #red
2960   red
2961   \\hspace #2
2962   \\with-color #green
2963   green
2964   \\hspace #2
2965   \\with-color #blue
2966   blue
2967 }
2968 @end lilypond"
2969   (let ((stil (interpret-markup layout props arg)))
2970     (ly:make-stencil (list 'color color (ly:stencil-expr stil))
2971                      (ly:stencil-extent stil X)
2972                      (ly:stencil-extent stil Y))))
2973
2974 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2975 ;; glyphs
2976 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2977
2978 (define-markup-command (arrow-head layout props axis dir filled)
2979   (integer? ly:dir? boolean?)
2980   #:category graphic
2981   "Produce an arrow head in specified direction and axis.
2982 Use the filled head if @var{filled} is specified.
2983 @lilypond[verbatim,quote]
2984 \\markup {
2985   \\fontsize #5 {
2986     \\general-align #Y #DOWN {
2987       \\arrow-head #Y #UP ##t
2988       \\arrow-head #Y #DOWN ##f
2989       \\hspace #2
2990       \\arrow-head #X #RIGHT ##f
2991       \\arrow-head #X #LEFT ##f
2992     }
2993   }
2994 }
2995 @end lilypond"
2996   (let*
2997       ((name (format #f "arrowheads.~a.~a~a"
2998                      (if filled
2999                          "close"
3000                          "open")
3001                      axis
3002                      dir)))
3003     (ly:font-get-glyph
3004      (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
3005                                      props))
3006      name)))
3007
3008 (define-markup-command (lookup layout props glyph-name)
3009   (string?)
3010   #:category other
3011   "Lookup a glyph by name.
3012
3013 @lilypond[verbatim,quote]
3014 \\markup {
3015   \\override #'(font-encoding . fetaBraces) {
3016     \\lookup #\"brace200\"
3017     \\hspace #2
3018     \\rotate #180
3019     \\lookup #\"brace180\"
3020   }
3021 }
3022 @end lilypond"
3023   (ly:font-get-glyph (ly:paper-get-font layout props)
3024                      glyph-name))
3025
3026 (define-markup-command (char layout props num)
3027   (integer?)
3028   #:category other
3029   "Produce a single character.  Characters encoded in hexadecimal
3030 format require the prefix @code{#x}.
3031
3032 @lilypond[verbatim,quote]
3033 \\markup {
3034   \\char #65 \\char ##x00a9
3035 }
3036 @end lilypond"
3037   (ly:text-interface::interpret-markup layout props (ly:wide-char->utf-8 num)))
3038
3039 (define number->mark-letter-vector (make-vector 25 #\A))
3040
3041 (do ((i 0 (1+ i))
3042      (j 0 (1+ j)))
3043     ((>= i 26))
3044   (if (= i (- (char->integer #\I) (char->integer #\A)))
3045       (set! i (1+ i)))
3046   (vector-set! number->mark-letter-vector j
3047                (integer->char (+ i (char->integer #\A)))))
3048
3049 (define number->mark-alphabet-vector (list->vector
3050                                       (map (lambda (i) (integer->char (+ i (char->integer #\A)))) (iota 26))))
3051
3052 (define (number->markletter-string vec n)
3053   "Double letters for big marks."
3054   (let* ((lst (vector-length vec)))
3055
3056     (if (>= n lst)
3057         (string-append (number->markletter-string vec (1- (quotient n lst)))
3058                        (number->markletter-string vec (remainder n lst)))
3059         (make-string 1 (vector-ref vec n)))))
3060
3061 (define-markup-command (markletter layout props num)
3062   (integer?)
3063   #:category other
3064   "Make a markup letter for @var{num}.  The letters start with A
3065 to@tie{}Z (skipping letter@tie{}I), and continue with double letters.
3066
3067 @lilypond[verbatim,quote]
3068 \\markup {
3069   \\markletter #8
3070   \\hspace #2
3071   \\markletter #26
3072 }
3073 @end lilypond"
3074   (ly:text-interface::interpret-markup layout props
3075                                        (number->markletter-string number->mark-letter-vector num)))
3076
3077 (define-markup-command (markalphabet layout props num)
3078   (integer?)
3079   #:category other
3080   "Make a markup letter for @var{num}.  The letters start with A to@tie{}Z
3081 and continue with double letters.
3082
3083 @lilypond[verbatim,quote]
3084 \\markup {
3085   \\markalphabet #8
3086   \\hspace #2
3087   \\markalphabet #26
3088 }
3089 @end lilypond"
3090   (ly:text-interface::interpret-markup layout props
3091                                        (number->markletter-string number->mark-alphabet-vector num)))
3092
3093 (define-public (horizontal-slash-interval num forward number-interval mag)
3094   (if forward
3095       (cond ;; ((= num 6) (interval-widen number-interval (* mag 0.5)))
3096        ;; ((= num 5) (interval-widen number-interval (* mag 0.5)))
3097        (else (interval-widen number-interval (* mag 0.25))))
3098       (cond ((= num 6) (interval-widen number-interval (* mag 0.5)))
3099             ;; ((= num 5) (interval-widen number-interval (* mag 0.5)))
3100             (else (interval-widen number-interval (* mag 0.25))))
3101       ))
3102
3103 (define-public (adjust-slash-stencil num forward stencil mag)
3104   (if forward
3105       (cond ((= num 2)
3106              (ly:stencil-translate stencil (cons (* mag -0.00) (* mag 0.2))))
3107             ((= num 3)
3108              (ly:stencil-translate stencil (cons (* mag -0.00) (* mag 0.2))))
3109             ;; ((= num 5)
3110             ;;     (ly:stencil-translate stencil (cons (* mag -0.00) (* mag -0.07))))
3111             ;; ((= num 7)
3112             ;;     (ly:stencil-translate stencil (cons (* mag -0.00) (* mag -0.15))))
3113             (else stencil))
3114       (cond ((= num 6)
3115              (ly:stencil-translate stencil (cons (* mag -0.00) (* mag 0.15))))
3116             ;; ((= num 8)
3117             ;;     (ly:stencil-translate stencil (cons (* mag -0.00) (* mag -0.15))))
3118             (else stencil))
3119       )
3120   )
3121
3122 (define (slashed-digit-internal layout props num forward font-size thickness)
3123   (let* ((mag (magstep font-size))
3124          (thickness (* mag
3125                        (ly:output-def-lookup layout 'line-thickness)
3126                        thickness))
3127          ;; backward slashes might use slope and point in the other direction!
3128          (dy (* mag (if forward 0.4 -0.4)))
3129          (number-stencil (interpret-markup layout
3130                                            (prepend-alist-chain 'font-encoding 'fetaText props)
3131                                            (number->string num)))
3132          (num-x (horizontal-slash-interval num forward (ly:stencil-extent number-stencil X) mag))
3133          (center (interval-center (ly:stencil-extent number-stencil Y)))
3134          ;; Use the real extents of the slash, not the whole number,
3135          ;; because we might translate the slash later on!
3136          (num-y (interval-widen (cons center center) (abs dy)))
3137          (is-sane (and (interval-sane? num-x) (interval-sane? num-y)))
3138          (slash-stencil (if is-sane
3139                             (make-line-stencil thickness
3140                                                (car num-x) (- (interval-center num-y) dy)
3141                                                (cdr num-x) (+ (interval-center num-y) dy))
3142                             #f)))
3143     (if (ly:stencil? slash-stencil)
3144         (begin
3145           ;; for some numbers we need to shift the slash/backslash up or
3146           ;; down to make the slashed digit look better
3147           (set! slash-stencil (adjust-slash-stencil num forward slash-stencil mag))
3148           (set! number-stencil
3149                 (ly:stencil-add number-stencil slash-stencil)))
3150         (ly:warning "Unable to create slashed digit ~a" num))
3151     number-stencil))
3152
3153
3154 (define-markup-command (slashed-digit layout props num)
3155   (integer?)
3156   #:category other
3157   #:properties ((font-size 0)
3158                 (thickness 1.6))
3159   "
3160 @cindex slashed digits
3161
3162 A feta number, with slash.  This is for use in the context of
3163 figured bass notation.
3164 @lilypond[verbatim,quote]
3165 \\markup {
3166   \\slashed-digit #5
3167   \\hspace #2
3168   \\override #'(thickness . 3)
3169   \\slashed-digit #7
3170 }
3171 @end lilypond"
3172   (slashed-digit-internal layout props num #t font-size thickness))
3173
3174 (define-markup-command (backslashed-digit layout props num)
3175   (integer?)
3176   #:category other
3177   #:properties ((font-size 0)
3178                 (thickness 1.6))
3179   "
3180 @cindex backslashed digits
3181
3182 A feta number, with backslash.  This is for use in the context of
3183 figured bass notation.
3184 @lilypond[verbatim,quote]
3185 \\markup {
3186   \\backslashed-digit #5
3187   \\hspace #2
3188   \\override #'(thickness . 3)
3189   \\backslashed-digit #7
3190 }
3191 @end lilypond"
3192   (slashed-digit-internal layout props num #f font-size thickness))
3193
3194 ;; eyeglasses
3195 (define eyeglassespath
3196   '((moveto 0.42 0.77)
3197     (rcurveto 0 0.304 -0.246 0.55 -0.55 0.55)
3198     (rcurveto -0.304 0 -0.55 -0.246 -0.55 -0.55)
3199     (rcurveto 0 -0.304 0.246 -0.55 0.55 -0.55)
3200     (rcurveto 0.304 0 0.55 0.246 0.55 0.55)
3201     (closepath)
3202     (moveto 2.07 0.77)
3203     (rcurveto 0 0.304 -0.246 0.55 -0.55 0.55)
3204     (rcurveto -0.304 0 -0.55 -0.246 -0.55 -0.55)
3205     (rcurveto 0 -0.304 0.246 -0.55 0.55 -0.55)
3206     (rcurveto 0.304 0 0.55 0.246 0.55 0.55)
3207     (closepath)
3208     (moveto 1.025 0.935)
3209     (rcurveto 0 0.182 -0.148 0.33 -0.33 0.33)
3210     (rcurveto -0.182 0 -0.33 -0.148 -0.33 -0.33)
3211     (moveto -0.68 0.77)
3212     (rlineto 0.66 1.43)
3213     (rcurveto 0.132 0.286 0.55 0.44 0.385 -0.33)
3214     (moveto 2.07 0.77)
3215     (rlineto 0.66 1.43)
3216     (rcurveto 0.132 0.286 0.55 0.44 0.385 -0.33)))
3217
3218 (define-markup-command (eyeglasses layout props)
3219   ()
3220   #:category other
3221   "Prints out eyeglasses, indicating strongly to look at the conductor.
3222 @lilypond[verbatim,quote]
3223 \\markup { \\eyeglasses }
3224 @end lilypond"
3225   (interpret-markup layout props
3226                     (make-override-markup '(line-cap-style . butt)
3227                                           (make-path-markup 0.15 eyeglassespath))))
3228
3229 (define-markup-command (left-brace layout props size)
3230   (number?)
3231   #:category other
3232   "
3233 A feta brace in point size @var{size}.
3234
3235 @lilypond[verbatim,quote]
3236 \\markup {
3237   \\left-brace #35
3238   \\hspace #2
3239   \\left-brace #45
3240 }
3241 @end lilypond"
3242   (let* ((font (ly:paper-get-font layout
3243                                   (cons '((font-encoding . fetaBraces)
3244                                           (font-name . #f))
3245                                         props)))
3246          (glyph-count (1- (ly:otf-glyph-count font)))
3247          (scale (ly:output-def-lookup layout 'output-scale))
3248          (scaled-size (/ (ly:pt size) scale))
3249          (glyph (lambda (n)
3250                   (ly:font-get-glyph font (string-append "brace"
3251                                                          (number->string n)))))
3252          (get-y-from-brace (lambda (brace)
3253                              (interval-length
3254                               (ly:stencil-extent (glyph brace) Y))))
3255          (find-brace (binary-search 0 glyph-count get-y-from-brace scaled-size))
3256          (glyph-found (glyph find-brace)))
3257
3258     (if (or (null? (ly:stencil-expr glyph-found))
3259             (< scaled-size (interval-length (ly:stencil-extent (glyph 0) Y)))
3260             (> scaled-size (interval-length
3261                             (ly:stencil-extent (glyph glyph-count) Y))))
3262         (begin
3263           (ly:warning (_ "no brace found for point size ~S ") size)
3264           (ly:warning (_ "defaulting to ~S pt")
3265                       (/ (* scale (interval-length
3266                                    (ly:stencil-extent glyph-found Y)))
3267                          (ly:pt 1)))))
3268     glyph-found))
3269
3270 (define-markup-command (right-brace layout props size)
3271   (number?)
3272   #:category other
3273   "
3274 A feta brace in point size @var{size}, rotated 180 degrees.
3275
3276 @lilypond[verbatim,quote]
3277 \\markup {
3278   \\right-brace #45
3279   \\hspace #2
3280   \\right-brace #35
3281 }
3282 @end lilypond"
3283   (interpret-markup layout props (markup #:rotate 180 #:left-brace size)))
3284
3285 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3286 ;; the note command.
3287 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3288
3289 ;; TODO: better syntax.
3290
3291 (define-markup-command (note-by-number layout props log dot-count dir)
3292   (number? number? number?)
3293   #:category music
3294   #:properties ((font-size 0)
3295                 (flag-style '())
3296                 (style '()))
3297   "
3298 @cindex notes within text by log and dot-count
3299
3300 Construct a note symbol, with stem and flag.  By using fractional values for
3301 @var{dir}, longer or shorter stems can be obtained.
3302 Supports all note-head-styles.
3303 Supported flag-styles are @code{default}, @code{old-straight-flag} and
3304 @code{modern-straight-flag}.
3305
3306 @lilypond[verbatim,quote]
3307 \\markup {
3308   \\note-by-number #3 #0 #DOWN
3309   \\hspace #2
3310   \\note-by-number #1 #2 #0.8
3311 }
3312 @end lilypond"
3313   (define (get-glyph-name-candidates dir log style)
3314     (map (lambda (dir-name)
3315            (format #f "noteheads.~a~a" dir-name
3316                    (if (and (symbol? style)
3317                             (not (equal? 'default style)))
3318                        (select-head-glyph style (min log 2))
3319                        (min log 2))))
3320          (list (if (= dir UP) "u" "d")
3321                "s")))
3322
3323   (define (get-glyph-name font cands)
3324     (if (null? cands)
3325         ""
3326         (if (ly:stencil-empty? (ly:font-get-glyph font (car cands)))
3327             (get-glyph-name font (cdr cands))
3328             (car cands))))
3329
3330   (define (buildflags flag-stencil remain curr-stencil spacing)
3331     ;; Function to recursively create a stencil with @code{remain} flags
3332     ;; from the single-flag stencil @code{curr-stencil}, which is already
3333     ;; translated to the position of the previous flag position.
3334     ;;
3335     ;; Copy and paste from /scm/flag-styles.scm
3336     (if (> remain 0)
3337         (let* ((translated-stencil
3338                 (ly:stencil-translate-axis curr-stencil spacing Y))
3339                (new-stencil (ly:stencil-add flag-stencil translated-stencil)))
3340           (buildflags new-stencil (- remain 1) translated-stencil spacing))
3341         flag-stencil))
3342
3343   (define (straight-flag-mrkp flag-thickness flag-spacing
3344                               upflag-angle upflag-length
3345                               downflag-angle downflag-length
3346                               dir)
3347     ;; Create a stencil for a straight flag.  @var{flag-thickness} and
3348     ;; @var{flag-spacing} are given in staff spaces, @var{upflag-angle} and
3349     ;; @var{downflag-angle} are given in degrees, and @var{upflag-length} and
3350     ;; @var{downflag-length} are given in staff spaces.
3351     ;;
3352     ;; All lengths are scaled according to the font size of the note.
3353     ;;
3354     ;; From /scm/flag-styles.scm, modified to fit here.
3355
3356     (let* ((stem-up (> dir 0))
3357            ;; scale with the note size
3358            (factor (magstep font-size))
3359            (stem-thickness (* factor 0.1))
3360            (line-thickness (ly:output-def-lookup layout 'line-thickness))
3361            (half-stem-thickness (/ (* stem-thickness line-thickness) 2))
3362            (raw-length (if stem-up upflag-length downflag-length))
3363            (angle (if stem-up upflag-angle downflag-angle))
3364            (flag-length (+ (* raw-length factor) half-stem-thickness))
3365            (flag-end (polar->rectangular flag-length angle))
3366            (thickness (* flag-thickness factor))
3367            (thickness-offset (cons 0 (* -1 thickness dir)))
3368            (spacing (* -1 flag-spacing factor dir))
3369            (start (cons (- half-stem-thickness) (* half-stem-thickness dir)))
3370            ;; The points of a round-filled-polygon need to be given in
3371            ;; clockwise order, otherwise the polygon will be enlarged by
3372            ;; blot-size*2!
3373            (points (if stem-up (list start flag-end
3374                                      (offset-add flag-end thickness-offset)
3375                                      (offset-add start thickness-offset))
3376                        (list start
3377                              (offset-add start thickness-offset)
3378                              (offset-add flag-end thickness-offset)
3379                              flag-end)))
3380            (stencil (ly:round-filled-polygon points half-stem-thickness))
3381            ;; Log for 1/8 is 3, so we need to subtract 3
3382            (flag-stencil (buildflags stencil (- log 3) stencil spacing)))
3383       flag-stencil))
3384
3385   (let* ((font (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
3386                                                props)))
3387          (size-factor (magstep font-size))
3388          (blot (ly:output-def-lookup layout 'blot-diameter))
3389          (head-glyph-name
3390           (let ((result (get-glyph-name font
3391                                         (get-glyph-name-candidates
3392                                          (sign dir) log style))))
3393             (if (string-null? result)
3394                 ;; If no glyph name can be found, select default heads.
3395                 ;; Though this usually means an unsupported style has been
3396                 ;; chosen, it also prevents unrelated 'style settings from
3397                 ;; other grobs (e.g., TextSpanner and TimeSignature) leaking
3398                 ;; into markup.
3399                 (get-glyph-name font
3400                                 (get-glyph-name-candidates
3401                                  (sign dir) log 'default))
3402                 result)))
3403          (head-glyph (ly:font-get-glyph font head-glyph-name))
3404          (ancient-flags? (or (eq? style 'mensural) (eq? style 'neomensural)))
3405          (attach-indices (ly:note-head::stem-attachment font head-glyph-name))
3406          (stem-length (* size-factor (max 3 (- log 1))))
3407          ;; With ancient-flags we want a tighter stem
3408          (stem-thickness (* size-factor (if ancient-flags? 0.1 0.13)))
3409          (stemy (* dir stem-length))
3410          (attach-off (cons (interval-index
3411                             (ly:stencil-extent head-glyph X)
3412                             (* (sign dir) (car attach-indices)))
3413                            ;; fixme, this is inconsistent between X & Y.
3414                            (* (sign dir)
3415                               (interval-index
3416                                (ly:stencil-extent head-glyph Y)
3417                                (cdr attach-indices)))))
3418          ;; For a tighter stem (with ancient-flags) the stem-width has to be
3419          ;; adjusted.
3420          (stem-X-corr (if ancient-flags? (* 0.5 dir stem-thickness) 0))
3421          (stem-glyph (and (> log 0)
3422                           (ly:round-filled-box
3423                            (ordered-cons (+ stem-X-corr (car attach-off))
3424                                          (+ stem-X-corr (car attach-off)
3425                                             (* (- (sign dir)) stem-thickness)))
3426                            (cons (min stemy (cdr attach-off))
3427                                  (max stemy (cdr attach-off)))
3428                            (/ stem-thickness 3))))
3429          (dot (ly:font-get-glyph font "dots.dot"))
3430          (dotwid (interval-length (ly:stencil-extent dot X)))
3431          (dots (and (> dot-count 0)
3432                     (apply ly:stencil-add
3433                            (map (lambda (x)
3434                                   (ly:stencil-translate-axis
3435                                    dot (* 2 x dotwid) X))
3436                                 (iota dot-count)))))
3437          ;; Straight-flags. Values taken from /scm/flag-style.scm
3438          (modern-straight-flag (straight-flag-mrkp 0.55 1 -18 1.1 22 1.2 dir))
3439          (old-straight-flag (straight-flag-mrkp 0.55 1 -45 1.2 45 1.4 dir))
3440          ;; Calculate a corrective to avoid a gap between
3441          ;; straight-flags and the stem.
3442          (flag-style-Y-corr (if (or (eq? flag-style 'modern-straight-flag)
3443                                     (eq? flag-style 'old-straight-flag))
3444                                 (/ blot 10 (* -1 dir))
3445                                 0))
3446          (flaggl (and (> log 2)
3447                       (ly:stencil-translate
3448                        (cond ((eq? flag-style 'modern-straight-flag)
3449                               modern-straight-flag)
3450                              ((eq? flag-style 'old-straight-flag)
3451                               old-straight-flag)
3452                              (else
3453                               (ly:font-get-glyph font
3454                                                  (format #f (if ancient-flags?
3455                                                                 "flags.mensural~a2~a"
3456                                                                 "flags.~a~a")
3457                                                          (if (> dir 0) "u" "d")
3458                                                          log))))
3459                        (cons (+ (car attach-off)
3460                                 ;; For tighter stems (with ancient-flags) the
3461                                 ;; flag has to be adjusted different.
3462                                 (if (and (not ancient-flags?) (< dir 0))
3463                                     stem-thickness
3464                                     0))
3465                              (+ stemy flag-style-Y-corr))))))
3466
3467     ;; If there is a flag on an upstem and the stem is short, move the dots
3468     ;; to avoid the flag.  16th notes get a special case because their flags
3469     ;; hang lower than any other flags.
3470     ;; Not with ancient flags or straight-flags.
3471     (if (and dots (> dir 0) (> log 2)
3472              (or (eq? flag-style 'default) (null? flag-style))
3473              (not ancient-flags?)
3474              (or (< dir 1.15) (and (= log 4) (< dir 1.3))))
3475         (set! dots (ly:stencil-translate-axis dots 0.5 X)))
3476     (if flaggl
3477         (set! stem-glyph (ly:stencil-add flaggl stem-glyph)))
3478     (if (ly:stencil? stem-glyph)
3479         (set! stem-glyph (ly:stencil-add stem-glyph head-glyph))
3480         (set! stem-glyph head-glyph))
3481     (if (ly:stencil? dots)
3482         (set! stem-glyph
3483               (ly:stencil-add
3484                (ly:stencil-translate-axis
3485                 dots
3486                 (+ (cdr (ly:stencil-extent head-glyph X)) dotwid)
3487                 X)
3488                stem-glyph)))
3489     stem-glyph))
3490
3491 (define-public log2
3492   (let ((divisor (log 2)))
3493     (lambda (z) (inexact->exact (/ (log z) divisor)))))
3494
3495 (define (parse-simple-duration duration-string)
3496   "Parse the `duration-string', e.g. ''4..'' or ''breve.'',
3497 and return a (log dots) list."
3498   (let ((match (regexp-exec (make-regexp "(breve|longa|maxima|[0-9]+)(\\.*)")
3499                             duration-string)))
3500     (if (and match (string=? duration-string (match:substring match 0)))
3501         (let ((len (match:substring match 1))
3502               (dots (match:substring match 2)))
3503           (list (cond ((string=? len "breve") -1)
3504                       ((string=? len "longa") -2)
3505                       ((string=? len "maxima") -3)
3506                       (else (log2 (string->number len))))
3507                 (if dots (string-length dots) 0)))
3508         (ly:error (_ "not a valid duration string: ~a") duration-string))))
3509
3510 (define-markup-command (note layout props duration dir)
3511   (string? number?)
3512   #:category music
3513   #:properties (note-by-number-markup)
3514   "
3515 @cindex notes within text by string
3516
3517 This produces a note with a stem pointing in @var{dir} direction, with
3518 the @var{duration} for the note head type and augmentation dots.  For
3519 example, @code{\\note #\"4.\" #-0.75} creates a dotted quarter note, with
3520 a shortened down stem.
3521
3522 @lilypond[verbatim,quote]
3523 \\markup {
3524   \\override #'(style . cross) {
3525     \\note #\"4..\" #UP
3526   }
3527   \\hspace #2
3528   \\note #\"breve\" #0
3529 }
3530 @end lilypond"
3531   (let ((parsed (parse-simple-duration duration)))
3532     (note-by-number-markup layout props (car parsed) (cadr parsed) dir)))
3533
3534 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3535 ;; the rest command.
3536 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3537
3538 (define-markup-command (rest-by-number layout props log dot-count)
3539   (number? number?)
3540   #:category music
3541   #:properties ((font-size 0)
3542                 (style '())
3543                 (multi-measure-rest #f))
3544   "
3545 @cindex rests or multi-measure-rests within text by log and dot-count
3546
3547 A rest or multi-measure-rest symbol.
3548
3549 @lilypond[verbatim,quote]
3550 \\markup {
3551   \\rest-by-number #3 #2
3552   \\hspace #2
3553   \\rest-by-number #0 #1
3554   \\hspace #2
3555   \\override #'(multi-measure-rest . #t)
3556   \\rest-by-number #0 #0
3557 }
3558 @end lilypond"
3559
3560   (define (get-glyph-name-candidates log style)
3561     (let* (;; Choose the style-string to be added.
3562            ;; If no glyph exists, select others for the specified styles
3563            ;; otherwise defaulting.
3564            (style-strg
3565             (cond (
3566                    ;; 'baroque needs to be special-cased, otherwise
3567                    ;; `select-head-glyph´ would catch neomensural-glyphs for
3568                    ;; this style, if (< log 0).
3569                    (eq? style 'baroque)
3570                    (string-append (number->string log) ""))
3571                   ((eq? style 'petrucci)
3572                    (string-append (number->string log) "mensural"))
3573                   ;; In other cases `select-head-glyph´ from output-lib.scm
3574                   ;; works for rest-glyphs, too.
3575                   ((and (symbol? style) (not (eq? style 'default)))
3576                    (select-head-glyph style log))
3577                   (else log)))
3578            ;; Choose ledgered glyphs for whole and half rest.
3579            ;; Except for the specified styles, logs and MultiMeasureRests.
3580            (ledger-style-rests
3581             (if (and (or (list? style)
3582                          (not (member style
3583                                       '(neomensural mensural petrucci))))
3584                      (not multi-measure-rest)
3585                      (or (= log 0) (= log 1)))
3586                 "o"
3587                 "")))
3588       (format #f "rests.~a~a" style-strg ledger-style-rests)))
3589
3590   (define (get-glyph-name font cands)
3591     (if (ly:stencil-empty? (ly:font-get-glyph font cands))
3592         ""
3593         cands))
3594
3595   (let* ((font
3596           (ly:paper-get-font layout
3597                              (cons '((font-encoding . fetaMusic)) props)))
3598          (rest-glyph-name
3599           (let ((result
3600                  (get-glyph-name font
3601                                  (get-glyph-name-candidates log style))))
3602             (if (string-null? result)
3603                 ;; If no glyph name can be found, select default rests.  Though
3604                 ;; this usually means an unsupported style has been chosen, it
3605                 ;; also prevents unrelated 'style settings from other grobs
3606                 ;; (e.g., TextSpanner and TimeSignature) leaking into markup.
3607                 (get-glyph-name font (get-glyph-name-candidates log 'default))
3608                 result)))
3609          (rest-glyph (ly:font-get-glyph font rest-glyph-name))
3610          (dot (ly:font-get-glyph font "dots.dot"))
3611          (dot-width (interval-length (ly:stencil-extent dot X)))
3612          (dots (and (> dot-count 0)
3613                     (apply ly:stencil-add
3614                            (map (lambda (x)
3615                                   (ly:stencil-translate-axis
3616                                    dot (* 2 x dot-width) X))
3617                                 (iota dot-count))))))
3618
3619     ;; Apart from mensural-, neomensural- and petrucci-style ledgered
3620     ;; glyphs are taken for whole and half rests.
3621     ;; If they are dotted, move the dots in X-direction to avoid collision.
3622     (if (and dots
3623              (< log 2)
3624              (>= log 0)
3625              (not (member style '(neomensural mensural petrucci))))
3626         (set! dots (ly:stencil-translate-axis dots dot-width X)))
3627
3628     ;; Add dots to the rest-glyph.
3629     ;;
3630     ;; Not sure how to vertical align dots.
3631     ;; For now the dots are centered for half, whole or longer rests.
3632     ;; Otherwise placed near the top of the rest.
3633     ;;
3634     ;; Dots for rests with (< log 0) dots are allowed, but not
3635     ;; if multi-measure-rest is set #t.
3636     (if (and (not multi-measure-rest) dots)
3637         (set! rest-glyph
3638               (ly:stencil-add
3639                (ly:stencil-translate
3640                 dots
3641                 (cons
3642                  (+ (cdr (ly:stencil-extent rest-glyph X)) dot-width)
3643                  (if (< log 2)
3644                      (interval-center (ly:stencil-extent rest-glyph Y))
3645                      (- (interval-end (ly:stencil-extent rest-glyph Y))
3646                         (/ (* 2 dot-width) 3)))))
3647                rest-glyph)))
3648     rest-glyph))
3649
3650 (define-markup-command (rest layout props duration)
3651   (string?)
3652   #:category music
3653   #:properties ((style '())
3654                 (multi-measure-rest #f)
3655                 (multi-measure-rest-number #t)
3656                 (word-space 0.6))
3657   "
3658 @cindex rests or multi-measure-rests within text by string
3659
3660 This produces a rest, with the @var{duration} for the rest type and
3661 augmentation dots.
3662 @code{\"breve\"}, @code{\"longa\"} and @code{\"maxima\"} are valid
3663 input-strings.
3664
3665 Printing MultiMeasureRests could be enabled with
3666 @code{\\override #'(multi-measure-rest . #t)}
3667 If MultiMeasureRests are taken, the MultiMeasureRestNumber is printed above.
3668 This is enabled for all styles using default-glyphs.
3669 Could be disabled with @code{\\override #'(multi-measure-rest-number . #f)}
3670
3671 @lilypond[verbatim,quote]
3672 \\markup {
3673   \\rest #\"4..\"
3674   \\hspace #2
3675   \\rest #\"breve\"
3676   \\hspace #2
3677   \\override #'(multi-measure-rest . #t)
3678   {
3679   \\rest #\"7\"
3680   \\hspace #2
3681   \\override #'(multi-measure-rest-number . #f)
3682   \\rest #\"7\"
3683   }
3684 }
3685 @end lilypond"
3686   ;; Get the number of mmr-glyphs.
3687   ;; Store them in a list.
3688   ;; example: (mmr-numbers 25) -> '(3 0 0 1)
3689   (define (mmr-numbers nmbr)
3690     (let* ((8-bar-glyph (floor (/ nmbr 8)))
3691            (8-remainder (remainder nmbr 8))
3692            (4-bar-glyph (floor (/ 8-remainder 4)))
3693            (4-remainder (remainder nmbr 4))
3694            (2-bar-glyph (floor (/ 4-remainder 2)))
3695            (2-remainder (remainder 4-remainder 2))
3696            (1-bar-glyph (floor (/ 2-remainder 1))))
3697       (list 8-bar-glyph 4-bar-glyph 2-bar-glyph 1-bar-glyph)))
3698
3699   ;; Get the correct mmr-glyphs.
3700   ;; Store them in a list.
3701   ;; example:
3702   ;; (get-mmr-glyphs '(1 0 1 0) '("rests.M3" "rests.M2" "rests.M1" "rests.0"))
3703   ;; -> ("rests.M3" "rests.M1")
3704   (define (get-mmr-glyphs lst1 lst2)
3705     (define (helper l1 l2 l3)
3706       (if (null? l1)
3707           (reverse l3)
3708           (helper (cdr l1)
3709                   (cdr l2)
3710                   (append (make-list (car l1) (car l2)) l3))))
3711     (helper lst1 lst2 '()))
3712
3713   ;; If duration is not valid, print a warning and return empty-stencil
3714   (if (or (and (not (integer? (car (parse-simple-duration duration))))
3715                (not multi-measure-rest))
3716           (and (= (string-length (car (string-split duration #\. ))) 1)
3717                (= (string->number (car (string-split duration #\. ))) 0)))
3718       (begin
3719         (ly:warning (_ "not a valid duration string: ~a - ignoring") duration)
3720         empty-stencil)
3721       (let* (
3722              ;; For simple rests:
3723              ;; Get a (log dots) list.
3724              (parsed (parse-simple-duration duration))
3725              ;; Create the rest-stencil
3726              (stil
3727               (rest-by-number-markup layout props (car parsed) (cadr parsed)))
3728              ;; For MultiMeasureRests:
3729              ;; Get the duration-part of duration
3730              (dur-part-string (car (string-split duration #\. )))
3731              ;; Get the duration of MMR:
3732              ;; If not a number (eg. "maxima") calculate it.
3733              (mmr-duration
3734               (or (string->number dur-part-string) (expt 2 (abs (car parsed)))))
3735              ;; Get a list of the correct number of each mmr-glyph.
3736              (count-mmr-glyphs-list (mmr-numbers mmr-duration))
3737              ;; Create a list of mmr-stencils,
3738              ;; translating the glyph for a whole rest.
3739              (mmr-stils-list
3740               (map
3741                (lambda (x)
3742                  (let ((single-mmr-stil
3743                         (rest-by-number-markup layout props (* -1 x) 0)))
3744                    (if (= x 0)
3745                        (ly:stencil-translate-axis
3746                         single-mmr-stil
3747                         ;; Ugh, hard-coded, why 1?
3748                         1
3749                         Y)
3750                        single-mmr-stil)))
3751                (get-mmr-glyphs count-mmr-glyphs-list (reverse (iota 4)))))
3752              ;; Adjust the space between the mmr-glyphs,
3753              ;; if not default-glyphs are used.
3754              (word-space (if (member style
3755                                      '(neomensural mensural petrucci))
3756                              (/ (* word-space 2) 3)
3757                              word-space))
3758              ;; Create the final mmr-stencil
3759              ;; via `stack-stencil-line´ from /scm/markup.scm
3760              (mmr-stil (stack-stencil-line word-space mmr-stils-list)))
3761
3762         ;; Print the number above a multi-measure-rest
3763         ;; Depends on duration, style and multi-measure-rest-number set #t
3764         (if (and multi-measure-rest
3765                  multi-measure-rest-number
3766                  (> mmr-duration 1)
3767                  (not (member style '(neomensural mensural petrucci))))
3768             (let* ((mmr-stil-x-center
3769                     (interval-center (ly:stencil-extent mmr-stil X)))
3770                    (duration-markup
3771                     (markup
3772                      #:fontsize -2
3773                      #:override '(font-encoding . fetaText)
3774                      (number->string mmr-duration)))
3775                    (mmr-number-stil
3776                     (interpret-markup layout props duration-markup))
3777                    (mmr-number-stil-x-center
3778                     (interval-center (ly:stencil-extent mmr-number-stil X))))
3779
3780               (set! mmr-stil (ly:stencil-combine-at-edge
3781                               mmr-stil
3782                               Y UP
3783                               (ly:stencil-translate-axis
3784                                mmr-number-stil
3785                                (- mmr-stil-x-center mmr-number-stil-x-center)
3786                                X)
3787                               ;; Ugh, hardcoded
3788                               0.8))))
3789         (if multi-measure-rest
3790             mmr-stil
3791             stil))))
3792
3793 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3794 ;; fermata markup
3795 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3796
3797 (define-markup-command (fermata layout props) ()
3798   #:category music
3799   #:properties ((direction UP))
3800   "Create a fermata glyph.  When @var{direction} is @code{DOWN}, use
3801 an inverted glyph.  Note that within music, one would usually use the
3802 @code{\\fermata} articulation instead of a markup.
3803
3804 @lilypond[verbatim,quote]
3805  { c1^\\markup \\fermata d1_\\markup \\fermata }
3806
3807 \\markup { \\fermata \\override #`(direction . ,DOWN) \\fermata }
3808 @end lilypond
3809 "
3810   (interpret-markup layout props
3811                     (if (eqv? direction DOWN)
3812                         (markup #:musicglyph "scripts.dfermata")
3813                         (markup #:musicglyph "scripts.ufermata"))))
3814   
3815 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3816 ;; translating.
3817 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3818
3819 (define-markup-command (lower layout props amount arg)
3820   (number? markup?)
3821   #:category align
3822   "
3823 @cindex lowering text
3824
3825 Lower @var{arg} by the distance @var{amount}.
3826 A negative @var{amount} indicates raising; see also @code{\\raise}.
3827
3828 @lilypond[verbatim,quote]
3829 \\markup {
3830   one
3831   \\lower #3
3832   two
3833   three
3834 }
3835 @end lilypond"
3836   (ly:stencil-translate-axis (interpret-markup layout props arg)
3837                              (- amount) Y))
3838
3839 (define-markup-command (translate-scaled layout props offset arg)
3840   (number-pair? markup?)
3841   #:category align
3842   #:properties ((font-size 0))
3843   "
3844 @cindex translating text
3845 @cindex scaling text
3846
3847 Translate @var{arg} by @var{offset}, scaling the offset by the
3848 @code{font-size}.
3849
3850 @lilypond[verbatim,quote]
3851 \\markup {
3852   \\fontsize #5 {
3853     * \\translate #'(2 . 3) translate
3854     \\hspace #2
3855     * \\translate-scaled #'(2 . 3) translate-scaled
3856   }
3857 }
3858 @end lilypond"
3859   (let* ((factor (magstep font-size))
3860          (scaled (cons (* factor (car offset))
3861                        (* factor (cdr offset)))))
3862     (ly:stencil-translate (interpret-markup layout props arg)
3863                           scaled)))
3864
3865 (define-markup-command (raise layout props amount arg)
3866   (number? markup?)
3867   #:category align
3868   "
3869 @cindex raising text
3870
3871 Raise @var{arg} by the distance @var{amount}.
3872 A negative @var{amount} indicates lowering, see also @code{\\lower}.
3873
3874 The argument to @code{\\raise} is the vertical displacement amount,
3875 measured in (global) staff spaces.  @code{\\raise} and @code{\\super}
3876 raise objects in relation to their surrounding markups.
3877
3878 If the text object itself is positioned above or below the staff, then
3879 @code{\\raise} cannot be used to move it, since the mechanism that
3880 positions it next to the staff cancels any shift made with
3881 @code{\\raise}.  For vertical positioning, use the @code{padding}
3882 and/or @code{extra-offset} properties.
3883
3884 @lilypond[verbatim,quote]
3885 \\markup {
3886   C
3887   \\small
3888   \\bold
3889   \\raise #1.0
3890   9/7+
3891 }
3892 @end lilypond"
3893   (ly:stencil-translate-axis (interpret-markup layout props arg) amount Y))
3894
3895 (define-markup-command (fraction layout props arg1 arg2)
3896   (markup? markup?)
3897   #:category other
3898   #:properties ((font-size 0))
3899   "
3900 @cindex creating text fractions
3901
3902 Make a fraction of two markups.
3903 @lilypond[verbatim,quote]
3904 \\markup {
3905   π ≈
3906   \\fraction 355 113
3907 }
3908 @end lilypond"
3909   (let* ((m1 (interpret-markup layout props arg1))
3910          (m2 (interpret-markup layout props arg2))
3911          (factor (magstep font-size))
3912          (boxdimen (cons (* factor -0.05) (* factor 0.05)))
3913          (padding (* factor 0.2))
3914          (baseline (* factor 0.6))
3915          (offset (* factor 0.75)))
3916     (set! m1 (ly:stencil-aligned-to m1 X CENTER))
3917     (set! m2 (ly:stencil-aligned-to m2 X CENTER))
3918     (let* ((x1 (ly:stencil-extent m1 X))
3919            (x2 (ly:stencil-extent m2 X))
3920            (line (ly:round-filled-box (interval-union x1 x2) boxdimen 0.0))
3921            ;; should stack mols separately, to maintain LINE on baseline
3922            (stack (stack-lines DOWN padding baseline (list m1 line m2))))
3923       (set! stack
3924             (ly:stencil-aligned-to stack Y CENTER))
3925       (set! stack
3926             (ly:stencil-aligned-to stack X LEFT))
3927       ;; should have EX dimension
3928       ;; empirical anyway
3929       (ly:stencil-translate-axis stack offset Y))))
3930
3931 (define-markup-command (normal-size-super layout props arg)
3932   (markup?)
3933   #:category font
3934   #:properties ((baseline-skip))
3935   "
3936 @cindex setting superscript in standard font size
3937
3938 Set @var{arg} in superscript with a normal font size.
3939
3940 @lilypond[verbatim,quote]
3941 \\markup {
3942   default
3943   \\normal-size-super {
3944     superscript in standard size
3945   }
3946 }
3947 @end lilypond"
3948   (ly:stencil-translate-axis
3949    (interpret-markup layout props arg)
3950    (* 0.5 baseline-skip) Y))
3951
3952 (define-markup-command (super layout props arg)
3953   (markup?)
3954   #:category font
3955   #:properties ((font-size 0)
3956                 (baseline-skip))
3957   "
3958 @cindex superscript text
3959
3960 Set @var{arg} in superscript.
3961
3962 @lilypond[verbatim,quote]
3963 \\markup {
3964   E =
3965   \\concat {
3966     mc
3967     \\super
3968     2
3969   }
3970 }
3971 @end lilypond"
3972   (ly:stencil-translate-axis
3973    (interpret-markup
3974     layout
3975     (cons `((font-size . ,(- font-size 3))) props)
3976     arg)
3977    (* 0.5 baseline-skip)
3978    Y))
3979
3980 (define-markup-command (translate layout props offset arg)
3981   (number-pair? markup?)
3982   #:category align
3983   "
3984 @cindex translating text
3985
3986 Translate @var{arg} relative to its surroundings.  @var{offset}
3987 is a pair of numbers representing the displacement in the X and Y axis.
3988
3989 @lilypond[verbatim,quote]
3990 \\markup {
3991   *
3992   \\translate #'(2 . 3)
3993   \\line { translated two spaces right, three up }
3994 }
3995 @end lilypond"
3996   (ly:stencil-translate (interpret-markup layout props arg)
3997                         offset))
3998
3999 (define-markup-command (sub layout props arg)
4000   (markup?)
4001   #:category font
4002   #:properties ((font-size 0)
4003                 (baseline-skip))
4004   "
4005 @cindex subscript text
4006
4007 Set @var{arg} in subscript.
4008
4009 @lilypond[verbatim,quote]
4010 \\markup {
4011   \\concat {
4012     H
4013     \\sub {
4014       2
4015     }
4016     O
4017   }
4018 }
4019 @end lilypond"
4020   (ly:stencil-translate-axis
4021    (interpret-markup
4022     layout
4023     (cons `((font-size . ,(- font-size 3))) props)
4024     arg)
4025    (* -0.5 baseline-skip)
4026    Y))
4027
4028 (define-markup-command (normal-size-sub layout props arg)
4029   (markup?)
4030   #:category font
4031   #:properties ((baseline-skip))
4032   "
4033 @cindex setting subscript in standard font size
4034
4035 Set @var{arg} in subscript with a normal font size.
4036
4037 @lilypond[verbatim,quote]
4038 \\markup {
4039   default
4040   \\normal-size-sub {
4041     subscript in standard size
4042   }
4043 }
4044 @end lilypond"
4045   (ly:stencil-translate-axis
4046    (interpret-markup layout props arg)
4047    (* -0.5 baseline-skip)
4048    Y))
4049
4050 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4051 ;; brackets.
4052 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4053
4054 (define-markup-command (hbracket layout props arg)
4055   (markup?)
4056   #:category graphic
4057   "
4058 @cindex placing horizontal brackets around text
4059
4060 Draw horizontal brackets around @var{arg}.
4061
4062 @lilypond[verbatim,quote]
4063 \\markup {
4064   \\hbracket {
4065     \\line {
4066       one two three
4067     }
4068   }
4069 }
4070 @end lilypond"
4071   (let ((th 0.1) ;; todo: take from GROB.
4072         (m (interpret-markup layout props arg)))
4073     (bracketify-stencil m X th (* 2.5 th) th)))
4074
4075 (define-markup-command (bracket layout props arg)
4076   (markup?)
4077   #:category graphic
4078   "
4079 @cindex placing vertical brackets around text
4080
4081 Draw vertical brackets around @var{arg}.
4082
4083 @lilypond[verbatim,quote]
4084 \\markup {
4085   \\bracket {
4086     \\note #\"2.\" #UP
4087   }
4088 }
4089 @end lilypond"
4090   (let ((th 0.1) ;; todo: take from GROB.
4091         (m (interpret-markup layout props arg)))
4092     (bracketify-stencil m Y th (* 2.5 th) th)))
4093
4094 (define-markup-command (parenthesize layout props arg)
4095   (markup?)
4096   #:category graphic
4097   #:properties ((angularity 0)
4098                 (padding)
4099                 (size 1)
4100                 (thickness 1)
4101                 (width 0.25))
4102   "
4103 @cindex placing parentheses around text
4104
4105 Draw parentheses around @var{arg}.  This is useful for parenthesizing
4106 a column containing several lines of text.
4107
4108 @lilypond[verbatim,quote]
4109 \\markup {
4110   \\line {
4111     \\parenthesize {
4112       \\column {
4113         foo
4114         bar
4115       }
4116     }
4117     \\override #'(angularity . 2) {
4118       \\parenthesize {
4119         \\column {
4120           bah
4121           baz
4122         }
4123       }
4124     }
4125   }
4126 }
4127 @end lilypond"
4128   (let* ((markup (interpret-markup layout props arg))
4129          (scaled-width (* size width))
4130          (scaled-thickness
4131           (* (chain-assoc-get 'line-thickness props 0.1)
4132              thickness))
4133          (half-thickness
4134           (min (* size 0.5 scaled-thickness)
4135                (* (/ 4 3.0) scaled-width)))
4136          (padding (chain-assoc-get 'padding props half-thickness)))
4137     (parenthesize-stencil
4138      markup half-thickness scaled-width angularity padding)))
4139
4140
4141 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4142 ;; Delayed markup evaluation
4143 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4144
4145 (define-markup-command (page-ref layout props label gauge default)
4146   (symbol? markup? markup?)
4147   #:category other
4148   "
4149 @cindex referencing page numbers in text
4150
4151 Reference to a page number.  @var{label} is the label set on the referenced
4152 page (using the @code{\\label} command), @var{gauge} a markup used to estimate
4153 the maximum width of the page number, and @var{default} the value to display
4154 when @var{label} is not found."
4155   (let* ((gauge-stencil (interpret-markup layout props gauge))
4156          (x-ext (ly:stencil-extent gauge-stencil X))
4157          (y-ext (ly:stencil-extent gauge-stencil Y)))
4158     (ly:make-stencil
4159      `(delay-stencil-evaluation
4160        ,(delay (ly:stencil-expr
4161                 (let* ((table (ly:output-def-lookup layout 'label-page-table))
4162                        (page-number (if (list? table)
4163                                         (assoc-get label table)
4164                                         #f))
4165                        (page-markup (if page-number (format #f "~a" page-number) default))
4166                        (page-stencil (interpret-markup layout props page-markup))
4167                        (gap (- (interval-length x-ext)
4168                                (interval-length (ly:stencil-extent page-stencil X)))))
4169                   (interpret-markup layout props
4170                                     (markup #:hspace gap page-markup))))))
4171      x-ext
4172      y-ext)))
4173
4174 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4175 ;; scaling
4176 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4177
4178 (define-markup-command (scale layout props factor-pair arg)
4179   (number-pair? markup?)
4180   #:category graphic
4181   "
4182 @cindex scaling markup
4183 @cindex mirroring markup
4184
4185 Scale @var{arg}.  @var{factor-pair} is a pair of numbers
4186 representing the scaling-factor in the X and Y axes.
4187 Negative values may be used to produce mirror images.
4188
4189 @lilypond[verbatim,quote]
4190 \\markup {
4191   \\line {
4192     \\scale #'(2 . 1)
4193     stretched
4194     \\scale #'(1 . -1)
4195     mirrored
4196   }
4197 }
4198 @end lilypond"
4199   (let ((stil (interpret-markup layout props arg))
4200         (sx (car factor-pair))
4201         (sy (cdr factor-pair)))
4202     (ly:stencil-scale stil sx sy)))
4203
4204 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4205 ;; Repeating
4206 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4207
4208 (define-markup-command (pattern layout props count axis space pattern)
4209   (integer? integer? number? markup?)
4210   #:category other
4211   "
4212 Prints @var{count} times a @var{pattern} markup.
4213 Patterns are spaced apart by @var{space}.
4214 Patterns are distributed on @var{axis}.
4215
4216 @lilypond[verbatim, quote]
4217 \\markup \\column {
4218   \"Horizontally repeated :\"
4219   \\pattern #7 #X #2 \\flat
4220   \\null
4221   \"Vertically repeated :\"
4222   \\pattern #3 #Y #0.5 \\flat
4223 }
4224 @end lilypond"
4225   (let ((pattern-width (interval-length
4226                         (ly:stencil-extent (interpret-markup layout props pattern) X)))
4227         (new-props (prepend-alist-chain 'word-space 0 (prepend-alist-chain 'baseline-skip 0 props))))
4228     (let loop ((i (1- count)) (patterns (markup)))
4229       (if (zero? i)
4230           (interpret-markup
4231            layout
4232            new-props
4233            (if (= axis X)
4234                (markup patterns pattern)
4235                (markup #:column (patterns pattern))))
4236           (loop (1- i)
4237                 (if (= axis X)
4238                     (markup patterns pattern #:hspace space)
4239                     (markup #:column (patterns pattern #:vspace space))))))))
4240
4241 (define-markup-command (fill-with-pattern layout props space dir pattern left right)
4242   (number? ly:dir? markup? markup? markup?)
4243   #:category align
4244   #:properties ((word-space)
4245                 (line-width))
4246   "
4247 Put @var{left} and @var{right} in a horizontal line of width @code{line-width}
4248 with a line of markups @var{pattern} in between.
4249 Patterns are spaced apart by @var{space}.
4250 Patterns are aligned to the @var{dir} markup.
4251
4252 @lilypond[verbatim, quote]
4253 \\markup \\column {
4254   \"right-aligned :\"
4255   \\fill-with-pattern #1 #RIGHT . first right
4256   \\fill-with-pattern #1 #RIGHT . second right
4257   \\null
4258   \"center-aligned :\"
4259   \\fill-with-pattern #1.5 #CENTER - left right
4260   \\null
4261   \"left-aligned :\"
4262   \\override #'(line-width . 50)
4263   \\fill-with-pattern #2 #LEFT : left first
4264   \\override #'(line-width . 50)
4265   \\fill-with-pattern #2 #LEFT : left second
4266 }
4267 @end lilypond"
4268   (let* ((pattern-x-extent (ly:stencil-extent (interpret-markup layout props pattern) X))
4269          (pattern-width (interval-length pattern-x-extent))
4270          (left-width (interval-length (ly:stencil-extent (interpret-markup layout props left) X)))
4271          (right-width (interval-length (ly:stencil-extent (interpret-markup layout props right) X)))
4272          (middle-width (max 0 (- line-width (+ (+ left-width right-width) (* word-space 2)))))
4273          (period (+ space pattern-width))
4274          (count (truncate (/ (- middle-width pattern-width) period)))
4275          (x-offset (+ (* (- (- middle-width (* count period)) pattern-width) (/ (1+ dir) 2)) (abs (car pattern-x-extent)))))
4276     (interpret-markup layout props
4277                       (markup left
4278                               #:with-dimensions (cons 0 middle-width) '(0 . 0)
4279                               #:translate (cons x-offset 0)
4280                               #:pattern (1+ count) X space pattern
4281                               right))))
4282
4283 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4284 ;; Replacements
4285 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4286
4287 (define-markup-command (replace layout props replacements arg)
4288   (list? markup?)
4289   #:category font
4290   "
4291 Used to automatically replace a string by another in the markup @var{arg}.
4292 Each pair of the alist @var{replacements} specifies what should be replaced.
4293 The @code{key} is the string to be replaced by the @code{value} string.
4294
4295 @lilypond[verbatim, quote]
4296 \\markup \\replace #'((\"thx\" . \"Thanks!\")) thx
4297 @end lilypond"
4298   (interpret-markup
4299    layout
4300    (internal-add-text-replacements
4301     props
4302     replacements)
4303    (markup arg)))
4304
4305 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4306 ;; Markup list commands
4307 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4308
4309 (define-public (space-lines baseline stils)
4310   (let space-stil ((stils stils)
4311                    (result (list)))
4312     (if (null? stils)
4313         (reverse! result)
4314         (let* ((stil (car stils))
4315                (dy-top (max (- (/ baseline 1.5)
4316                                (interval-bound (ly:stencil-extent stil Y) UP))
4317                             0.0))
4318                (dy-bottom (max (+ (/ baseline 3.0)
4319                                   (interval-bound (ly:stencil-extent stil Y) DOWN))
4320                                0.0))
4321                (new-stil (ly:make-stencil
4322                           (ly:stencil-expr stil)
4323                           (ly:stencil-extent stil X)
4324                           (cons (- (interval-bound (ly:stencil-extent stil Y) DOWN)
4325                                    dy-bottom)
4326                                 (+ (interval-bound (ly:stencil-extent stil Y) UP)
4327                                    dy-top)))))
4328           (space-stil (cdr stils) (cons new-stil result))))))
4329
4330 (define-markup-list-command (justified-lines layout props args)
4331   (markup-list?)
4332   #:properties ((baseline-skip)
4333                 wordwrap-internal-markup-list)
4334   "
4335 @cindex justifying lines of text
4336
4337 Like @code{\\justify}, but return a list of lines instead of a single markup.
4338 Use @code{\\override-lines #'(line-width . @var{X})} to set the line width;
4339 @var{X}@tie{}is the number of staff spaces."
4340   (space-lines baseline-skip
4341                (interpret-markup-list layout props
4342                                       (make-wordwrap-internal-markup-list #t args))))
4343
4344 (define-markup-list-command (wordwrap-lines layout props args)
4345   (markup-list?)
4346   #:properties ((baseline-skip)
4347                 wordwrap-internal-markup-list)
4348   "Like @code{\\wordwrap}, but return a list of lines instead of a single markup.
4349 Use @code{\\override-lines #'(line-width . @var{X})} to set the line width,
4350 where @var{X} is the number of staff spaces."
4351   (space-lines baseline-skip
4352                (interpret-markup-list layout props
4353                                       (make-wordwrap-internal-markup-list #f args))))
4354
4355 (define-markup-list-command (column-lines layout props args)
4356   (markup-list?)
4357   #:properties ((baseline-skip))
4358   "Like @code{\\column}, but return a list of lines instead of a single markup.
4359 @code{baseline-skip} determines the space between each markup in @var{args}."
4360   (space-lines baseline-skip
4361                (interpret-markup-list layout props args)))
4362
4363 (define-markup-list-command (override-lines layout props new-prop args)
4364   (pair? markup-list?)
4365   "Like @code{\\override}, for markup lists."
4366   (interpret-markup-list layout (cons (list new-prop) props) args))
4367
4368 (define-markup-list-command (map-markup-commands layout props compose args)
4369   (procedure? markup-list?)
4370   "This applies the function @var{compose} to every markup in
4371 @var{args} (including elements of markup list command calls) in order
4372 to produce a new markup list.  Since the return value from a markup
4373 list command call is not a markup list but rather a list of stencils,
4374 this requires passing those stencils off as the results of individual
4375 markup calls.  That way, the results should work out as long as no
4376 markups rely on side effects."
4377   (let ((key (make-symbol "key")))
4378     (catch
4379      key
4380      (lambda ()
4381        ;; if `compose' does not actually interpret its markup
4382        ;; argument, we still need to return a list of stencils,
4383        ;; created from the single returned stencil
4384        (list
4385         (interpret-markup layout props
4386                           (compose
4387                            (make-on-the-fly-markup
4388                             (lambda (layout props m)
4389                               ;; here all effects of `compose' on the
4390                               ;; properties should be visible, so we
4391                               ;; call interpret-markup-list at this
4392                               ;; point of time and harvest its
4393                               ;; stencils
4394                               (throw key
4395                                      (interpret-markup-list
4396                                       layout props args)))
4397                             (make-null-markup))))))
4398      (lambda (key stencils)
4399        (map
4400         (lambda (sten)
4401           (interpret-markup layout props
4402                             (compose (make-stencil-markup sten))))
4403         stencils)))))