]> git.donarmstrong.com Git - lilypond.git/blob - scm/markup.scm
markup.scm: use stencil extents when stacking; issue 723
[lilypond.git] / scm / markup.scm
1 ;;;; This file is part of LilyPond, the GNU music typesetter.
2 ;;;;
3 ;;;; Copyright (C) 2003--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
4 ;;;;
5 ;;;; LilyPond is free software: you can redistribute it and/or modify
6 ;;;; it under the terms of the GNU General Public License as published by
7 ;;;; the Free Software Foundation, either version 3 of the License, or
8 ;;;; (at your option) any later version.
9 ;;;;
10 ;;;; LilyPond is distributed in the hope that it will be useful,
11 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ;;;; GNU General Public License for more details.
14 ;;;;
15 ;;;; You should have received a copy of the GNU General Public License
16 ;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
17
18 (defmacro*-public markup (#:rest body)
19   "The `markup' macro provides a lilypond-like syntax for building markups.
20
21  - #:COMMAND is used instead of \\COMMAND
22  - #:line ( ... ) is used instead of \\line { ... }
23  - etc.
24
25 Example:
26   \\markup { foo
27             \\raise #0.2 \\hbracket \\bold bar
28             \\override #'(baseline-skip . 4)
29             \\bracket \\column { baz bazr bla }
30   }
31          <==>
32   (markup \"foo\"
33           #:raise 0.2 #:hbracket #:bold \"bar\"
34           #:override '(baseline-skip . 4)
35           #:bracket #:column (\"baz\" \"bazr\" \"bla\"))"
36
37   (car (compile-all-markup-expressions `(#:line ,body))))
38
39 ;; utility
40
41 (define (markup-join markups sep)
42   "Return line-markup of MARKUPS, joining them with markup SEP"
43   (if (pair? markups)
44       (make-line-markup (list-insert-separator markups sep))
45       empty-markup))
46
47
48 (define-public interpret-markup ly:text-interface::interpret-markup)
49
50 (define-public (interpret-markup-list layout props markup-list)
51   (let ((stencils (list)))
52     (for-each (lambda (m)
53                 (set! stencils
54                       (if (markup-command-list? m)
55                           (append! (reverse! (apply (car m) layout props (cdr m)))
56                                    stencils)
57                           (cons (interpret-markup layout props m) stencils))))
58               markup-list)
59     (reverse! stencils)))
60
61 (define-public (prepend-alist-chain key val chain)
62   (cons (acons key val (car chain)) (cdr chain)))
63
64 (define-public (stack-stencil-line space stencils)
65   "Adjoin a list of STENCILS along the X axis, leaving SPACE between the
66    end of each stencil and the reference point of the following stencil."
67   (if (and (pair? stencils)
68            (ly:stencil? (car stencils)))
69
70       (if (and (pair? (cdr stencils))
71                (ly:stencil? (cadr stencils)))
72           (let* ((tail (stack-stencil-line space (cdr stencils)))
73                  (head (car stencils))
74                  (xoff (+ space (interval-end (ly:stencil-extent head X)))))
75             (ly:stencil-add head
76                             (ly:stencil-translate-axis tail xoff X)))
77           (car stencils))
78       (ly:make-stencil '() '(0 . 0) '(0 . 0))))
79
80
81 ;;; convert a full markup object to an approximate pure string representation
82
83 (define-public (markup->string m . argscopes)
84 (let* ((scopes (if (pair? argscopes) (car argscopes) '())))
85   ;; markup commands with one markup argument, formatting ignored
86   (define markups-first-argument '(list
87                                    bold-markup box-markup caps-markup dynamic-markup finger-markup
88                                    fontCaps-markup huge-markup italic-markup large-markup larger-markup
89                                    medium-markup normal-size-sub-markup normal-size-super-markup
90                                    normal-text-markup normalsize-markup number-markup roman-markup
91                                    sans-markup simple-markup small-markup smallCaps-markup smaller-markup
92                                    sub-markup super-markup teeny-markup text-markup tiny-markup
93                                    typewriter-markup underline-markup upright-markup bracket-markup
94                                    circle-markup hbracket-markup parenthesize-markup rounded-box-markup
95
96                                    center-align-markup center-column-markup column-markup dir-column-markup
97                                    fill-line-markup justify-markup justify-string-markup left-align-markup
98                                    left-column-markup line-markup right-align-markup right-column-markup
99                                    vcenter-markup wordwrap-markup wordwrap-string-markup ))
100
101   ;; markup commands with markup as second argument, first argument
102   ;; specifies some formatting and is ignored
103   (define markups-second-argument '(list
104                                     abs-fontsize-markup fontsize-markup magnify-markup lower-markup
105                                     pad-around-markup pad-markup-markup pad-x-markup raise-markup
106                                     halign-markup hcenter-in-markup rotate-markup translate-markup
107                                     translate-scaled-markup with-url-markup scale-markup ))
108
109   ;; helper functions to handle string cons like string lists
110   (define (markup-cons->string-cons c scopes)
111     (if (not (pair? c)) (markup->string c scopes)
112         (cons (markup->string (car c) scopes) (markup-cons->string-cons (cdr c) scopes))))
113   (define (string-cons-join c)
114     (if (not (pair? c)) c
115         (string-join (list (car c) (string-cons-join (cdr c))) "")))
116
117   (cond
118    ((string? m) m)
119    ((null? m) "")
120    ((not (pair? m)) "")
121
122    ;; handle \concat (string-join without spaces)
123    ((and (pair? m) (equal? (car m) concat-markup))
124     (string-cons-join (markup-cons->string-cons (cadr m) scopes)) )
125
126    ;; markup functions with the markup as first arg
127    ((member (car m) (primitive-eval markups-first-argument))
128     (markup->string (cadr m) scopes))
129
130    ;; markup functions with markup as second arg
131    ((member (car m) (primitive-eval markups-second-argument))
132     (markup->string (cddr m) scopes))
133
134    ;; fromproperty-markup reads property values from the header block:
135    ((equal? (car m) fromproperty-markup)
136     (let* ((varname (symbol->string (cadr m)))
137            ;; cut off the header: prefix from the variable name:
138            (newvarname (if (string-prefix? "header:" varname) (substring varname 7) varname))
139            (var (string->symbol newvarname))
140            (mod (make-module 1)))
141       ;; Prevent loops by temporarily clearing the variable we have just looked up
142       (module-define! mod var "")
143       (markup->string (ly:modules-lookup scopes var) (cons mod scopes))))
144
145    ;; ignore all other markup functions
146    ((markup-function? (car m)) "")
147
148    ;; handle markup lists
149    ((list? m)
150     (string-join (map (lambda (mm) (markup->string mm scopes)) m) " "))
151
152    (else "ERROR, unable to extract string from markup"))))