Indenting individual systems: Difference between revisions
No edit summary |
mNo edit summary |
||
| (3 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
LilyPond scores are indented | LilyPond scores are indented similar to text paragraphs: all systems except the first one are indented by the same amount (the value of the <code>short-indent</code> 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 [https://lists.gnu.org/archive/html/lilypond-user/2014-12/msg00436.html this discussion] of problems with this approach. | |||
This snippet demonstrates | 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 [https://gitlab.com/lilypond/lilypond/-/issues/3761 arcane misuse] of the <code>LeftEdge</code> grob 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. | |||
* The indenting mechanism is based on an | |||
* The code is not protected against multiple calls per system break | |||
<lilypond version="2.24" full> | <lilypond version="2.24" full> | ||
%%%%%%%% HEADER %%%%%%%% | %%%%%%%% HEADER %%%%%%%% | ||
% | % | ||
% | % This code was prompted by | ||
% https://lists.gnu.org/archive/html/lilypond-user/2019-07/msg00139.html | % | ||
% and offers a | % 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 = | pseudoIndent = | ||
#(define-music-function (name-tweaks left-indent) | #(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 { | \paper { | ||
indent = 55 | indent = 55\mm | ||
short-indent = 40 | short-indent = 40\mm | ||
system-system-spacing.basic-distance = 10 | system-system-spacing.basic-distance = 10\mm | ||
tagline = ##f | tagline = ##f | ||
} | } | ||
| Line 160: | Line 234: | ||
m = { f'4 f'4 f'4 f'4 } % one measure | m = { f'4 f'4 f'4 f'4 } % one measure | ||
showInfo = #(define-music-function (info) (markup?) | 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 %%%%%%%% | %%%%%%%% BASIC EXAMPLE %%%%%%%% | ||
basic-info-line = \markup \translate #'(0 . -0.2) | % trace short indentation | ||
\with-color #blue | basic-info-line = \markup \translate #'(0 . -0.2) | ||
\with-color #blue | |||
\draw-dashed-line #'(0 . -49) | |||
v-gap = \markup \vspace #2.25 | v-gap = \markup \vspace #2.25 | ||
basic-info-text = \markup \translate #'(-24 . 8.8) | basic-info-text = \markup \translate #'(-24 . 8.8) \column { | ||
\column { | \italic "(indent)" | ||
\italic "(indent)" | \v-gap | ||
\v-gap | \italic "(short-indent)" | ||
\italic "(short-indent)" | \v-gap | ||
\v-gap | "\pseudoIndent 22" | ||
"\pseudoIndent 22" | \v-gap | ||
\v-gap | "\pseudoIndent 44" | ||
"\pseudoIndent 44" | \v-gap | ||
\v-gap | "\pseudoIndents 22 22" | ||
"\pseudoIndents 22 22" | \v-gap | ||
\v-gap | \line { "\pseudoIndents 0 44" | ||
\line { "\pseudoIndents 0 44" \translate #'(53 . 0) \italic | \translate #'(53 . 0) | ||
\italic "with ragged-right ##f (default)" } | |||
\v-gap | \v-gap | ||
\line { "\pseudoIndents 0 20" \translate #'(72 . 0) \italic | \line { "\pseudoIndents 0 20" | ||
\right-column { "ragged-last ##f" "(default)" }}} | \translate #'(72 . 0) | ||
\italic \right-column { "ragged-last ##f" "(default)" } } | |||
} | |||
basic = { | basic = { | ||
\omit Score.BarNumber | \omit Score.BarNumber | ||
\m \m \m \m \m \m | \m \m \m \m \m \m | ||
\break % a short-indented system for reference (also info anchor:) | \break % a short-indented system for reference (also info anchor:) | ||
\showInfo \markup \combine \basic-info-text \basic-info-line | \showInfo \markup \combine \basic-info-text \basic-info-line | ||
\m \m \m \m \m \m \m | \m \m \m \m \m \m \m | ||
\pseudoIndent 22 | \pseudoIndent 22 | ||
\m \m \m \m \m | \m \m \m \m \m | ||
\pseudoIndent 44 | \pseudoIndent 44 | ||
\m \m \m | \m \m \m | ||
\pseudoIndents 22 22 | \pseudoIndents 22 22 | ||
\m \m \m | \m \m \m | ||
\pseudoIndents 0 44 | \pseudoIndents 0 44 | ||
\m \m \m | \m \m \m | ||
\pseudoIndents 0 20 | \pseudoIndents 0 20 | ||
\m \m \m \m \m \bar "|." | \m \m \m \m \m \bar "|." | ||
| Line 214: | Line 295: | ||
\score { | \score { | ||
\new Staff { \basic } | \new Staff { \basic } | ||
\layout {} | \layout {} | ||
} | } | ||
%%%%%%%% DEMO EXAMPLE %%%%%%%% | %%%%%%%% DEMO EXAMPLE %%%%%%%% | ||
demo-info-line = \markup\translate #'(85.3 . 20.3) | % trace right margin | ||
\with-color #blue | 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) | demo-info-text = \markup \translate #'(-24 . 17.3) \column \italic { | ||
\column \italic { | "right-indent at head" | ||
"right-indent at head" | " " | ||
" " | "stop/startStaff OK" | ||
"stop/startStaff OK" | " " | ||
" " | " " | ||
" " | " " | ||
" " | " " | ||
" " | |||
"(short-indent)" | "(short-indent)" | ||
" " | " " | ||
" " | " " | ||
" " | " " | ||
" " | " " | ||
"outdent without stretching" | "outdent without stretching" | ||
" " | " " | ||
"name-tweaks displaying" | "name-tweaks displaying" | ||
"how its list is ordered" | "how its list is ordered" | ||
" " | " " | ||
" " | " " | ||
\line {"using name-tweaks " | \line { "using name-tweaks " | ||
\column \upright { " " "\"\"" "\\mkCoda" * } | |||
" to " | |||
\column { " " "hide name" | |||
"change name" "(leave name as it is)" } } | |||
} | } | ||
mkCoda = \markup | % See https://wiki.lilypond.community/wiki/Coda_ahead_of_a_line_of_its_own | ||
\vcenter { \bold "coda" \fontsize #3 \musicglyph "scripts.coda" } | mkCoda = \markup \vcenter { | ||
\bold "coda" \fontsize #3 \musicglyph "scripts.coda" } | |||
demo = { | demo = { | ||
\pseudoIndents 0 22 % no additional left-indenting applied | \pseudoIndents 0 22 % no additional left-indenting applied | ||
s1*4 | s1*4 | ||
\break % a short-indented system for reference (also info anchor:) | \break % a short-indented system for reference (also info anchor:) | ||
\showInfo \markup \combine \demo-info-text \demo-info-line | \showInfo \markup \combine \demo-info-text \demo-info-line | ||
s1*7 | s1*7 | ||
\pseudoIndents \markuplist { 1 2 3 } 11 -4 | % display the instrument name ordering | ||
s1*6 | \pseudoIndents \markuplist { 1 2 3 } 11 -4 | ||
\pseudoIndent \markuplist { "" * \mkCoda } 55 | s1*6 | ||
% hide 1; leave 2; change 3 | |||
\pseudoIndent \markuplist { "" * \mkCoda } 55 | |||
s1*2 \bar "|." | s1*2 \bar "|." | ||
} | } | ||
demoHi = { | demoHi = { | ||
\m \m \m \m | \m \m \m \m | ||
\m \m \m \m \m \m \m | \m \m \m \m \m \m \m | ||
\m \m \m \m \m \m | \m \m \m \m \m \m | ||
\m \m | \m \m | ||
} | } | ||
demoLo = { | demoLo = { | ||
\m \m \stopStaff s1 \startStaff \m | \m \m \stopStaff s1 \startStaff \m | ||
\m \m \m \m \m \m \m | \m \m \m \m \m \m \m | ||
\m \m \m \m \m \m | \m \m \m \m \m \m | ||
\m \m | \m \m | ||
} | } | ||
\markup \huge \bold \column { " " " Further possibilities" " "} | \markup \huge \bold \column { " " " Further possibilities" " " } | ||
\score { | \score { | ||
\new StaffGroup | \new StaffGroup \with { | ||
instrumentName = "SYS" | |||
<< | shortInstrumentName = "sys" } | ||
\new Staff | << | ||
\new Staff \with { | |||
instrumentName = "HI" | |||
\new RhythmicStaff | shortInstrumentName = "hi" } | ||
<< \demo \demoHi >> | |||
\new RhythmicStaff \with { | |||
instrumentName = "LO" | |||
shortInstrumentName = "lo" } | |||
{ \demoLo } | { \demoLo } | ||
>> | >> | ||
\layout { | \layout { | ||
\override Score.InstrumentName.self-alignment-X = #RIGHT | \override Score.InstrumentName.self-alignment-X = #RIGHT | ||
| Line 302: | Line 392: | ||
</lilypond> | </lilypond> | ||
[[Category:Workaround]][[Category:Snippet]] | [[Category:Breaks]] | ||
[[Category:Scheme]] | |||
[[Category:Staff notation]] | |||
[[Category:Tweaks and overrides]] | |||
[[Category:Workaround]] | |||
[[Category:Snippet]] | |||