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