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