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