From 2134c6269640637cd5a0385ef7e5d53180443e4a Mon Sep 17 00:00:00 2001 From: David Kastrup Date: Wed, 20 Aug 2014 14:27:55 +0200 Subject: [PATCH] Issue 3518: Support temporary divisi staves This provides the low-level support for temporary divisi staves by adding a `VerticalAxisGroup.remove-layer' property of type integer that interacts with the "Keep_alive_together_engraver": when set to a numeric value, staves with the same numeric value are kept alive together as one group. Of several such groups with live staves, only the one with the lowest common numeric `remove-layer' is retained. --- lily/hara-kiri-group-spanner.cc | 12 ++++++-- lily/keep-alive-together-engraver.cc | 42 ++++++++++++++++++++++------ scm/define-grob-properties.scm | 8 ++++++ 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/lily/hara-kiri-group-spanner.cc b/lily/hara-kiri-group-spanner.cc index b7c55b5045..8afef8f5ea 100644 --- a/lily/hara-kiri-group-spanner.cc +++ b/lily/hara-kiri-group-spanner.cc @@ -77,6 +77,11 @@ bool find_in_range (SCM vector, int low, int hi, int min, int max) bool Hara_kiri_group_spanner::request_suicide (Grob *me, int start, int end) { + extract_grob_set (me, "make-dead-when", foes); + for (vsize i = 0; i < foes.size (); i++) + if (foes[i]->is_live () && !request_suicide_alone (foes[i], start, end)) + return true; + if (!request_suicide_alone (me, start, end)) return false; @@ -185,13 +190,16 @@ 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.", + " 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.", /* properties */ "items-worth-living " "important-column-ranks " "keep-alive-with " + "make-dead-when " "remove-empty " "remove-first " + "remove-layer " ); - diff --git a/lily/keep-alive-together-engraver.cc b/lily/keep-alive-together-engraver.cc index 78a10050cd..c65ff45531 100644 --- a/lily/keep-alive-together-engraver.cc +++ b/lily/keep-alive-together-engraver.cc @@ -51,14 +51,40 @@ Keep_alive_together_engraver::finalize () { for (vsize i = 0; i < group_spanners_.size (); ++i) { - SCM grob_array_scm = Grob_array::make_array (); - Grob_array *ga = Grob_array::unsmob (grob_array_scm); - - // It would make Hara_kiri_group_spanner::request_suicide a _little_ - // faster if we removed each grob from its own array. It seems - // unnecessary for now, though. - ga->set_array (group_spanners_); - group_spanners_[i]->set_object ("keep-alive-with", grob_array_scm); + SCM this_layer = group_spanners_[i]->get_property ("remove-layer"); + if (scm_is_false (this_layer)) + continue; + + SCM live_scm = Grob_array::make_array (); + Grob_array *live = Grob_array::unsmob (live_scm); + SCM dead_scm = Grob_array::make_array (); + Grob_array *dead = Grob_array::unsmob (dead_scm); + + for (vsize j = 0; j < group_spanners_.size (); ++j) + { + if (i == j) + 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 + live->add (group_spanners_[j]); + continue; + } + // an explicit layer is only affected by explicit layers + if (!scm_is_integer (that_layer)) + continue; + if (scm_is_true (scm_num_eq_p (that_layer, this_layer))) + live->add (group_spanners_[j]); + else if (scm_is_true (scm_less_p (that_layer, this_layer))) + dead->add (group_spanners_[j]); + } + if (!live->empty ()) + group_spanners_[i]->set_object ("keep-alive-with", live_scm); + if (!dead->empty ()) + group_spanners_[i]->set_object ("make-dead-when", dead_scm); } } diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 485c3519dc..a81eed5009 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -788,6 +788,12 @@ 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.") (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.") @@ -1241,6 +1247,8 @@ empty in a particular staff, then that staff is erased.") (left-neighbor ,ly:grob? "The right-most column that has a spacing-wish for this column.") + (make-dead-when ,ly:grob-array? "An array of other +@code{VerticalAxisGroup}s. If any of them are alive, then we will turn dead.") (melody-spanner ,ly:grob? "The @code{MelodyItem} object for a stem.") (minimum-translations-alist ,list? "An list of translations for a given start and end point.") -- 2.39.2