| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Markups are implemented as special Scheme functions which produce a
Stencil object given a number of arguments.
| 2.5.1 Markup construction in Scheme | ||
| 2.5.2 How markups work internally | ||
| 2.5.3 New markup command definition | ||
| 2.5.4 New markup list command definition |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Markup expressions are internally represented in Scheme using the
markup macro:
(markup expr) |
To see a markup expression in its Scheme form, use the
\displayScheme command:
\displayScheme
\markup {
\column {
\line { \bold \italic "hello" \raise #0.4 "world" }
\larger \line { foo bar baz }
}
}
|
Compiling the code above will send the following to the display console:
(markup
#:line
(#:column
(#:line
(#:bold (#:italic "hello") #:raise 0.4 "world")
#:larger
(#:line
(#:simple "foo" #:simple "bar" #:simple "baz")))))
|
To prevent the markup from printing on the page, use
‘\void \displayScheme markup’. Also, as with the
\displayMusic command, the output of \displayScheme
can be saved to an external file. See
Displaying music expressions.
This example demonstrates the main translation rules between regular
LilyPond markup syntax and Scheme markup syntax. Using #{
… #} for entering in LilyPond syntax will often be most
convenient, but we explain how to use the markup macro to get a
Scheme-only solution.
LilyPond Scheme \markup markup1(markup markup1)\markup { markup1 markup2 … }(markup markup1 markup2 … )\markup-command#:markup-command\variablevariable\center-column { … }#:center-column ( … )string"string"#scheme-argscheme-arg
The whole Scheme language is accessible inside the
markup macro. For example, You may use function calls inside
markup in order to manipulate character strings. This is
useful when defining new markup commands (see
New markup command definition).
The markup-list argument of commands such as #:line,
#:center, and #:column cannot be a variable or
the result of a function call.
(markup #:line (function-that-returns-markups)) |
is invalid. One should use the make-line-markup,
make-center-markup, or make-column-markup functions
instead,
(markup (make-line-markup (function-that-returns-markups))) |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In a markup like
\raise #0.5 "text example" |
\raise is actually represented by the raise-markup
function. The markup expression is stored as
(list raise-markup 0.5 (list simple-markup "text example")) |
When the markup is converted to printable objects (Stencils), the
raise-markup function is called as
(apply raise-markup
\layout object
list of property alists
0.5
the "text example" markup)
|
The raise-markup function first creates the stencil for the
text example string, and then it raises that Stencil by 0.5
staff space. This is a rather simple example; more complex examples
are in the rest
of this section, and in ‘scm/define-markup-commands.scm’.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section discusses the definition of new markup commands.
| Markup command definition syntax | ||
| On properties | ||
| A complete example | ||
| Adapting builtin commands |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
New markup commands can be defined using the
define-markup-command Scheme macro, at top-level.
(define-markup-command (command-name layout props arg1 arg2 …)
(arg1-type? arg2-type? …)
[ #:properties ((property1 default-value1)
…) ]
…command body…)
|
The arguments are
command-namethe markup command name
layoutthe ‘layout’ definition.
propsa list of associative lists, containing all active properties.
argiith command argument
argi-type?a type predicate for the ith argument
If the command uses properties from the props arguments,
the #:properties keyword can be used to specify which
properties are used along with their default values.
Arguments are distinguished according to their type:
markup?;
markup-list?;
list?, number?, boolean?, etc.
There is no limitation on the order of arguments (after the
standard layout and props arguments). However,
markup functions taking a markup as their last argument are
somewhat special as you can apply them to a markup list, and the
result is a markup list where the markup function (with the
specified leading arguments) has been applied to every element of
the original markup list.
Since replicating the leading arguments for applying a markup function to a markup list is cheap mostly for Scheme arguments, you avoid performance pitfalls by just using Scheme arguments for the leading arguments of markup functions that take a markup as their last argument.
Markup commands have a rather complex life cycle. The body of a
markup command definition is responsible for converting the
arguments of the markup command into a stencil expression which is
returned. Quite often this is accomplished by calling the
interpret-markup function on a markup expression, passing
the layout and props arguments on to it. Those
arguments are usually only known at a very late stage in
typesetting. Markup expressions have their components assembled
into markup expressions already when \markup in a LilyPond
expression or the markup macro in Scheme is expanded. The
evaluation and typechecking of markup command arguments happens at
the time \markup/markup are interpreted.
But the actual conversion of markup expressions into stencil
expressions by executing the markup function bodies only happens
when interpret-markup is called on a markup expression.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The layout and props arguments of markup commands bring a
context for the markup interpretation: font size, line width, etc.
The layout argument allows access to properties defined in
paper blocks, using the ly:output-def-lookup function.
For instance, the line width (the same as the one used in scores) is
read using:
(ly:output-def-lookup layout 'line-width) |
The props argument makes some properties accessible to markup
commands. For instance, when a book title markup is interpreted, all
the variables defined in the \header block are automatically
added to props, so that the book title markup can access the book
title, composer, etc. It is also a way to configure the behaviour of a
markup command: for example, when a command uses font size during
processing, the font size is read from props rather than having a
font-size argument. The caller of a markup command may change
the value of the font size property in order to change the behaviour.
Use the #:properties keyword of define-markup-command to
specify which properties shall be read from the props arguments.
The example in next section illustrates how to access and override properties in a markup command.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following example defines a markup command to draw a double box around a piece of text.
Firstly, we need to build an approximative result using markups.
Consulting the
(notation)Text markup commands section ‘Text markup commands’ in Notation Reference shows us the \box
command is useful:
\markup \box \box HELLO
Now, we consider that more padding between the text and the boxes is
preferable. According to the \box documentation, this command
uses a box-padding property, which defaults to 0.2. The
documentation also mentions how to override it:
\markup \box \override #'(box-padding . 0.6) \box A
Then, the padding between the two boxes is considered too small, so we override it too:
\markup \override #'(box-padding . 0.4) \box \override #'(box-padding . 0.6) \box A
Repeating this lengthy markup would be painful. This is where a markup
command is needed. Thus, we write a double-box markup command,
taking one argument (the text). This draws the two boxes, with some
padding.
#(define-markup-command (double-box layout props text) (markup?)
"Draw a double box around text."
(interpret-markup layout props
#{\markup \override #'(box-padding . 0.4) \box
\override #'(box-padding . 0.6) \box { #text }#}))
|
or, equivalently
#(define-markup-command (double-box layout props text) (markup?)
"Draw a double box around text."
(interpret-markup layout props
(markup #:override '(box-padding . 0.4) #:box
#:override '(box-padding . 0.6) #:box text)))
|
text is the name of the command argument, and markup? its
type: it identifies it as a markup. The interpret-markup
function is used in most of markup commands: it builds a stencil, using
layout, props, and a markup. In the second case, this
markup is built using the markup scheme macro, see Markup construction in Scheme. The transformation from \markup
expression to scheme markup expression is straight-forward.
The new command can be used as follow:
\markup \double-box A |
It would be nice to make the double-box command customizable:
here, the box-padding values are hard coded, and cannot be
changed by the user. Also, it would be better to distinguish the
padding between the two boxes, from the padding between the inner box
and the text. So we will introduce a new property,
inter-box-padding, for the padding between the two boxes. The
box-padding will be used for the inner padding. The new code is
now as follows:
#(define-markup-command (double-box layout props text) (markup?)
#:properties ((inter-box-padding 0.4)
(box-padding 0.6))
"Draw a double box around text."
(interpret-markup layout props
#{\markup \override #`(box-padding . ,inter-box-padding) \box
\override #`(box-padding . ,box-padding) \box
{ #text } #}))
|
Again, the equivalent version using the markup macro would be:
#(define-markup-command (double-box layout props text) (markup?)
#:properties ((inter-box-padding 0.4)
(box-padding 0.6))
"Draw a double box around text."
(interpret-markup layout props
(markup #:override `(box-padding . ,inter-box-padding) #:box
#:override `(box-padding . ,box-padding) #:box text)))
|
Here, the #:properties keyword is used so that the
inter-box-padding and box-padding properties are read from
the props argument, and default values are given to them if the
properties are not defined.
Then, these values are used to override the box-padding
properties used by the two \box commands. Note the backquote and
the comma in the \override argument: they allow you to introduce
a variable value into a literal expression.
Now, the command can be used in a markup, and the boxes padding be customized:
#(define-markup-command (double-box layout props text) (markup?) #:properties ((inter-box-padding 0.4) (box-padding 0.6)) "Draw a double box around text." (interpret-markup layout props #{\markup \override #`(box-padding . ,inter-box-padding) \box \override #`(box-padding . ,box-padding) \box { #text } #})) \markup \double-box A \markup \override #'(inter-box-padding . 0.8) \double-box A \markup \override #'(box-padding . 1.0) \double-box A
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A good way to start writing a new markup command, is to take example on a builtin one. Most of the markup commands provided with LilyPond can be found in file ‘scm/define-markup-commands.scm’.
For instance, we would like to adapt the \draw-line command, to
draw a double line instead. The \draw-line command is defined as
follow (documentation stripped):
(define-markup-command (draw-line layout props dest)
(number-pair?)
#:category graphic
#:properties ((thickness 1))
"…documentation…"
(let ((th (* (ly:output-def-lookup layout 'line-thickness)
thickness))
(x (car dest))
(y (cdr dest)))
(make-line-stencil th 0 0 x y)))
|
To define a new command based on an existing one, copy the definition,
and change the command name. The #:category keyword can be
safely removed, as it is only used for generating LilyPond
documentation, and is of no use for user-defined markup commands.
(define-markup-command (draw-double-line layout props dest)
(number-pair?)
#:properties ((thickness 1))
"…documentation…"
(let ((th (* (ly:output-def-lookup layout 'line-thickness)
thickness))
(x (car dest))
(y (cdr dest)))
(make-line-stencil th 0 0 x y)))
|
Then, a property for setting the gap between two lines is added, called
line-gap, defaulting e.g. to 0.6:
(define-markup-command (draw-double-line layout props dest)
(number-pair?)
#:properties ((thickness 1)
(line-gap 0.6))
"…documentation…"
…
|
Finally, the code for drawing two lines is added. Two calls to
make-line-stencil are used to draw the lines, and the resulting
stencils are combined using ly:stencil-add:
#(define-markup-command (my-draw-line layout props dest) (number-pair?) #:properties ((thickness 1) (line-gap 0.6)) "..documentation.." (let* ((th (* (ly:output-def-lookup layout 'line-thickness) thickness)) (dx (car dest)) (dy (cdr dest)) (w (/ line-gap 2.0)) (x (cond ((= dx 0) w) ((= dy 0) 0) (else (/ w (sqrt (+ 1 (* (/ dx dy) (/ dx dy)))))))) (y (* (if (< (* dx dy) 0) 1 -1) (cond ((= dy 0) w) ((= dx 0) 0) (else (/ w (sqrt (+ 1 (* (/ dy dx) (/ dy dx)))))))))) (ly:stencil-add (make-line-stencil th x y (+ dx x) (+ dy y)) (make-line-stencil th (- x) (- y) (- dx x) (- dy y))))) \markup \my-draw-line #'(4 . 3) \markup \override #'(line-gap . 1.2) \my-draw-line #'(4 . 3)
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Markup list commands are defined with the
define-markup-list-command Scheme macro, which is similar to the
define-markup-command macro described in
New markup command definition, except that where the latter returns
a single stencil, the former returns a list of stencils.
In a similar vein, interpret-markup-list is used instead of
interpret-markup for converting a markup list into a list
of stencils.
In the following example, a \paragraph markup list command is
defined, which returns a list of justified lines, the first one being
indented. The indent width is taken from the props argument.
#(define-markup-list-command (paragraph layout props args) (markup-list?)
#:properties ((par-indent 2))
(interpret-markup-list layout props
#{\markuplist \justified-lines { \hspace #par-indent #args } #}))
|
The version using just Scheme is more complex:
#(define-markup-list-command (paragraph layout props args) (markup-list?)
#:properties ((par-indent 2))
(interpret-markup-list layout props
(make-justified-lines-markup-list (cons (make-hspace-markup par-indent)
args))))
|
Besides the usual layout and props arguments, the
paragraph markup list command takes a markup list argument, named
args. The predicate for markup lists is markup-list?.
First, the function gets the indent width, a property here named
par-indent, from the property list props. If the
property is not found, the default value is 2. Then, a
list of justified lines is made using the built-in markup list command
\justified-lines, which is related to the
make-justified-lines-markup-list function. A
horizontal space is added at the beginning using \hspace (or the
make-hspace-markup function). Finally, the markup list is
interpreted using the interpret-markup-list function.
This new markup list command can be used as follows:
\markuplist {
\paragraph {
The art of music typography is called \italic {(plate) engraving.}
The term derives from the traditional process of music printing.
Just a few decades ago, sheet music was made by cutting and stamping
the music into a zinc or pewter plate in mirror image.
}
\override-lines #'(par-indent . 4) \paragraph {
The plate would be inked, the depressions caused by the cutting
and stamping would hold ink. An image was formed by pressing paper
to the plate. The stamping and cutting was completely done by
hand.
}
}
|
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated by gub on July 13, 2020 using texi2html 1.82.
Altres idiomes: deutsch, español, français.
Quant a la selecció automàtica de la llengua.