]> git.donarmstrong.com Git - lilypond.git/blob - scm/define-markup-commands.scm
*** empty log message ***
[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--2004  Han-Wen Nienhuys <hanwen@cs.uu.nl>
6 ;;;;                  Jan Nieuwenhuizen <janneke@gnu.org>
7
8 ;;; markup commands
9 ;;; TODO:
10 ;;;  * each markup function should have a doc string with
11 ;;     syntax, description and example. 
12
13 (define-public empty-stencil (ly:make-stencil '() '(1 . -1) '(1 . -1)))
14 (define-public point-stencil (ly:make-stencil "" '(0 . 0) '(0 . 0)))
15
16 (def-markup-command (stencil layout props stil) (ly:stencil?)
17   "Stencil as markup"
18   stil)
19
20 (def-markup-command (score layout props score) (ly:score?)
21   "Inline an image of music."
22   (let* ((systems (ly:score-embedded-format score layout)))
23
24     (if (= 0 (vector-length systems))
25         (begin
26           (ly:warn "No systems found in \\score markup. Did you forget \\layout?")
27           empty-markup)
28         (begin
29           (let* ((stencil (ly:paper-system-stencil (vector-ref systems 0)))) 
30
31             (ly:stencil-align-to! stencil Y CENTER)
32             stencil)))))
33
34 (def-markup-command (simple layout props str) (string?)
35   "A simple text string; @code{\\markup @{ foo @}} is equivalent with
36 @code{\\markup @{ \\simple #\"foo\" @}}."
37   (interpret-markup layout props str))
38
39 (def-markup-command (encoded-simple layout props sym str) (symbol? string?)
40   "A text string, encoded with encoding @var{sym}. See
41 @usermanref{Text encoding} for more information."
42   (Text_interface::interpret_string layout
43                                     props sym str))
44
45
46 ;; TODO: use font recoding.
47 ;;                    (make-line-markup
48 ;;                     (map make-word-markup (string-tokenize str)))))
49
50 (define-public empty-markup
51   (make-simple-markup ""))
52
53
54 (def-markup-command (postscript layout props str) (string?)
55
56   "This inserts @var{str} directly into the output as a PostScript
57 command string.  Due to technicalities of the output backends,
58 different scales should be used for the @TeX{} and PostScript backend,
59 selected with @code{-f}. 
60
61
62 For the TeX backend, the following string prints a rotated text
63
64 @cindex rotated text
65
66 @verbatim
67 0 0 moveto /ecrm10 findfont 
68 1.75 scalefont setfont 90 rotate (hello) show
69 @end verbatim
70
71 @noindent
72 The magical constant 1.75 scales from LilyPond units (staff spaces) to
73 TeX dimensions.
74
75 For the postscript backend, use the following
76
77 @verbatim
78 gsave /ecrm10 findfont 
79  10.0 output-scale div 
80  scalefont setfont 90 rotate (hello) show grestore 
81 @end verbatim
82 "
83   ;; FIXME
84   
85   (ly:make-stencil
86    (list 'embedded-ps str)
87    '(0 . 0) '(0 . 0)))
88
89 ;;(def-markup-command (fill-line layout props line-width markups)
90 ;;  (number? markup-list?)
91 ;; no parser tag -- should make number? markuk-list? thingy
92 (def-markup-command (fill-line layout props markups)
93   (markup-list?)
94   "Put @var{markups} in a horizontal line of width @var{line-width}.
95    The markups are spaced/flushed to fill the entire line.
96    If there are no arguments, return an empty stencil.
97 "
98
99   (let* ((orig-stencils
100           (map (lambda (x) (interpret-markup layout props x))
101                markups))
102          (stencils
103           (map (lambda (stc)
104                  (if (ly:stencil-empty? stc)
105                      point-stencil
106                      stc)) orig-stencils))
107          (text-width (apply +
108                             (map (lambda (stc)
109                                    (if (ly:stencil-empty? stc)
110                                        0.0
111                                        (interval-length (ly:stencil-extent stc X))))
112                                  stencils)))
113          (word-count (length stencils))
114          (word-space (chain-assoc-get 'word-space props))
115          (line-width (chain-assoc-get 'linewidth props))
116          (fill-space (if (< line-width text-width)
117                          word-space
118                          (/ (- line-width text-width)
119                             (if (= word-count 1) 2 (- word-count 1)))))
120          (line-stencils (if (= word-count 1)
121                             (list
122                              point-stencil
123                              (car stencils)
124                              point-stencil)
125                             stencils)))
126
127     (if (null? (remove ly:stencil-empty? orig-stencils))
128         empty-stencil
129         (stack-stencils X RIGHT fill-space line-stencils))))
130
131 (define (font-markup qualifier value)
132   (lambda (layout props arg)
133     (interpret-markup layout
134                       (prepend-alist-chain qualifier value props)
135                       arg)))
136
137
138 (def-markup-command (line layout props args) (markup-list?)
139   "Put @var{args} in a horizontal line.  The property @code{word-space}
140 determines the space between each markup in @var{args}."
141   (stack-stencil-line
142    (chain-assoc-get 'word-space props)
143    (map (lambda (m) (interpret-markup layout props m)) args)))
144
145 (def-markup-command (fromproperty layout props symbol) (symbol?)
146   "Read the @var{symbol} from property settings, and produce a stencil from the markup contained within. If @var{symbol} is not defined, it returns an empty markup"
147   (let* ((m (chain-assoc-get symbol props)))
148
149     (if (markup? m)
150         (interpret-markup layout props m)
151         (ly:make-stencil '()  '(1 . -1) '(1 . -1)))))
152
153
154 (def-markup-command (on-the-fly layout props procedure arg) (symbol? markup?)
155   "Apply the @var{procedure} markup command to
156 @var{arg}. @var{procedure} should take a single argument."
157   (let* ((anonymous-with-signature (lambda (layout props arg) (procedure layout props arg))))
158
159     (set-object-property! anonymous-with-signature
160                           'markup-signature
161                           (list markup?))
162     
163     (interpret-markup layout props (list anonymous-with-signature arg))))
164
165
166 (def-markup-command (combine layout props m1 m2) (markup? markup?)
167   "Print two markups on top of each other."
168   (let* ((s1 (interpret-markup layout props m1))
169          (s2 (interpret-markup layout props m2)))
170     
171     (ly:stencil-add s1 s2)))
172
173 (def-markup-command (finger layout props arg) (markup?)
174   "Set the argument as small numbers."
175   (interpret-markup layout
176                     (cons '((font-size . -5) (font-encoding . fetaNumber)) props)
177                     arg))
178
179 (def-markup-command (fontsize layout props mag arg) (number? markup?)
180   "This sets the relative font size, e.g.
181 @example
182 A \\fontsize #2 @{ B C @} D
183 @end example
184
185
186 This will enlarge the B and the C by two steps.
187 "
188   (interpret-markup
189    layout 
190    (prepend-alist-chain 'font-size mag props)
191    arg))
192
193 (def-markup-command (magnify layout props sz arg) (number? markup?)
194   "This sets the font magnification for the its argument. In the following
195 example, the middle A will be 10% larger:
196 @example
197 A \\magnify #1.1 @{ A @} A
198 @end example
199
200 Note: magnification only works if a font-name is explicitly selected.
201 Use @code{\\fontsize} otherwise."
202
203   (interpret-markup
204    layout 
205    (prepend-alist-chain 'font-magnification sz props)
206    arg))
207
208 (def-markup-command (bold layout props arg) (markup?)
209   "Switch to bold font-series"
210   (interpret-markup layout (prepend-alist-chain 'font-series 'bold props) arg))
211
212 (def-markup-command (sans layout props arg) (markup?)
213   "Switch to the sans serif family"
214   (interpret-markup layout (prepend-alist-chain 'font-family 'sans props) arg))
215
216 (def-markup-command (number layout props arg) (markup?)
217   "Set font family to @code{number}, which yields the font used for
218 time signatures and fingerings.  This font only contains numbers and
219 some punctuation. It doesn't have any letters.  "
220   (interpret-markup layout (prepend-alist-chain 'font-encoding 'fetaNumber props) arg))
221
222 (def-markup-command (roman layout props arg) (markup?)
223   "Set font family to @code{roman}."
224   (interpret-markup layout (prepend-alist-chain 'font-family 'roman props) arg))
225
226 (def-markup-command (huge layout props arg) (markup?)
227   "Set font size to +2."
228   (interpret-markup layout (prepend-alist-chain 'font-size 2 props) arg))
229
230 (def-markup-command (large layout props arg) (markup?)
231   "Set font size to +1."
232   (interpret-markup layout (prepend-alist-chain 'font-size 1 props) arg))
233
234 (def-markup-command (normalsize layout props arg) (markup?)
235   "Set font size to default."
236   (interpret-markup layout (prepend-alist-chain 'font-size 0 props) arg))
237
238 (def-markup-command (small layout props arg) (markup?)
239   "Set font size to -1."
240   (interpret-markup layout (prepend-alist-chain 'font-size -1 props) arg))
241
242 (def-markup-command (tiny layout props arg) (markup?)
243   "Set font size to -2."
244   (interpret-markup layout (prepend-alist-chain 'font-size -2 props) arg))
245
246 (def-markup-command (teeny layout props arg) (markup?)
247   "Set font size to -3."
248   (interpret-markup layout (prepend-alist-chain 'font-size -3 props) arg))
249
250 (def-markup-command (caps layout props arg) (markup?)
251   "Set @code{font-shape} to @code{caps}."
252   (interpret-markup layout (prepend-alist-chain 'font-shape 'caps props) arg))
253
254                                         ;(def-markup-command (latin-i layout props arg) (markup?)
255                                         ;  "TEST latin1 encoding."
256                                         ;  (interpret-markup layout (prepend-alist-chain 'font-shape 'latin1 props) arg))
257
258 (def-markup-command (dynamic layout props arg) (markup?)
259   "Use the dynamic font.  This font only contains @b{s}, @b{f}, @b{m},
260 @b{z}, @b{p}, and @b{r}.  When producing phrases, like ``pi@`{u} @b{f}'', the
261 normal words (like ``pi@`{u}'') should be done in a different font.  The
262 recommend font for this is bold and italic"
263   (interpret-markup
264    layout (prepend-alist-chain 'font-encoding 'fetaDynamic props) arg))
265
266 (def-markup-command (italic layout props arg) (markup?)
267   "Use italic @code{font-shape} for @var{arg}. "
268   (interpret-markup layout (prepend-alist-chain 'font-shape 'italic props) arg))
269
270 (def-markup-command (typewriter layout props arg) (markup?)
271   "Use @code{font-family} typewriter for @var{arg}."
272   (interpret-markup
273    layout (prepend-alist-chain 'font-family 'typewriter props) arg))
274
275 (def-markup-command (upright layout props arg) (markup?)
276   "Set font shape to @code{upright}."
277   (interpret-markup
278    layout (prepend-alist-chain 'font-shape 'upright props) arg))
279
280 (def-markup-command (doublesharp layout props) ()
281   "Draw a double sharp symbol."
282
283   (interpret-markup layout props (markup #:musicglyph "accidentals.4")))
284 (def-markup-command (sesquisharp layout props) ()
285   "Draw a 3/2 sharp symbol."
286   (interpret-markup layout props (markup #:musicglyph "accidentals.3")))
287
288 (def-markup-command (sharp layout props) ()
289   "Draw a sharp symbol."
290   (interpret-markup layout props (markup #:musicglyph "accidentals.2")))
291 (def-markup-command (semisharp layout props) ()
292   "Draw a semi sharp symbol."
293   (interpret-markup layout props (markup #:musicglyph "accidentals.1")))
294 (def-markup-command (natural layout props) ()
295   "Draw a natural symbol."
296
297   (interpret-markup layout props (markup #:musicglyph "accidentals.0")))
298 (def-markup-command (semiflat layout props) ()
299   "Draw a semiflat."
300   (interpret-markup layout props (markup #:musicglyph "accidentals.M1")))
301 (def-markup-command (flat layout props) ()
302   "Draw a flat symbol."
303   
304   (interpret-markup layout props (markup #:musicglyph "accidentals.M2")))
305 (def-markup-command (sesquiflat layout props) ()
306   "Draw a 3/2 flat symbol."
307   
308   (interpret-markup layout props (markup #:musicglyph "accidentals.M3")))
309 (def-markup-command (doubleflat layout props) ()
310   "Draw a double flat symbol."
311
312   (interpret-markup layout props (markup #:musicglyph "accidentals.M4")))
313
314
315 (def-markup-command (column layout props args) (markup-list?)
316   "Stack the markups in @var{args} vertically.  The property
317 @code{baseline-skip} determines the space between each markup in @var{args}."
318   (stack-lines
319    -1 0.0 (chain-assoc-get 'baseline-skip props)
320    (remove ly:stencil-empty?
321            (map (lambda (m) (interpret-markup layout props m)) args))))
322
323 (def-markup-command (dir-column layout props args) (markup-list?)
324   "Make a column of args, going up or down, depending on the setting
325 of the @code{#'direction} layout property."
326   (let* ((dir (chain-assoc-get 'direction props)))
327     (stack-lines
328      (if (number? dir) dir -1)
329      0.0
330      (chain-assoc-get 'baseline-skip props)
331      (map (lambda (x) (interpret-markup layout props x)) args))))
332
333 (def-markup-command (center-align layout props args) (markup-list?)
334   "Put @code{args} in a centered column. "
335   (let* ((mols (map (lambda (x) (interpret-markup layout props x)) args))
336          (cmols (map (lambda (x) (ly:stencil-align-to! x X CENTER)) mols)))
337     (stack-lines -1 0.0 (chain-assoc-get 'baseline-skip props) cmols)))
338
339 (def-markup-command (vcenter layout props arg) (markup?)
340   "Align @code{arg} to its center. "
341   (let* ((mol (interpret-markup layout props arg)))
342     (ly:stencil-align-to! mol Y CENTER)
343     mol))
344
345 (def-markup-command (right-align layout props arg) (markup?)
346   (let* ((m (interpret-markup layout props arg)))
347     (ly:stencil-align-to! m X RIGHT)
348     m))
349
350 (def-markup-command (left-align layout props arg) (markup?)
351   "Align @var{arg} on its left edge. "
352   
353   (let* ((m (interpret-markup layout props arg)))
354     (ly:stencil-align-to! m X LEFT)
355     m))
356
357 (def-markup-command (general-align layout props axis dir arg)  (integer? number? markup?)
358   "Align @var{arg} in @var{axis} direction to the @var{dir} side."
359   (let* ((m (interpret-markup layout props arg)))
360
361     (ly:stencil-align-to! m axis dir)
362     m))
363
364 (def-markup-command (halign layout props dir arg) (number? markup?)
365   "Set horizontal alignment. If @var{dir} is @code{-1}, then it is
366 left-aligned, while @code{+1} is right. Values in between interpolate
367 alignment accordingly."
368
369   
370   (let* ((m (interpret-markup layout props arg)))
371     (ly:stencil-align-to! m X dir)
372     m))
373
374 (def-markup-command (musicglyph layout props glyph-name) (string?)
375   "This is converted to a musical symbol, e.g. @code{\\musicglyph
376 #\"accidentals-0\"} will select the natural sign from the music font.
377 See @usermanref{The Feta font} for  a complete listing of the possible glyphs.
378 "
379   (ly:font-get-glyph
380    (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
381                                    props))
382    glyph-name))
383
384
385 (def-markup-command (lookup layout props glyph-name) (string?)
386   "Lookup a glyph by name."
387   (ly:font-get-glyph (ly:paper-get-font layout props)
388                      glyph-name))
389
390 (def-markup-command (char layout props num) (integer?)
391   "Produce a single character, e.g. @code{\\char #65} produces the 
392 letter 'A'."
393   (ly:get-glyph (ly:paper-get-font layout props) num))
394
395 (def-markup-command (raise layout props amount arg) (number? markup?)
396   "
397 This  raises  @var{arg}, by the distance @var{amount}.
398 A negative @var{amount} indicates lowering:
399 @c
400 @lilypond[verbatim,fragment,relative=1]
401  c1^\\markup { C \\small \\raise #1.0 \\bold { \"9/7+\" }}
402 @end lilypond
403 The argument to @code{\\raise} is the vertical displacement amount,
404 measured in (global) staff spaces.  @code{\\raise} and @code{\\super}
405 raise objects in relation to their surrounding markups.
406
407 If the text object itself is positioned above or below the staff, then
408 @code{\\raise} cannot be used to move it, since the mechanism that
409 positions it next to the staff cancels any shift made with
410 @code{\\raise}. For vertical positioning, use the @code{padding}
411 and/or @code{extra-offset} properties. "
412
413   
414   (ly:stencil-translate-axis (interpret-markup layout props arg)
415                              amount Y))
416
417 (def-markup-command (fraction layout props arg1 arg2) (markup? markup?)
418   "Make a fraction of two markups."
419   
420   (let* ((m1 (interpret-markup layout props arg1))
421          (m2 (interpret-markup layout props arg2)))
422     (ly:stencil-align-to! m1 X CENTER)
423     (ly:stencil-align-to! m2 X CENTER)    
424     (let* ((x1 (ly:stencil-extent m1 X))
425            (x2 (ly:stencil-extent m2 X))
426            (line (ly:round-filled-box (interval-union x1 x2) '(-0.05 . 0.05) 0.0))
427            ;; should stack mols separately, to maintain LINE on baseline
428            (stack (stack-lines -1 0.2 0.6 (list m1 line m2))))
429       (ly:stencil-align-to! stack Y CENTER)
430       (ly:stencil-align-to! stack X LEFT)
431       ;; should have EX dimension
432       ;; empirical anyway
433       (ly:stencil-translate-axis stack 0.75 Y))))
434
435
436 ;; TODO: better syntax.
437
438 (def-markup-command (note-by-number layout props log dot-count dir) (number? number? number?)
439   "Construct a note symbol, with stem.  By using fractional values for
440 @var{dir}, you can obtain longer or shorter stems."
441   
442   (let* ((font (ly:paper-get-font layout (cons '((font-encoding . fetaMusic)) props)))
443          (size (chain-assoc-get 'font-size props 0))
444          (stem-length (* (magstep size) (max 3 (- log 1))))
445          (head-glyph (ly:font-get-glyph
446                       font
447                       (string-append "noteheads.s" (number->string (min log 2)))))
448          (stem-thickness 0.13)
449          (stemy (* dir stem-length))
450          (attachx (if (> dir 0)
451                       (- (cdr (ly:stencil-extent head-glyph X)) stem-thickness)
452                       0))
453          (attachy (* dir 0.28))
454          (stem-glyph (and (> log 0)
455                           (ly:round-filled-box
456                            (cons attachx (+ attachx  stem-thickness))
457                            (cons (min stemy attachy)
458                                  (max stemy attachy))
459                            (/ stem-thickness 3))))
460          (dot (ly:font-get-glyph font "dots-dot"))
461          (dotwid (interval-length (ly:stencil-extent dot X)))
462          (dots (and (> dot-count 0)
463                     (apply ly:stencil-add
464                            (map (lambda (x)
465                                   (ly:stencil-translate-axis
466                                    dot  (* (+ 1 (* 2 x)) dotwid) X))
467                                 (iota dot-count 1)))))
468          (flaggl (and (> log 2)
469                       (ly:stencil-translate
470                        (ly:font-get-glyph font
471                                           (string-append "flags."
472                                                          (if (> dir 0) "u" "d")
473                                                          (number->string log)))
474                        (cons (+ attachx (/ stem-thickness 2)) stemy)))))
475     (if flaggl
476         (set! stem-glyph (ly:stencil-add flaggl stem-glyph)))
477     (if (ly:stencil? stem-glyph)
478         (set! stem-glyph (ly:stencil-add stem-glyph head-glyph))
479         (set! stem-glyph head-glyph))
480     (if (ly:stencil? dots)
481         (set! stem-glyph
482               (ly:stencil-add
483                (ly:stencil-translate-axis dots
484                                           (+ (if (and (> dir 0) (> log 2))
485                                                  (* 1.5 dotwid)
486                                                  0)
487                                              ;; huh ? why not necessary?
488                                              ;;(cdr (ly:stencil-extent head-glyph X))
489                                              dotwid)
490                                           X)
491                stem-glyph)))
492     stem-glyph))
493
494 (use-modules (ice-9 regex))
495
496 (define-public log2 
497   (let ((divisor (log 2)))
498     (lambda (z) (inexact->exact (/ (log z) divisor)))))
499
500 (define (parse-simple-duration duration-string)
501   "Parse the `duration-string', e.g. ''4..'' or ''breve.'', and return a (log dots) list."
502   (let ((match (regexp-exec (make-regexp "(breve|longa|maxima|[0-9]+)(\\.*)") duration-string)))
503     (if (and match (string=? duration-string (match:substring match 0)))
504         (let ((len  (match:substring match 1))
505               (dots (match:substring match 2)))
506           (list (cond ((string=? len "breve")  -1)
507                       ((string=? len "longa")  -2)
508                       ((string=? len "maxima") -3)
509                       (else (log2 (string->number len))))
510                 (if dots (string-length dots) 0)))
511         (error "This is not a valid duration string:" duration-string))))
512
513 (def-markup-command (note layout props duration dir) (string? number?)
514   "This produces a note with a stem pointing in @var{dir} direction, with
515 the @var{duration} for the note head type and augmentation dots. For
516 example, @code{\\note #\"4.\" #-0.75} creates a dotted quarter note, with
517 a shortened down stem."
518   
519   (let ((parsed (parse-simple-duration duration)))
520     (note-by-number-markup layout props (car parsed) (cadr parsed) dir)))
521
522 (def-markup-command (normal-size-super layout props arg) (markup?)
523   "Set @var{arg} in superscript with a normal font size."
524   
525   (ly:stencil-translate-axis (interpret-markup
526                               layout
527                               props arg)
528                              (* 0.5  (chain-assoc-get 'baseline-skip props))
529                              Y))
530
531 (def-markup-command (super layout props arg) (markup?)
532   "
533 @cindex raising text
534 @cindex lowering text
535 @cindex moving text
536 @cindex translating text
537
538 @cindex @code{\\super}
539
540
541 Raising and lowering texts can be done with @code{\\super} and
542 @code{\\sub}:
543
544 @lilypond[verbatim,fragment,relative=1]
545  c1^\\markup { E \"=\" mc \\super \"2\" }
546 @end lilypond
547
548 "
549   
550   (ly:stencil-translate-axis
551    (interpret-markup
552     layout
553     (cons `((font-size . ,(- (chain-assoc-get 'font-size props 0) 3))) props)
554     arg)
555    (* 0.5 (chain-assoc-get 'baseline-skip props))
556    Y))
557
558 (def-markup-command (translate layout props offset arg) (number-pair? markup?)
559   "This translates an object. Its first argument is a cons of numbers
560 @example
561 A \\translate #(cons 2 -3) @{ B C @} D
562 @end example
563 This moves `B C' 2 spaces to the right, and 3 down, relative to its
564 surroundings. This command cannot be used to move isolated scripts
565 vertically, for the same reason that @code{\\raise} cannot be used for
566 that.
567
568 "
569   
570   (ly:stencil-translate (interpret-markup  layout props arg)
571                         offset))
572
573 (def-markup-command (sub layout props arg) (markup?)
574   "Set @var{arg} in subscript."
575   
576   (ly:stencil-translate-axis
577    (interpret-markup
578     layout
579     (cons `((font-size . ,(- (chain-assoc-get 'font-size props 0) 3))) props)
580     arg)
581    (* -0.5 (chain-assoc-get 'baseline-skip props))
582    Y))
583
584 (def-markup-command (normal-size-sub layout props arg) (markup?)
585   "Set @var{arg} in subscript, in a normal font size."
586
587   (ly:stencil-translate-axis
588    (interpret-markup layout props arg)
589    (* -0.5 (chain-assoc-get 'baseline-skip props))
590    Y))
591
592 (def-markup-command (hbracket layout props arg) (markup?)
593   "Draw horizontal brackets around @var{arg}."  
594   (let ((th 0.1) ;; todo: take from GROB.
595         (m (interpret-markup layout props arg)))
596     (bracketify-stencil m X th (* 2.5 th) th)))
597
598 (def-markup-command (bracket layout props arg) (markup?)
599   "Draw vertical brackets around @var{arg}."  
600   (let ((th 0.1) ;; todo: take from GROB.
601         (m (interpret-markup layout props arg)))
602     (bracketify-stencil m Y th (* 2.5 th) th)))
603
604 ;; todo: fix negative space
605 (def-markup-command (hspace layout props amount) (number?)
606   "This produces a invisible object taking horizontal space.
607 @example 
608 \\markup @{ A \\hspace #2.0 B @} 
609 @end example
610 will put extra space between A and B, on top of the space that is
611 normally inserted before elements on a line.
612 "
613   (if (> amount 0)
614       (ly:make-stencil "" (cons 0 amount) '(-1 . 1))
615       (ly:make-stencil "" (cons amount amount) '(-1 . 1))))
616
617 (def-markup-command (override layout props new-prop arg) (pair? markup?)
618   "Add the first argument in to the property list.  Properties may be
619 any sort of property supported by @internalsref{font-interface} and
620 @internalsref{text-interface}, for example
621
622 @verbatim
623 \\override #'(font-family . married) \"bla\"
624 @end verbatim
625
626 "
627   (interpret-markup layout (cons (list new-prop) props) arg))
628
629 (def-markup-command (smaller layout props arg) (markup?)
630   "Decrease the font size relative to current setting"
631   (let* ((fs (chain-assoc-get 'font-size props 0))
632          (entry (cons 'font-size (- fs 1))))
633     (interpret-markup layout (cons (list entry) props) arg)))
634
635
636 (def-markup-command (bigger layout props arg) (markup?)
637   "Increase the font size relative to current setting"
638   (let* ((fs (chain-assoc-get 'font-size props 0))
639          (entry (cons 'font-size (+ fs 1))))
640     (interpret-markup layout (cons (list entry) props) arg)))
641
642 (def-markup-command larger (markup?)
643   bigger-markup)
644
645 (def-markup-command (box layout props arg) (markup?)
646   "Draw a box round @var{arg}.  Looks at @code{thickness} and
647 @code{box-padding} properties to determine line thickness and padding
648 around the markup."
649   (let ((th (chain-assoc-get 'thickness props  0.1))
650         (pad (chain-assoc-get 'box-padding props 0.2))
651         (m (interpret-markup layout props arg)))
652     (box-stencil m th pad)))
653
654 ;;FIXME: is this working? 
655 (def-markup-command (strut layout props) ()
656   
657   "Create a box of the same height as the space in the current font."
658   
659   (let ((m (Text_interface::interpret_markup layout props " ")))
660     (ly:stencil-set-extent! m X '(1000 . -1000))
661     m))
662
663 (define number->mark-letter-vector (make-vector 25 #\A))
664
665 (do ((i 0 (1+ i))
666      (j 0 (1+ j)))
667     ((>= i 26))
668   (if (= i (- (char->integer #\I) (char->integer #\A)))
669       (set! i (1+ i)))
670   (vector-set! number->mark-letter-vector j
671                (integer->char (+ i (char->integer #\A)))))
672
673 (define number->mark-alphabet-vector (list->vector
674   (map (lambda (i) (integer->char (+ i (char->integer #\A)))) (iota 26))))
675
676 (define (number->markletter-string vec n)
677   "Double letters for big marks."
678   (let* ((lst (vector-length vec)))
679     
680     (if (>= n lst)
681         (string-append (number->markletter-string vec (1- (quotient n lst)))
682                        (number->markletter-string vec (remainder n lst)))
683         (make-string 1 (vector-ref vec n)))))
684
685 (def-markup-command (markletter layout props num) (integer?)
686   "Make a markup letter for @var{num}.  The letters start with A to Z
687  (skipping I), and continues with double letters."
688   
689   (Text_interface::interpret_markup layout props
690     (number->markletter-string number->mark-letter-vector num)))
691
692 (def-markup-command (markalphabet layout props num) (integer?)
693    "Make a markup letter for @var{num}.  The letters start with A to Z
694  and continues with double letters."
695    (Text_interface::interpret_markup layout props
696      (number->markletter-string number->mark-alphabet-vector num)))
697
698 (def-markup-command (bracketed-y-column layout props indices args)
699   (list? markup-list?)
700   "Make a column of the markups in @var{args}, putting brackets around
701 the elements marked in @var{indices}, which is a list of numbers."
702
703   (define (sublist lst start stop)
704     (take (drop lst start) (- (1+ stop) start)))
705
706   (define (stencil-list-extent ss axis)
707     (cons
708      (apply min (map (lambda (x) (car (ly:stencil-extent x axis))) ss))
709      (apply max (map (lambda (x) (cdr (ly:stencil-extent x axis))) ss))))
710   
711   (define (stack-stencils stencils bskip last-stencil)
712     (cond
713      ((null? stencils) '())
714      ((not last-stencil)
715       (cons (car stencils)
716             (stack-stencils (cdr stencils) bskip (car stencils))))
717      (else
718       (let* ((orig (car stencils))
719              (dir (chain-assoc-get 'direction  props DOWN))
720              (new (ly:stencil-moved-to-edge last-stencil Y dir
721                                             orig
722                                             0.1 bskip)))
723
724         (cons new (stack-stencils (cdr stencils) bskip new))))))
725
726   (define (make-brackets stencils indices acc)
727     (if (and stencils
728              (pair? indices)
729              (pair? (cdr indices)))
730         (let* ((encl (sublist stencils (car indices) (cadr indices)))
731                (x-ext (stencil-list-extent encl X))
732                (y-ext (stencil-list-extent encl Y))
733                (thick 0.10)
734                (pad 0.35)
735                (protusion (* 2.5 thick))
736                (lb
737                 (ly:stencil-translate-axis 
738                  (ly:bracket Y y-ext thick protusion)
739                  (- (car x-ext) pad) X))
740                (rb (ly:stencil-translate-axis
741                     (ly:bracket Y y-ext thick (- protusion))
742                     (+ (cdr x-ext) pad) X)))
743
744           (make-brackets
745            stencils (cddr indices)
746            (append
747             (list lb rb)
748             acc)))
749         acc))
750
751   (let* ((stencils
752           (map (lambda (x)
753                  (interpret-markup
754                   layout
755                   props
756                   x)) args))
757          (leading
758           (chain-assoc-get 'baseline-skip props))
759          (stacked (stack-stencils stencils 1.25 #f))
760          (brackets (make-brackets stacked indices '())))
761
762     (apply ly:stencil-add
763            (append stacked brackets))))