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