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