[ << Tweaking output ] | [Top][Contents][Index] | [ Templates >> ] |
[ < Length and thickness of objects ] | [ Up : Tweaking output ] | [ Placement of objects > ] |
5.4 Offsets and alignments
LilyPond needs to know where each and every grob should be placed. This placement information is stored using relative coordinates: the position of a grob is defined relative to the position of its parent (if we had to use absolute coordinates instead – e.g., distances from the edges of the page – it would be hard to maintain spatial relationships between grobs).
Every grob knows which grob is its parent in the respective axis.
For example, a Flag
grob knows that its x-parent is a
particular Stem
grob.
Relative coordinates that describe a grob’s placement are stored
in grob properties called X-offset
and Y-offset
.
They are measured in staff spaces. X-offset
is the
horizontal displacement between a grob’s reference point and
the reference point of a grob’s x-parent (similarly with
Y-offset
).
What is a reference point? It’s a special point that defines the grob’s position. Think about geometry: if you have to define where a figure is placed on a plane, you’ll usually say something like “the lower left corner of this square has coordinates (0, 2)”, or “the center of this circle is at (-1, 3)”. ‘Lower left corner’ and ‘center’ would be the reference points for square and circle, respectively.
This illustration shows where reference points of particular grobs are located, indicated as red dots (for example, the middle staff line for bars and stems, the intersection between the baseline and the left edge for a text box, or the vertical center at the left side for a note head).
{ \override NoteHead.style = #'altdefault % for breve \time 4/2 g'2-> c''\fermata as'1^"Yogi" | b'\breve _"Larry" | \mark "Twinkle" e''8 s4.. \bar "|." }
By overriding the X-offset
or Y-offset
value we can
move grobs relative to their parents:
{ \override Script.X-offset = 3 % fermata, accent \override TextScript.X-offset = 2 % "Yogi", "Larry" \override Stem.X-offset = -2 \override Score.RehearsalMark.Y-offset = 5 % "Twinkle" \override NoteHead.style = #'altdefault % for breve \time 4/2 g'2-> c''\fermata as'1^"Yogi" | b'\breve _"Larry" | \mark "Twinkle" e''8 s4.. \bar "|." }
Note that the Flag
grob moved together with its Stem
grob.
Note: Changing X-offset
or Y-offset
doesn’t
always work as expected, see Aligning objects.
Now, let’s explain another pair of properties: X-extent
and
Y-extent
. Each of them is a pair of numbers (internally,
LilyPond calls this an interval), and they store a grob’s
dimensions relative to its reference point. For example,
X-extent
equal to (-1 . 4) means that the left
edge of the grob is 1 staff space to the left of its
reference point, and the right edge is 4 staff spaces to the
right from reference point, for a total width of 4 - (-1)
= 4 + 1 = 5 staff spaces. Both numbers in an extent may
be positive; for example, (2 . 3) is a valid extent: it means
that the whole grob is on the right of its reference point, and
the width of the grob is 3 - 2 = 1 staff space.
Similarly, both numbers can be negative; these situations are
quite unusual but won’t give LilyPond headaches. The most common
situation (at least for X-extent
) is that the first number
is 0, which means that the reference point is on the left
edge of the grob.
The previous example demonstrates this nicely: both the accent’s
and the fermata’s left edge is left of the reference point; the
same holds for the breve note head (we selected the
'altdefault
note head style to make this better visible).
Now, suppose that we want to position a RehearsalMark
grob
so that its right edge is aligned with a bar line (by default,
LilyPond horizontally centers the rehearsal mark). With
X-offset
equal to zero (i.e., its reference point is
aligned on the parent, which is equal to the bar line in this
situation), the RehearsalMark
grob is placed like this:
{ \override Score.RehearsalMark.X-offset = 0 b4 b b b \mark "Twinkle" b b b b }
So, we need to shift it. Remember what the second number in
X-extent
means? It’s the position of a grob’s right edge
relative to its reference point. If we subtract this value from
zero, we’ll get the x-offset we want:
{ % value -10.4 found by trial and error \override Score.RehearsalMark.X-offset = -10.4 b4 b b b \mark "Twinkle" b b b b }
What if we wanted to center some grob on the reference point on its parent? That’s simple: calculate the displacement between a grob’s reference point and the center of its extent. Some examples:
-
X-extent
= (-2 . 2)
⇒X-offset
= 0 - 0 = 0 -
X-extent
= (0 . 4)
⇒X-offset
= 0 - (0 + 0.5 * 4) = -2 -
X-extent
= (-2 . 4)
⇒X-offset
= 0 - ((0.5 * -2) + (0.5 * 4)) = 0 - (-1 + 2) = -1
There is already a function with a super-long name available that can do these calculations for us:
\override GrobName.X-offset = #ly:self-alignment-interface::x-aligned-on-self
and we only need to specify what alignment we want:
\override GrobName.self-alignment-X = #RIGHT
This code tells the procedure to find the displacement between a grob’s reference point and its right edge, and use it as the x-offset, which will result in the grob being right-aligned.
So, if you change a grob’s extent, you will affect how it will be aligned (because LilyPond will think that the grob’s dimensions are different):
{ \override Score.RehearsalMark.X-extent = #'(0 . 8) \override Score.RehearsalMark.self-alignment-X = #RIGHT b4 b b b \mark "Twinkle" b b b b }
Also, if a grob’s extent is empty (i.e., it’s not an interval
pair), procedures like x-aligned-on-self
won’t have any
information about a grob’s dimensions, so they won’t be able to
calculate an offset (they’ll just return value 0). In other
words, a grob with an empty extent can only be ‘aligned’ on its
reference point because there’s no other information that can be
used for alignment:
{ \override Score.RehearsalMark.X-extent = ##f b4 b b b \mark "Twinkle" b b b b }
Notice that an empty extent and a zero extent result in the same positioning:
{ \override Score.RehearsalMark.X-extent = #'(0 . 0) b4 b b b \mark "Twinkle" b b b b }
However, an empty extent (or a zero extent, or any other extent) doesn’t prevent us from placing the grob at any location we want – we just can’t use alignment procedures for that. We can still specify any offset we want, and it will work as usual:
{ \override Score.RehearsalMark.X-extent = ##f \override Score.RehearsalMark.X-offset = -10.4 b4 b b b \mark "Twinkle" b b b b }
Now, there is one more thing to keep in mind: a grob’s parent has its own dimensions, too, and we need to take them into account. For example, if we write
{ a'1 } \addlyrics { \override LyricText.X-offset = #ly:self-alignment-interface::x-aligned-on-self \override LyricText.self-alignment-X = #CENTER nn }
the LyricText
grob will be centered, but on the
reference point of its parent (i.e., the center of the syllable
will be aligned to the reference point of the note head). If we
want the center of the LyricText
grob to be aligned with
the center of its parent NoteHead
grob, we have to use a
different procedure: aligned-on-x-parent
. It works very
similar to x-aligned-on-self
, but in addition to
calculating an offset based on a grob’s own extent, it also uses
the grob’s parent extent and computes positions relative to the
center of the extent:
{ a'1 } \addlyrics { \override LyricText.X-offset = #ly:self-alignment-interface::aligned-on-x-parent \override LyricText.self-alignment-X = #CENTER nn }
[ << Tweaking output ] | [Top][Contents][Index] | [ Templates >> ] |
[ < Length and thickness of objects ] | [ Up : Tweaking output ] | [ Placement of objects > ] |