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