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