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