]> git.donarmstrong.com Git - lilypond.git/blob - scm/define-markup-commands.scm
Split WWW target in two stages WWW-1 and WWW-2
[lilypond.git] / scm / define-markup-commands.scm
1 ;;;; define-markup-commands.scm -- markup commands
2 ;;;;
3 ;;;;  source file of the GNU LilyPond music typesetter
4 ;;;; 
5 ;;;; (c) 2000--2007  Han-Wen Nienhuys <hanwen@xs4all.nl>
6 ;;;;                  Jan Nieuwenhuizen <janneke@gnu.org>
7
8
9 ;;; markup commands
10 ;;;  * each markup function should have a doc string with
11 ;;     syntax, description and example. 
12
13 (use-modules (ice-9 regex))
14
15 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16 ;; utility functions
17 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18
19 (define-public empty-stencil (ly:make-stencil '() '(1 . -1) '(1 . -1)))
20 (define-public point-stencil (ly:make-stencil "" '(0 . 0) '(0 . 0)))
21
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;; geometric shapes
24 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25
26 (define-builtin-markup-command (draw-line layout props dest)
27   (number-pair?)
28   graphic
29   ((thickness 1))
30   "
31 @cindex drawing lines within text
32
33 A simple line."
34   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
35                thickness))
36         (x (car dest))
37         (y (cdr dest)))
38     (ly:make-stencil
39      `(draw-line
40        ,th
41        0 0
42        ,x ,y)
43      (cons (min x 0) (max x 0))
44      (cons (min y 0) (max y 0)))))
45
46 (define-builtin-markup-command (draw-circle layout props radius thickness fill)
47   (number? number? boolean?)
48   graphic
49   ()
50   "
51 @cindex drawing circles within text
52
53 A circle of radius @var{radius}, thickness @var{thickness} and
54 optionally filled.
55 @c
56 @lilypond[verbatim,quote]
57 \\markup { \\draw-circle #2 #0.5 ##f \\hspace #2 \\draw-circle #2 #0 ##t }
58 @end lilypond"
59   (make-circle-stencil radius thickness fill))
60
61 (define-builtin-markup-command (triangle layout props filled)
62   (boolean?)
63   graphic
64   ((thickness 0.1)
65    (font-size 0)
66    (baseline-skip 2))
67   "
68 @cindex drawing triangles within text
69
70 A triangle, either filled or empty.
71 @c
72 @lilypond[verbatim,quote]
73 \\markup { \\triangle ##f \\triangle ##t }
74 @end lilypond"
75   (let ((ex (* (magstep font-size) 0.8 baseline-skip)))
76     (ly:make-stencil
77      `(polygon '(0.0 0.0
78                      ,ex 0.0
79                      ,(* 0.5 ex)
80                      ,(* 0.86 ex))
81            ,thickness
82            ,filled)
83      (cons 0 ex)
84      (cons 0 (* .86 ex)))))
85
86 (define-builtin-markup-command (circle layout props arg)
87   (markup?)
88   graphic
89   ((thickness 1)
90    (font-size 0)
91    (circle-padding 0.2))
92   "
93 @cindex circling text
94
95 Draw a circle around @var{arg}.  Use @code{thickness},
96 @code{circle-padding} and @code{font-size} properties to determine line
97 thickness and padding around the markup."
98   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
99                thickness))
100          (pad (* (magstep font-size) circle-padding))
101          (m (interpret-markup layout props arg)))
102     (circle-stencil m th pad)))
103
104 (define-builtin-markup-command (with-url layout props url arg)
105   (string? markup?)
106   graphic
107   ()
108   "
109 @cindex inserting URL links into text
110
111 Add a link to URL @var{url} around @var{arg}.  This only works in
112 the PDF backend.
113 @lilypond[verbatim,quote]
114 \\markup {
115   \\with-url #\"http://lilypond.org/web/\" {
116     LilyPond ... \\italic \"music notation for everyone\"
117   }
118 }
119 @end lilypond"
120   (let* ((stil (interpret-markup layout props arg))
121          (xextent (ly:stencil-extent stil X))
122          (yextent (ly:stencil-extent stil Y))
123          (old-expr (ly:stencil-expr stil))
124          (url-expr (list 'url-link url `(quote ,xextent) `(quote ,yextent))))
125
126     (ly:stencil-add (ly:make-stencil url-expr xextent yextent) stil)))
127
128 (define-builtin-markup-command (beam layout props width slope thickness)
129   (number? number? number?)
130   graphic
131   ()
132   "
133 @cindex drawing beams within text
134
135 Create a beam with the specified parameters."
136   (let* ((y (* slope width))
137          (yext (cons (min 0 y) (max 0 y)))
138          (half (/ thickness 2)))
139
140     (ly:make-stencil
141      `(polygon ',(list 
142                   0 (/ thickness -2)
143                     width (+ (* width slope)  (/ thickness -2))
144                     width (+ (* width slope)  (/ thickness 2))
145                     0 (/ thickness 2))
146                ,(ly:output-def-lookup layout 'blot-diameter)
147                #t)
148      (cons 0 width)
149      (cons (+ (- half) (car yext))
150            (+ half (cdr yext))))))
151
152 (define-builtin-markup-command (underline layout props arg)
153   (markup?)
154   music
155   ((thickness 1))
156   "
157 @cindex underlining text
158
159 Underline @var{arg}.  Looks at @code{thickness} to determine line
160 thickness and y offset."
161   (let* ((thick (* (ly:output-def-lookup layout 'line-thickness)
162                    thickness))
163          (markup (interpret-markup layout props arg))
164          (x1 (car (ly:stencil-extent markup X)))
165          (x2 (cdr (ly:stencil-extent markup X)))
166          (y (* thick -2))
167          (line (ly:make-stencil
168                 `(draw-line ,thick ,x1 ,y ,x2 ,y)
169                 (cons (min x1 0) (max x2 0))
170                 (cons thick thick))))
171     (ly:stencil-add markup line)))
172
173 (define-builtin-markup-command (box layout props arg)
174   (markup?)
175   font
176   ((thickness 1)
177    (font-size 0)
178    (box-padding 0.2))
179   "
180 @cindex enclosing text within a box
181
182 Draw a box round @var{arg}.  Looks at @code{thickness},
183 @code{box-padding} and @code{font-size} properties to determine line
184 thickness and padding around the markup."  
185   (let* ((th (* (ly:output-def-lookup layout 'line-thickness)
186                 thickness))
187          (pad (* (magstep font-size) box-padding))
188          (m (interpret-markup layout props arg)))
189     (box-stencil m th pad)))
190
191 (define-builtin-markup-command (filled-box layout props xext yext blot)
192   (number-pair? number-pair? number?)
193   graphic
194   ()
195   "
196 @cindex drawing solid boxes within text
197 @cindex drawing boxes with rounded corners
198
199 Draw a box with rounded corners of dimensions @var{xext} and
200 @var{yext}.  For example,
201 @verbatim
202 \\filled-box #'(-.3 . 1.8) #'(-.3 . 1.8) #0
203 @end verbatim
204 creates a box extending horizontally from -0.3 to 1.8 and
205 vertically from -0.3 up to 1.8, with corners formed from a
206 circle of diameter@tie{}0 (i.e. sharp corners)."
207   (ly:round-filled-box
208    xext yext blot))
209
210 (define-builtin-markup-command (rounded-box layout props arg)
211   (markup?)
212   graphic
213   ((thickness 1)
214    (corner-radius 1)
215    (font-size 0)
216    (box-padding 0.5))
217   "@cindex enclosing text in a bow with rounded corners
218    @cindex drawing boxes with rounded corners around text
219 Draw a box with rounded corners around @var{arg}.  Looks at @code{thickness},
220 @code{box-padding} and @code{font-size} properties to determine line
221 thickness and padding around the markup; the @code{corner-radius} property
222 makes possible to define another shape for the corners (default is 1).
223
224 @lilypond[quote,verbatim,fragment,relative=2]
225 c^\\markup{ \\rounded-box Overtura }
226 c,8. c16 c4 r
227 @end lilypond" 
228   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
229                thickness))
230         (pad (* (magstep font-size) box-padding))
231         (m (interpret-markup layout props arg)))
232     (ly:stencil-add (rounded-box-stencil m th pad corner-radius)
233                     m)))
234
235 (define-builtin-markup-command (rotate layout props ang arg)
236   (number? markup?)
237   align
238   ()
239   "
240 @cindex rotating text
241
242 Rotate object with @var{ang} degrees around its center."
243   (let* ((stil (interpret-markup layout props arg)))
244     (ly:stencil-rotate stil ang 0 0)))
245
246 (define-builtin-markup-command (whiteout layout props arg)
247   (markup?)
248   other
249   ()
250   "
251 @cindex adding a white background to text
252
253 Provide a white background for @var{arg}."
254   (stencil-whiteout (interpret-markup layout props arg)))
255
256 (define-builtin-markup-command (pad-markup layout props padding arg)
257   (number? markup?)
258   align
259   ()
260   "
261 @cindex padding text
262 @cindex putting space around text
263
264 Add space around a markup object."
265   (let*
266       ((stil (interpret-markup layout props arg))
267        (xext (ly:stencil-extent stil X))
268        (yext (ly:stencil-extent stil Y)))
269
270     (ly:make-stencil
271      (ly:stencil-expr stil)
272      (interval-widen xext padding)
273      (interval-widen yext padding))))
274
275 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
276 ;; space
277 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
278
279 (define-builtin-markup-command (strut layout props)
280   ()
281   other
282   ()
283   "
284 @cindex creating vertical spaces in text
285
286 Create a box of the same height as the space in the current font."
287   (let ((m (ly:text-interface::interpret-markup layout props " ")))
288     (ly:make-stencil (ly:stencil-expr m)
289                      '(0 . 0)
290                      (ly:stencil-extent m X)
291                      )))
292
293 ;; todo: fix negative space
294 (define-builtin-markup-command (hspace layout props amount)
295   (number?)
296   align
297   ()
298   "
299 @cindex creating horizontal spaces in text
300
301 This produces a invisible object taking horizontal space.  For example,
302
303 @example 
304 \\markup @{ A \\hspace #2.0 B @} 
305 @end example
306
307 @noindent
308 puts extra space between A and@tie{}B, on top of the space that is
309 normally inserted before elements on a line."
310   (if (> amount 0)
311       (ly:make-stencil "" (cons 0 amount) '(-1 . 1))
312       (ly:make-stencil "" (cons amount amount) '(-1 . 1))))
313
314
315 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
316 ;; importing graphics.
317 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
318
319 (define-builtin-markup-command (stencil layout props stil)
320   (ly:stencil?)
321   other
322   ()
323   "
324 @cindex importing stencils into text
325
326 Use a stencil as markup."
327   stil)
328
329 (define bbox-regexp
330   (make-regexp "%%BoundingBox:[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)"))
331
332 (define (get-postscript-bbox string)
333   "Extract the bbox from STRING, or return #f if not present."
334   (let*
335       ((match (regexp-exec bbox-regexp string)))
336     
337     (if match
338         (map (lambda (x)
339                (string->number (match:substring match x)))
340              (cdr (iota 5)))
341              
342         #f)))
343
344 (define-builtin-markup-command (epsfile layout props axis size file-name)
345   (number? number? string?)
346   graphic
347   ()
348   "
349 @cindex inlining an Encapsulated PostScript image
350
351 Inline an EPS image.  The image is scaled along @var{axis} to
352 @var{size}."
353   (if (ly:get-option 'safe)
354       (interpret-markup layout props "not allowed in safe")
355       (eps-file->stencil axis size file-name)
356       ))
357
358 (define-builtin-markup-command (postscript layout props str)
359   (string?)
360   graphic
361   ()
362   "
363 @cindex inserting PostScript directly into text
364
365 This inserts @var{str} directly into the output as a PostScript
366 command string.  Due to technicalities of the output backends,
367 different scales should be used for the @TeX{} and PostScript backend,
368 selected with @code{-f}. 
369
370 For the @TeX{} backend, the following string prints a rotated text
371
372 @example
373 0 0 moveto /ecrm10 findfont 
374 1.75 scalefont setfont 90 rotate (hello) show
375 @end example
376
377 @noindent
378 The magical constant 1.75 scales from LilyPond units (staff spaces) to
379 @TeX{} dimensions.
380
381 For the postscript backend, use the following
382
383 @example
384 gsave /ecrm10 findfont 
385  10.0 output-scale div 
386  scalefont setfont 90 rotate (hello) show grestore 
387 @end example"
388   ;; FIXME
389   (ly:make-stencil
390    (list 'embedded-ps
391          (format "
392 gsave currentpoint translate
393 0.1 setlinewidth
394  ~a
395 grestore
396 "
397                  str))
398    '(0 . 0) '(0 . 0)))
399
400 (define-builtin-markup-command (score layout props score)
401   (ly:score?)
402   music
403   ()
404   "
405 @cindex inserting music into text
406
407 Inline an image of music."
408   (let* ((output (ly:score-embedded-format score layout)))
409
410     (if (ly:music-output? output)
411         (paper-system-stencil
412          (vector-ref (ly:paper-score-paper-systems output) 0))
413         (begin
414           (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?"))
415           empty-stencil))))
416
417 (define-builtin-markup-command (null layout props)
418   ()
419   other
420   ()
421   "
422 @cindex creating empty text objects
423
424 An empty markup with extents of a single point."
425   point-stencil)
426
427 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
428 ;; basic formatting.
429 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
430
431 (define-builtin-markup-command (simple layout props str)
432   (string?)
433   font
434   ()
435   "
436 @cindex simple text strings
437
438 A simple text string; @code{\\markup @{ foo @}} is equivalent with
439 @code{\\markup @{ \\simple #\"foo\" @}}."
440   (interpret-markup layout props str))
441
442 (define-builtin-markup-command (tied-lyric layout props str)
443   (string?)
444   music
445   ()
446   "
447 @cindex simple text strings with tie characters
448
449 Like simple-markup, but use tie characters for @q{~} tilde symbols."
450   (if (string-contains str "~")
451       (let*
452           ((parts (string-split str #\~))
453            (tie-str (ly:wide-char->utf-8 #x203f))
454            (joined  (list-join parts tie-str))
455            (join-stencil (interpret-markup layout props tie-str))
456            )
457
458         (interpret-markup layout 
459                           (prepend-alist-chain
460                            'word-space
461                            (/ (interval-length (ly:stencil-extent join-stencil X)) -3.5)
462                            props)
463                           (make-line-markup joined)))
464                            ;(map (lambda (s) (interpret-markup layout props s)) parts))
465       (interpret-markup layout props str)))
466
467 (define-public empty-markup
468   (make-simple-markup ""))
469
470 ;; helper for justifying lines.
471 (define (get-fill-space word-count line-width text-widths)
472   "Calculate the necessary paddings between each two adjacent texts.
473         The lengths of all texts are stored in @var{text-widths}.
474         The normal formula for the padding between texts a and b is:
475         padding = line-width/(word-count - 1) - (length(a) + length(b))/2
476         The first and last padding have to be calculated specially using the
477         whole length of the first or last text.
478         Return a list of paddings."
479   (cond
480    ((null? text-widths) '())
481    
482    ;; special case first padding
483    ((= (length text-widths) word-count)
484     (cons 
485      (- (- (/ line-width (1- word-count)) (car text-widths))
486         (/ (car (cdr text-widths)) 2))
487      (get-fill-space word-count line-width (cdr text-widths))))
488    ;; special case last padding
489    ((= (length text-widths) 2)
490     (list (- (/ line-width (1- word-count))
491              (+ (/ (car text-widths) 2) (car (cdr text-widths)))) 0))
492    (else
493     (cons 
494      (- (/ line-width (1- word-count))
495         (/ (+ (car text-widths) (car (cdr text-widths))) 2))
496      (get-fill-space word-count line-width (cdr text-widths))))))
497
498 (define-builtin-markup-command (fill-line layout props markups)
499   (markup-list?)
500   align
501   ((text-direction RIGHT)
502    (word-space 1)
503    (line-width #f))
504   "Put @var{markups} in a horizontal line of width @var{line-width}.
505 The markups are spaced or flushed to fill the entire line.
506 If there are no arguments, return an empty stencil."
507  
508   (let* ((orig-stencils (interpret-markup-list layout props markups))
509          (stencils
510           (map (lambda (stc)
511                  (if (ly:stencil-empty? stc)
512                      point-stencil
513                      stc)) orig-stencils))
514          (text-widths
515           (map (lambda (stc)
516                  (if (ly:stencil-empty? stc)
517                      0.0
518                      (interval-length (ly:stencil-extent stc X))))
519                stencils))
520          (text-width (apply + text-widths))
521          (word-count (length stencils))
522          (prop-line-width (chain-assoc-get 'line-width props #f))
523          (line-width (or line-width (ly:output-def-lookup layout 'line-width)))
524          (fill-space
525                 (cond
526                         ((= word-count 1) 
527                                 (list
528                                         (/ (- line-width text-width) 2)
529                                         (/ (- line-width text-width) 2)))
530                         ((= word-count 2)
531                                 (list
532                                         (- line-width text-width)))
533                         (else 
534                                 (get-fill-space word-count line-width text-widths))))
535          (fill-space-normal
536           (map (lambda (x)
537                  (if (< x word-space)
538                      word-space
539                      x))
540                fill-space))
541                                         
542          (line-stencils (if (= word-count 1)
543                             (list
544                              point-stencil
545                              (car stencils)
546                              point-stencil)
547                             stencils)))
548
549     (if (= text-direction LEFT)
550         (set! line-stencils (reverse line-stencils)))
551
552     (if (null? (remove ly:stencil-empty? orig-stencils))
553         empty-stencil
554         (stack-stencils-padding-list X
555                                      RIGHT fill-space-normal line-stencils))))
556         
557 (define-builtin-markup-command (line layout props args)
558   (markup-list?)
559   align
560   ((word-space)
561    (text-direction RIGHT))
562   "Put @var{args} in a horizontal line.  The property @code{word-space}
563 determines the space between each markup in @var{args}."
564   (let ((stencils (interpret-markup-list layout props args)))
565     (if (= text-direction LEFT)
566         (set! stencils (reverse stencils)))
567     (stack-stencil-line
568      word-space
569      (remove ly:stencil-empty? stencils))))
570
571 (define-builtin-markup-command (concat layout props args)
572   (markup-list?)
573   align
574   ()
575   "
576 @cindex concatenating text
577 @cindex ligatures in text
578
579 Concatenate @var{args} in a horizontal line, without spaces inbetween.
580 Strings and simple markups are concatenated on the input level, allowing
581 ligatures.  For example, @code{\\concat @{ \"f\" \\simple #\"i\" @}} is
582 equivalent to @code{\"fi\"}."
583   (define (concat-string-args arg-list)
584     (fold-right (lambda (arg result-list)
585                   (let ((result (if (pair? result-list)
586                                     (car result-list)
587                                   '())))
588                     (if (and (pair? arg) (eqv? (car arg) simple-markup))
589                       (set! arg (cadr arg)))
590                     (if (and (string? result) (string? arg))
591                         (cons (string-append arg result) (cdr result-list))
592                       (cons arg result-list))))
593                 '()
594                 arg-list))
595
596   (interpret-markup layout
597                     (prepend-alist-chain 'word-space 0 props)
598                     (make-line-markup (if (markup-command-list? args)
599                                           args
600                                           (concat-string-args args)))))
601
602 (define (wordwrap-stencils stencils
603                            justify base-space line-width text-dir)
604   "Perform simple wordwrap, return stencil of each line."  
605   (define space (if justify
606                     ;; justify only stretches lines.
607                     (* 0.7 base-space)
608                     base-space))
609   (define (take-list width space stencils
610                      accumulator accumulated-width)
611     "Return (head-list . tail) pair, with head-list fitting into width"
612     (if (null? stencils)
613         (cons accumulator stencils)
614         (let* ((first (car stencils))
615                (first-wid (cdr (ly:stencil-extent (car stencils) X)))
616                (newwid (+ space first-wid accumulated-width)))
617           (if (or (null? accumulator)
618                   (< newwid width))
619               (take-list width space
620                          (cdr stencils)
621                          (cons first accumulator)
622                          newwid)
623               (cons accumulator stencils)))))
624   (let loop ((lines '())
625              (todo stencils))
626     (let* ((line-break (take-list line-width space todo
627                                   '() 0.0))
628            (line-stencils (car line-break))
629            (space-left (- line-width
630                           (apply + (map (lambda (x) (cdr (ly:stencil-extent x X)))
631                                         line-stencils))))
632            (line-word-space (cond ((not justify) space)
633                                   ;; don't stretch last line of paragraph.
634                                   ;; hmmm . bug - will overstretch the last line in some case. 
635                                   ((null? (cdr line-break))
636                                    base-space)
637                                   ((null? line-stencils) 0.0)
638                                   ((null? (cdr line-stencils)) 0.0)
639                                   (else (/ space-left (1- (length line-stencils))))))
640            (line (stack-stencil-line line-word-space
641                                      (if (= text-dir RIGHT)
642                                          (reverse line-stencils)
643                                          line-stencils))))
644       (if (pair? (cdr line-break))
645           (loop (cons line lines)
646                 (cdr line-break))
647           (begin
648             (if (= text-dir LEFT)
649                 (set! line
650                       (ly:stencil-translate-axis
651                        line
652                        (- line-width (interval-end (ly:stencil-extent line X)))
653                        X)))
654             (reverse (cons line lines)))))))
655
656 (define-builtin-markup-list-command (wordwrap-internal layout props justify args)
657   (boolean? markup-list?)
658   ((line-width #f)
659    (word-space)
660    (text-direction RIGHT))
661   "Internal markup list command used to define @code{\\justify} and @code{\\wordwrap}."
662   (wordwrap-stencils (remove ly:stencil-empty?
663                              (interpret-markup-list layout props args))
664                      justify
665                      word-space
666                      (or line-width
667                          (ly:output-def-lookup layout 'line-width))
668                      text-direction))
669
670 (define-builtin-markup-command (justify layout props args)
671   (markup-list?)
672   align
673   ((baseline-skip)
674    wordwrap-internal-markup-list)
675   "
676 @cindex justifying text
677
678 Like wordwrap, but with lines stretched to justify the margins.
679 Use @code{\\override #'(line-width . @var{X})} to set the line width;
680 @var{X}@tie{}is the number of staff spaces."
681   (stack-lines DOWN 0.0 baseline-skip
682                (wordwrap-internal-markup-list layout props #t args)))
683
684 (define-builtin-markup-command (wordwrap layout props args)
685   (markup-list?)
686   align
687   ((baseline-skip)
688    wordwrap-internal-markup-list)
689   "Simple wordwrap.  Use @code{\\override #'(line-width . @var{X})} to set
690 the line width, where @var{X} is the number of staff spaces."
691   (stack-lines DOWN 0.0 baseline-skip
692                (wordwrap-internal-markup-list layout props #f args)))
693
694 (define-builtin-markup-list-command (wordwrap-string-internal layout props justify arg)
695   (boolean? string?)
696   ((line-width)
697    (word-space)
698    (text-direction RIGHT))
699   "Internal markup list command used to define @code{\\justify-string} and
700 @code{\\wordwrap-string}."
701   (let* ((para-strings (regexp-split
702                         (string-regexp-substitute
703                          "\r" "\n"
704                          (string-regexp-substitute "\r\n" "\n" arg))
705                         "\n[ \t\n]*\n[ \t\n]*"))
706          (list-para-words (map (lambda (str)
707                                  (regexp-split str "[ \t\n]+"))
708                                para-strings))
709          (para-lines (map (lambda (words)
710                             (let* ((stencils
711                                     (remove ly:stencil-empty?
712                                             (map (lambda (x)
713                                                    (interpret-markup layout props x))
714                                                  words))))
715                               (wordwrap-stencils stencils
716                                                  justify word-space
717                                                  line-width text-direction)))
718                           list-para-words)))
719     (apply append para-lines)))
720
721 (define-builtin-markup-command (wordwrap-string layout props arg)
722   (string?)
723   align
724   ((baseline-skip)
725    wordwrap-string-internal-markup-list)
726   "Wordwrap a string.  Paragraphs may be separated with double newlines."
727   (stack-lines DOWN 0.0 baseline-skip
728                (wordwrap-string-internal-markup-list layout props #f arg)))
729
730 (define-builtin-markup-command (justify-string layout props arg)
731   (string?)
732   align
733   ((baseline-skip)
734    wordwrap-string-internal-markup-list)
735   "Justify a string.  Paragraphs may be separated with double newlines"
736   (stack-lines DOWN 0.0 baseline-skip
737                (wordwrap-string-internal-markup-list layout props #t arg)))
738
739 (define-builtin-markup-command (wordwrap-field layout props symbol)
740   (symbol?)
741   align
742   ()
743   "Wordwrap the data which has been assigned to @var{symbol}."
744   (let* ((m (chain-assoc-get symbol props)))
745     (if (string? m)
746         (wordwrap-string-markup layout props m)
747         empty-stencil)))
748
749 (define-builtin-markup-command (justify-field layout props symbol)
750   (symbol?)
751   align
752   ()
753   "Justify the data which has been assigned to @var{symbol}."
754   (let* ((m (chain-assoc-get symbol props)))
755     (if (string? m)
756         (justify-string-markup layout props m)
757         empty-stencil)))
758
759 (define-builtin-markup-command (combine layout props m1 m2)
760   (markup? markup?)
761   align
762   ()
763   "
764 @cindex merging text
765
766 Print two markups on top of each other."
767   (let* ((s1 (interpret-markup layout props m1))
768          (s2 (interpret-markup layout props m2)))
769     (ly:stencil-add s1 s2)))
770
771 ;;
772 ;; TODO: should extract baseline-skip from each argument somehow..
773 ;; 
774 (define-builtin-markup-command (column layout props args)
775   (markup-list?)
776   align
777   ((baseline-skip))
778   "
779 @cindex stacking text in a column
780
781 Stack the markups in @var{args} vertically.  The property
782 @code{baseline-skip} determines the space between each markup in @var{args}."
783   (let ((arg-stencils (interpret-markup-list layout props args)))
784     (stack-lines -1 0.0 baseline-skip
785                  (remove ly:stencil-empty? arg-stencils))))
786
787 (define-builtin-markup-command (dir-column layout props args)
788   (markup-list?)
789   align
790   ((direction)
791    (baseline-skip))
792   "
793 @cindex changing direction of text columns
794
795 Make a column of args, going up or down, depending on the setting
796 of the @code{#'direction} layout property."
797   (stack-lines (if (number? direction) direction -1)
798                0.0
799                baseline-skip
800                (interpret-markup-list layout props args)))
801
802 (define-builtin-markup-command (center-align layout props args)
803   (markup-list?)
804   align
805   ((baseline-skip))
806   "
807 @cindex centering a column of text
808
809 Put @code{args} in a centered column."
810   (let* ((mols (interpret-markup-list layout props args))
811          (cmols (map (lambda (x) (ly:stencil-aligned-to x X CENTER)) mols)))
812     (stack-lines -1 0.0 baseline-skip cmols)))
813
814 (define-builtin-markup-command (vcenter layout props arg)
815   (markup?)
816   align
817   ()
818   "
819 @cindex vertically centering text
820
821 Align @code{arg} to its Y@tie{}center."
822   (let* ((mol (interpret-markup layout props arg)))
823     (ly:stencil-aligned-to mol Y CENTER)))
824
825 (define-builtin-markup-command (hcenter layout props arg)
826   (markup?)
827   align
828   ()
829   "
830 @cindex horizontally centering text
831
832 Align @code{arg} to its X@tie{}center."
833   (let* ((mol (interpret-markup layout props arg)))
834     (ly:stencil-aligned-to mol X CENTER)))
835
836 (define-builtin-markup-command (right-align layout props arg)
837   (markup?)
838   align
839   ()
840   "
841 @cindex right aligning text
842
843 Align @var{arg} on its right edge."
844   (let* ((m (interpret-markup layout props arg)))
845     (ly:stencil-aligned-to m X RIGHT)))
846
847 (define-builtin-markup-command (left-align layout props arg)
848   (markup?)
849   align
850   ()
851   "
852 @cindex left aligning text
853
854 Align @var{arg} on its left edge."
855   (let* ((m (interpret-markup layout props arg)))
856     (ly:stencil-aligned-to m X LEFT)))
857
858 (define-builtin-markup-command (general-align layout props axis dir arg)
859   (integer? number? markup?)
860   align
861   ()
862   "
863 @cindex controlling general text alignment
864
865 Align @var{arg} in @var{axis} direction to the @var{dir} side."
866   (let* ((m (interpret-markup layout props arg)))
867     (ly:stencil-aligned-to m axis dir)))
868
869 (define-builtin-markup-command (halign layout props dir arg)
870   (number? markup?)
871   align
872   ()
873   "
874 @cindex setting horizontal text alignment
875
876 Set horizontal alignment.  If @var{dir} is @code{-1}, then it is
877 left-aligned, while @code{+1} is right.  Values inbetween interpolate
878 alignment accordingly."
879   (let* ((m (interpret-markup layout props arg)))
880     (ly:stencil-aligned-to m X dir)))
881
882 (define-builtin-markup-command (with-dimensions layout props x y arg)
883   (number-pair? number-pair? markup?)
884   other
885   ()
886   "
887 @cindex setting extent of text objects
888
889 Set the dimensions of @var{arg} to @var{x} and@tie{}@var{y}."  
890   (let* ((m (interpret-markup layout props arg)))
891     (ly:make-stencil (ly:stencil-expr m) x y)))
892
893 (define-builtin-markup-command (pad-around layout props amount arg)
894   (number? markup?)
895   align
896   ()
897   "Add padding @var{amount} all around @var{arg}."  
898   (let* ((m (interpret-markup layout props arg))
899          (x (ly:stencil-extent m X))
900          (y (ly:stencil-extent m Y)))
901     (ly:make-stencil (ly:stencil-expr m)
902                      (interval-widen x amount)
903                      (interval-widen y amount))))
904
905 (define-builtin-markup-command (pad-x layout props amount arg)
906   (number? markup?)
907   align
908   ()
909   "
910 @cindex padding text horizontally
911
912 Add padding @var{amount} around @var{arg} in the X@tie{}direction."
913   (let* ((m (interpret-markup layout props arg))
914          (x (ly:stencil-extent m X))
915          (y (ly:stencil-extent m Y)))
916     (ly:make-stencil (ly:stencil-expr m)
917                      (interval-widen x amount)
918                      y)))
919
920 (define-builtin-markup-command (put-adjacent layout props arg1 axis dir arg2)
921   (markup? integer? ly:dir? markup?)
922   align
923   ()
924   "Put @var{arg2} next to @var{arg1}, without moving @var{arg1}."
925   (let ((m1 (interpret-markup layout props arg1))
926         (m2 (interpret-markup layout props arg2)))
927     (ly:stencil-combine-at-edge m1 axis dir m2 0.0)))
928
929 (define-builtin-markup-command (transparent layout props arg)
930   (markup?)
931   other
932   ()
933   "Make the argument transparent."
934   (let* ((m (interpret-markup layout props arg))
935          (x (ly:stencil-extent m X))
936          (y (ly:stencil-extent m Y)))
937     (ly:make-stencil "" x y)))
938
939 (define-builtin-markup-command (pad-to-box layout props x-ext y-ext arg)
940   (number-pair? number-pair? markup?)
941   align
942   ()
943   "Make @var{arg} take at least @var{x-ext}, @var{y-ext} space."
944   (let* ((m (interpret-markup layout props arg))
945          (x (ly:stencil-extent m X))
946          (y (ly:stencil-extent m Y)))
947     (ly:make-stencil (ly:stencil-expr m)
948                      (interval-union x-ext x)
949                      (interval-union y-ext y))))
950
951 (define-builtin-markup-command (hcenter-in layout props length arg)
952   (number? markup?)
953   align
954   ()
955   "Center @var{arg} horizontally within a box of extending
956 @var{length}/2 to the left and right."
957   (interpret-markup layout props
958                     (make-pad-to-box-markup
959                      (cons (/ length -2) (/ length 2))
960                      '(0 . 0)
961                      (make-hcenter-markup arg))))
962
963 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
964 ;; property
965 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
966
967 (define-builtin-markup-command (fromproperty layout props symbol)
968   (symbol?)
969   other
970   ()
971   "Read the @var{symbol} from property settings, and produce a stencil
972 from the markup contained within.  If @var{symbol} is not defined, it
973 returns an empty markup."
974   (let ((m (chain-assoc-get symbol props)))
975     (if (markup? m)
976         (interpret-markup layout props m)
977         empty-stencil)))
978
979 (define-builtin-markup-command (on-the-fly layout props procedure arg)
980   (symbol? markup?)
981   other
982   ()
983   "Apply the @var{procedure} markup command to @var{arg}.
984 @var{procedure} should take a single argument."
985   (let ((anonymous-with-signature (lambda (layout props arg) (procedure layout props arg))))
986     (set-object-property! anonymous-with-signature
987                           'markup-signature
988                           (list markup?))
989     (interpret-markup layout props (list anonymous-with-signature arg))))
990
991 (define-builtin-markup-command (override layout props new-prop arg)
992   (pair? markup?)
993   other
994   ()
995   "
996 @cindex overriding properties within text markup
997
998 Add the first argument in to the property list.  Properties may be
999 any sort of property supported by @rinternals{font-interface} and
1000 @rinternals{text-interface}, for example
1001
1002 @example
1003 \\override #'(font-family . married) \"bla\"
1004 @end example"
1005   (interpret-markup layout (cons (list new-prop) props) arg))
1006
1007 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1008 ;; files
1009 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1010
1011 (define-builtin-markup-command (verbatim-file layout props name)
1012   (string?)
1013   other
1014   ()
1015   "Read the contents of a file, and include it verbatim."
1016   (interpret-markup layout props
1017                     (if  (ly:get-option 'safe)
1018                          "verbatim-file disabled in safe mode"
1019                          (let* ((str (ly:gulp-file name))
1020                                 (lines (string-split str #\nl)))
1021                            (make-typewriter-markup
1022                             (make-column-markup lines))))))
1023
1024 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1025 ;; fonts.
1026 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1027
1028 (define-builtin-markup-command (bigger layout props arg)
1029   (markup?)
1030   font
1031   ()
1032   "Increase the font size relative to current setting."
1033   (interpret-markup layout props
1034    `(,fontsize-markup 1 ,arg)))
1035
1036 (define-builtin-markup-command (smaller layout props arg)
1037   (markup?)
1038   font
1039   ()
1040   "Decrease the font size relative to current setting."
1041   (interpret-markup layout props
1042    `(,fontsize-markup -1 ,arg)))
1043
1044 (define-builtin-markup-command larger
1045   (markup?)
1046   font
1047   bigger-markup)
1048
1049 (define-builtin-markup-command (finger layout props arg)
1050   (markup?)
1051   font
1052   ()
1053   "Set the argument as small numbers."
1054   (interpret-markup layout
1055                     (cons '((font-size . -5) (font-encoding . fetaNumber)) props)
1056                     arg))
1057
1058 (define-builtin-markup-command (fontsize layout props increment arg)
1059   (number? markup?)
1060   font
1061   ((font-size 0)
1062    (word-space 1)
1063    (baseline-skip 2))
1064   "Add @var{increment} to the font-size.  Adjust baseline skip accordingly."
1065   (let ((entries (list
1066                   (cons 'baseline-skip (* baseline-skip (magstep increment)))
1067                   (cons 'word-space (* word-space (magstep increment)))
1068                   (cons 'font-size (+ font-size increment)))))
1069     (interpret-markup layout (cons entries props) arg)))
1070
1071 (define-builtin-markup-command (magnify layout props sz arg)
1072   (number? markup?)
1073   font
1074   ()
1075   "
1076 @cindex magnifying text
1077
1078 Set the font magnification for its argument.  In the following
1079 example, the middle@tie{}A is 10% larger:
1080
1081 @example
1082 A \\magnify #1.1 @{ A @} A
1083 @end example
1084
1085 Note: Magnification only works if a font name is explicitly selected.
1086 Use @code{\\fontsize} otherwise."
1087   (interpret-markup
1088    layout 
1089    (prepend-alist-chain 'font-size (magnification->font-size sz) props)
1090    arg))
1091
1092 (define-builtin-markup-command (bold layout props arg)
1093   (markup?)
1094   font
1095   ()
1096   "Switch to bold font-series."
1097   (interpret-markup layout (prepend-alist-chain 'font-series 'bold props) arg))
1098
1099 (define-builtin-markup-command (sans layout props arg)
1100   (markup?)
1101   font
1102   ()
1103   "Switch to the sans serif family."
1104   (interpret-markup layout (prepend-alist-chain 'font-family 'sans props) arg))
1105
1106 (define-builtin-markup-command (number layout props arg)
1107   (markup?)
1108   font
1109   ()
1110   "Set font family to @code{number}, which yields the font used for
1111 time signatures and fingerings.  This font only contains numbers and
1112 some punctuation.  It doesn't have any letters."
1113   (interpret-markup layout (prepend-alist-chain 'font-encoding 'fetaNumber props) arg))
1114
1115 (define-builtin-markup-command (roman layout props arg)
1116   (markup?)
1117   font
1118   ()
1119   "Set font family to @code{roman}."
1120   (interpret-markup layout (prepend-alist-chain 'font-family 'roman props) arg))
1121
1122 (define-builtin-markup-command (huge layout props arg)
1123   (markup?)
1124   font
1125   ()
1126   "Set font size to +2."
1127   (interpret-markup layout (prepend-alist-chain 'font-size 2 props) arg))
1128
1129 (define-builtin-markup-command (large layout props arg)
1130   (markup?)
1131   font
1132   ()
1133   "Set font size to +1."
1134   (interpret-markup layout (prepend-alist-chain 'font-size 1 props) arg))
1135
1136 (define-builtin-markup-command (normalsize layout props arg)
1137   (markup?)
1138   font
1139   ()
1140   "Set font size to default."
1141   (interpret-markup layout (prepend-alist-chain 'font-size 0 props) arg))
1142
1143 (define-builtin-markup-command (small layout props arg)
1144   (markup?)
1145   font
1146   ()
1147   "Set font size to -1."
1148   (interpret-markup layout (prepend-alist-chain 'font-size -1 props) arg))
1149
1150 (define-builtin-markup-command (tiny layout props arg)
1151   (markup?)
1152   font
1153   ()
1154   "Set font size to -2."
1155   (interpret-markup layout (prepend-alist-chain 'font-size -2 props) arg))
1156
1157 (define-builtin-markup-command (teeny layout props arg)
1158   (markup?)
1159   font
1160   ()
1161   "Set font size to -3."
1162   (interpret-markup layout (prepend-alist-chain 'font-size -3 props) arg))
1163
1164 (define-builtin-markup-command (fontCaps layout props arg)
1165   (markup?)
1166   font
1167   ()
1168   "Set @code{font-shape} to @code{caps}."
1169   (interpret-markup layout (prepend-alist-chain 'font-shape 'caps props) arg))
1170
1171 ;; Poor man's caps
1172 (define-builtin-markup-command (smallCaps layout props text)
1173   (markup?)
1174   font
1175   ()
1176   "Turn @code{text}, which should be a string, to small caps.
1177 @example
1178 \\markup \\smallCaps \"Text between double quotes\"
1179 @end example
1180
1181 Note: @code{\\smallCaps} does not support accented characters."
1182   (define (char-list->markup chars lower)
1183     (let ((final-string (string-upcase (reverse-list->string chars))))
1184       (if lower
1185           (markup #:fontsize -2 final-string)
1186           final-string)))
1187   (define (make-small-caps rest-chars currents current-is-lower prev-result)
1188     (if (null? rest-chars)
1189         (make-concat-markup
1190           (reverse! (cons (char-list->markup currents current-is-lower)
1191                           prev-result)))
1192         (let* ((ch (car rest-chars))
1193                (is-lower (char-lower-case? ch)))
1194           (if (or (and current-is-lower is-lower)
1195                   (and (not current-is-lower) (not is-lower)))
1196               (make-small-caps (cdr rest-chars)
1197                                (cons ch currents)
1198                                is-lower
1199                                prev-result)
1200               (make-small-caps (cdr rest-chars)
1201                                (list ch)
1202                                is-lower
1203                                (if (null? currents)
1204                                    prev-result
1205                                    (cons (char-list->markup
1206                                             currents current-is-lower)
1207                                          prev-result)))))))
1208   (interpret-markup layout props
1209     (if (string? text)
1210         (make-small-caps (string->list text) (list) #f (list))
1211         text)))
1212
1213 (define-builtin-markup-command (caps layout props arg)
1214   (markup?)
1215   font
1216   ()
1217   "Emit @var{arg} as small caps."
1218   (interpret-markup layout props (make-smallCaps-markup arg)))
1219
1220 (define-builtin-markup-command (dynamic layout props arg)
1221   (markup?)
1222   font
1223   ()
1224   "Use the dynamic font.  This font only contains @b{s}, @b{f}, @b{m},
1225 @b{z}, @b{p}, and @b{r}.  When producing phrases, like
1226 @q{pi@`{u}@tie{}@b{f}}, the normal words (like @q{pi@`{u}}) should be
1227 done in a different font.  The recommended font for this is bold and italic."
1228   (interpret-markup
1229    layout (prepend-alist-chain 'font-encoding 'fetaDynamic props) arg))
1230
1231 (define-builtin-markup-command (text layout props arg)
1232   (markup?)
1233   font
1234   ()
1235   "Use a text font instead of music symbol or music alphabet font."  
1236
1237   ;; ugh - latin1
1238   (interpret-markup layout (prepend-alist-chain 'font-encoding 'latin1 props)
1239                     arg))
1240
1241 (define-builtin-markup-command (italic layout props arg)
1242   (markup?)
1243   font
1244   ()
1245   "Use italic @code{font-shape} for @var{arg}."
1246   (interpret-markup layout (prepend-alist-chain 'font-shape 'italic props) arg))
1247
1248 (define-builtin-markup-command (typewriter layout props arg)
1249   (markup?)
1250   font
1251   ()
1252   "Use @code{font-family} typewriter for @var{arg}."
1253   (interpret-markup
1254    layout (prepend-alist-chain 'font-family 'typewriter props) arg))
1255
1256 (define-builtin-markup-command (upright layout props arg)
1257   (markup?)
1258   font
1259   ()
1260   "Set font shape to @code{upright}.  This is the opposite of @code{italic}."
1261   (interpret-markup
1262    layout (prepend-alist-chain 'font-shape 'upright props) arg))
1263
1264 (define-builtin-markup-command (medium layout props arg)
1265   (markup?)
1266   font
1267   ()
1268   "Switch to medium font series (in contrast to bold)."
1269   (interpret-markup layout (prepend-alist-chain 'font-series 'medium props)
1270                     arg))
1271
1272 (define-builtin-markup-command (normal-text layout props arg)
1273   (markup?)
1274   font
1275   ()
1276   "Set all font related properties (except the size) to get the default
1277 normal text font, no matter what font was used earlier."
1278   ;; ugh - latin1
1279   (interpret-markup layout
1280                     (cons '((font-family . roman) (font-shape . upright)
1281                             (font-series . medium) (font-encoding . latin1))
1282                           props)
1283                     arg))
1284
1285 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1286 ;; symbols.
1287 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1288
1289 (define-builtin-markup-command (doublesharp layout props)
1290   ()
1291   music
1292   ()
1293   "Draw a double sharp symbol.
1294 @c
1295 @lilypond[verbatim,quote]
1296 \\markup { \\doublesharp }
1297 @end lilypond"
1298   (interpret-markup layout props (markup #:musicglyph (assoc-get 1 standard-alteration-glyph-name-alist ""))))
1299
1300 (define-builtin-markup-command (sesquisharp layout props)
1301   ()
1302   music
1303   ()
1304   "Draw a 3/2 sharp symbol.
1305 @c
1306 @lilypond[verbatim,quote]
1307 \\markup { \\sesquisharp }
1308 @end lilypond"
1309   (interpret-markup layout props (markup #:musicglyph (assoc-get 3/4 standard-alteration-glyph-name-alist ""))))                                         
1310
1311 (define-builtin-markup-command (sharp layout props)
1312   ()
1313   music
1314   ()
1315   "Draw a sharp symbol.
1316 @c
1317 @lilypond[verbatim,quote]
1318 \\markup { \\sharp }
1319 @end lilypond"
1320   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/2 standard-alteration-glyph-name-alist ""))))
1321
1322 (define-builtin-markup-command (semisharp layout props)
1323   ()
1324   music
1325   ()
1326   "Draw a semi sharp symbol.
1327 @c
1328 @lilypond[verbatim,quote]
1329 \\markup { \\semisharp }
1330 @end lilypond"
1331   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/4 standard-alteration-glyph-name-alist ""))))
1332
1333 (define-builtin-markup-command (natural layout props)
1334   ()
1335   music
1336   ()
1337   "Draw a natural symbol.
1338 @c
1339 @lilypond[verbatim,quote]
1340 \\markup { \\natural }
1341 @end lilypond"
1342   (interpret-markup layout props (markup #:musicglyph (assoc-get 0 standard-alteration-glyph-name-alist ""))))
1343
1344 (define-builtin-markup-command (semiflat layout props)
1345   ()
1346   music
1347   ()
1348   "Draw a semiflat symbol.
1349 @c
1350 @lilypond[verbatim,quote]
1351 \\markup { \\semiflat }
1352 @end lilypond"
1353   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/4 standard-alteration-glyph-name-alist ""))))
1354
1355 (define-builtin-markup-command (flat layout props)
1356   ()
1357   music
1358   ()
1359   "Draw a flat symbol.
1360 @c
1361 @lilypond[verbatim,quote]
1362 \\markup { \\flat }
1363 @end lilypond"
1364   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/2 standard-alteration-glyph-name-alist ""))))
1365
1366 (define-builtin-markup-command (sesquiflat layout props)
1367   ()
1368   music
1369   ()
1370   "Draw a 3/2 flat symbol.
1371 @c
1372 @lilypond[verbatim,quote]
1373 \\markup { \\sesquiflat }
1374 @end lilypond"
1375   (interpret-markup layout props (markup #:musicglyph (assoc-get -3/4 standard-alteration-glyph-name-alist ""))))
1376
1377 (define-builtin-markup-command (doubleflat layout props)
1378   ()
1379   music
1380   ()
1381   "Draw a double flat symbol.
1382 @c
1383 @lilypond[verbatim,quote]
1384 \\markup { \\doubleflat }
1385 @end lilypond"
1386   (interpret-markup layout props (markup #:musicglyph (assoc-get -1 standard-alteration-glyph-name-alist ""))))
1387
1388 (define-builtin-markup-command (with-color layout props color arg)
1389   (color? markup?)
1390   other
1391   ()
1392   "
1393 @cindex coloring text
1394
1395 Draw @var{arg} in color specified by @var{color}."
1396   (let ((stil (interpret-markup layout props arg)))
1397     (ly:make-stencil (list 'color color (ly:stencil-expr stil))
1398                      (ly:stencil-extent stil X)
1399                      (ly:stencil-extent stil Y))))
1400 \f
1401 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1402 ;; glyphs
1403 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1404
1405 (define-builtin-markup-command (arrow-head layout props axis direction filled)
1406   (integer? ly:dir? boolean?)
1407   graphic
1408   ()
1409   "Produce an arrow head in specified direction and axis.
1410 Use the filled head if @var{filled} is specified."
1411   (let*
1412       ((name (format "arrowheads.~a.~a~a"
1413                      (if filled
1414                          "close"
1415                          "open")
1416                      axis
1417                      direction)))
1418     (ly:font-get-glyph
1419      (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
1420                                      props))
1421      name)))
1422
1423 (define-builtin-markup-command (musicglyph layout props glyph-name)
1424   (string?)
1425   music
1426   ()
1427   "@var{glyph-name} is converted to a musical symbol; for example,
1428 @code{\\musicglyph #\"accidentals.natural\"} selects the natural sign from
1429 the music font.  See @ruser{The Feta font} for a complete listing of
1430 the possible glyphs."
1431   (ly:font-get-glyph
1432    (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
1433                                    props))
1434    glyph-name))
1435
1436 (define-builtin-markup-command (lookup layout props glyph-name)
1437   (string?)
1438   other
1439   ()
1440   "Lookup a glyph by name."
1441   (ly:font-get-glyph (ly:paper-get-font layout props)
1442                      glyph-name))
1443
1444 (define-builtin-markup-command (char layout props num)
1445   (integer?)
1446   other
1447   ()
1448   "Produce a single character.  For example, @code{\\char #65} produces the 
1449 letter @q{A}."
1450   (ly:text-interface::interpret-markup layout props (ly:wide-char->utf-8 num)))
1451
1452 (define number->mark-letter-vector (make-vector 25 #\A))
1453
1454 (do ((i 0 (1+ i))
1455      (j 0 (1+ j)))
1456     ((>= i 26))
1457   (if (= i (- (char->integer #\I) (char->integer #\A)))
1458       (set! i (1+ i)))
1459   (vector-set! number->mark-letter-vector j
1460                (integer->char (+ i (char->integer #\A)))))
1461
1462 (define number->mark-alphabet-vector (list->vector
1463   (map (lambda (i) (integer->char (+ i (char->integer #\A)))) (iota 26))))
1464
1465 (define (number->markletter-string vec n)
1466   "Double letters for big marks."
1467   (let* ((lst (vector-length vec)))
1468     
1469     (if (>= n lst)
1470         (string-append (number->markletter-string vec (1- (quotient n lst)))
1471                        (number->markletter-string vec (remainder n lst)))
1472         (make-string 1 (vector-ref vec n)))))
1473
1474 (define-builtin-markup-command (markletter layout props num)
1475   (integer?)
1476   other
1477   ()
1478   "Make a markup letter for @var{num}.  The letters start with A to@tie{}Z
1479 (skipping letter@tie{}I), and continue with double letters."
1480   (ly:text-interface::interpret-markup layout props
1481     (number->markletter-string number->mark-letter-vector num)))
1482
1483 (define-builtin-markup-command (markalphabet layout props num)
1484   (integer?)
1485   other
1486   ()
1487    "Make a markup letter for @var{num}.  The letters start with A to@tie{}Z
1488 and continue with double letters."
1489    (ly:text-interface::interpret-markup layout props
1490      (number->markletter-string number->mark-alphabet-vector num)))
1491
1492 (define-builtin-markup-command (slashed-digit layout props num)
1493   (integer?)
1494   other
1495   ((font-size 0)
1496    (thickness 1.6))
1497   "
1498 @cindex slashed digits
1499
1500 A feta number, with slash.  This is for use in the context of
1501 figured bass notation."
1502   (let* ((mag (magstep font-size))
1503          (thickness (* mag
1504                        (ly:output-def-lookup layout 'line-thickness)
1505                        thickness))
1506          (dy (* mag 0.15))
1507          (number-stencil (interpret-markup layout
1508                                            (prepend-alist-chain 'font-encoding 'fetaNumber props)
1509                                            (number->string num)))
1510          (num-x (interval-widen (ly:stencil-extent number-stencil X)
1511                                 (* mag 0.2)))
1512          (num-y (ly:stencil-extent number-stencil Y))
1513          (is-sane (and (interval-sane? num-x) (interval-sane? num-y)))
1514          (slash-stencil (if is-sane
1515                             (ly:make-stencil
1516                              `(draw-line ,thickness
1517                                          ,(car num-x) ,(- (interval-center num-y) dy)
1518                                          ,(cdr num-x) ,(+ (interval-center num-y) dy))
1519                              num-x num-y)
1520                             #f)))
1521     (set! slash-stencil
1522           (cond ((not (ly:stencil? slash-stencil)) #f)
1523                 ((= num 5)
1524                  (ly:stencil-translate slash-stencil
1525                                        ;;(cons (* mag -0.05) (* mag 0.42))
1526                                        (cons (* mag -0.00) (* mag -0.07))))
1527                 ((= num 7)
1528                  (ly:stencil-translate slash-stencil
1529                                        ;;(cons (* mag -0.05) (* mag 0.42))
1530                                        (cons (* mag -0.00) (* mag -0.15))))
1531                 (else slash-stencil)))
1532     (if slash-stencil
1533         (set! number-stencil
1534               (ly:stencil-add number-stencil slash-stencil))
1535         (ly:warning "invalid number for slashed digit ~a" num))
1536     number-stencil))
1537 \f
1538 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1539 ;; the note command.
1540 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1541
1542 ;; TODO: better syntax.
1543
1544 (define-builtin-markup-command (note-by-number layout props log dot-count dir)
1545   (number? number? number?)
1546   music
1547   ((font-size 0)
1548    (style '()))
1549   "
1550 @cindex notes within text by log and dot-count
1551
1552 Construct a note symbol, with stem.  By using fractional values for
1553 @var{dir}, you can obtain longer or shorter stems."
1554
1555   (define (get-glyph-name-candidates dir log style)
1556     (map (lambda (dir-name)
1557      (format "noteheads.~a~a~a" dir-name (min log 2)
1558              (if (and (symbol? style)
1559                       (not (equal? 'default style)))
1560                  (symbol->string style)
1561                  "")))
1562          (list (if (= dir UP) "u" "d")
1563                "s")))
1564                    
1565   (define (get-glyph-name font cands)
1566     (if (null? cands)
1567      ""
1568      (if (ly:stencil-empty? (ly:font-get-glyph font (car cands)))
1569          (get-glyph-name font (cdr cands))
1570          (car cands))))
1571     
1572   (let* ((font (ly:paper-get-font layout (cons '((font-encoding . fetaMusic)) props)))
1573          (size-factor (magstep font-size))
1574          (stem-length (*  size-factor (max 3 (- log 1))))
1575          (head-glyph-name (get-glyph-name font (get-glyph-name-candidates (sign dir) log style)))
1576          (head-glyph (ly:font-get-glyph font head-glyph-name))
1577          (attach-indices (ly:note-head::stem-attachment font head-glyph-name))
1578          (stem-thickness (* size-factor 0.13))
1579          (stemy (* dir stem-length))
1580          (attach-off (cons (interval-index
1581                             (ly:stencil-extent head-glyph X)
1582                             (* (sign dir) (car attach-indices)))
1583                            (* (sign dir)        ; fixme, this is inconsistent between X & Y.
1584                               (interval-index
1585                                (ly:stencil-extent head-glyph Y)
1586                                (cdr attach-indices)))))
1587          (stem-glyph (and (> log 0)
1588                           (ly:round-filled-box
1589                            (ordered-cons (car attach-off)
1590                                          (+ (car attach-off)  (* (- (sign dir)) stem-thickness)))
1591                            (cons (min stemy (cdr attach-off))
1592                                  (max stemy (cdr attach-off)))
1593                            (/ stem-thickness 3))))
1594          
1595          (dot (ly:font-get-glyph font "dots.dot"))
1596          (dotwid (interval-length (ly:stencil-extent dot X)))
1597          (dots (and (> dot-count 0)
1598                     (apply ly:stencil-add
1599                            (map (lambda (x)
1600                                   (ly:stencil-translate-axis
1601                                    dot (* 2 x dotwid) X))
1602                                 (iota dot-count)))))
1603          (flaggl (and (> log 2)
1604                       (ly:stencil-translate
1605                        (ly:font-get-glyph font
1606                                           (string-append "flags."
1607                                                          (if (> dir 0) "u" "d")
1608                                                          (number->string log)))
1609                        (cons (+ (car attach-off) (if (< dir 0) stem-thickness 0)) stemy)))))
1610
1611     ; If there is a flag on an upstem and the stem is short, move the dots to avoid the flag.
1612     ; 16th notes get a special case because their flags hang lower than any other flags.
1613     (if (and dots (> dir 0) (> log 2) (or (< dir 1.15) (and (= log 4) (< dir 1.3))))
1614         (set! dots (ly:stencil-translate-axis dots 0.5 X)))
1615     (if flaggl
1616         (set! stem-glyph (ly:stencil-add flaggl stem-glyph)))
1617     (if (ly:stencil? stem-glyph)
1618         (set! stem-glyph (ly:stencil-add stem-glyph head-glyph))
1619         (set! stem-glyph head-glyph))
1620     (if (ly:stencil? dots)
1621         (set! stem-glyph
1622               (ly:stencil-add
1623                (ly:stencil-translate-axis
1624                 dots
1625                 (+ (cdr (ly:stencil-extent head-glyph X)) dotwid)
1626                 X)
1627                stem-glyph)))
1628     stem-glyph))
1629
1630 (define-public log2 
1631   (let ((divisor (log 2)))
1632     (lambda (z) (inexact->exact (/ (log z) divisor)))))
1633
1634 (define (parse-simple-duration duration-string)
1635   "Parse the `duration-string', e.g. ''4..'' or ''breve.'', and return a (log dots) list."
1636   (let ((match (regexp-exec (make-regexp "(breve|longa|maxima|[0-9]+)(\\.*)") duration-string)))
1637     (if (and match (string=? duration-string (match:substring match 0)))
1638         (let ((len  (match:substring match 1))
1639               (dots (match:substring match 2)))
1640           (list (cond ((string=? len "breve") -1)
1641                       ((string=? len "longa") -2)
1642                       ((string=? len "maxima") -3)
1643                       (else (log2 (string->number len))))
1644                 (if dots (string-length dots) 0)))
1645         (ly:error (_ "not a valid duration string: ~a") duration-string))))
1646
1647 (define-builtin-markup-command (note layout props duration dir)
1648   (string? number?)
1649   music
1650   (note-by-number-markup)
1651   "
1652 @cindex notes within text by string
1653
1654 This produces a note with a stem pointing in @var{dir} direction, with
1655 the @var{duration} for the note head type and augmentation dots.  For
1656 example, @code{\\note #\"4.\" #-0.75} creates a dotted quarter note, with
1657 a shortened down stem."
1658   (let ((parsed (parse-simple-duration duration)))
1659     (note-by-number-markup layout props (car parsed) (cadr parsed) dir)))
1660 \f
1661 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1662 ;; translating.
1663 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1664
1665 (define-builtin-markup-command (lower layout props amount arg)
1666   (number? markup?)
1667   align
1668   ()
1669   "
1670 @cindex lowering text
1671
1672 Lower @var{arg} by the distance @var{amount}.
1673 A negative @var{amount} indicates raising; see also @code{\\raise}."
1674   (ly:stencil-translate-axis (interpret-markup layout props arg)
1675                              (- amount) Y))
1676
1677 (define-builtin-markup-command (translate-scaled layout props offset arg)
1678   (number-pair? markup?)
1679   other
1680   ((font-size 0))
1681   "
1682 @cindex translating text
1683 @cindex scaling text
1684
1685 Translate @var{arg} by @var{offset}, scaling the offset by the
1686 @code{font-size}."
1687   (let* ((factor (magstep font-size))
1688          (scaled (cons (* factor (car offset))
1689                        (* factor (cdr offset)))))
1690     (ly:stencil-translate (interpret-markup layout props arg)
1691                           scaled)))
1692
1693 (define-builtin-markup-command (raise layout props amount arg)
1694   (number? markup?)
1695   align
1696   ()
1697   "
1698 @cindex raising text
1699   
1700 Raise @var{arg} by the distance @var{amount}.
1701 A negative @var{amount} indicates lowering, see also @code{\\lower}.
1702
1703 The argument to @code{\\raise} is the vertical displacement amount,
1704 measured in (global) staff spaces.  @code{\\raise} and @code{\\super}
1705 raise objects in relation to their surrounding markups.
1706
1707 If the text object itself is positioned above or below the staff, then
1708 @code{\\raise} cannot be used to move it, since the mechanism that
1709 positions it next to the staff cancels any shift made with
1710 @code{\\raise}.  For vertical positioning, use the @code{padding}
1711 and/or @code{extra-offset} properties.
1712 @c
1713 @lilypond[verbatim,quote]
1714 \\markup { C \\small \\raise #1.0 \\bold { \"9/7+\" } }
1715 @end lilypond"
1716   (ly:stencil-translate-axis (interpret-markup layout props arg) amount Y))
1717
1718 (define-builtin-markup-command (fraction layout props arg1 arg2)
1719   (markup? markup?)
1720   other
1721   ((font-size 0))
1722   "
1723 @cindex creating text fractions
1724
1725 Make a fraction of two markups."
1726   (let* ((m1 (interpret-markup layout props arg1))
1727          (m2 (interpret-markup layout props arg2))
1728          (factor (magstep font-size))
1729          (boxdimen (cons (* factor -0.05) (* factor 0.05)))
1730          (padding (* factor 0.2))
1731          (baseline (* factor 0.6))
1732          (offset (* factor 0.75)))
1733     (set! m1 (ly:stencil-aligned-to m1 X CENTER))
1734     (set! m2 (ly:stencil-aligned-to m2 X CENTER))
1735     (let* ((x1 (ly:stencil-extent m1 X))
1736            (x2 (ly:stencil-extent m2 X))
1737            (line (ly:round-filled-box (interval-union x1 x2) boxdimen 0.0))
1738            ;; should stack mols separately, to maintain LINE on baseline
1739            (stack (stack-lines DOWN padding baseline (list m1 line m2))))
1740       (set! stack
1741             (ly:stencil-aligned-to stack Y CENTER))
1742       (set! stack
1743             (ly:stencil-aligned-to stack X LEFT))
1744       ;; should have EX dimension
1745       ;; empirical anyway
1746       (ly:stencil-translate-axis stack offset Y))))
1747
1748 (define-builtin-markup-command (normal-size-super layout props arg)
1749   (markup?)
1750   font
1751   ((baseline-skip))
1752   "
1753 @cindex setting superscript in standard font size
1754
1755 Set @var{arg} in superscript with a normal font size."
1756   (ly:stencil-translate-axis
1757    (interpret-markup layout props arg)
1758    (* 0.5 baseline-skip) Y))
1759
1760 (define-builtin-markup-command (super layout props arg)
1761   (markup?)
1762   font
1763   ((font-size 0)
1764    (baseline-skip))
1765   "  
1766 @cindex superscript text
1767
1768 Raising and lowering texts can be done with @code{\\super} and
1769 @code{\\sub}:
1770 @c
1771 @lilypond[verbatim,quote]
1772 \\markup { E \"=\" \\concat { \"mc\" \\super \"2\" } }
1773 @end lilypond"
1774   (ly:stencil-translate-axis
1775    (interpret-markup
1776     layout
1777     (cons `((font-size . ,(- font-size 3))) props)
1778     arg)
1779    (* 0.5 baseline-skip)
1780    Y))
1781
1782 (define-builtin-markup-command (translate layout props offset arg)
1783   (number-pair? markup?)
1784   align
1785   ()
1786   "
1787 @cindex translating text
1788   
1789 This translates an object.  Its first argument is a cons of numbers.
1790
1791 @example
1792 A \\translate #(cons 2 -3) @{ B C @} D
1793 @end example
1794
1795 This moves @q{B C} 2@tie{}spaces to the right, and 3 down, relative to its
1796 surroundings.  This command cannot be used to move isolated scripts
1797 vertically, for the same reason that @code{\\raise} cannot be used for
1798 that."
1799   (ly:stencil-translate (interpret-markup  layout props arg)
1800                         offset))
1801
1802 (define-builtin-markup-command (sub layout props arg)
1803   (markup?)
1804   font
1805   ((font-size 0)
1806    (baseline-skip))
1807   "
1808 @cindex subscript text
1809
1810 Set @var{arg} in subscript."
1811   (ly:stencil-translate-axis
1812    (interpret-markup
1813     layout
1814     (cons `((font-size . ,(- font-size 3))) props)
1815     arg)
1816    (* -0.5 baseline-skip)
1817    Y))
1818
1819 (define-builtin-markup-command (normal-size-sub layout props arg)
1820   (markup?)
1821   font
1822   ((baseline-skip))
1823   "
1824 @cindex setting subscript in standard font size
1825
1826 Set @var{arg} in subscript, in a normal font size."
1827   (ly:stencil-translate-axis
1828    (interpret-markup layout props arg)
1829    (* -0.5 baseline-skip)
1830    Y))
1831 \f
1832 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1833 ;; brackets.
1834 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1835
1836 (define-builtin-markup-command (hbracket layout props arg)
1837   (markup?)
1838   graphic
1839   ()
1840   "
1841 @cindex placing horizontal brackets around text
1842   
1843 Draw horizontal brackets around @var{arg}."  
1844   (let ((th 0.1) ;; todo: take from GROB.
1845         (m (interpret-markup layout props arg)))
1846     (bracketify-stencil m X th (* 2.5 th) th)))
1847
1848 (define-builtin-markup-command (bracket layout props arg)
1849   (markup?)
1850   graphic
1851   ()
1852   "
1853 @cindex placing vertical brackets around text
1854   
1855 Draw vertical brackets around @var{arg}."  
1856   (let ((th 0.1) ;; todo: take from GROB.
1857         (m (interpret-markup layout props arg)))
1858     (bracketify-stencil m Y th (* 2.5 th) th)))
1859 \f
1860 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1861 ;; Delayed markup evaluation
1862 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1863
1864 (define-builtin-markup-command (page-ref layout props label gauge default)
1865   (symbol? markup? markup?)
1866   other
1867   ()
1868   "
1869 @cindex referencing page numbers in text
1870
1871 Reference to a page number. @var{label} is the label set on the referenced
1872 page (using the @code{\\label} command), @var{gauge} a markup used to estimate
1873 the maximum width of the page number, and @var{default} the value to display
1874 when @var{label} is not found."
1875   (let* ((gauge-stencil (interpret-markup layout props gauge))
1876          (x-ext (ly:stencil-extent gauge-stencil X))
1877          (y-ext (ly:stencil-extent gauge-stencil Y)))
1878     (ly:make-stencil
1879      `(delay-stencil-evaluation
1880        ,(delay (ly:stencil-expr
1881                 (let* ((table (ly:output-def-lookup layout 'label-page-table))
1882                        (label-page (and (list? table) (assoc label table)))
1883                        (page-number (and label-page (cdr label-page)))
1884                        (page-markup (if page-number (format "~a" page-number) default))
1885                        (page-stencil (interpret-markup layout props page-markup))
1886                        (gap (- (interval-length x-ext)
1887                                (interval-length (ly:stencil-extent page-stencil X)))))
1888                   (interpret-markup layout props
1889                                     (markup #:concat (#:hspace gap page-markup)))))))
1890      x-ext
1891      y-ext)))
1892 \f
1893 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1894 ;; Markup list commands
1895 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1896
1897 (define-public (space-lines baseline-skip lines)
1898   (map (lambda (line)
1899          (stack-lines DOWN 0.0 (/ baseline-skip 2.0)
1900                       (list point-stencil
1901                             line
1902                             point-stencil)))
1903        lines))
1904
1905 (define-builtin-markup-list-command (justified-lines layout props args)
1906   (markup-list?)
1907   ((baseline-skip)
1908    wordwrap-internal-markup-list)
1909   "
1910 @cindex justifying lines of text
1911
1912 Like @code{\\justify}, but return a list of lines instead of a single markup.
1913 Use @code{\\override-lines #'(line-width . @var{X})} to set the line width;
1914 @var{X}@tie{}is the number of staff spaces."
1915   (space-lines baseline-skip
1916                (interpret-markup-list layout props
1917                                       (make-wordwrap-internal-markup-list #t args))))
1918
1919 (define-builtin-markup-list-command (wordwrap-lines layout props args)
1920   (markup-list?)
1921   ((baseline-skip)
1922    wordwrap-internal-markup-list)
1923   "Like @code{\\wordwrap}, but return a list of lines instead of a single markup.
1924 Use @code{\\override-lines #'(line-width . @var{X})} to set the line width,
1925 where @var{X} is the number of staff spaces."
1926   (space-lines baseline-skip
1927                (interpret-markup-list layout props
1928                                       (make-wordwrap-internal-markup-list #f args))))
1929
1930 (define-builtin-markup-list-command (column-lines layout props args)
1931   (markup-list?)
1932   ((baseline-skip))
1933   "Like @code{\\column}, but return a list of lines instead of a single markup.
1934 @code{baseline-skip} determines the space between each markup in @var{args}."
1935   (space-lines (chain-assoc-get 'baseline-skip props)
1936                (interpret-markup-list layout props args)))
1937
1938 (define-builtin-markup-list-command (override-lines layout props new-prop args)
1939   (pair? markup-list?)
1940   ()
1941   "Like @code{\\override}, for markup lists."
1942   (interpret-markup-list layout (cons (list new-prop) props) args))