]> git.donarmstrong.com Git - lilypond.git/blob - scm/define-markup-commands.scm
Markups: document define-builtin-markup-command
[lilypond.git] / scm / define-markup-commands.scm
1 ;;;; define-markup-commands.scm -- markup commands
2 ;;;;
3 ;;;;  source file of the GNU LilyPond music typesetter
4 ;;;;
5 ;;;; (c) 2000--2009  Han-Wen Nienhuys <hanwen@xs4all.nl>
6 ;;;;                  Jan Nieuwenhuizen <janneke@gnu.org>
7
8 ;;;
9 ;;; Markup commands and markup-list commands definitions.
10 ;;;
11 ;;; Markup commands which are part of LilyPond, are defined
12 ;;; in the (lily) module, which is the current module in this file,
13 ;;; using the `define-builtin-markup-command' macro.
14 ;;;
15 ;;; Usage:
16 ;;;
17 ;;; (define-builtin-markup-command (command-name layout props args...)
18 ;;;   args-signature
19 ;;;   category
20 ;;;   property-bindings
21 ;;;   documentation-string
22 ;;;   ..body..)
23 ;;;
24 ;;; with:
25 ;;;   command-name
26 ;;;     the name of the markup command
27 ;;;
28 ;;;   layout and props
29 ;;;     arguments that are automatically passed to the command when it
30 ;;;     is interpreted.
31 ;;;     `layout' is an output def, which properties can be accessed
32 ;;;     using `ly:output-def-lookup'.
33 ;;;     `props' is a list of property settings which can be accessed
34 ;;;     using `chain-assoc-get' (more on that below)
35 ;;;
36 ;;;   args...
37 ;;;     the command arguments. There are restrictions on the
38 ;;;     possible arguments for a markup command.
39 ;;;     First, arguments are distingued according to their type:
40 ;;;       1) a markup (or a string), corresponding to type predicate `markup?'
41 ;;;       2) a list of markups, corresponding to type predicate `markup-list?'
42 ;;;       3) any scheme object, corresponding to type predicates such as
43 ;;;       `list?', 'number?', 'boolean?', etc.
44 ;;;     The supported arrangements of arguments, according to their type, are:
45 ;;;       - no argument
46 ;;;       - markup
47 ;;;       - scheme
48 ;;;       - markup, markup
49 ;;;       - markup-list
50 ;;;       - scheme, scheme
51 ;;;       - scheme, markup
52 ;;;       - scheme, scheme, markup
53 ;;;       - scheme, scheme, markup, markup
54 ;;;       - scheme, markup, markup
55 ;;;       - scheme, scheme, scheme
56 ;;;     This combinations are hard-coded in the lexer and in the parser
57 ;;;     (lily/lexer.ll and lily/parser.yy)
58 ;;;
59 ;;;   args-signature
60 ;;;     the arguments signature, i.e. a list of type predicates which
61 ;;;     are used to type check the arguments, and also to define the general
62 ;;;     argument types (markup, markup-list, scheme) that the command is
63 ;;;     expecting.
64 ;;;     For instance, if a command expects a number, then a markup, the
65 ;;;     signature would be: (number? markup?)
66 ;;;
67 ;;;   category
68 ;;;     for documentation purpose, builtin markup commands are grouped by
69 ;;;     category. This can be any symbol. When documentation is generated,
70 ;;;     the symbol is converted to a capitalized string, where hyphens are
71 ;;;     replaced by spaces.
72 ;;;
73 ;;;   property-bindings
74 ;;;     this is used both for documentation generation, and to ease
75 ;;;     programming the command itself. It is list of
76 ;;;        (property-name default-value)
77 ;;;     or (property-name)
78 ;;;     elements. Each property is looked-up in the `props' argument, and
79 ;;;     the symbol naming the property is bound to its value.
80 ;;;     When the property is not found in `props', then the symbol is bound
81 ;;;     to the given default value. When no default value is given, #f is
82 ;;;     used instead.
83 ;;;     Thus, using the following property bindings:
84 ;;;       ((thickness 0.1)
85 ;;;        (font-size 0))
86 ;;;     is equivalent to writing:
87 ;;;       (let ((thickness (chain-assoc-get 'thickness props 0.1))
88 ;;;             (font-size (chain-assoc-get 'font-size props 0)))
89 ;;;         ..body..)
90 ;;;     When a command `B' internally calls an other command `A', it may
91 ;;;     desirable to see in `B' documentation all the properties and
92 ;;;     default values used by `A'. In that case, add `A-markup' to the
93 ;;;     property-bindings of B. (This is used when generating
94 ;;;     documentation, but won't create bindings.)
95 ;;;
96 ;;;   documentation-string
97 ;;;     the command documentation string (used to generate manuals)
98 ;;;
99 ;;;   body
100 ;;;     the command body. The function is supposed to return a stencil.
101 ;;;
102 ;;; Each markup command definition shall have a documentation string
103 ;;; with description, syntax and example.
104
105 (use-modules (ice-9 regex))
106
107 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
108 ;; utility functions
109 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
110
111 (define-public empty-stencil (ly:make-stencil '() '(1 . -1) '(1 . -1)))
112 (define-public point-stencil (ly:make-stencil "" '(0 . 0) '(0 . 0)))
113
114 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
115 ;; geometric shapes
116 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
117
118 (define-builtin-markup-command (draw-line layout props dest)
119   (number-pair?)
120   graphic
121   ((thickness 1))
122   "
123 @cindex drawing lines within text
124
125 A simple line.
126 @lilypond[verbatim,quote]
127 \\markup {
128   \\draw-line #'(4 . 4)
129   \\override #'(thickness . 5)
130   \\draw-line #'(-3 . 0)
131 }
132 @end lilypond"
133   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
134                thickness))
135         (x (car dest))
136         (y (cdr dest)))
137     (make-line-stencil th 0 0 x y)))
138
139 (define-builtin-markup-command (draw-circle layout props radius thickness filled)
140   (number? number? boolean?)
141   graphic
142   ()
143   "
144 @cindex drawing circles within text
145
146 A circle of radius @var{radius} and thickness @var{thickness},
147 optionally filled.
148
149 @lilypond[verbatim,quote]
150 \\markup {
151   \\draw-circle #2 #0.5 ##f
152   \\hspace #2
153   \\draw-circle #2 #0 ##t
154 }
155 @end lilypond"
156   (make-circle-stencil radius thickness filled))
157
158 (define-builtin-markup-command (triangle layout props filled)
159   (boolean?)
160   graphic
161   ((thickness 0.1)
162    (font-size 0)
163    (baseline-skip 2))
164   "
165 @cindex drawing triangles within text
166
167 A triangle, either filled or empty.
168
169 @lilypond[verbatim,quote]
170 \\markup {
171   \\triangle ##t
172   \\hspace #2
173   \\triangle ##f
174 }
175 @end lilypond"
176   (let ((ex (* (magstep font-size) 0.8 baseline-skip)))
177     (ly:make-stencil
178      `(polygon '(0.0 0.0
179                      ,ex 0.0
180                      ,(* 0.5 ex)
181                      ,(* 0.86 ex))
182            ,thickness
183            ,filled)
184      (cons 0 ex)
185      (cons 0 (* .86 ex)))))
186
187 (define-builtin-markup-command (circle layout props arg)
188   (markup?)
189   graphic
190   ((thickness 1)
191    (font-size 0)
192    (circle-padding 0.2))
193   "
194 @cindex circling text
195
196 Draw a circle around @var{arg}.  Use @code{thickness},
197 @code{circle-padding} and @code{font-size} properties to determine line
198 thickness and padding around the markup.
199
200 @lilypond[verbatim,quote]
201 \\markup {
202   \\circle {
203     Hi
204   }
205 }
206 @end lilypond"
207   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
208                thickness))
209          (pad (* (magstep font-size) circle-padding))
210          (m (interpret-markup layout props arg)))
211     (circle-stencil m th pad)))
212
213 (define-builtin-markup-command (with-url layout props url arg)
214   (string? markup?)
215   graphic
216   ()
217   "
218 @cindex inserting URL links into text
219
220 Add a link to URL @var{url} around @var{arg}.  This only works in
221 the PDF backend.
222
223 @lilypond[verbatim,quote]
224 \\markup {
225   \\with-url #\"http://lilypond.org/web/\" {
226     LilyPond ... \\italic {
227       music notation for everyone
228     }
229   }
230 }
231 @end lilypond"
232   (let* ((stil (interpret-markup layout props arg))
233          (xextent (ly:stencil-extent stil X))
234          (yextent (ly:stencil-extent stil Y))
235          (old-expr (ly:stencil-expr stil))
236          (url-expr (list 'url-link url `(quote ,xextent) `(quote ,yextent))))
237
238     (ly:stencil-add (ly:make-stencil url-expr xextent yextent) stil)))
239
240 (define-builtin-markup-command (beam layout props width slope thickness)
241   (number? number? number?)
242   graphic
243   ()
244   "
245 @cindex drawing beams within text
246
247 Create a beam with the specified parameters.
248 @lilypond[verbatim,quote]
249 \\markup {
250   \\beam #5 #1 #2
251 }
252 @end lilypond"
253   (let* ((y (* slope width))
254          (yext (cons (min 0 y) (max 0 y)))
255          (half (/ thickness 2)))
256
257     (ly:make-stencil
258      `(polygon ',(list
259                   0 (/ thickness -2)
260                     width (+ (* width slope)  (/ thickness -2))
261                     width (+ (* width slope)  (/ thickness 2))
262                     0 (/ thickness 2))
263                ,(ly:output-def-lookup layout 'blot-diameter)
264                #t)
265      (cons 0 width)
266      (cons (+ (- half) (car yext))
267            (+ half (cdr yext))))))
268
269 (define-builtin-markup-command (underline layout props arg)
270   (markup?)
271   font
272   ((thickness 1))
273   "
274 @cindex underlining text
275
276 Underline @var{arg}.  Looks at @code{thickness} to determine line
277 thickness and y-offset.
278
279 @lilypond[verbatim,quote]
280 \\markup {
281   default
282   \\hspace #2
283   \\override #'(thickness . 2)
284   \\underline {
285     underline
286   }
287 }
288 @end lilypond"
289   (let* ((thick (* (ly:output-def-lookup layout 'line-thickness)
290                    thickness))
291          (markup (interpret-markup layout props arg))
292          (x1 (car (ly:stencil-extent markup X)))
293          (x2 (cdr (ly:stencil-extent markup X)))
294          (y (* thick -2))
295          (line (make-line-stencil thick x1 y x2 y)))
296     (ly:stencil-add markup line)))
297
298 (define-builtin-markup-command (box layout props arg)
299   (markup?)
300   font
301   ((thickness 1)
302    (font-size 0)
303    (box-padding 0.2))
304   "
305 @cindex enclosing text within a box
306
307 Draw a box round @var{arg}.  Looks at @code{thickness},
308 @code{box-padding} and @code{font-size} properties to determine line
309 thickness and padding around the markup.
310
311 @lilypond[verbatim,quote]
312 \\markup {
313   \\override #'(box-padding . 0.5)
314   \\box
315   \\line { V. S. }
316 }
317 @end lilypond"
318   (let* ((th (* (ly:output-def-lookup layout 'line-thickness)
319                 thickness))
320          (pad (* (magstep font-size) box-padding))
321          (m (interpret-markup layout props arg)))
322     (box-stencil m th pad)))
323
324 (define-builtin-markup-command (filled-box layout props xext yext blot)
325   (number-pair? number-pair? number?)
326   graphic
327   ()
328   "
329 @cindex drawing solid boxes within text
330 @cindex drawing boxes with rounded corners
331
332 Draw a box with rounded corners of dimensions @var{xext} and
333 @var{yext}.  For example,
334 @verbatim
335 \\filled-box #'(-.3 . 1.8) #'(-.3 . 1.8) #0
336 @end verbatim
337 creates a box extending horizontally from -0.3 to 1.8 and
338 vertically from -0.3 up to 1.8, with corners formed from a
339 circle of diameter@tie{}0 (i.e., sharp corners).
340
341 @lilypond[verbatim,quote]
342 \\markup {
343   \\filled-box #'(0 . 4) #'(0 . 4) #0
344   \\filled-box #'(0 . 2) #'(-4 . 2) #0.4
345   \\filled-box #'(1 . 8) #'(0 . 7) #0.2
346   \\with-color #white
347   \\filled-box #'(-4.5 . -2.5) #'(3.5 . 5.5) #0.7
348 }
349 @end lilypond"
350   (ly:round-filled-box
351    xext yext blot))
352
353 (define-builtin-markup-command (rounded-box layout props arg)
354   (markup?)
355   graphic
356   ((thickness 1)
357    (corner-radius 1)
358    (font-size 0)
359    (box-padding 0.5))
360   "@cindex enclosing text in a box with rounded corners
361    @cindex drawing boxes with rounded corners around text
362 Draw a box with rounded corners around @var{arg}.  Looks at @code{thickness},
363 @code{box-padding} and @code{font-size} properties to determine line
364 thickness and padding around the markup; the @code{corner-radius} property
365 makes it possible to define another shape for the corners (default is 1).
366
367 @lilypond[quote,verbatim,relative=2]
368 c4^\\markup {
369   \\rounded-box {
370     Overtura
371   }
372 }
373 c,8. c16 c4 r
374 @end lilypond"
375   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
376                thickness))
377         (pad (* (magstep font-size) box-padding))
378         (m (interpret-markup layout props arg)))
379     (ly:stencil-add (rounded-box-stencil m th pad corner-radius)
380                     m)))
381
382 (define-builtin-markup-command (rotate layout props ang arg)
383   (number? markup?)
384   align
385   ()
386   "
387 @cindex rotating text
388
389 Rotate object with @var{ang} degrees around its center.
390
391 @lilypond[verbatim,quote]
392 \\markup {
393   default
394   \\hspace #2
395   \\rotate #45
396   \\line {
397     rotated 45°
398   }
399 }
400 @end lilypond"
401   (let* ((stil (interpret-markup layout props arg)))
402     (ly:stencil-rotate stil ang 0 0)))
403
404 (define-builtin-markup-command (whiteout layout props arg)
405   (markup?)
406   other
407   ()
408   "
409 @cindex adding a white background to text
410
411 Provide a white background for @var{arg}.
412
413 @lilypond[verbatim,quote]
414 \\markup {
415   \\combine
416     \\filled-box #'(-1 . 10) #'(-3 . 4) #1
417     \\whiteout whiteout
418 }
419 @end lilypond"
420   (stencil-whiteout (interpret-markup layout props arg)))
421
422 (define-builtin-markup-command (pad-markup layout props amount arg)
423   (number? markup?)
424   align
425   ()
426   "
427 @cindex padding text
428 @cindex putting space around text
429
430 Add space around a markup object.
431
432 @lilypond[verbatim,quote]
433 \\markup {
434   \\box {
435     default
436   }
437   \\hspace #2
438   \\box {
439     \\pad-markup #1 {
440       padded
441     }
442   }
443 }
444 @end lilypond"
445   (let*
446       ((stil (interpret-markup layout props arg))
447        (xext (ly:stencil-extent stil X))
448        (yext (ly:stencil-extent stil Y)))
449
450     (ly:make-stencil
451      (ly:stencil-expr stil)
452      (interval-widen xext amount)
453      (interval-widen yext amount))))
454
455 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
456 ;; space
457 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
458
459 (define-builtin-markup-command (strut layout props)
460   ()
461   other
462   ()
463   "
464 @cindex creating vertical spaces in text
465
466 Create a box of the same height as the space in the current font."
467   (let ((m (ly:text-interface::interpret-markup layout props " ")))
468     (ly:make-stencil (ly:stencil-expr m)
469                      '(0 . 0)
470                      (ly:stencil-extent m X)
471                      )))
472
473 ;; todo: fix negative space
474 (define-builtin-markup-command (hspace layout props amount)
475   (number?)
476   align
477   ()
478   "
479 @cindex creating horizontal spaces in text
480
481 Create an invisible object taking up horizontal space @var{amount}.
482
483 @lilypond[verbatim,quote]
484 \\markup {
485   one
486   \\hspace #2
487   two
488   \\hspace #8
489   three
490 }
491 @end lilypond"
492   (if (> amount 0)
493       (ly:make-stencil "" (cons 0 amount) '(-1 . 1))
494       (ly:make-stencil "" (cons amount amount) '(-1 . 1))))
495
496 ;; todo: fix negative space
497 (define-builtin-markup-command (vspace layout props amount)
498  (number?)
499  align
500  ()
501  "
502 @cindex creating vertical spaces in text
503
504 Create an invisible object taking up vertical space
505 of @var{amount} multiplied by 3.
506
507 @lilypond[verbatim,quote]
508 \\markup {
509     \\center-column {
510     one
511     \\vspace #2
512     two
513     \\vspace #5
514     three
515   }
516 }
517 @end lilypond"
518   (let ((amount (* amount 3.0)))
519     (if (> amount 0)
520         (ly:make-stencil "" (cons -1 1) (cons 0 amount))
521         (ly:make-stencil "" (cons -1 1) (cons amount amount)))))
522
523
524 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
525 ;; importing graphics.
526 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
527
528 (define-builtin-markup-command (stencil layout props stil)
529   (ly:stencil?)
530   other
531   ()
532   "
533 @cindex importing stencils into text
534
535 Use a stencil as markup.
536
537 @lilypond[verbatim,quote]
538 \\markup {
539   \\stencil #(make-circle-stencil 2 0 #t)
540 }
541 @end lilypond"
542   stil)
543
544 (define bbox-regexp
545   (make-regexp "%%BoundingBox:[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)"))
546
547 (define (get-postscript-bbox string)
548   "Extract the bbox from STRING, or return #f if not present."
549   (let*
550       ((match (regexp-exec bbox-regexp string)))
551
552     (if match
553         (map (lambda (x)
554                (string->number (match:substring match x)))
555              (cdr (iota 5)))
556
557         #f)))
558
559 (define-builtin-markup-command (epsfile layout props axis size file-name)
560   (number? number? string?)
561   graphic
562   ()
563   "
564 @cindex inlining an Encapsulated PostScript image
565
566 Inline an EPS image.  The image is scaled along @var{axis} to
567 @var{size}.
568
569 @lilypond[verbatim,quote]
570 \\markup {
571   \\general-align #Y #DOWN {
572     \\epsfile #X #20 #\"context-example.eps\"
573     \\epsfile #Y #20 #\"context-example.eps\"
574   }
575 }
576 @end lilypond"
577   (if (ly:get-option 'safe)
578       (interpret-markup layout props "not allowed in safe")
579       (eps-file->stencil axis size file-name)
580       ))
581
582 (define-builtin-markup-command (postscript layout props str)
583   (string?)
584   graphic
585   ()
586   "
587 @cindex inserting PostScript directly into text
588 This inserts @var{str} directly into the output as a PostScript
589 command string.
590
591 @lilypond[verbatim,quote]
592 ringsps = #\"
593   0.15 setlinewidth
594   0.9 0.6 moveto
595   0.4 0.6 0.5 0 361 arc
596   stroke
597   1.0 0.6 0.5 0 361 arc
598   stroke
599   \"
600
601 rings = \\markup {
602   \\with-dimensions #'(-0.2 . 1.6) #'(0 . 1.2)
603   \\postscript #ringsps
604 }
605
606 \\relative c'' {
607   c2^\\rings
608   a2_\\rings
609 }
610 @end lilypond"
611   ;; FIXME
612   (ly:make-stencil
613    (list 'embedded-ps
614          (format "
615 gsave currentpoint translate
616 0.1 setlinewidth
617  ~a
618 grestore
619 "
620                  str))
621    '(0 . 0) '(0 . 0)))
622
623 (define-builtin-markup-command (score layout props score)
624   (ly:score?)
625   music
626   ((baseline-skip))
627   "
628 @cindex inserting music into text
629
630 Inline an image of music.
631
632 @lilypond[verbatim,quote]
633 \\markup {
634   \\score {
635     \\new PianoStaff <<
636       \\new Staff \\relative c' {
637         \\key f \\major
638         \\time 3/4
639         \\mark \\markup { Allegro }
640         f2\\p( a4)
641         c2( a4)
642         bes2( g'4)
643         f8( e) e4 r
644       }
645       \\new Staff \\relative c {
646         \\clef bass
647         \\key f \\major
648         \\time 3/4
649         f8( a c a c a
650         f c' es c es c)
651         f,( bes d bes d bes)
652         f( g bes g bes g)
653       }
654     >>
655     \\layout {
656       indent = 0.0\\cm
657       \\context {
658         \\Score
659         \\override RehearsalMark #'break-align-symbols =
660           #'(time-signature key-signature)
661         \\override RehearsalMark #'self-alignment-X = #LEFT
662       }
663       \\context {
664         \\Staff
665         \\override TimeSignature #'break-align-anchor-alignment = #LEFT
666       }
667     }
668   }
669 }
670 @end lilypond"
671   (let ((output (ly:score-embedded-format score layout)))
672
673     (if (ly:music-output? output)
674         (stack-stencils Y DOWN baseline-skip
675                         (map paper-system-stencil
676                              (vector->list
677                               (ly:paper-score-paper-systems output))))
678         (begin
679           (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?"))
680           empty-stencil))))
681
682 (define-builtin-markup-command (null layout props)
683   ()
684   other
685   ()
686   "
687 @cindex creating empty text objects
688
689 An empty markup with extents of a single point.
690
691 @lilypond[verbatim,quote]
692 \\markup {
693   \\null
694 }
695 @end lilypond"
696   point-stencil)
697
698 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
699 ;; basic formatting.
700 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
701
702 (define-builtin-markup-command (simple layout props str)
703   (string?)
704   font
705   ()
706   "
707 @cindex simple text strings
708
709 A simple text string; @code{\\markup @{ foo @}} is equivalent with
710 @code{\\markup @{ \\simple #\"foo\" @}}.
711
712 Note: for creating standard text markup or defining new markup commands,
713 the use of @code{\\simple} is unnecessary.
714
715 @lilypond[verbatim,quote]
716 \\markup {
717   \\simple #\"simple\"
718   \\simple #\"text\"
719   \\simple #\"strings\"
720 }
721 @end lilypond"
722   (interpret-markup layout props str))
723
724 (define-builtin-markup-command (tied-lyric layout props str)
725   (string?)
726   music
727   ()
728   "
729 @cindex simple text strings with tie characters
730
731 Like simple-markup, but use tie characters for @q{~} tilde symbols.
732
733 @lilypond[verbatim,quote]
734 \\markup {
735   \\tied-lyric #\"Lasciate~i monti\"
736 }
737 @end lilypond"
738   (if (string-contains str "~")
739       (let*
740           ((parts (string-split str #\~))
741            (tie-str (ly:wide-char->utf-8 #x203f))
742            (joined  (list-join parts tie-str))
743            (join-stencil (interpret-markup layout props tie-str))
744            )
745
746         (interpret-markup layout
747                           (prepend-alist-chain
748                            'word-space
749                            (/ (interval-length (ly:stencil-extent join-stencil X)) -3.5)
750                            props)
751                           (make-line-markup joined)))
752                            ;(map (lambda (s) (interpret-markup layout props s)) parts))
753       (interpret-markup layout props str)))
754
755 (define-public empty-markup
756   (make-simple-markup ""))
757
758 ;; helper for justifying lines.
759 (define (get-fill-space word-count line-width text-widths)
760   "Calculate the necessary paddings between each two adjacent texts.
761         The lengths of all texts are stored in @var{text-widths}.
762         The normal formula for the padding between texts a and b is:
763         padding = line-width/(word-count - 1) - (length(a) + length(b))/2
764         The first and last padding have to be calculated specially using the
765         whole length of the first or last text.
766         Return a list of paddings."
767   (cond
768    ((null? text-widths) '())
769
770    ;; special case first padding
771    ((= (length text-widths) word-count)
772     (cons
773      (- (- (/ line-width (1- word-count)) (car text-widths))
774         (/ (car (cdr text-widths)) 2))
775      (get-fill-space word-count line-width (cdr text-widths))))
776    ;; special case last padding
777    ((= (length text-widths) 2)
778     (list (- (/ line-width (1- word-count))
779              (+ (/ (car text-widths) 2) (car (cdr text-widths)))) 0))
780    (else
781     (cons
782      (- (/ line-width (1- word-count))
783         (/ (+ (car text-widths) (car (cdr text-widths))) 2))
784      (get-fill-space word-count line-width (cdr text-widths))))))
785
786 (define-builtin-markup-command (fill-line layout props args)
787   (markup-list?)
788   align
789   ((text-direction RIGHT)
790    (word-space 1)
791    (line-width #f))
792   "Put @var{markups} in a horizontal line of width @var{line-width}.
793 The markups are spaced or flushed to fill the entire line.
794 If there are no arguments, return an empty stencil.
795
796 @lilypond[verbatim,quote]
797 \\markup {
798   \\column {
799     \\fill-line {
800       Words evenly spaced across the page
801     }
802     \\null
803     \\fill-line {
804       \\line { Text markups }
805       \\line {
806         \\italic { evenly spaced }
807       }
808       \\line { across the page }
809     }
810   }
811 }
812 @end lilypond"
813   (let* ((orig-stencils (interpret-markup-list layout props args))
814          (stencils
815           (map (lambda (stc)
816                  (if (ly:stencil-empty? stc)
817                      point-stencil
818                      stc)) orig-stencils))
819          (text-widths
820           (map (lambda (stc)
821                  (if (ly:stencil-empty? stc)
822                      0.0
823                      (interval-length (ly:stencil-extent stc X))))
824                stencils))
825          (text-width (apply + text-widths))
826          (word-count (length stencils))
827          (prop-line-width (chain-assoc-get 'line-width props #f))
828          (line-width (or line-width (ly:output-def-lookup layout 'line-width)))
829          (fill-space
830                 (cond
831                         ((= word-count 1)
832                                 (list
833                                         (/ (- line-width text-width) 2)
834                                         (/ (- line-width text-width) 2)))
835                         ((= word-count 2)
836                                 (list
837                                         (- line-width text-width)))
838                         (else
839                                 (get-fill-space word-count line-width text-widths))))
840          (fill-space-normal
841           (map (lambda (x)
842                  (if (< x word-space)
843                      word-space
844                      x))
845                fill-space))
846
847          (line-stencils (if (= word-count 1)
848                             (list
849                              point-stencil
850                              (car stencils)
851                              point-stencil)
852                             stencils)))
853
854     (if (= text-direction LEFT)
855         (set! line-stencils (reverse line-stencils)))
856
857     (if (null? (remove ly:stencil-empty? orig-stencils))
858         empty-stencil
859         (stack-stencils-padding-list X
860                                      RIGHT fill-space-normal line-stencils))))
861
862 (define-builtin-markup-command (line layout props args)
863   (markup-list?)
864   align
865   ((word-space)
866    (text-direction RIGHT))
867   "Put @var{args} in a horizontal line.  The property @code{word-space}
868 determines the space between markups in @var{args}.
869
870 @lilypond[verbatim,quote]
871 \\markup {
872   \\line {
873     one two three
874   }
875 }
876 @end lilypond"
877   (let ((stencils (interpret-markup-list layout props args)))
878     (if (= text-direction LEFT)
879         (set! stencils (reverse stencils)))
880     (stack-stencil-line
881      word-space
882      (remove ly:stencil-empty? stencils))))
883
884 (define-builtin-markup-command (concat layout props args)
885   (markup-list?)
886   align
887   ()
888   "
889 @cindex concatenating text
890 @cindex ligatures in text
891
892 Concatenate @var{args} in a horizontal line, without spaces in between.
893 Strings and simple markups are concatenated on the input level, allowing
894 ligatures.  For example, @code{\\concat @{ \"f\" \\simple #\"i\" @}} is
895 equivalent to @code{\"fi\"}.
896
897 @lilypond[verbatim,quote]
898 \\markup {
899   \\concat {
900     one
901     two
902     three
903   }
904 }
905 @end lilypond"
906   (define (concat-string-args arg-list)
907     (fold-right (lambda (arg result-list)
908                   (let ((result (if (pair? result-list)
909                                     (car result-list)
910                                   '())))
911                     (if (and (pair? arg) (eqv? (car arg) simple-markup))
912                       (set! arg (cadr arg)))
913                     (if (and (string? result) (string? arg))
914                         (cons (string-append arg result) (cdr result-list))
915                       (cons arg result-list))))
916                 '()
917                 arg-list))
918
919   (interpret-markup layout
920                     (prepend-alist-chain 'word-space 0 props)
921                     (make-line-markup (if (markup-command-list? args)
922                                           args
923                                           (concat-string-args args)))))
924
925 (define (wordwrap-stencils stencils
926                            justify base-space line-width text-dir)
927   "Perform simple wordwrap, return stencil of each line."
928   (define space (if justify
929                     ;; justify only stretches lines.
930                     (* 0.7 base-space)
931                     base-space))
932   (define (take-list width space stencils
933                      accumulator accumulated-width)
934     "Return (head-list . tail) pair, with head-list fitting into width"
935     (if (null? stencils)
936         (cons accumulator stencils)
937         (let* ((first (car stencils))
938                (first-wid (cdr (ly:stencil-extent (car stencils) X)))
939                (newwid (+ space first-wid accumulated-width)))
940           (if (or (null? accumulator)
941                   (< newwid width))
942               (take-list width space
943                          (cdr stencils)
944                          (cons first accumulator)
945                          newwid)
946               (cons accumulator stencils)))))
947   (let loop ((lines '())
948              (todo stencils))
949     (let* ((line-break (take-list line-width space todo
950                                   '() 0.0))
951            (line-stencils (car line-break))
952            (space-left (- line-width
953                           (apply + (map (lambda (x) (cdr (ly:stencil-extent x X)))
954                                         line-stencils))))
955            (line-word-space (cond ((not justify) space)
956                                   ;; don't stretch last line of paragraph.
957                                   ;; hmmm . bug - will overstretch the last line in some case.
958                                   ((null? (cdr line-break))
959                                    base-space)
960                                   ((null? line-stencils) 0.0)
961                                   ((null? (cdr line-stencils)) 0.0)
962                                   (else (/ space-left (1- (length line-stencils))))))
963            (line (stack-stencil-line line-word-space
964                                      (if (= text-dir RIGHT)
965                                          (reverse line-stencils)
966                                          line-stencils))))
967       (if (pair? (cdr line-break))
968           (loop (cons line lines)
969                 (cdr line-break))
970           (begin
971             (if (= text-dir LEFT)
972                 (set! line
973                       (ly:stencil-translate-axis
974                        line
975                        (- line-width (interval-end (ly:stencil-extent line X)))
976                        X)))
977             (reverse (cons line lines)))))))
978
979 (define-builtin-markup-list-command (wordwrap-internal layout props justify args)
980   (boolean? markup-list?)
981   ((line-width #f)
982    (word-space)
983    (text-direction RIGHT))
984   "Internal markup list command used to define @code{\\justify} and @code{\\wordwrap}."
985   (wordwrap-stencils (remove ly:stencil-empty?
986                              (interpret-markup-list layout props args))
987                      justify
988                      word-space
989                      (or line-width
990                          (ly:output-def-lookup layout 'line-width))
991                      text-direction))
992
993 (define-builtin-markup-command (justify layout props args)
994   (markup-list?)
995   align
996   ((baseline-skip)
997    wordwrap-internal-markup-list)
998   "
999 @cindex justifying text
1000
1001 Like @code{\\wordwrap}, but with lines stretched to justify the margins.
1002 Use @code{\\override #'(line-width . @var{X})} to set the line width;
1003 @var{X}@tie{}is the number of staff spaces.
1004
1005 @lilypond[verbatim,quote]
1006 \\markup {
1007   \\justify {
1008     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
1009     do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1010     Ut enim ad minim veniam, quis nostrud exercitation ullamco
1011     laboris nisi ut aliquip ex ea commodo consequat.
1012   }
1013 }
1014 @end lilypond"
1015   (stack-lines DOWN 0.0 baseline-skip
1016                (wordwrap-internal-markup-list layout props #t args)))
1017
1018 (define-builtin-markup-command (wordwrap layout props args)
1019   (markup-list?)
1020   align
1021   ((baseline-skip)
1022    wordwrap-internal-markup-list)
1023   "Simple wordwrap.  Use @code{\\override #'(line-width . @var{X})} to set
1024 the line width, where @var{X} is the number of staff spaces.
1025
1026 @lilypond[verbatim,quote]
1027 \\markup {
1028   \\wordwrap {
1029     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
1030     do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1031     Ut enim ad minim veniam, quis nostrud exercitation ullamco
1032     laboris nisi ut aliquip ex ea commodo consequat.
1033   }
1034 }
1035 @end lilypond"
1036   (stack-lines DOWN 0.0 baseline-skip
1037                (wordwrap-internal-markup-list layout props #f args)))
1038
1039 (define-builtin-markup-list-command (wordwrap-string-internal layout props justify arg)
1040   (boolean? string?)
1041   ((line-width)
1042    (word-space)
1043    (text-direction RIGHT))
1044   "Internal markup list command used to define @code{\\justify-string} and
1045 @code{\\wordwrap-string}."
1046   (let* ((para-strings (regexp-split
1047                         (string-regexp-substitute
1048                          "\r" "\n"
1049                          (string-regexp-substitute "\r\n" "\n" arg))
1050                         "\n[ \t\n]*\n[ \t\n]*"))
1051          (list-para-words (map (lambda (str)
1052                                  (regexp-split str "[ \t\n]+"))
1053                                para-strings))
1054          (para-lines (map (lambda (words)
1055                             (let* ((stencils
1056                                     (remove ly:stencil-empty?
1057                                             (map (lambda (x)
1058                                                    (interpret-markup layout props x))
1059                                                  words))))
1060                               (wordwrap-stencils stencils
1061                                                  justify word-space
1062                                                  line-width text-direction)))
1063                           list-para-words)))
1064     (apply append para-lines)))
1065
1066 (define-builtin-markup-command (wordwrap-string layout props arg)
1067   (string?)
1068   align
1069   ((baseline-skip)
1070    wordwrap-string-internal-markup-list)
1071   "Wordwrap a string.  Paragraphs may be separated with double newlines.
1072
1073 @lilypond[verbatim,quote]
1074 \\markup {
1075   \\override #'(line-width . 40)
1076   \\wordwrap-string #\"Lorem ipsum dolor sit amet, consectetur
1077       adipisicing elit, sed do eiusmod tempor incididunt ut labore
1078       et dolore magna aliqua.
1079
1080
1081       Ut enim ad minim veniam, quis nostrud exercitation ullamco
1082       laboris nisi ut aliquip ex ea commodo consequat.
1083
1084
1085       Excepteur sint occaecat cupidatat non proident, sunt in culpa
1086       qui officia deserunt mollit anim id est laborum\"
1087 }
1088 @end lilypond"
1089   (stack-lines DOWN 0.0 baseline-skip
1090                (wordwrap-string-internal-markup-list layout props #f arg)))
1091
1092 (define-builtin-markup-command (justify-string layout props arg)
1093   (string?)
1094   align
1095   ((baseline-skip)
1096    wordwrap-string-internal-markup-list)
1097   "Justify a string.  Paragraphs may be separated with double newlines
1098
1099 @lilypond[verbatim,quote]
1100 \\markup {
1101   \\override #'(line-width . 40)
1102   \\justify-string #\"Lorem ipsum dolor sit amet, consectetur
1103       adipisicing elit, sed do eiusmod tempor incididunt ut labore
1104       et dolore magna aliqua.
1105
1106
1107       Ut enim ad minim veniam, quis nostrud exercitation ullamco
1108       laboris nisi ut aliquip ex ea commodo consequat.
1109
1110
1111       Excepteur sint occaecat cupidatat non proident, sunt in culpa
1112       qui officia deserunt mollit anim id est laborum\"
1113 }
1114 @end lilypond"
1115   (stack-lines DOWN 0.0 baseline-skip
1116                (wordwrap-string-internal-markup-list layout props #t arg)))
1117
1118 (define-builtin-markup-command (wordwrap-field layout props symbol)
1119   (symbol?)
1120   align
1121   ()
1122   "Wordwrap the data which has been assigned to @var{symbol}.
1123
1124 @lilypond[verbatim,quote]
1125 \\header {
1126   title = \"My title\"
1127   myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing
1128     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
1129     aliqua.  Ut enim ad minim veniam, quis nostrud exercitation ullamco
1130     laboris nisi ut aliquip ex ea commodo consequat.\"
1131 }
1132
1133 \\paper {
1134   bookTitleMarkup = \\markup {
1135     \\column {
1136       \\fill-line { \\fromproperty #'header:title }
1137       \\null
1138       \\wordwrap-field #'header:myText
1139     }
1140   }
1141 }
1142
1143 \\markup {
1144   \\null
1145 }
1146 @end lilypond"
1147   (let* ((m (chain-assoc-get symbol props)))
1148     (if (string? m)
1149         (wordwrap-string-markup layout props m)
1150         empty-stencil)))
1151
1152 (define-builtin-markup-command (justify-field layout props symbol)
1153   (symbol?)
1154   align
1155   ()
1156   "Justify the data which has been assigned to @var{symbol}.
1157
1158 @lilypond[verbatim,quote]
1159 \\header {
1160   title = \"My title\"
1161   myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing
1162     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
1163     aliqua.  Ut enim ad minim veniam, quis nostrud exercitation ullamco
1164     laboris nisi ut aliquip ex ea commodo consequat.\"
1165 }
1166
1167 \\paper {
1168   bookTitleMarkup = \\markup {
1169     \\column {
1170       \\fill-line { \\fromproperty #'header:title }
1171       \\null
1172       \\justify-field #'header:myText
1173     }
1174   }
1175 }
1176
1177 \\markup {
1178   \\null
1179 }
1180 @end lilypond"
1181   (let* ((m (chain-assoc-get symbol props)))
1182     (if (string? m)
1183         (justify-string-markup layout props m)
1184         empty-stencil)))
1185
1186 (define-builtin-markup-command (combine layout props arg1 arg2)
1187   (markup? markup?)
1188   align
1189   ()
1190   "
1191 @cindex merging text
1192
1193 Print two markups on top of each other.
1194
1195 Note: @code{\\combine} cannot take a list of markups enclosed in
1196 curly braces as an argument; the follow example will not compile:
1197
1198 @example
1199 \\combine @{ a list @}
1200 @end example
1201
1202 @lilypond[verbatim,quote]
1203 \\markup {
1204   \\fontsize #5
1205   \\override #'(thickness . 2)
1206   \\combine
1207     \\draw-line #'(0 . 4)
1208     \\arrow-head #Y #DOWN ##f
1209 }
1210 @end lilypond"
1211   (let* ((s1 (interpret-markup layout props arg1))
1212          (s2 (interpret-markup layout props arg2)))
1213     (ly:stencil-add s1 s2)))
1214
1215 ;;
1216 ;; TODO: should extract baseline-skip from each argument somehow..
1217 ;;
1218 (define-builtin-markup-command (column layout props args)
1219   (markup-list?)
1220   align
1221   ((baseline-skip))
1222   "
1223 @cindex stacking text in a column
1224
1225 Stack the markups in @var{args} vertically.  The property
1226 @code{baseline-skip} determines the space between markups
1227 in @var{args}.
1228
1229 @lilypond[verbatim,quote]
1230 \\markup {
1231   \\column {
1232     one
1233     two
1234     three
1235   }
1236 }
1237 @end lilypond"
1238   (let ((arg-stencils (interpret-markup-list layout props args)))
1239     (stack-lines -1 0.0 baseline-skip
1240                  (remove ly:stencil-empty? arg-stencils))))
1241
1242 (define-builtin-markup-command (dir-column layout props args)
1243   (markup-list?)
1244   align
1245   ((direction)
1246    (baseline-skip))
1247   "
1248 @cindex changing direction of text columns
1249
1250 Make a column of @var{args}, going up or down, depending on the
1251 setting of the @code{direction} layout property.
1252
1253 @lilypond[verbatim,quote]
1254 \\markup {
1255   \\override #`(direction . ,UP) {
1256     \\dir-column {
1257       going up
1258     }
1259   }
1260   \\hspace #1
1261   \\dir-column {
1262     going down
1263   }
1264   \\hspace #1
1265   \\override #'(direction . 1) {
1266     \\dir-column {
1267       going up
1268     }
1269   }
1270 }
1271 @end lilypond"
1272   (stack-lines (if (number? direction) direction -1)
1273                0.0
1274                baseline-skip
1275                (interpret-markup-list layout props args)))
1276
1277 (define (general-column align-dir baseline mols)
1278   "Stack @var{mols} vertically, aligned to  @var{align-dir} horizontally."
1279
1280   (let* ((aligned-mols (map (lambda (x) (ly:stencil-aligned-to x X align-dir)) mols)))
1281     (stack-lines -1 0.0 baseline aligned-mols)))
1282
1283 (define-builtin-markup-command (center-column layout props args)
1284   (markup-list?)
1285   align
1286   ((baseline-skip))
1287   "
1288 @cindex centering a column of text
1289
1290 Put @code{args} in a centered column.
1291
1292 @lilypond[verbatim,quote]
1293 \\markup {
1294   \\center-column {
1295     one
1296     two
1297     three
1298   }
1299 }
1300 @end lilypond"
1301   (general-column CENTER baseline-skip (interpret-markup-list layout props args)))
1302
1303 (define-builtin-markup-command (left-column layout props args)
1304   (markup-list?)
1305   align
1306   ((baseline-skip))
1307  "
1308 @cindex text columns, left-aligned
1309
1310 Put @code{args} in a left-aligned column.
1311
1312 @lilypond[verbatim,quote]
1313 \\markup {
1314   \\left-column {
1315     one
1316     two
1317     three
1318   }
1319 }
1320 @end lilypond"
1321   (general-column LEFT baseline-skip (interpret-markup-list layout props args)))
1322
1323 (define-builtin-markup-command (right-column layout props args)
1324   (markup-list?)
1325   align
1326   ((baseline-skip))
1327  "
1328 @cindex text columns, right-aligned
1329
1330 Put @code{args} in a right-aligned column.
1331
1332 @lilypond[verbatim,quote]
1333 \\markup {
1334   \\right-column {
1335     one
1336     two
1337     three
1338   }
1339 }
1340 @end lilypond"
1341   (general-column RIGHT baseline-skip (interpret-markup-list layout props args)))
1342
1343 (define-builtin-markup-command (vcenter layout props arg)
1344   (markup?)
1345   align
1346   ()
1347   "
1348 @cindex vertically centering text
1349
1350 Align @code{arg} to its Y@tie{}center.
1351
1352 @lilypond[verbatim,quote]
1353 \\markup {
1354   one
1355   \\vcenter
1356   two
1357   three
1358 }
1359 @end lilypond"
1360   (let* ((mol (interpret-markup layout props arg)))
1361     (ly:stencil-aligned-to mol Y CENTER)))
1362
1363 (define-builtin-markup-command (center-align layout props arg)
1364   (markup?)
1365   align
1366   ()
1367   "
1368 @cindex horizontally centering text
1369
1370 Align @code{arg} to its X@tie{}center.
1371
1372 @lilypond[verbatim,quote]
1373 \\markup {
1374   \\column {
1375     one
1376     \\center-align
1377     two
1378     three
1379   }
1380 }
1381 @end lilypond"
1382   (let* ((mol (interpret-markup layout props arg)))
1383     (ly:stencil-aligned-to mol X CENTER)))
1384
1385 (define-builtin-markup-command (right-align layout props arg)
1386   (markup?)
1387   align
1388   ()
1389   "
1390 @cindex right aligning text
1391
1392 Align @var{arg} on its right edge.
1393
1394 @lilypond[verbatim,quote]
1395 \\markup {
1396   \\column {
1397     one
1398     \\right-align
1399     two
1400     three
1401   }
1402 }
1403 @end lilypond"
1404   (let* ((m (interpret-markup layout props arg)))
1405     (ly:stencil-aligned-to m X RIGHT)))
1406
1407 (define-builtin-markup-command (left-align layout props arg)
1408   (markup?)
1409   align
1410   ()
1411   "
1412 @cindex left aligning text
1413
1414 Align @var{arg} on its left edge.
1415
1416 @lilypond[verbatim,quote]
1417 \\markup {
1418   \\column {
1419     one
1420     \\left-align
1421     two
1422     three
1423   }
1424 }
1425 @end lilypond"
1426   (let* ((m (interpret-markup layout props arg)))
1427     (ly:stencil-aligned-to m X LEFT)))
1428
1429 (define-builtin-markup-command (general-align layout props axis dir arg)
1430   (integer? number? markup?)
1431   align
1432   ()
1433   "
1434 @cindex controlling general text alignment
1435
1436 Align @var{arg} in @var{axis} direction to the @var{dir} side.
1437
1438 @lilypond[verbatim,quote]
1439 \\markup {
1440   \\column {
1441     one
1442     \\general-align #X #LEFT
1443     two
1444     three
1445     \\null
1446     one
1447     \\general-align #X #CENTER
1448     two
1449     three
1450     \\null
1451     \\line {
1452       one
1453       \\general-align #Y #UP
1454       two
1455       three
1456     }
1457     \\null
1458     \\line {
1459       one
1460       \\general-align #Y #3.2
1461       two
1462       three
1463     }
1464   }
1465 }
1466 @end lilypond"
1467   (let* ((m (interpret-markup layout props arg)))
1468     (ly:stencil-aligned-to m axis dir)))
1469
1470 (define-builtin-markup-command (halign layout props dir arg)
1471   (number? markup?)
1472   align
1473   ()
1474   "
1475 @cindex setting horizontal text alignment
1476
1477 Set horizontal alignment.  If @var{dir} is @code{-1}, then it is
1478 left-aligned, while @code{+1} is right.  Values in between interpolate
1479 alignment accordingly.
1480
1481 @lilypond[verbatim,quote]
1482 \\markup {
1483   \\column {
1484     one
1485     \\halign #LEFT
1486     two
1487     three
1488     \\null
1489     one
1490     \\halign #CENTER
1491     two
1492     three
1493     \\null
1494     one
1495     \\halign #RIGHT
1496     two
1497     three
1498     \\null
1499     one
1500     \\halign #-5
1501     two
1502     three
1503   }
1504 }
1505 @end lilypond"
1506   (let* ((m (interpret-markup layout props arg)))
1507     (ly:stencil-aligned-to m X dir)))
1508
1509 (define-builtin-markup-command (with-dimensions layout props x y arg)
1510   (number-pair? number-pair? markup?)
1511   other
1512   ()
1513   "
1514 @cindex setting extent of text objects
1515
1516 Set the dimensions of @var{arg} to @var{x} and@tie{}@var{y}."
1517   (let* ((m (interpret-markup layout props arg)))
1518     (ly:make-stencil (ly:stencil-expr m) x y)))
1519
1520 (define-builtin-markup-command (pad-around layout props amount arg)
1521   (number? markup?)
1522   align
1523   ()
1524   "Add padding @var{amount} all around @var{arg}.
1525
1526 @lilypond[verbatim,quote]
1527 \\markup {
1528   \\box {
1529     default
1530   }
1531   \\hspace #2
1532   \\box {
1533     \\pad-around #0.5 {
1534       padded
1535     }
1536   }
1537 }
1538 @end lilypond"
1539   (let* ((m (interpret-markup layout props arg))
1540          (x (ly:stencil-extent m X))
1541          (y (ly:stencil-extent m Y)))
1542     (ly:make-stencil (ly:stencil-expr m)
1543                      (interval-widen x amount)
1544                      (interval-widen y amount))))
1545
1546 (define-builtin-markup-command (pad-x layout props amount arg)
1547   (number? markup?)
1548   align
1549   ()
1550   "
1551 @cindex padding text horizontally
1552
1553 Add padding @var{amount} around @var{arg} in the X@tie{}direction.
1554
1555 @lilypond[verbatim,quote]
1556 \\markup {
1557   \\box {
1558     default
1559   }
1560   \\hspace #4
1561   \\box {
1562     \\pad-x #2 {
1563       padded
1564     }
1565   }
1566 }
1567 @end lilypond"
1568   (let* ((m (interpret-markup layout props arg))
1569          (x (ly:stencil-extent m X))
1570          (y (ly:stencil-extent m Y)))
1571     (ly:make-stencil (ly:stencil-expr m)
1572                      (interval-widen x amount)
1573                      y)))
1574
1575 (define-builtin-markup-command (put-adjacent layout props axis dir arg1 arg2)
1576   (integer? ly:dir? markup? markup?)
1577   align
1578   ()
1579   "Put @var{arg2} next to @var{arg1}, without moving @var{arg1}."
1580   (let ((m1 (interpret-markup layout props arg1))
1581         (m2 (interpret-markup layout props arg2)))
1582     (ly:stencil-combine-at-edge m1 axis dir m2 0.0)))
1583
1584 (define-builtin-markup-command (transparent layout props arg)
1585   (markup?)
1586   other
1587   ()
1588   "Make @var{arg} transparent.
1589
1590 @lilypond[verbatim,quote]
1591 \\markup {
1592   \\transparent {
1593     invisible text
1594   }
1595 }
1596 @end lilypond"
1597   (let* ((m (interpret-markup layout props arg))
1598          (x (ly:stencil-extent m X))
1599          (y (ly:stencil-extent m Y)))
1600     (ly:make-stencil "" x y)))
1601
1602 (define-builtin-markup-command (pad-to-box layout props x-ext y-ext arg)
1603   (number-pair? number-pair? markup?)
1604   align
1605   ()
1606   "Make @var{arg} take at least @var{x-ext}, @var{y-ext} space.
1607
1608 @lilypond[verbatim,quote]
1609 \\markup {
1610   \\box {
1611     default
1612   }
1613   \\hspace #4
1614   \\box {
1615     \\pad-to-box #'(0 . 10) #'(0 . 3) {
1616       padded
1617     }
1618   }
1619 }
1620 @end lilypond"
1621   (let* ((m (interpret-markup layout props arg))
1622          (x (ly:stencil-extent m X))
1623          (y (ly:stencil-extent m Y)))
1624     (ly:make-stencil (ly:stencil-expr m)
1625                      (interval-union x-ext x)
1626                      (interval-union y-ext y))))
1627
1628 (define-builtin-markup-command (hcenter-in layout props length arg)
1629   (number? markup?)
1630   align
1631   ()
1632   "Center @var{arg} horizontally within a box of extending
1633 @var{length}/2 to the left and right.
1634
1635 @lilypond[quote,verbatim]
1636 \\new StaffGroup <<
1637   \\new Staff {
1638     \\set Staff.instrumentName = \\markup {
1639       \\hcenter-in #12
1640       Oboe
1641     }
1642     c''1
1643   }
1644   \\new Staff {
1645     \\set Staff.instrumentName = \\markup {
1646       \\hcenter-in #12
1647       Bassoon
1648     }
1649     \\clef tenor
1650     c'1
1651   }
1652 >>
1653 @end lilypond"
1654   (interpret-markup layout props
1655                     (make-pad-to-box-markup
1656                      (cons (/ length -2) (/ length 2))
1657                      '(0 . 0)
1658                      (make-center-align-markup arg))))
1659
1660 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1661 ;; property
1662 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1663
1664 (define-builtin-markup-command (fromproperty layout props symbol)
1665   (symbol?)
1666   other
1667   ()
1668   "Read the @var{symbol} from property settings, and produce a stencil
1669 from the markup contained within.  If @var{symbol} is not defined, it
1670 returns an empty markup.
1671
1672 @lilypond[verbatim,quote]
1673 \\header {
1674   myTitle = \"myTitle\"
1675   title = \\markup {
1676     from
1677     \\italic
1678     \\fromproperty #'header:myTitle
1679   }
1680 }
1681 \\markup {
1682   \\null
1683 }
1684 @end lilypond"
1685   (let ((m (chain-assoc-get symbol props)))
1686     (if (markup? m)
1687         (interpret-markup layout props m)
1688         empty-stencil)))
1689
1690 (define-builtin-markup-command (on-the-fly layout props procedure arg)
1691   (symbol? markup?)
1692   other
1693   ()
1694   "Apply the @var{procedure} markup command to @var{arg}.
1695 @var{procedure} should take a single argument."
1696   (let ((anonymous-with-signature (lambda (layout props arg) (procedure layout props arg))))
1697     (set-object-property! anonymous-with-signature
1698                           'markup-signature
1699                           (list markup?))
1700     (interpret-markup layout props (list anonymous-with-signature arg))))
1701
1702 (define-builtin-markup-command (override layout props new-prop arg)
1703   (pair? markup?)
1704   other
1705   ()
1706   "
1707 @cindex overriding properties within text markup
1708
1709 Add the argument @var{new-prop} to the property list.  Properties
1710 may be any property supported by @rinternals{font-interface},
1711 @rinternals{text-interface} and
1712 @rinternals{instrument-specific-markup-interface}.
1713
1714 @lilypond[verbatim,quote]
1715 \\markup {
1716   \\line {
1717     \\column {
1718       default
1719       baseline-skip
1720     }
1721     \\hspace #2
1722     \\override #'(baseline-skip . 4) {
1723       \\column {
1724         increased
1725         baseline-skip
1726       }
1727     }
1728   }
1729 }
1730 @end lilypond"
1731   (interpret-markup layout (cons (list new-prop) props) arg))
1732
1733 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1734 ;; files
1735 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1736
1737 (define-builtin-markup-command (verbatim-file layout props name)
1738   (string?)
1739   other
1740   ()
1741   "Read the contents of file @var{name}, and include it verbatim.
1742
1743 @lilypond[verbatim,quote]
1744 \\markup {
1745   \\verbatim-file #\"simple.ly\"
1746 }
1747 @end lilypond"
1748   (interpret-markup layout props
1749                     (if  (ly:get-option 'safe)
1750                          "verbatim-file disabled in safe mode"
1751                          (let* ((str (ly:gulp-file name))
1752                                 (lines (string-split str #\nl)))
1753                            (make-typewriter-markup
1754                             (make-column-markup lines))))))
1755
1756 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1757 ;; fonts.
1758 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1759
1760
1761 (define-builtin-markup-command (smaller layout props arg)
1762   (markup?)
1763   font
1764   ()
1765   "Decrease the font size relative to the current setting.
1766
1767 @lilypond[verbatim,quote]
1768 \\markup {
1769   \\fontsize #3.5 {
1770     some large text
1771     \\hspace #2
1772     \\smaller {
1773       a bit smaller
1774     }
1775     \\hspace #2
1776     more large text
1777   }
1778 }
1779 @end lilypond"
1780   (interpret-markup layout props
1781    `(,fontsize-markup -1 ,arg)))
1782
1783 (define-builtin-markup-command (larger layout props arg)
1784   (markup?)
1785   font
1786   ()
1787   "Increase the font size relative to the current setting.
1788
1789 @lilypond[verbatim,quote]
1790 \\markup {
1791   default
1792   \\hspace #2
1793   \\larger
1794   larger
1795 }
1796 @end lilypond"
1797   (interpret-markup layout props
1798    `(,fontsize-markup 1 ,arg)))
1799
1800 (define-builtin-markup-command (finger layout props arg)
1801   (markup?)
1802   font
1803   ()
1804   "Set @var{arg} as small numbers.
1805
1806 @lilypond[verbatim,quote]
1807 \\markup {
1808   \\finger {
1809     1 2 3 4 5
1810   }
1811 }
1812 @end lilypond"
1813   (interpret-markup layout
1814                     (cons '((font-size . -5) (font-encoding . fetaNumber)) props)
1815                     arg))
1816
1817 (define-builtin-markup-command (abs-fontsize layout props size arg)
1818   (number? markup?)
1819   font
1820   ()
1821   "Use @var{size} as the absolute font size to display @var{arg}.
1822 Adjusts @code{baseline-skip} and @code{word-space} accordingly.
1823
1824 @lilypond[verbatim,quote]
1825 \\markup {
1826   default text font size
1827   \\hspace #2
1828   \\abs-fontsize #16 { text font size 16 }
1829   \\hspace #2
1830   \\abs-fontsize #12 { text font size 12 }
1831 }
1832 @end lilypond"
1833   (let* ((ref-size (ly:output-def-lookup layout 'text-font-size 12))
1834          (text-props (list (ly:output-def-lookup layout 'text-font-defaults)))
1835          (ref-word-space (chain-assoc-get 'word-space text-props 0.6))
1836          (ref-baseline (chain-assoc-get 'baseline-skip text-props 3))
1837          (magnification (/ size ref-size)))
1838     (interpret-markup layout
1839                       (cons `((baseline-skip . ,(* magnification ref-baseline))
1840                               (word-space . ,(* magnification ref-word-space))
1841                               (font-size . ,(magnification->font-size magnification)))
1842                             props)
1843                       arg)))
1844
1845 (define-builtin-markup-command (fontsize layout props increment arg)
1846   (number? markup?)
1847   font
1848   ((font-size 0)
1849    (word-space 1)
1850    (baseline-skip 2))
1851   "Add @var{increment} to the font-size.  Adjusts @code{baseline-skip}
1852 accordingly.
1853
1854 @lilypond[verbatim,quote]
1855 \\markup {
1856   default
1857   \\hspace #2
1858   \\fontsize #-1.5
1859   smaller
1860 }
1861 @end lilypond"
1862   (let ((entries (list
1863                   (cons 'baseline-skip (* baseline-skip (magstep increment)))
1864                   (cons 'word-space (* word-space (magstep increment)))
1865                   (cons 'font-size (+ font-size increment)))))
1866     (interpret-markup layout (cons entries props) arg)))
1867
1868 (define-builtin-markup-command (magnify layout props sz arg)
1869   (number? markup?)
1870   font
1871   ()
1872   "
1873 @cindex magnifying text
1874
1875 Set the font magnification for its argument.  In the following
1876 example, the middle@tie{}A is 10% larger:
1877
1878 @example
1879 A \\magnify #1.1 @{ A @} A
1880 @end example
1881
1882 Note: Magnification only works if a font name is explicitly selected.
1883 Use @code{\\fontsize} otherwise.
1884
1885 @lilypond[verbatim,quote]
1886 \\markup {
1887   default
1888   \\hspace #2
1889   \\magnify #1.5 {
1890     50% larger
1891   }
1892 }
1893 @end lilypond"
1894   (interpret-markup
1895    layout
1896    (prepend-alist-chain 'font-size (magnification->font-size sz) props)
1897    arg))
1898
1899 (define-builtin-markup-command (bold layout props arg)
1900   (markup?)
1901   font
1902   ()
1903   "Switch to bold font-series.
1904
1905 @lilypond[verbatim,quote]
1906 \\markup {
1907   default
1908   \\hspace #2
1909   \\bold
1910   bold
1911 }
1912 @end lilypond"
1913   (interpret-markup layout (prepend-alist-chain 'font-series 'bold props) arg))
1914
1915 (define-builtin-markup-command (sans layout props arg)
1916   (markup?)
1917   font
1918   ()
1919   "Switch to the sans serif font family.
1920
1921 @lilypond[verbatim,quote]
1922 \\markup {
1923   default
1924   \\hspace #2
1925   \\sans {
1926     sans serif
1927   }
1928 }
1929 @end lilypond"
1930   (interpret-markup layout (prepend-alist-chain 'font-family 'sans props) arg))
1931
1932 (define-builtin-markup-command (number layout props arg)
1933   (markup?)
1934   font
1935   ()
1936   "Set font family to @code{number}, which yields the font used for
1937 time signatures and fingerings.  This font contains numbers and
1938 some punctuation; it has no letters.
1939
1940 @lilypond[verbatim,quote]
1941 \\markup {
1942   \\number {
1943     0 1 2 3 4 5 6 7 8 9 . ,
1944   }
1945 }
1946 @end lilypond"
1947   (interpret-markup layout (prepend-alist-chain 'font-encoding 'fetaNumber props) arg))
1948
1949 (define-builtin-markup-command (roman layout props arg)
1950   (markup?)
1951   font
1952   ()
1953   "Set font family to @code{roman}.
1954
1955 @lilypond[verbatim,quote]
1956 \\markup {
1957   \\sans \\bold {
1958     sans serif, bold
1959     \\hspace #2
1960     \\roman {
1961       text in roman font family
1962     }
1963     \\hspace #2
1964     return to sans
1965   }
1966 }
1967 @end lilypond"
1968   (interpret-markup layout (prepend-alist-chain 'font-family 'roman props) arg))
1969
1970 (define-builtin-markup-command (huge layout props arg)
1971   (markup?)
1972   font
1973   ()
1974   "Set font size to +2.
1975
1976 @lilypond[verbatim,quote]
1977 \\markup {
1978   default
1979   \\hspace #2
1980   \\huge
1981   huge
1982 }
1983 @end lilypond"
1984   (interpret-markup layout (prepend-alist-chain 'font-size 2 props) arg))
1985
1986 (define-builtin-markup-command (large layout props arg)
1987   (markup?)
1988   font
1989   ()
1990   "Set font size to +1.
1991
1992 @lilypond[verbatim,quote]
1993 \\markup {
1994   default
1995   \\hspace #2
1996   \\large
1997   large
1998 }
1999 @end lilypond"
2000   (interpret-markup layout (prepend-alist-chain 'font-size 1 props) arg))
2001
2002 (define-builtin-markup-command (normalsize layout props arg)
2003   (markup?)
2004   font
2005   ()
2006   "Set font size to default.
2007
2008 @lilypond[verbatim,quote]
2009 \\markup {
2010   \\teeny {
2011     this is very small
2012     \\hspace #2
2013     \\normalsize {
2014       normal size
2015     }
2016     \\hspace #2
2017     teeny again
2018   }
2019 }
2020 @end lilypond"
2021   (interpret-markup layout (prepend-alist-chain 'font-size 0 props) arg))
2022
2023 (define-builtin-markup-command (small layout props arg)
2024   (markup?)
2025   font
2026   ()
2027   "Set font size to -1.
2028
2029 @lilypond[verbatim,quote]
2030 \\markup {
2031   default
2032   \\hspace #2
2033   \\small
2034   small
2035 }
2036 @end lilypond"
2037   (interpret-markup layout (prepend-alist-chain 'font-size -1 props) arg))
2038
2039 (define-builtin-markup-command (tiny layout props arg)
2040   (markup?)
2041   font
2042   ()
2043   "Set font size to -2.
2044
2045 @lilypond[verbatim,quote]
2046 \\markup {
2047   default
2048   \\hspace #2
2049   \\tiny
2050   tiny
2051 }
2052 @end lilypond"
2053   (interpret-markup layout (prepend-alist-chain 'font-size -2 props) arg))
2054
2055 (define-builtin-markup-command (teeny layout props arg)
2056   (markup?)
2057   font
2058   ()
2059   "Set font size to -3.
2060
2061 @lilypond[verbatim,quote]
2062 \\markup {
2063   default
2064   \\hspace #2
2065   \\teeny
2066   teeny
2067 }
2068 @end lilypond"
2069   (interpret-markup layout (prepend-alist-chain 'font-size -3 props) arg))
2070
2071 (define-builtin-markup-command (fontCaps layout props arg)
2072   (markup?)
2073   font
2074   ()
2075   "Set @code{font-shape} to @code{caps}
2076
2077 Note: @code{\\fontCaps} requires the installation and selection of
2078 fonts which support the @code{caps} font shape."
2079   (interpret-markup layout (prepend-alist-chain 'font-shape 'caps props) arg))
2080
2081 ;; Poor man's caps
2082 (define-builtin-markup-command (smallCaps layout props arg)
2083   (markup?)
2084   font
2085   ()
2086   "Emit @var{arg} as small caps.
2087
2088 Note: @code{\\smallCaps} does not support accented characters.
2089
2090 @lilypond[verbatim,quote]
2091 \\markup {
2092   default
2093   \\hspace #2
2094   \\smallCaps {
2095     Text in small caps
2096   }
2097 }
2098 @end lilypond"
2099   (define (char-list->markup chars lower)
2100     (let ((final-string (string-upcase (reverse-list->string chars))))
2101       (if lower
2102           (markup #:fontsize -2 final-string)
2103           final-string)))
2104   (define (make-small-caps rest-chars currents current-is-lower prev-result)
2105     (if (null? rest-chars)
2106         (make-concat-markup
2107           (reverse! (cons (char-list->markup currents current-is-lower)
2108                           prev-result)))
2109         (let* ((ch (car rest-chars))
2110                (is-lower (char-lower-case? ch)))
2111           (if (or (and current-is-lower is-lower)
2112                   (and (not current-is-lower) (not is-lower)))
2113               (make-small-caps (cdr rest-chars)
2114                                (cons ch currents)
2115                                is-lower
2116                                prev-result)
2117               (make-small-caps (cdr rest-chars)
2118                                (list ch)
2119                                is-lower
2120                                (if (null? currents)
2121                                    prev-result
2122                                    (cons (char-list->markup
2123                                             currents current-is-lower)
2124                                          prev-result)))))))
2125   (interpret-markup layout props
2126     (if (string? arg)
2127         (make-small-caps (string->list arg) (list) #f (list))
2128         arg)))
2129
2130 (define-builtin-markup-command (caps layout props arg)
2131   (markup?)
2132   font
2133   ()
2134   "Copy of the @code{\\smallCaps} command.
2135
2136 @lilypond[verbatim,quote]
2137 \\markup {
2138   default
2139   \\hspace #2
2140   \\caps {
2141     Text in small caps
2142   }
2143 }
2144 @end lilypond"
2145   (interpret-markup layout props (make-smallCaps-markup arg)))
2146
2147 (define-builtin-markup-command (dynamic layout props arg)
2148   (markup?)
2149   font
2150   ()
2151   "Use the dynamic font.  This font only contains @b{s}, @b{f}, @b{m},
2152 @b{z}, @b{p}, and @b{r}.  When producing phrases, like
2153 @q{pi@`{u}@tie{}@b{f}}, the normal words (like @q{pi@`{u}}) should be
2154 done in a different font.  The recommended font for this is bold and italic.
2155 @lilypond[verbatim,quote]
2156 \\markup {
2157   \\dynamic {
2158     sfzp
2159   }
2160 }
2161 @end lilypond"
2162   (interpret-markup
2163    layout (prepend-alist-chain 'font-encoding 'fetaDynamic props) arg))
2164
2165 (define-builtin-markup-command (text layout props arg)
2166   (markup?)
2167   font
2168   ()
2169   "Use a text font instead of music symbol or music alphabet font.
2170
2171 @lilypond[verbatim,quote]
2172 \\markup {
2173   \\number {
2174     1, 2,
2175     \\text {
2176       three, four,
2177     }
2178     5
2179   }
2180 }
2181 @end lilypond"
2182
2183   ;; ugh - latin1
2184   (interpret-markup layout (prepend-alist-chain 'font-encoding 'latin1 props)
2185                     arg))
2186
2187 (define-builtin-markup-command (italic layout props arg)
2188   (markup?)
2189   font
2190   ()
2191   "Use italic @code{font-shape} for @var{arg}.
2192
2193 @lilypond[verbatim,quote]
2194 \\markup {
2195   default
2196   \\hspace #2
2197   \\italic
2198   italic
2199 }
2200 @end lilypond"
2201   (interpret-markup layout (prepend-alist-chain 'font-shape 'italic props) arg))
2202
2203 (define-builtin-markup-command (typewriter layout props arg)
2204   (markup?)
2205   font
2206   ()
2207   "Use @code{font-family} typewriter for @var{arg}.
2208
2209 @lilypond[verbatim,quote]
2210 \\markup {
2211   default
2212   \\hspace #2
2213   \\typewriter
2214   typewriter
2215 }
2216 @end lilypond"
2217   (interpret-markup
2218    layout (prepend-alist-chain 'font-family 'typewriter props) arg))
2219
2220 (define-builtin-markup-command (upright layout props arg)
2221   (markup?)
2222   font
2223   ()
2224   "Set @code{font-shape} to @code{upright}.  This is the opposite
2225 of @code{italic}.
2226
2227 @lilypond[verbatim,quote]
2228 \\markup {
2229   \\italic {
2230     italic text
2231     \\hspace #2
2232     \\upright {
2233       upright text
2234     }
2235     \\hspace #2
2236     italic again
2237   }
2238 }
2239 @end lilypond"
2240   (interpret-markup
2241    layout (prepend-alist-chain 'font-shape 'upright props) arg))
2242
2243 (define-builtin-markup-command (medium layout props arg)
2244   (markup?)
2245   font
2246   ()
2247   "Switch to medium font-series (in contrast to bold).
2248
2249 @lilypond[verbatim,quote]
2250 \\markup {
2251   \\bold {
2252     some bold text
2253     \\hspace #2
2254     \\medium {
2255       medium font series
2256     }
2257     \\hspace #2
2258     bold again
2259   }
2260 }
2261 @end lilypond"
2262   (interpret-markup layout (prepend-alist-chain 'font-series 'medium props)
2263                     arg))
2264
2265 (define-builtin-markup-command (normal-text layout props arg)
2266   (markup?)
2267   font
2268   ()
2269   "Set all font related properties (except the size) to get the default
2270 normal text font, no matter what font was used earlier.
2271
2272 @lilypond[verbatim,quote]
2273 \\markup {
2274   \\huge \\bold \\sans \\caps {
2275     Some text with font overrides
2276     \\hspace #2
2277     \\normal-text {
2278       Default text, same font-size
2279     }
2280     \\hspace #2
2281     More text as before
2282   }
2283 }
2284 @end lilypond"
2285   ;; ugh - latin1
2286   (interpret-markup layout
2287                     (cons '((font-family . roman) (font-shape . upright)
2288                             (font-series . medium) (font-encoding . latin1))
2289                           props)
2290                     arg))
2291
2292 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2293 ;; symbols.
2294 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2295
2296 (define-builtin-markup-command (doublesharp layout props)
2297   ()
2298   music
2299   ()
2300   "Draw a double sharp symbol.
2301
2302 @lilypond[verbatim,quote]
2303 \\markup {
2304   \\doublesharp
2305 }
2306 @end lilypond"
2307   (interpret-markup layout props (markup #:musicglyph (assoc-get 1 standard-alteration-glyph-name-alist ""))))
2308
2309 (define-builtin-markup-command (sesquisharp layout props)
2310   ()
2311   music
2312   ()
2313   "Draw a 3/2 sharp symbol.
2314
2315 @lilypond[verbatim,quote]
2316 \\markup {
2317   \\sesquisharp
2318 }
2319 @end lilypond"
2320   (interpret-markup layout props (markup #:musicglyph (assoc-get 3/4 standard-alteration-glyph-name-alist ""))))
2321
2322 (define-builtin-markup-command (sharp layout props)
2323   ()
2324   music
2325   ()
2326   "Draw a sharp symbol.
2327
2328 @lilypond[verbatim,quote]
2329 \\markup {
2330   \\sharp
2331 }
2332 @end lilypond"
2333   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/2 standard-alteration-glyph-name-alist ""))))
2334
2335 (define-builtin-markup-command (semisharp layout props)
2336   ()
2337   music
2338   ()
2339   "Draw a semisharp symbol.
2340
2341 @lilypond[verbatim,quote]
2342 \\markup {
2343   \\semisharp
2344 }
2345 @end lilypond"
2346   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/4 standard-alteration-glyph-name-alist ""))))
2347
2348 (define-builtin-markup-command (natural layout props)
2349   ()
2350   music
2351   ()
2352   "Draw a natural symbol.
2353
2354 @lilypond[verbatim,quote]
2355 \\markup {
2356   \\natural
2357 }
2358 @end lilypond"
2359   (interpret-markup layout props (markup #:musicglyph (assoc-get 0 standard-alteration-glyph-name-alist ""))))
2360
2361 (define-builtin-markup-command (semiflat layout props)
2362   ()
2363   music
2364   ()
2365   "Draw a semiflat symbol.
2366
2367 @lilypond[verbatim,quote]
2368 \\markup {
2369   \\semiflat
2370 }
2371 @end lilypond"
2372   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/4 standard-alteration-glyph-name-alist ""))))
2373
2374 (define-builtin-markup-command (flat layout props)
2375   ()
2376   music
2377   ()
2378   "Draw a flat symbol.
2379
2380 @lilypond[verbatim,quote]
2381 \\markup {
2382   \\flat
2383 }
2384 @end lilypond"
2385   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/2 standard-alteration-glyph-name-alist ""))))
2386
2387 (define-builtin-markup-command (sesquiflat layout props)
2388   ()
2389   music
2390   ()
2391   "Draw a 3/2 flat symbol.
2392
2393 @lilypond[verbatim,quote]
2394 \\markup {
2395   \\sesquiflat
2396 }
2397 @end lilypond"
2398   (interpret-markup layout props (markup #:musicglyph (assoc-get -3/4 standard-alteration-glyph-name-alist ""))))
2399
2400 (define-builtin-markup-command (doubleflat layout props)
2401   ()
2402   music
2403   ()
2404   "Draw a double flat symbol.
2405
2406 @lilypond[verbatim,quote]
2407 \\markup {
2408   \\doubleflat
2409 }
2410 @end lilypond"
2411   (interpret-markup layout props (markup #:musicglyph (assoc-get -1 standard-alteration-glyph-name-alist ""))))
2412
2413 (define-builtin-markup-command (with-color layout props color arg)
2414   (color? markup?)
2415   other
2416   ()
2417   "
2418 @cindex coloring text
2419
2420 Draw @var{arg} in color specified by @var{color}.
2421
2422 @lilypond[verbatim,quote]
2423 \\markup {
2424   \\with-color #red
2425   red
2426   \\hspace #2
2427   \\with-color #green
2428   green
2429   \\hspace #2
2430   \\with-color #blue
2431   blue
2432 }
2433 @end lilypond"
2434   (let ((stil (interpret-markup layout props arg)))
2435     (ly:make-stencil (list 'color color (ly:stencil-expr stil))
2436                      (ly:stencil-extent stil X)
2437                      (ly:stencil-extent stil Y))))
2438
2439 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2440 ;; glyphs
2441 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2442
2443 (define-builtin-markup-command (arrow-head layout props axis dir filled)
2444   (integer? ly:dir? boolean?)
2445   graphic
2446   ()
2447   "Produce an arrow head in specified direction and axis.
2448 Use the filled head if @var{filled} is specified.
2449 @lilypond[verbatim,quote]
2450 \\markup {
2451   \\fontsize #5 {
2452     \\general-align #Y #DOWN {
2453       \\arrow-head #Y #UP ##t
2454       \\arrow-head #Y #DOWN ##f
2455       \\hspace #2
2456       \\arrow-head #X #RIGHT ##f
2457       \\arrow-head #X #LEFT ##f
2458     }
2459   }
2460 }
2461 @end lilypond"
2462   (let*
2463       ((name (format "arrowheads.~a.~a~a"
2464                      (if filled
2465                          "close"
2466                          "open")
2467                      axis
2468                      dir)))
2469     (ly:font-get-glyph
2470      (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
2471                                      props))
2472      name)))
2473
2474 (define-builtin-markup-command (musicglyph layout props glyph-name)
2475   (string?)
2476   music
2477   ()
2478   "@var{glyph-name} is converted to a musical symbol; for example,
2479 @code{\\musicglyph #\"accidentals.natural\"} selects the natural sign from
2480 the music font.  See @ruser{The Feta font} for a complete listing of
2481 the possible glyphs.
2482
2483 @lilypond[verbatim,quote]
2484 \\markup {
2485   \\musicglyph #\"f\"
2486   \\musicglyph #\"rests.2\"
2487   \\musicglyph #\"clefs.G_change\"
2488 }
2489 @end lilypond"
2490   (let* ((font (ly:paper-get-font layout
2491                                   (cons '((font-encoding . fetaMusic)
2492                                           (font-name . #f))
2493
2494                                                  props)))
2495          (glyph (ly:font-get-glyph font glyph-name)))
2496     (if (null? (ly:stencil-expr glyph))
2497         (ly:warning (_ "Cannot find glyph ~a") glyph-name))
2498
2499     glyph))
2500
2501
2502 (define-builtin-markup-command (lookup layout props glyph-name)
2503   (string?)
2504   other
2505   ()
2506   "Lookup a glyph by name.
2507
2508 @lilypond[verbatim,quote]
2509 \\markup {
2510   \\override #'(font-encoding . fetaBraces) {
2511     \\lookup #\"brace200\"
2512     \\hspace #2
2513     \\rotate #180
2514     \\lookup #\"brace180\"
2515   }
2516 }
2517 @end lilypond"
2518   (ly:font-get-glyph (ly:paper-get-font layout props)
2519                      glyph-name))
2520
2521 (define-builtin-markup-command (char layout props num)
2522   (integer?)
2523   other
2524   ()
2525   "Produce a single character.  Characters encoded in hexadecimal
2526 format require the prefix @code{#x}.
2527
2528 @lilypond[verbatim,quote]
2529 \\markup {
2530   \\char #65 \\char ##x00a9
2531 }
2532 @end lilypond"
2533   (ly:text-interface::interpret-markup layout props (ly:wide-char->utf-8 num)))
2534
2535 (define number->mark-letter-vector (make-vector 25 #\A))
2536
2537 (do ((i 0 (1+ i))
2538      (j 0 (1+ j)))
2539     ((>= i 26))
2540   (if (= i (- (char->integer #\I) (char->integer #\A)))
2541       (set! i (1+ i)))
2542   (vector-set! number->mark-letter-vector j
2543                (integer->char (+ i (char->integer #\A)))))
2544
2545 (define number->mark-alphabet-vector (list->vector
2546   (map (lambda (i) (integer->char (+ i (char->integer #\A)))) (iota 26))))
2547
2548 (define (number->markletter-string vec n)
2549   "Double letters for big marks."
2550   (let* ((lst (vector-length vec)))
2551
2552     (if (>= n lst)
2553         (string-append (number->markletter-string vec (1- (quotient n lst)))
2554                        (number->markletter-string vec (remainder n lst)))
2555         (make-string 1 (vector-ref vec n)))))
2556
2557 (define-builtin-markup-command (markletter layout props num)
2558   (integer?)
2559   other
2560   ()
2561   "Make a markup letter for @var{num}.  The letters start with A to@tie{}Z
2562 (skipping letter@tie{}I), and continue with double letters.
2563
2564 @lilypond[verbatim,quote]
2565 \\markup {
2566   \\markletter #8
2567   \\hspace #2
2568   \\markletter #26
2569 }
2570 @end lilypond"
2571   (ly:text-interface::interpret-markup layout props
2572     (number->markletter-string number->mark-letter-vector num)))
2573
2574 (define-builtin-markup-command (markalphabet layout props num)
2575   (integer?)
2576   other
2577   ()
2578    "Make a markup letter for @var{num}.  The letters start with A to@tie{}Z
2579 and continue with double letters.
2580
2581 @lilypond[verbatim,quote]
2582 \\markup {
2583   \\markalphabet #8
2584   \\hspace #2
2585   \\markalphabet #26
2586 }
2587 @end lilypond"
2588    (ly:text-interface::interpret-markup layout props
2589      (number->markletter-string number->mark-alphabet-vector num)))
2590
2591 (define-public (horizontal-slash-interval num forward number-interval mag)
2592   (if forward
2593     (cond ;((= num 6) (interval-widen number-interval (* mag 0.5)))
2594           ;((= num 5) (interval-widen number-interval (* mag 0.5)))
2595           (else (interval-widen number-interval (* mag 0.25))))
2596     (cond ((= num 6) (interval-widen number-interval (* mag 0.5)))
2597           ;((= num 5) (interval-widen number-interval (* mag 0.5)))
2598           (else (interval-widen number-interval (* mag 0.25))))
2599   ))
2600
2601 (define-public (adjust-slash-stencil num forward stencil mag)
2602   (if forward
2603     (cond ((= num 2)
2604               (ly:stencil-translate stencil (cons (* mag -0.00) (* mag 0.2))))
2605           ((= num 3)
2606               (ly:stencil-translate stencil (cons (* mag -0.00) (* mag 0.2))))
2607           ;((= num 5)
2608               ;(ly:stencil-translate stencil (cons (* mag -0.00) (* mag -0.07))))
2609           ;((= num 7)
2610           ;    (ly:stencil-translate stencil (cons (* mag -0.00) (* mag -0.15))))
2611           (else stencil))
2612     (cond ((= num 6)
2613               (ly:stencil-translate stencil (cons (* mag -0.00) (* mag 0.15))))
2614           ;((= num 8)
2615           ;    (ly:stencil-translate stencil (cons (* mag -0.00) (* mag -0.15))))
2616           (else stencil))
2617   )
2618 )
2619
2620 (define (slashed-digit-internal layout props num forward font-size thickness)
2621   (let* ((mag (magstep font-size))
2622          (thickness (* mag
2623                        (ly:output-def-lookup layout 'line-thickness)
2624                        thickness))
2625          ; backward slashes might use slope and point in the other direction!
2626          (dy (* mag (if forward 0.4 -0.4)))
2627          (number-stencil (interpret-markup layout
2628                                            (prepend-alist-chain 'font-encoding 'fetaNumber props)
2629                                            (number->string num)))
2630          (num-x (horizontal-slash-interval num forward (ly:stencil-extent number-stencil X) mag))
2631          (center (interval-center (ly:stencil-extent number-stencil Y)))
2632          ; Use the real extents of the slash, not the whole number, because we
2633          ; might translate the slash later on!
2634          (num-y (interval-widen (cons center center) (abs dy)))
2635          (is-sane (and (interval-sane? num-x) (interval-sane? num-y)))
2636          (slash-stencil (if is-sane
2637                             (make-line-stencil thickness
2638                                          (car num-x) (- (interval-center num-y) dy)
2639                                          (cdr num-x) (+ (interval-center num-y) dy))
2640                             #f)))
2641     (if (ly:stencil? slash-stencil)
2642       (begin
2643         ; for some numbers we need to shift the slash/backslash up or down to make
2644         ; the slashed digit look better
2645         (set! slash-stencil (adjust-slash-stencil num forward slash-stencil mag))
2646         (set! number-stencil
2647           (ly:stencil-add number-stencil slash-stencil)))
2648       (ly:warning "Unable to create slashed digit ~a" num))
2649     number-stencil))
2650
2651
2652 (define-builtin-markup-command (slashed-digit layout props num)
2653   (integer?)
2654   other
2655   ((font-size 0)
2656    (thickness 1.6))
2657   "
2658 @cindex slashed digits
2659
2660 A feta number, with slash.  This is for use in the context of
2661 figured bass notation.
2662 @lilypond[verbatim,quote]
2663 \\markup {
2664   \\slashed-digit #5
2665   \\hspace #2
2666   \\override #'(thickness . 3)
2667   \\slashed-digit #7
2668 }
2669 @end lilypond"
2670   (slashed-digit-internal layout props num #t font-size thickness))
2671
2672 (define-builtin-markup-command (backslashed-digit layout props num)
2673   (integer?)
2674   other
2675   ((font-size 0)
2676    (thickness 1.6))
2677   "
2678 @cindex backslashed digits
2679
2680 A feta number, with backslash.  This is for use in the context of
2681 figured bass notation.
2682 @lilypond[verbatim,quote]
2683 \\markup {
2684   \\backslashed-digit #5
2685   \\hspace #2
2686   \\override #'(thickness . 3)
2687   \\backslashed-digit #7
2688 }
2689 @end lilypond"
2690   (slashed-digit-internal layout props num #f font-size thickness))
2691
2692 ;; eyeglasses
2693 (define eyeglassesps
2694      "0.15 setlinewidth
2695       -0.9 0 translate
2696       1.1 1.1 scale
2697       1.2 0.7 moveto
2698       0.7 0.7 0.5 0 361 arc
2699       stroke
2700       2.20 0.70 0.50 0 361 arc
2701       stroke
2702       1.45 0.85 0.30 0 180 arc
2703       stroke
2704       0.20 0.70 moveto
2705       0.80 2.00 lineto
2706       0.92 2.26 1.30 2.40 1.15 1.70 curveto
2707       stroke
2708       2.70 0.70 moveto
2709       3.30 2.00 lineto
2710       3.42 2.26 3.80 2.40 3.65 1.70 curveto
2711       stroke")
2712
2713 (define-builtin-markup-command (eyeglasses layout props) () other ()
2714   "Prints out eyeglasses, indicating strongly to look at the conductor.
2715 @lilypond[verbatim,quote]
2716 \\markup { \\eyeglasses }
2717 @end lilypond"
2718   (interpret-markup layout props
2719     (make-with-dimensions-markup '(-0.61 . 3.22) '(0.2 . 2.41)
2720       (make-postscript-markup eyeglassesps))))
2721
2722 (define-builtin-markup-command (left-brace layout props size)
2723   (number?)
2724   other
2725   ()
2726   "
2727 A feta brace in point size @var{size}.
2728
2729 @lilypond[verbatim,quote]
2730 \\markup {
2731   \\left-brace #35
2732   \\hspace #2
2733   \\left-brace #45
2734 }
2735 @end lilypond"
2736   (let* ((font (ly:paper-get-font layout
2737                                   (cons '((font-encoding . fetaBraces)
2738                                           (font-name . #f))
2739                                         props)))
2740          (glyph-count (1- (ly:otf-glyph-count font)))
2741          (scale (ly:output-def-lookup layout 'output-scale))
2742          (scaled-size (/ (ly:pt size) scale))
2743          (glyph (lambda (n)
2744                   (ly:font-get-glyph font (string-append "brace"
2745                                                          (number->string n)))))
2746          (get-y-from-brace (lambda (brace)
2747                              (interval-length
2748                               (ly:stencil-extent (glyph brace) Y))))
2749          (find-brace (binary-search 0 glyph-count get-y-from-brace scaled-size))
2750          (glyph-found (glyph find-brace)))
2751
2752     (if (or (null? (ly:stencil-expr glyph-found))
2753             (< scaled-size (interval-length (ly:stencil-extent (glyph 0) Y)))
2754             (> scaled-size (interval-length
2755                             (ly:stencil-extent (glyph glyph-count) Y))))
2756         (begin
2757           (ly:warning (_ "no brace found for point size ~S ") size)
2758           (ly:warning (_ "defaulting to ~S pt")
2759                       (/ (* scale (interval-length
2760                                    (ly:stencil-extent glyph-found Y)))
2761                          (ly:pt 1)))))
2762     glyph-found))
2763
2764 (define-builtin-markup-command (right-brace layout props size)
2765   (number?)
2766   other
2767   ()
2768   "
2769 A feta brace in point size @var{size}, rotated 180 degrees.
2770
2771 @lilypond[verbatim,quote]
2772 \\markup {
2773   \\right-brace #45
2774   \\hspace #2
2775   \\right-brace #35
2776 }
2777 @end lilypond"
2778   (interpret-markup layout props (markup #:rotate 180 #:left-brace size)))
2779
2780 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2781 ;; the note command.
2782 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2783
2784 ;; TODO: better syntax.
2785
2786 (define-builtin-markup-command (note-by-number layout props log dot-count dir)
2787   (number? number? number?)
2788   music
2789   ((font-size 0)
2790    (style '()))
2791   "
2792 @cindex notes within text by log and dot-count
2793
2794 Construct a note symbol, with stem.  By using fractional values for
2795 @var{dir}, longer or shorter stems can be obtained.
2796
2797 @lilypond[verbatim,quote]
2798 \\markup {
2799   \\note-by-number #3 #0 #DOWN
2800   \\hspace #2
2801   \\note-by-number #1 #2 #0.8
2802 }
2803 @end lilypond"
2804   (define (get-glyph-name-candidates dir log style)
2805     (map (lambda (dir-name)
2806      (format "noteheads.~a~a~a" dir-name (min log 2)
2807              (if (and (symbol? style)
2808                       (not (equal? 'default style)))
2809                  (symbol->string style)
2810                  "")))
2811          (list (if (= dir UP) "u" "d")
2812                "s")))
2813
2814   (define (get-glyph-name font cands)
2815     (if (null? cands)
2816      ""
2817      (if (ly:stencil-empty? (ly:font-get-glyph font (car cands)))
2818          (get-glyph-name font (cdr cands))
2819          (car cands))))
2820
2821   (let* ((font (ly:paper-get-font layout (cons '((font-encoding . fetaMusic)) props)))
2822          (size-factor (magstep font-size))
2823          (stem-length (*  size-factor (max 3 (- log 1))))
2824          (head-glyph-name (get-glyph-name font (get-glyph-name-candidates (sign dir) log style)))
2825          (head-glyph (ly:font-get-glyph font head-glyph-name))
2826          (attach-indices (ly:note-head::stem-attachment font head-glyph-name))
2827          (stem-thickness (* size-factor 0.13))
2828          (stemy (* dir stem-length))
2829          (attach-off (cons (interval-index
2830                             (ly:stencil-extent head-glyph X)
2831                             (* (sign dir) (car attach-indices)))
2832                            (* (sign dir)        ; fixme, this is inconsistent between X & Y.
2833                               (interval-index
2834                                (ly:stencil-extent head-glyph Y)
2835                                (cdr attach-indices)))))
2836          (stem-glyph (and (> log 0)
2837                           (ly:round-filled-box
2838                            (ordered-cons (car attach-off)
2839                                          (+ (car attach-off)  (* (- (sign dir)) stem-thickness)))
2840                            (cons (min stemy (cdr attach-off))
2841                                  (max stemy (cdr attach-off)))
2842                            (/ stem-thickness 3))))
2843
2844          (dot (ly:font-get-glyph font "dots.dot"))
2845          (dotwid (interval-length (ly:stencil-extent dot X)))
2846          (dots (and (> dot-count 0)
2847                     (apply ly:stencil-add
2848                            (map (lambda (x)
2849                                   (ly:stencil-translate-axis
2850                                    dot (* 2 x dotwid) X))
2851                                 (iota dot-count)))))
2852          (flaggl (and (> log 2)
2853                       (ly:stencil-translate
2854                        (ly:font-get-glyph font
2855                                           (string-append "flags."
2856                                                          (if (> dir 0) "u" "d")
2857                                                          (number->string log)))
2858                        (cons (+ (car attach-off) (if (< dir 0) stem-thickness 0)) stemy)))))
2859
2860     ; If there is a flag on an upstem and the stem is short, move the dots to avoid the flag.
2861     ; 16th notes get a special case because their flags hang lower than any other flags.
2862     (if (and dots (> dir 0) (> log 2) (or (< dir 1.15) (and (= log 4) (< dir 1.3))))
2863         (set! dots (ly:stencil-translate-axis dots 0.5 X)))
2864     (if flaggl
2865         (set! stem-glyph (ly:stencil-add flaggl stem-glyph)))
2866     (if (ly:stencil? stem-glyph)
2867         (set! stem-glyph (ly:stencil-add stem-glyph head-glyph))
2868         (set! stem-glyph head-glyph))
2869     (if (ly:stencil? dots)
2870         (set! stem-glyph
2871               (ly:stencil-add
2872                (ly:stencil-translate-axis
2873                 dots
2874                 (+ (cdr (ly:stencil-extent head-glyph X)) dotwid)
2875                 X)
2876                stem-glyph)))
2877     stem-glyph))
2878
2879 (define-public log2
2880   (let ((divisor (log 2)))
2881     (lambda (z) (inexact->exact (/ (log z) divisor)))))
2882
2883 (define (parse-simple-duration duration-string)
2884   "Parse the `duration-string', e.g. ''4..'' or ''breve.'', and return a (log dots) list."
2885   (let ((match (regexp-exec (make-regexp "(breve|longa|maxima|[0-9]+)(\\.*)") duration-string)))
2886     (if (and match (string=? duration-string (match:substring match 0)))
2887         (let ((len  (match:substring match 1))
2888               (dots (match:substring match 2)))
2889           (list (cond ((string=? len "breve") -1)
2890                       ((string=? len "longa") -2)
2891                       ((string=? len "maxima") -3)
2892                       (else (log2 (string->number len))))
2893                 (if dots (string-length dots) 0)))
2894         (ly:error (_ "not a valid duration string: ~a") duration-string))))
2895
2896 (define-builtin-markup-command (note layout props duration dir)
2897   (string? number?)
2898   music
2899   (note-by-number-markup)
2900   "
2901 @cindex notes within text by string
2902
2903 This produces a note with a stem pointing in @var{dir} direction, with
2904 the @var{duration} for the note head type and augmentation dots.  For
2905 example, @code{\\note #\"4.\" #-0.75} creates a dotted quarter note, with
2906 a shortened down stem.
2907
2908 @lilypond[verbatim,quote]
2909 \\markup {
2910   \\override #'(style . cross) {
2911     \\note #\"4..\" #UP
2912   }
2913   \\hspace #2
2914   \\note #\"breve\" #0
2915 }
2916 @end lilypond"
2917   (let ((parsed (parse-simple-duration duration)))
2918     (note-by-number-markup layout props (car parsed) (cadr parsed) dir)))
2919
2920 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2921 ;; translating.
2922 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2923
2924 (define-builtin-markup-command (lower layout props amount arg)
2925   (number? markup?)
2926   align
2927   ()
2928   "
2929 @cindex lowering text
2930
2931 Lower @var{arg} by the distance @var{amount}.
2932 A negative @var{amount} indicates raising; see also @code{\\raise}.
2933
2934 @lilypond[verbatim,quote]
2935 \\markup {
2936   one
2937   \\lower #3
2938   two
2939   three
2940 }
2941 @end lilypond"
2942   (ly:stencil-translate-axis (interpret-markup layout props arg)
2943                              (- amount) Y))
2944
2945 (define-builtin-markup-command (translate-scaled layout props offset arg)
2946   (number-pair? markup?)
2947   align
2948   ((font-size 0))
2949   "
2950 @cindex translating text
2951 @cindex scaling text
2952
2953 Translate @var{arg} by @var{offset}, scaling the offset by the
2954 @code{font-size}.
2955
2956 @lilypond[verbatim,quote]
2957 \\markup {
2958   \\fontsize #5 {
2959     * \\translate #'(2 . 3) translate
2960     \\hspace #2
2961     * \\translate-scaled #'(2 . 3) translate-scaled
2962   }
2963 }
2964 @end lilypond"
2965   (let* ((factor (magstep font-size))
2966          (scaled (cons (* factor (car offset))
2967                        (* factor (cdr offset)))))
2968     (ly:stencil-translate (interpret-markup layout props arg)
2969                           scaled)))
2970
2971 (define-builtin-markup-command (raise layout props amount arg)
2972   (number? markup?)
2973   align
2974   ()
2975   "
2976 @cindex raising text
2977
2978 Raise @var{arg} by the distance @var{amount}.
2979 A negative @var{amount} indicates lowering, see also @code{\\lower}.
2980
2981 The argument to @code{\\raise} is the vertical displacement amount,
2982 measured in (global) staff spaces.  @code{\\raise} and @code{\\super}
2983 raise objects in relation to their surrounding markups.
2984
2985 If the text object itself is positioned above or below the staff, then
2986 @code{\\raise} cannot be used to move it, since the mechanism that
2987 positions it next to the staff cancels any shift made with
2988 @code{\\raise}.  For vertical positioning, use the @code{padding}
2989 and/or @code{extra-offset} properties.
2990
2991 @lilypond[verbatim,quote]
2992 \\markup {
2993   C
2994   \\small
2995   \\bold
2996   \\raise #1.0
2997   9/7+
2998 }
2999 @end lilypond"
3000   (ly:stencil-translate-axis (interpret-markup layout props arg) amount Y))
3001
3002 (define-builtin-markup-command (fraction layout props arg1 arg2)
3003   (markup? markup?)
3004   other
3005   ((font-size 0))
3006   "
3007 @cindex creating text fractions
3008
3009 Make a fraction of two markups.
3010 @lilypond[verbatim,quote]
3011 \\markup {
3012   Ï€ â‰ˆ
3013   \\fraction 355 113
3014 }
3015 @end lilypond"
3016   (let* ((m1 (interpret-markup layout props arg1))
3017          (m2 (interpret-markup layout props arg2))
3018          (factor (magstep font-size))
3019          (boxdimen (cons (* factor -0.05) (* factor 0.05)))
3020          (padding (* factor 0.2))
3021          (baseline (* factor 0.6))
3022          (offset (* factor 0.75)))
3023     (set! m1 (ly:stencil-aligned-to m1 X CENTER))
3024     (set! m2 (ly:stencil-aligned-to m2 X CENTER))
3025     (let* ((x1 (ly:stencil-extent m1 X))
3026            (x2 (ly:stencil-extent m2 X))
3027            (line (ly:round-filled-box (interval-union x1 x2) boxdimen 0.0))
3028            ;; should stack mols separately, to maintain LINE on baseline
3029            (stack (stack-lines DOWN padding baseline (list m1 line m2))))
3030       (set! stack
3031             (ly:stencil-aligned-to stack Y CENTER))
3032       (set! stack
3033             (ly:stencil-aligned-to stack X LEFT))
3034       ;; should have EX dimension
3035       ;; empirical anyway
3036       (ly:stencil-translate-axis stack offset Y))))
3037
3038 (define-builtin-markup-command (normal-size-super layout props arg)
3039   (markup?)
3040   font
3041   ((baseline-skip))
3042   "
3043 @cindex setting superscript in standard font size
3044
3045 Set @var{arg} in superscript with a normal font size.
3046
3047 @lilypond[verbatim,quote]
3048 \\markup {
3049   default
3050   \\normal-size-super {
3051     superscript in standard size
3052   }
3053 }
3054 @end lilypond"
3055   (ly:stencil-translate-axis
3056    (interpret-markup layout props arg)
3057    (* 0.5 baseline-skip) Y))
3058
3059 (define-builtin-markup-command (super layout props arg)
3060   (markup?)
3061   font
3062   ((font-size 0)
3063    (baseline-skip))
3064   "
3065 @cindex superscript text
3066
3067 Set @var{arg} in superscript.
3068
3069 @lilypond[verbatim,quote]
3070 \\markup {
3071   E =
3072   \\concat {
3073     mc
3074     \\super
3075     2
3076   }
3077 }
3078 @end lilypond"
3079   (ly:stencil-translate-axis
3080    (interpret-markup
3081     layout
3082     (cons `((font-size . ,(- font-size 3))) props)
3083     arg)
3084    (* 0.5 baseline-skip)
3085    Y))
3086
3087 (define-builtin-markup-command (translate layout props offset arg)
3088   (number-pair? markup?)
3089   align
3090   ()
3091   "
3092 @cindex translating text
3093
3094 Translate @var{arg} relative to its surroundings.  @var{offset}
3095 is a pair of numbers representing the displacement in the X and Y axis.
3096
3097 @lilypond[verbatim,quote]
3098 \\markup {
3099   *
3100   \\translate #'(2 . 3)
3101   \\line { translated two spaces right, three up }
3102 }
3103 @end lilypond"
3104   (ly:stencil-translate (interpret-markup layout props arg)
3105                         offset))
3106
3107 (define-builtin-markup-command (sub layout props arg)
3108   (markup?)
3109   font
3110   ((font-size 0)
3111    (baseline-skip))
3112   "
3113 @cindex subscript text
3114
3115 Set @var{arg} in subscript.
3116
3117 @lilypond[verbatim,quote]
3118 \\markup {
3119   \\concat {
3120     H
3121     \\sub {
3122       2
3123     }
3124     O
3125   }
3126 }
3127 @end lilypond"
3128   (ly:stencil-translate-axis
3129    (interpret-markup
3130     layout
3131     (cons `((font-size . ,(- font-size 3))) props)
3132     arg)
3133    (* -0.5 baseline-skip)
3134    Y))
3135
3136 (define-builtin-markup-command (normal-size-sub layout props arg)
3137   (markup?)
3138   font
3139   ((baseline-skip))
3140   "
3141 @cindex setting subscript in standard font size
3142
3143 Set @var{arg} in subscript with a normal font size.
3144
3145 @lilypond[verbatim,quote]
3146 \\markup {
3147   default
3148   \\normal-size-sub {
3149     subscript in standard size
3150   }
3151 }
3152 @end lilypond"
3153   (ly:stencil-translate-axis
3154    (interpret-markup layout props arg)
3155    (* -0.5 baseline-skip)
3156    Y))
3157
3158 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3159 ;; brackets.
3160 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3161
3162 (define-builtin-markup-command (hbracket layout props arg)
3163   (markup?)
3164   graphic
3165   ()
3166   "
3167 @cindex placing horizontal brackets around text
3168
3169 Draw horizontal brackets around @var{arg}.
3170
3171 @lilypond[verbatim,quote]
3172 \\markup {
3173   \\hbracket {
3174     \\line {
3175       one two three
3176     }
3177   }
3178 }
3179 @end lilypond"
3180   (let ((th 0.1) ;; todo: take from GROB.
3181         (m (interpret-markup layout props arg)))
3182     (bracketify-stencil m X th (* 2.5 th) th)))
3183
3184 (define-builtin-markup-command (bracket layout props arg)
3185   (markup?)
3186   graphic
3187   ()
3188   "
3189 @cindex placing vertical brackets around text
3190
3191 Draw vertical brackets around @var{arg}.
3192
3193 @lilypond[verbatim,quote]
3194 \\markup {
3195   \\bracket {
3196     \\note #\"2.\" #UP
3197   }
3198 }
3199 @end lilypond"
3200   (let ((th 0.1) ;; todo: take from GROB.
3201         (m (interpret-markup layout props arg)))
3202     (bracketify-stencil m Y th (* 2.5 th) th)))
3203
3204 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3205 ;; Delayed markup evaluation
3206 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3207
3208 (define-builtin-markup-command (page-ref layout props label gauge default)
3209   (symbol? markup? markup?)
3210   other
3211   ()
3212   "
3213 @cindex referencing page numbers in text
3214
3215 Reference to a page number. @var{label} is the label set on the referenced
3216 page (using the @code{\\label} command), @var{gauge} a markup used to estimate
3217 the maximum width of the page number, and @var{default} the value to display
3218 when @var{label} is not found."
3219   (let* ((gauge-stencil (interpret-markup layout props gauge))
3220          (x-ext (ly:stencil-extent gauge-stencil X))
3221          (y-ext (ly:stencil-extent gauge-stencil Y)))
3222     (ly:make-stencil
3223      `(delay-stencil-evaluation
3224        ,(delay (ly:stencil-expr
3225                 (let* ((table (ly:output-def-lookup layout 'label-page-table))
3226                        (page-number (if (list? table)
3227                                         (assoc-get label table)
3228                                         #f))
3229                        (page-markup (if page-number (format "~a" page-number) default))
3230                        (page-stencil (interpret-markup layout props page-markup))
3231                        (gap (- (interval-length x-ext)
3232                                (interval-length (ly:stencil-extent page-stencil X)))))
3233                   (interpret-markup layout props
3234                                     (markup #:concat (#:hspace gap page-markup)))))))
3235      x-ext
3236      y-ext)))
3237
3238 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3239 ;; Markup list commands
3240 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3241
3242 (define-public (space-lines baseline stils)
3243   (let space-stil ((stils stils)
3244                    (result (list)))
3245     (if (null? stils)
3246         (reverse! result)
3247         (let* ((stil (car stils))
3248                (dy-top (max (- (/ baseline 1.5)
3249                                (interval-bound (ly:stencil-extent stil Y) UP))
3250                             0.0))
3251                (dy-bottom (max (+ (/ baseline 3.0)
3252                                   (interval-bound (ly:stencil-extent stil Y) DOWN))
3253                                0.0))
3254                (new-stil (ly:make-stencil
3255                           (ly:stencil-expr stil)
3256                           (ly:stencil-extent stil X)
3257                           (cons (- (interval-bound (ly:stencil-extent stil Y) DOWN)
3258                                    dy-bottom)
3259                                 (+ (interval-bound (ly:stencil-extent stil Y) UP)
3260                                    dy-top)))))
3261           (space-stil (cdr stils) (cons new-stil result))))))
3262
3263 (define-builtin-markup-list-command (justified-lines layout props args)
3264   (markup-list?)
3265   ((baseline-skip)
3266    wordwrap-internal-markup-list)
3267   "
3268 @cindex justifying lines of text
3269
3270 Like @code{\\justify}, but return a list of lines instead of a single markup.
3271 Use @code{\\override-lines #'(line-width . @var{X})} to set the line width;
3272 @var{X}@tie{}is the number of staff spaces."
3273   (space-lines baseline-skip
3274                (interpret-markup-list layout props
3275                                       (make-wordwrap-internal-markup-list #t args))))
3276
3277 (define-builtin-markup-list-command (wordwrap-lines layout props args)
3278   (markup-list?)
3279   ((baseline-skip)
3280    wordwrap-internal-markup-list)
3281   "Like @code{\\wordwrap}, but return a list of lines instead of a single markup.
3282 Use @code{\\override-lines #'(line-width . @var{X})} to set the line width,
3283 where @var{X} is the number of staff spaces."
3284   (space-lines baseline-skip
3285                (interpret-markup-list layout props
3286                                       (make-wordwrap-internal-markup-list #f args))))
3287
3288 (define-builtin-markup-list-command (column-lines layout props args)
3289   (markup-list?)
3290   ((baseline-skip))
3291   "Like @code{\\column}, but return a list of lines instead of a single markup.
3292 @code{baseline-skip} determines the space between each markup in @var{args}."
3293   (space-lines (chain-assoc-get 'baseline-skip props)
3294                (interpret-markup-list layout props args)))
3295
3296 (define-builtin-markup-list-command (override-lines layout props new-prop args)
3297   (pair? markup-list?)
3298   ()
3299   "Like @code{\\override}, for markup lists."
3300   (interpret-markup-list layout (cons (list new-prop) props) args))