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