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