]> git.donarmstrong.com Git - lilypond.git/blob - scm/define-markup-commands.scm
(note-by-number): read font-size
[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          (size (chain-assoc-get 'font-size props 0))
409          (stem-length (* (magstep size) (max 3 (- log 1))))
410          (head-glyph (ly:find-glyph-by-name
411                   font
412                   (string-append "noteheads-" (number->string (min log 2)))))
413          (stem-thickness 0.13)
414          (stemy (* dir stem-length))
415          (attachx (if (> dir 0)
416                       (- (cdr (ly:stencil-extent head-glyph X)) stem-thickness)
417                       0))
418          (attachy (* dir 0.28))
419          (stem-glyph (and (> log 0)
420                       (ly:round-filled-box
421                        (cons attachx (+ attachx  stem-thickness))
422                        (cons (min stemy attachy)
423                              (max stemy attachy))
424                        (/ stem-thickness 3))))
425          (dot (ly:find-glyph-by-name font "dots-dot"))
426          (dotwid (interval-length (ly:stencil-extent dot X)))
427          (dots (and (> dot-count 0)
428                     (apply ly:stencil-add
429                            (map (lambda (x)
430                                   (ly:stencil-translate-axis
431                                    dot  (* (+ 1 (* 2 x)) dotwid) X) )
432                                 (iota dot-count 1)))))
433          (flaggl (and (> log 2)
434                       (ly:stencil-translate
435                        (ly:find-glyph-by-name font
436                                               (string-append "flags-"
437                                                              (if (> dir 0) "u" "d")
438                                                              (number->string log)))
439                        (cons (+ attachx (/ stem-thickness 2)) stemy)))))
440     (if flaggl
441         (set! stem-glyph (ly:stencil-add flaggl stem-glyph)))
442     (if (ly:stencil? stem-glyph)
443         (set! stem-glyph (ly:stencil-add stem-glyph head-glyph))
444         (set! stem-glyph head-glyph))
445     (if (ly:stencil? dots)
446         (set! stem-glyph
447               (ly:stencil-add
448                (ly:stencil-translate-axis dots
449                                            (+ (if (and (> dir 0) (> log 2))
450                                                   (* 1.5 dotwid)
451                                                   0)
452                                               ;; huh ? why not necessary?
453                                               ;;(cdr (ly:stencil-extent head-glyph X))
454                                               dotwid)
455                                            X)
456                stem-glyph)))
457     stem-glyph))
458
459 (use-modules (ice-9 regex))
460
461 (define-public log2 
462   (let ((divisor (log 2)))
463     (lambda (z) (inexact->exact (/ (log z) divisor)))))
464
465 (define (parse-simple-duration duration-string)
466   "Parse the `duration-string', e.g. ''4..'' or ''breve.'', and return a (log dots) list."
467   (let ((match (regexp-exec (make-regexp "(breve|longa|maxima|[0-9]+)(\\.*)") duration-string)))
468     (if (and match (string=? duration-string (match:substring match 0)))
469         (let ((len  (match:substring match 1))
470               (dots (match:substring match 2)))
471           (list (cond ((string=? len "breve")  -1)
472                       ((string=? len "longa")  -2)
473                       ((string=? len "maxima") -3)
474                       (else (log2 (string->number len))))
475                 (if dots (string-length dots) 0)))
476         (error "This is not a valid duration string:" duration-string))))
477
478 (def-markup-command (note paper props duration dir) (string? number?)
479   "This produces a note with a stem pointing in @var{dir} direction, with
480 the @var{duration} for the note head type and augmentation dots. For
481 example, @code{\\note #\"4.\" #-0.75} creates a dotted quarter note, with
482 a shortened down stem."
483   
484   (let ((parsed (parse-simple-duration duration)))
485     (note-by-number-markup paper props (car parsed) (cadr parsed) dir)))
486
487 (def-markup-command (normal-size-super paper props arg) (markup?)
488   "Set @var{arg} in superscript with a normal font size."
489   
490   (ly:stencil-translate-axis (interpret-markup
491                                paper
492                                props arg)
493                               (* 0.5  (chain-assoc-get 'baseline-skip props))
494                               Y))
495
496 (def-markup-command (super paper props arg) (markup?)
497   "
498 @cindex raising text
499 @cindex lowering text
500 @cindex moving text
501 @cindex translating text
502
503 @cindex @code{\\super}
504
505
506 Raising and lowering texts can be done with @code{\\super} and
507 @code{\\sub}:
508
509 @lilypond[verbatim,fragment,relative=1]
510  c1^\\markup { E \"=\" mc \\super \"2\" }
511 @end lilypond
512
513 "
514   
515   (ly:stencil-translate-axis
516    (interpret-markup
517     paper
518     (cons `((font-size . ,(- (chain-assoc-get 'font-size props 0) 3))) props)
519     arg)
520    (* 0.5 (chain-assoc-get 'baseline-skip props))
521    Y))
522
523 (def-markup-command (translate paper props offset arg) (number-pair? markup?)
524   "This translates an object. Its first argument is a cons of numbers
525 @example
526 A \\translate #(cons 2 -3) @{ B C @} D
527 @end example
528 This moves `B C' 2 spaces to the right, and 3 down, relative to its
529 surroundings. This command cannot be used to move isolated scripts
530 vertically, for the same reason that @code{\\raise} cannot be used for
531 that.
532
533 "
534   
535   (ly:stencil-translate (interpret-markup  paper props arg)
536                          offset))
537
538 (def-markup-command (sub paper props arg) (markup?)
539   "Set @var{arg} in subscript."
540   
541   (ly:stencil-translate-axis
542    (interpret-markup
543     paper
544     (cons `((font-size . ,(- (chain-assoc-get 'font-size props 0) 3))) props)
545     arg)
546    (* -0.5 (chain-assoc-get 'baseline-skip props))
547    Y))
548
549 (def-markup-command (normal-size-sub paper props arg) (markup?)
550   "Set @var{arg} in subscript, in a normal font size."
551
552   (ly:stencil-translate-axis
553    (interpret-markup paper props arg)
554    (* -0.5 (chain-assoc-get 'baseline-skip props))
555    Y))
556
557 (def-markup-command (hbracket paper props arg) (markup?)
558   "Draw horizontal brackets around @var{arg}."  
559   (let ((th 0.1) ;; todo: take from GROB.
560         (m (interpret-markup paper props arg)))
561     (bracketify-stencil m X th (* 2.5 th) th)))
562
563 (def-markup-command (bracket paper props arg) (markup?)
564   "Draw vertical brackets around @var{arg}."  
565   (let ((th 0.1) ;; todo: take from GROB.
566         (m (interpret-markup paper props arg)))
567     (bracketify-stencil m Y th (* 2.5 th) th)))
568
569 ;; todo: fix negative space
570 (def-markup-command (hspace paper props amount) (number?)
571   "This produces a invisible object taking horizontal space.
572 @example 
573 \\markup @{ A \\hspace #2.0 B @} 
574 @end example
575 will put extra space between A and B, on top of the space that is
576 normally inserted before elements on a line.
577 "
578   (if (> amount 0)
579       (ly:make-stencil "" (cons 0 amount) '(-1 . 1) )
580       (ly:make-stencil "" (cons amount amount) '(-1 . 1))))
581
582 (def-markup-command (override paper props new-prop arg) (pair? markup?)
583   "Add the first argument in to the property list.  Properties may be
584 any sort of property supported by @internalsref{font-interface} and
585 @internalsref{text-interface}, for example
586
587 @verbatim
588 \\override #'(font-family . married) \"bla\"
589 @end verbatim
590
591 "
592   (interpret-markup paper (cons (list new-prop) props) arg))
593
594 (def-markup-command (smaller paper props arg) (markup?)
595   "Decrease the font size relative to current setting"
596   (let* ((fs (chain-assoc-get 'font-size props 0))
597          (entry (cons 'font-size (- fs 1))))
598     (interpret-markup paper (cons (list entry) props) arg)))
599
600
601 (def-markup-command (bigger paper props arg) (markup?)
602   "Increase the font size relative to current setting"
603   (let* ((fs (chain-assoc-get 'font-size props 0))
604          (entry (cons 'font-size (+ fs 1))))
605     (interpret-markup paper (cons (list entry) props) arg)))
606
607 (def-markup-command larger (markup?)
608   bigger-markup)
609
610
611 (def-markup-command (box paper props arg) (markup?)
612   "Draw a box round @var{arg}.  Looks at @code{thickness} and
613 @code{box-padding} properties to determine line thickness and padding
614 around the markup."
615   (let ((th (chain-assoc-get 'thickness props  0.1))
616         (pad (chain-assoc-get 'box-padding props 0.2))
617         (m (interpret-markup paper props arg)))
618     (box-stencil m th pad)))
619
620 ;FIXME: is this working? 
621 (def-markup-command (strut paper props) ()
622   
623   "Create a box of the same height as the space in the current font."
624   
625   (let ((m (Text_item::interpret_markup paper props " ")))
626     (ly:stencil-set-extent! m X '(1000 . -1000))
627     m))
628
629 (define number->mark-letter-vector (make-vector 25 #\A))
630
631 (do ((i 0 (1+ i))
632      (j 0 (1+ j)))
633     ((>= i 26))
634   (if (= i (- (char->integer #\I) (char->integer #\A)))
635       (set! i (1+ i)))
636   (vector-set! number->mark-letter-vector j
637                (integer->char (+ i (char->integer #\A)))))
638
639 (define (number->markletter-string n)
640   "Double letters for big marks."
641   (let*
642       ((l (vector-length number->mark-letter-vector)))
643     
644   (if (>= n l)
645       (string-append (number->markletter-string (1- (quotient n l)))
646                      (number->markletter-string (remainder n l)))
647       (make-string 1 (vector-ref number->mark-letter-vector n)))))
648
649
650 (def-markup-command (markletter paper props num) (integer?)
651    "Make a markup letter for @var{num}.  The letters start with A to Z
652  (skipping I), and continues with double letters."
653  
654    (Text_item::interpret_markup paper props (number->markletter-string num)))
655
656
657
658
659 (def-markup-command (bracketed-y-column paper props indices args)
660   (list? markup-list?)
661   "Make a column of the markups in @var{args}, putting brackets around
662 the elements marked in @var{indices}, which is a list of numbers."
663
664     (define (sublist l start stop)
665     (take (drop l start)  (- (1+ stop) start)) )
666
667   (define (stencil-list-extent ss axis)
668     (cons
669      (apply min (map (lambda (x) (car (ly:stencil-extent x axis))) ss))
670      (apply max (map (lambda (x) (cdr (ly:stencil-extent x axis))) ss))))
671             
672   (define (stack-stencils stencils bskip last-stencil)
673     (cond
674      ((null? stencils) '())
675      ((not last-stencil)
676       (cons (car stencils)
677             (stack-stencils (cdr stencils) bskip (car stencils))))
678      (else
679       (let*
680           ((orig (car stencils))
681            (dir (chain-assoc-get 'direction  props DOWN))
682            (new (ly:stencil-moved-to-edge last-stencil Y dir
683                                           orig
684                                           0.1 bskip))
685            )
686
687         (cons new (stack-stencils (cdr stencils) bskip new))))
688     ))
689
690   (define (make-brackets stencils indices acc)
691     (if (and stencils
692              (pair? indices)
693              (pair? (cdr indices)))
694         (let*
695             ((encl (sublist stencils (car indices) (cadr indices)))
696              (x-ext (stencil-list-extent encl X))
697              (y-ext (stencil-list-extent encl Y))
698              (thick 0.10)
699              (pad 0.35)
700              (protusion (* 2.5 thick))
701              (lb
702               (ly:stencil-translate-axis 
703                (ly:bracket Y y-ext thick protusion)
704                (- (car x-ext) pad) X))
705              (rb (ly:stencil-translate-axis
706                   (ly:bracket Y y-ext thick (- protusion))
707                   (+ (cdr x-ext) pad) X))
708              )
709
710           (make-brackets
711            stencils (cddr indices)
712            (append
713             (list lb rb)
714              acc)))
715         acc))
716
717   (let*
718       ((stencils
719         (map (lambda (x)
720                (interpret-markup
721                 paper
722                 props
723                 x)) args))
724        (leading
725          (chain-assoc-get 'baseline-skip props))
726        (stacked (stack-stencils stencils 1.25 #f))
727        (brackets (make-brackets stacked indices '()))
728        )
729
730     (apply ly:stencil-add
731            (append stacked brackets)
732            )))
733
734
735              
736
737   
738   
739
740