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