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