From 5944d20489bb5b8e4c4907fa3b3bcae9ec275ccb Mon Sep 17 00:00:00 2001 From: Mark Knoop Date: Thu, 8 Sep 2016 18:56:16 +0100 Subject: Keep a staff alive with multiple layers This allows the `VerticalAxisGroup.remove-layer' property to accept a list of values. The layer will stay alive with any other member of the Keep_alive_together_engrave group with a remove-layer value in that list. The principal reason for this patch was to allow the use of MarkLine contexts in a Frenched score, where the context should stay alive with any single staff in a StaffGroup. This implementation should also allow additional flexibility with ossia and divisi staves. --- .../new/using-marklines-in-a-frenched-score.ly | 97 ++++++++++++++++++++++ input/regression/remove-layer-symbol.ly | 65 +++++++++++++++ lily/hara-kiri-group-spanner.cc | 8 +- lily/keep-alive-together-engraver.cc | 35 +++++++- scm/define-grob-properties.scm | 16 ++-- 5 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 Documentation/snippets/new/using-marklines-in-a-frenched-score.ly create mode 100644 input/regression/remove-layer-symbol.ly diff --git a/Documentation/snippets/new/using-marklines-in-a-frenched-score.ly b/Documentation/snippets/new/using-marklines-in-a-frenched-score.ly new file mode 100644 index 0000000000..0fdefc9138 --- /dev/null +++ b/Documentation/snippets/new/using-marklines-in-a-frenched-score.ly @@ -0,0 +1,97 @@ +\version "2.19.48" +\header { + lsrtags = "contexts-and-engravers, staff-notation" + texidoc = " +Using @{MarkLine} contexts (such as in +@uref{http://lsr.di.unimi.it/LSR/Item?id=1010, LSR1010}) in a +Frenched score can be problematic if all the staves between two +@code{MarkLine}s are removed in one system. The +@code{Keep_alive_together_engraver} can be used within each +@code{StaffGroup} to keep the @code{MarkLine} alive only as long +as the other staves in the group stay alive. +" + doctitle = "Using marklines in a Frenched score" +} +bars = { + \tempo "Allegro" 4=120 + s1*2 + \repeat unfold 5 { \mark \default s1*2 } + \bar "||" + \tempo "Adagio" 4=40 + s1*2 + \repeat unfold 8 { \mark \default s1*2 } + \bar "|." +} +winds = \repeat unfold 120 { c''4 } +trumpet = { \repeat unfold 8 g'2 R1*16 \repeat unfold 4 g'2 R1*8 } +trombone = { \repeat unfold 4 c'1 R1*8 d'1 R1*17 } +strings = \repeat unfold 240 { c''8 } + +#(set-global-staff-size 16) +\paper { + systems-per-page = 5 + ragged-last-bottom = ##f +} + +\layout { + indent = 15\mm + short-indent = 5\mm + \context { + \name MarkLine + \type Engraver_group + \consists Output_property_engraver + \consists Axis_group_engraver + \consists Mark_engraver + \consists Metronome_mark_engraver + \override VerticalAxisGroup.remove-empty = ##t + \override VerticalAxisGroup.remove-layer = #'any + \override VerticalAxisGroup.staff-affinity = #DOWN + \override VerticalAxisGroup.nonstaff-relatedstaff-spacing.basic-distance = 1 + keepAliveInterfaces = #'() + } + \context { + \Staff + \override VerticalAxisGroup.remove-empty = ##t + \override VerticalAxisGroup.remove-layer = ##f + } + \context { + \StaffGroup + \accepts MarkLine + \consists Keep_alive_together_engraver + } + \context { + \Score + \remove Mark_engraver + \remove Metronome_mark_engraver + } +} + +\score { + << + \new StaffGroup = "winds" \with { + instrumentName = "Winds" + shortInstrumentName = "Winds" + } << + \new MarkLine \bars + \new Staff \winds + >> + \new StaffGroup = "brass" << + \new MarkLine \bars + \new Staff = "trumpet" \with { + instrumentName = "Trumpet" + shortInstrumentName = "Tpt" + } \trumpet + \new Staff = "trombone" \with { + instrumentName = "Trombone" + shortInstrumentName = "Tbn" + } \trombone + >> + \new StaffGroup = "strings" \with { + instrumentName = "Strings" + shortInstrumentName = "Strings" + } << + \new MarkLine \bars + \new Staff = "strings" { \strings } + >> + >> +} diff --git a/input/regression/remove-layer-symbol.ly b/input/regression/remove-layer-symbol.ly new file mode 100644 index 0000000000..d6fa93dcdd --- /dev/null +++ b/input/regression/remove-layer-symbol.ly @@ -0,0 +1,65 @@ +\version "2.19.48" + +\header { + texidoc = "The @code{VerticalAxisGroup.remove-layer} property + can be used to keep staves alive with reference to other staves + in the @code{Keep_alive_together_engraver} group." +} + +\layout { + indent = 40\mm + short-indent = 15\mm +} + +\score { + << + \new Staff \with { + instrumentName = "Continuous" + shortInstrumentName = "cont" + } { \repeat unfold 104 g'4 \bar "|." } + \new StaffGroup \with { + \consists Keep_alive_together_engraver + } << + \new Staff \with { + keepAliveInterfaces = #'() + instrumentName = \markup \center-column { "Alive with A or B" } + shortInstrumentName = "with A or B" + \override VerticalAxisGroup.remove-empty = ##t + \override VerticalAxisGroup.remove-first = ##t + \override VerticalAxisGroup.remove-layer = #'any + } { \repeat unfold 104 c''4 } + \new Staff \with { + instrumentName = "A" + shortInstrumentName = "A" + \override VerticalAxisGroup.remove-empty = ##t + \override VerticalAxisGroup.remove-first = ##t + \override VerticalAxisGroup.remove-layer = ##f + } { + \repeat unfold 16 c'4 + R1*4 + \repeat unfold 16 c'4 + R1*14 + } + \new Staff \with { + keepAliveInterfaces = #'() + instrumentName = \markup \center-column { "Alive with A" } + shortInstrumentName = "with A" + \override VerticalAxisGroup.remove-empty = ##t + \override VerticalAxisGroup.remove-first = ##t + \override VerticalAxisGroup.remove-layer = #'above + } { \repeat unfold 104 c''4 } + \new Staff \with { + instrumentName = "B" + shortInstrumentName = "B" + \override VerticalAxisGroup.remove-empty = ##t + \override VerticalAxisGroup.remove-first = ##t + \override VerticalAxisGroup.remove-layer = ##f + } { + R1*8 + \repeat unfold 16 c'4 + R1*13 + c'1 + } + >> + >> +} diff --git a/lily/hara-kiri-group-spanner.cc b/lily/hara-kiri-group-spanner.cc index 06410786a6..76207a5c92 100644 --- a/lily/hara-kiri-group-spanner.cc +++ b/lily/hara-kiri-group-spanner.cc @@ -190,9 +190,11 @@ Hara_kiri_group_spanner::add_interesting_item (Grob *me, Grob *n) ADD_INTERFACE (Hara_kiri_group_spanner, "A group spanner that keeps track of interesting items. If it" " doesn't contain any after line breaking, it removes itself" - " and all its children. Children may be prioritized in layers" - " via @code{remove-layer}, in which case only the" - " lowest-numbered non-empty layer is retained.", + " and all its children. Greater control can be exercised via" + " @code{remove-layer} which can prioritize layers so only the" + " lowest-numbered non-empty layer is retained; make the layer" + " independent of the group; or make it dependent on any other" + " member of the group", /* properties */ "items-worth-living " diff --git a/lily/keep-alive-together-engraver.cc b/lily/keep-alive-together-engraver.cc index 9b1cbe4a23..8931a819c6 100644 --- a/lily/keep-alive-together-engraver.cc +++ b/lily/keep-alive-together-engraver.cc @@ -22,6 +22,7 @@ #include "engraver.hh" #include "grob.hh" #include "grob-array.hh" +#include "international.hh" #include "translator.icc" @@ -64,12 +65,44 @@ Keep_alive_together_engraver::finalize () { if (i == j) continue; + + if (scm_is_symbol (this_layer)) + { + if (scm_is_eq (this_layer, ly_symbol2scm ("any"))) + { + // layer is kept alive by any other layer + live->add (group_spanners_[j]); + continue; + } + else if (scm_is_eq (this_layer, ly_symbol2scm ("above"))) + { + // layer is kept alive by the layer preceding it + if (i == j + 1) + live->add (group_spanners_[j]); + continue; + } + else if (scm_is_eq (this_layer, ly_symbol2scm ("below"))) + { + // layer is kept alive by the layer following it + if (i == j - 1) + live->add (group_spanners_[j]); + continue; + } + else + { + group_spanners_[i]->warning (_f ("unknown remove-layer value `%s'", + ly_symbol2string (this_layer).c_str ())); + continue; + } + } + SCM that_layer = group_spanners_[j]->get_property ("remove-layer"); + if (scm_is_false (that_layer)) continue; if (!scm_is_integer (this_layer)) { - // Unspecified layers are kept alive by anything else + // unset layers are kept alive by all but ignored layers live->add (group_spanners_[j]); continue; } diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 7ca44b6f3d..d55ab4c8c7 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -809,12 +809,16 @@ number, the quicker the slur attains its @code{height-limit}.") interesting items.") (remove-first ,boolean? "Remove the first staff of an orchestral score?") - (remove-layer ,integer? "The @code{Keep_alive_together_engraver} -removes all @code{VerticalAxisGroup} grobs with a @code{remove-layer} -larger than the smallest retained @code{remove-layer}. Set to -@code{#f} to make a layer invisible to the -@code{Keep_alive_together_engraver}, set to @code{'()} to have it not -participate in the layering decisions.") + (remove-layer ,key? "When set as a positive integer, the +@code{Keep_alive_together_engraver} removes all +@code{VerticalAxisGroup} grobs with a @code{remove-layer} larger than +the smallest retained @code{remove-layer}. Set to @code{#f} to make a +layer independent of the @code{Keep_alive_together_engraver}. Set to +@code{'()}, the layer does not participate in the layering decisions. +The property can also be set as a symbol for common behaviors: +@code{#'any} to keep the layer alive with any other layer in the +group; @code{#'above} or @code{#'below} to keep the layer alive with +the context immediately before or after it, respectively.") (replacement-alist ,list? "Alist of strings. The key is a string of the pattern to be replaced. The value is a string of what should be displayed. Useful for ligatures.") -- cgit v1.2.3