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