X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fspan-bar-stub-engraver.cc;fp=lily%2Fspan-bar-stub-engraver.cc;h=10d97241bde43c0563d749074c845eb4ca54fcec;hb=32a34dcef0c0041c6d62677487a380b5c8b85712;hp=0000000000000000000000000000000000000000;hpb=f41973ff763d5972a85995b6d40c864281ec6714;p=lilypond.git diff --git a/lily/span-bar-stub-engraver.cc b/lily/span-bar-stub-engraver.cc new file mode 100644 index 0000000000..10d97241bd --- /dev/null +++ b/lily/span-bar-stub-engraver.cc @@ -0,0 +1,192 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2011--2012 Mike Solomon + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#include + +#include "align-interface.hh" +#include "context.hh" +#include "grob.hh" +#include "item.hh" +#include "pointer-group-interface.hh" +#include "engraver.hh" + +/* + The Span_bar_stub_engraver creates SpanBarStub grobs in the contexts + that a grouping context contains. For example, if a PianoStaff contains + two Staffs, a Dynamics, and a Lyrics, SpanBarStubs will be created in + all contexts that do not have bar lines (Dynamics and Lyrics). + + We only want to create these SpanBarStubs in contexts that the SpanBar + traverses. However, Contexts do not contain layout information and it + is thus difficult to know if they will eventually be above or below other + Contexts. To determine this we use the VerticalAxisGroup created in the + Context. We relate VerticalAxisGroups to Contexts in the variable + axis_groups_ and weed out unused contexts after each translation timestep. + + Note that SpanBarStubs exist for pure height calculations ONLY. + They should never be visually present on the page and should never + be engraved in contexts where BarLines are engraved. +*/ + +class Span_bar_stub_engraver : public Engraver +{ + vector spanbars_; + SCM axis_groups_; + +public: + TRANSLATOR_DECLARATIONS (Span_bar_stub_engraver); +protected: + DECLARE_ACKNOWLEDGER (span_bar); + DECLARE_ACKNOWLEDGER (hara_kiri_group_spanner); + void process_acknowledged (); + void stop_translation_timestep (); + virtual void derived_mark () const; +}; + +Span_bar_stub_engraver::Span_bar_stub_engraver () +{ + axis_groups_ = SCM_EOL; +} + +void +Span_bar_stub_engraver::derived_mark () const +{ + scm_gc_mark (axis_groups_); +} + +void +Span_bar_stub_engraver::acknowledge_span_bar (Grob_info i) +{ + spanbars_.push_back (i.grob ()); +} + +void +Span_bar_stub_engraver::acknowledge_hara_kiri_group_spanner (Grob_info i) +{ + axis_groups_ = scm_cons (scm_cons (i.grob ()->self_scm (), i.context ()->self_scm ()), axis_groups_); +} + +void +Span_bar_stub_engraver::process_acknowledged () +{ + if (!spanbars_.size ()) + return; + + if (!scm_is_pair (axis_groups_)) + { + programming_error ("At least one vertical axis group needs to be created in the first time step."); + return; + } + Grob *vertical_alignment = Grob::get_root_vertical_alignment (unsmob_grob (scm_caar (axis_groups_))); + if (!vertical_alignment) // we are at the beginning of a score, so no need for stubs + return; + + for (vsize i = 0; i < spanbars_.size (); i++) + { + extract_grob_set (spanbars_[i], "elements", bars); + vector bar_axis_indices; + for (vsize j = 0; j < bars.size (); j++) + { + int i = Grob::get_vertical_axis_group_index (bars[j]); + if (i >= 0) + bar_axis_indices.push_back ((vsize) i); + } + vector affected_contexts; + vector y_parents; + vector keep_extent; + for (SCM s = axis_groups_; scm_is_pair (s); s = scm_cdr (s)) + { + Context *c = unsmob_context (scm_cdar (s)); + Grob *g = unsmob_grob (scm_caar (s)); + if (!c || !g) + continue; + if (c->is_removable ()) + continue; + + vsize j = Grob::get_vertical_axis_group_index (g); + if (j > bar_axis_indices[0] + && j < bar_axis_indices.back () + && find (bar_axis_indices.begin (), bar_axis_indices.end (), j) == bar_axis_indices.end ()) + { + vsize k = 0; + for (; k < bar_axis_indices.size (); k++) + if (bar_axis_indices[k] > j) + break; + + k--; + + if (c && c->get_parent_context ()) + { + keep_extent.push_back (to_boolean (bars[k]->get_property ("allow-span-bar"))); + y_parents.push_back (g); + affected_contexts.push_back (c); + } + } + } + + for (vsize j = 0; j < affected_contexts.size (); j++) + { + Item *it = new Item (updated_grob_properties (affected_contexts[j], ly_symbol2scm ("SpanBarStub"))); + it->set_parent (spanbars_[i], X_AXIS); + Grob_info gi = make_grob_info (it, spanbars_[i]->self_scm ()); + gi.rerouting_daddy_context_ = affected_contexts[j]; + announce_grob (gi); + if (!keep_extent[j]) + it->suicide (); + } + } + + spanbars_.clear (); +} + +// removes all unused contexts +void +Span_bar_stub_engraver::stop_translation_timestep () +{ + SCM axis_groups = SCM_EOL; + for (SCM s = axis_groups_; scm_is_pair (s); s = scm_cdr (s)) + { + Context *c = unsmob_context (scm_cdar (s)); + Grob *g = unsmob_grob (scm_caar (s)); + if (!c || !g) + continue; + if (c->is_removable ()) + continue; + axis_groups = scm_cons (scm_car (s), axis_groups); + } + axis_groups_ = axis_groups; +} + +#include "translator.icc" + +ADD_ACKNOWLEDGER (Span_bar_stub_engraver, span_bar); +ADD_ACKNOWLEDGER (Span_bar_stub_engraver, hara_kiri_group_spanner); +ADD_TRANSLATOR (Span_bar_stub_engraver, + /* doc */ + "Make stubs for span bars in all contexts that the span bars cross.", + + /* create */ + "SpanBarStub ", + + /* read */ + "", + + /* write */ + "" + );