Indenting individual systems
LilyPond scores are indented similar to text paragraphs: all systems except the first one are indented by the same amount (the value of the short-indent property). This layout constraint is applied in advance and cannot be modified later. In other words, indenting on a system-by-system basis is not possible with this mechanism.
Users who need a differently indented system can arrange for that system to start a new score, as demonstrated in the snippet Coda ahead of a line of its own. That may be a reasonable workaround at a more or less natural break such as a coda, but in general the structure clash introduces severe fragmentation requiring compensatory splicing and fudging; see this discussion of problems with this approach.
This snippet demonstrates a pseudo-indent workaround that superimposes an additional, system-wise indentation on the score's unmodified layout indentation, avoiding the abovementioned score change problems. It allows to change the left and right (pseudo) indentation independently; optionally, the instrument name can be changed, too.
Some caveats still apply, though.
- The indenting mechanism is based on an arcane misuse of the
LeftEdgegrob and may therefore become temporarily or permanently broken by side effects of future development changes in the LilyPond code base. - The code is not protected against multiple calls per system break.
\version "2.24"
%%%%%%%% HEADER %%%%%%%%
%
% This code was prompted by
%
% https://lists.gnu.org/archive/html/lilypond-user/2019-07/msg00139.html
%
% and offers a pseudo-indent hack suitable for general use.
%
% keywords:
%
% indent short-indent indentation system line
% mid-score temporarily arbitrary individual single just only once
% coda margin
%
% Put the code before the examples into a file `pseudo-indent.ily` that
% you can include later on in your code with
%
% \include "pseudo-indent.ily"
%%%%%%%% PSEUDO-INDENT FUNCTIONS START %%%%%%%%
% Two functions are provided for indenting individual systems.
%
% - To left-indent a system, apply `\pseudoIndent` before the music
% continues.
% - `\pseudoIndents` does the same but lets you also indent on the
% right.
%
% Both commands accept an optional argument for changing the affected
% system's instrument name(s).
%
% The following conditions must be met to make the functions work.
%
% - It is assumed that the score is not using a ragged-right layout
% (which is the default for multi-system scores).
% - A manual `\break` must be used to call the functions at the start
% of a system.
% - The functions misbehave if called more than once at the same
% system start.
%
% The syntax forms are as follows.
%
% \pseudoIndent [<name-tweaks>] <left-indent>
% \pseudoIndent [<name-tweaks>] <left-indent> <right-indent>
%
% <name-tweaks>
% An optional argument holding a markup list for instrument names
% as an ordered list. If an element is `*`, the previous
% instrument name stays unchanged.
% <left-indent>
% Additional left indentation, in staff-space units. This value
% can be negative with the restriction that the sum
%
% <left-indent> + `short-indent`
%
% must be larger or equal to zero to avoid unsupported
% stretching.
% <right-indent>
% Additional right indentation, in staff-space units; can be
% negative.
%
% Examples:
%
% \pseudoIndent 11
% \pseudoIndents 11 22
% \pseudoIndents \markuplist { "foo" * \myMarkup } 11 22
pseudoIndents =
#(define-music-function (name-tweaks left-indent right-indent)
((markup-list? '()) number? number?)
(define (warn-stretched p1 p2)
(ly:input-warning
(*location*)
(G_
" \\pseudoIndents ~s ~s is stretching staff; expect distorted layout")
p1 p2))
(let*
((narrowing (+ left-indent right-indent))
(set-staffsymbol!
(lambda (staffsymbol-grob) ; change staff to new width
(let*
((left-bound (ly:spanner-bound staffsymbol-grob LEFT))
(left-moment (ly:grob-property left-bound 'when))
;; in first system of score?
(capo? (moment<=? left-moment ZERO-MOMENT))
(layout (ly:grob-layout staffsymbol-grob))
;; debugging info
(lw (ly:output-def-lookup layout 'line-width))
(indent (ly:output-def-lookup
layout
(if capo? 'indent 'short-indent)))
(old-stil (ly:staff-symbol::print staffsymbol-grob))
(staffsymbol-x-ext (ly:stencil-extent old-stil X))
;; For LilyPond versions >=2.19.16 the first system has
;; `old-stil` already narrowed. Compensate for this
;; (i.e., being not pristine) when calculating.
;;
;; - old leftmost-x (its value is needed when setting
;; so-called 'width)
;; - the new width and position (via local variable
;; `narrowing_`)
(ss-t (ly:staff-symbol-line-thickness
staffsymbol-grob))
;; would expect half
(pristine? (<= 0 (car staffsymbol-x-ext) ss-t))
(leftmost-x (+ indent (if pristine? 0 narrowing)))
;; uses 0 if already narrowed
(narrowing_ (if pristine? narrowing 0))
(old-width (+ (interval-length staffsymbol-x-ext)
ss-t))
(new-width (- old-width narrowing_))
;; and set! this immediately
(new-rightmost-x (+ leftmost-x new-width))
(junk (ly:grob-set-property! staffsymbol-grob
'width new-rightmost-x))
(in-situ-stil (ly:staff-symbol::print
staffsymbol-grob))
(new-stil (ly:stencil-translate-axis in-situ-stil
narrowing_
X))
;; for debugging
;; (new-stil (stencil-with-color new-stil red))
(new-x-ext (ly:stencil-extent new-stil X)))
(ly:grob-set-property! staffsymbol-grob 'stencil
new-stil)
(ly:grob-set-property! staffsymbol-grob 'X-extent
new-x-ext))))
;; move grob across to line start
(set-X-offset!
(lambda (margin-grob)
(let* ((old (ly:grob-property-data margin-grob 'X-offset))
(new (lambda (grob)
(+ (if (procedure? old) (old grob) old)
narrowing))))
(ly:grob-set-property! margin-grob 'X-offset new))))
;; tweak both instrument name texts
(tweak-text!
(lambda (i-name-grob mkup)
(when (and (markup? mkup)
(not (string=? (markup->string mkup) "*")))
(ly:grob-set-property! i-name-grob 'long-text mkup)
(ly:grob-set-property! i-name-grob 'text mkup))))
;; on staves, + adapt left margin
(install-narrowing
(lambda (leftedge-grob)
(let*
((sys (ly:grob-system leftedge-grob))
(all-grobs (ly:grob-array->list
(ly:grob-object sys 'all-elements)))
(grobs-named
(lambda (name)
(filter (lambda (x)
(eq? name (grob::name x))) all-grobs)))
(first-leftedge-grob (list-ref
(grobs-named 'LeftEdge) 0))
(relsys-x-of (lambda (g)
(ly:grob-relative-coordinate g sys X)))
(leftedge-x (relsys-x-of first-leftedge-grob))
(leftedged? (lambda (g)
(= (relsys-x-of g) leftedge-x)))
(leftedged-ss (filter leftedged?
(grobs-named 'StaffSymbol))))
;; ignore other left-edges
(when (eq? leftedge-grob first-leftedge-grob)
(for-each set-staffsymbol! leftedged-ss)
(for-each set-X-offset! (grobs-named 'SystemStartBar))
(for-each set-X-offset! (grobs-named 'InstrumentName))
(for-each tweak-text! (grobs-named 'InstrumentName)
name-tweaks))))))
(when (negative? narrowing)
(warn-stretched left-indent right-indent))
;; and continue anyway
#{
% ensure that these overrides are applied only at begin-of-line
% (but this does not protect against unsupported multiple
% application)
\break
% give the spacing engine notice regarding the loss of width
% for music
\once \override Score.LeftEdge.X-extent =
#(cons narrowing narrowing)
% discard line start region of staff and reassemble left-margin
% elements
\once \override Score.LeftEdge.after-line-breaking =
#install-narrowing
% shift the system to partition the narrowing between left and
% right
\overrideProperty Score.NonMusicalPaperColumn
.line-break-system-details
.X-offset #(- right-indent)
% prevent a leftmost bar number entering a stretched staff
\once \override Score.BarNumber.horizon-padding =
#(max 1 (- 1 narrowing))
#}))
pseudoIndent =
#(define-music-function (name-tweaks left-indent)
((markup-list? '()) number?)
#{
\pseudoIndents $name-tweaks $left-indent 0
#})
%%%%%%%% PSEUDO-INDENT FUNCTIONS END %%%%%%%%
%%%%%%%% SETUP FOR WIKI EXAMPLES %%%%%%%%
\paper {
indent = 55\mm
short-indent = 40\mm
system-system-spacing.basic-distance = 10\mm
tagline = ##f
}
m = { f'4 f'4 f'4 f'4 } % one measure
showInfo =
#(define-music-function (info) (markup?)
#{
\once \override Score.LeftEdge.break-visibility =
#begin-of-line-visible
\once \override Score.LeftEdge.stencil =
#(lambda (grob) (grob-interpret-markup grob info))
#})
%%%%%%%% BASIC EXAMPLE %%%%%%%%
% trace short indentation
basic-info-line = \markup \translate #'(0 . -0.2)
\with-color #blue
\draw-dashed-line #'(0 . -49)
v-gap = \markup \vspace #2.25
basic-info-text = \markup \translate #'(-24 . 8.8) \column {
\italic "(indent)"
\v-gap
\italic "(short-indent)"
\v-gap
"\pseudoIndent 22"
\v-gap
"\pseudoIndent 44"
\v-gap
"\pseudoIndents 22 22"
\v-gap
\line { "\pseudoIndents 0 44"
\translate #'(53 . 0)
\italic "with ragged-right ##f (default)" }
\v-gap
\line { "\pseudoIndents 0 20"
\translate #'(72 . 0)
\italic \right-column { "ragged-last ##f" "(default)" } }
}
basic = {
\omit Score.BarNumber
\m \m \m \m \m \m
\break % a short-indented system for reference (also info anchor:)
\showInfo \markup \combine \basic-info-text \basic-info-line
\m \m \m \m \m \m \m
\pseudoIndent 22
\m \m \m \m \m
\pseudoIndent 44
\m \m \m
\pseudoIndents 22 22
\m \m \m
\pseudoIndents 0 44
\m \m \m
\pseudoIndents 0 20
\m \m \m \m \m \bar "|."
}
\markup \huge \bold \column { " " " Basic usage" " "}
\score {
\new Staff { \basic }
\layout {}
}
%%%%%%%% DEMO EXAMPLE %%%%%%%%
% trace right margin
demo-info-line = \markup \translate #'(85.3 . 20.3)
\with-color #blue
\draw-dashed-line #'(0 . -56)
demo-info-text = \markup \translate #'(-24 . 17.3) \column \italic {
"right-indent at head"
" "
"stop/startStaff OK"
" "
" "
" "
" "
"(short-indent)"
" "
" "
" "
" "
"outdent without stretching"
" "
"name-tweaks displaying"
"how its list is ordered"
" "
" "
\line { "using name-tweaks "
\column \upright { " " "\"\"" "\\mkCoda" * }
" to "
\column { " " "hide name"
"change name" "(leave name as it is)" } }
}
% See https://wiki.lilypond.community/wiki/Coda_ahead_of_a_line_of_its_own
mkCoda = \markup \vcenter {
\bold "coda" \fontsize #3 \musicglyph "scripts.coda" }
demo = {
\pseudoIndents 0 22 % no additional left-indenting applied
s1*4
\break % a short-indented system for reference (also info anchor:)
\showInfo \markup \combine \demo-info-text \demo-info-line
s1*7
% display the instrument name ordering
\pseudoIndents \markuplist { 1 2 3 } 11 -4
s1*6
% hide 1; leave 2; change 3
\pseudoIndent \markuplist { "" * \mkCoda } 55
s1*2 \bar "|."
}
demoHi = {
\m \m \m \m
\m \m \m \m \m \m \m
\m \m \m \m \m \m
\m \m
}
demoLo = {
\m \m \stopStaff s1 \startStaff \m
\m \m \m \m \m \m \m
\m \m \m \m \m \m
\m \m
}
\markup \huge \bold \column { " " " Further possibilities" " " }
\score {
\new StaffGroup \with {
instrumentName = "SYS"
shortInstrumentName = "sys" }
<<
\new Staff \with {
instrumentName = "HI"
shortInstrumentName = "hi" }
<< \demo \demoHi >>
\new RhythmicStaff \with {
instrumentName = "LO"
shortInstrumentName = "lo" }
{ \demoLo }
>>
\layout {
\override Score.InstrumentName.self-alignment-X = #RIGHT
\override Score.InstrumentName.padding = 2
}
}
%%%%%%%% END %%%%%%%%