X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fdynamic-align-engraver.cc;h=ae3f968c58084d7dd94a16e31590b822b45d0ad4;hb=a6a51abfd0195a3cf7d6ea095cf69808852f21ce;hp=77feb08628aef71e3284371c409c57530583b1bd;hpb=19e6facfeb5c2809ea8099bfaa81339cc44b04b3;p=lilypond.git diff --git a/lily/dynamic-align-engraver.cc b/lily/dynamic-align-engraver.cc index 77feb08628..ae3f968c58 100644 --- a/lily/dynamic-align-engraver.cc +++ b/lily/dynamic-align-engraver.cc @@ -1,10 +1,21 @@ -/* - dynamic-align-engraver.cc -- implement Dynamic_align_engraver - - source file of the GNU LilyPond music typesetter - - (c) 2008 Han-Wen Nienhuys - +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2008--2015 Han-Wen Nienhuys + + + 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 @@ -23,51 +34,83 @@ class Dynamic_align_engraver : public Engraver { TRANSLATOR_DECLARATIONS (Dynamic_align_engraver); - DECLARE_ACKNOWLEDGER (note_column); - DECLARE_ACKNOWLEDGER (dynamic); - DECLARE_END_ACKNOWLEDGER (dynamic); + void acknowledge_rhythmic_head (Grob_info); + void acknowledge_stem (Grob_info); + void acknowledge_dynamic (Grob_info); + void acknowledge_footnote_spanner (Grob_info); + void acknowledge_end_dynamic (Grob_info); protected: virtual void stop_translation_timestep (); private: - void create_line_spanner (Stream_event *cause); - Spanner* line_; - - vector ended_; - vector started_; - vector scripts_; - vector support_; - - set running_; + void create_line_spanner (Grob *cause); + void set_spanner_bounds (Spanner *line, bool end); + Spanner *line_; + Spanner *ended_line_; // Spanner manually broken, don't use it for new grobs + Spanner *current_dynamic_spanner_; + vector ended_; + vector started_; + vector scripts_; + vector support_; + + set running_; }; -Dynamic_align_engraver::Dynamic_align_engraver () +Dynamic_align_engraver::Dynamic_align_engraver (Context *c) + : Engraver (c) { line_ = 0; + ended_line_ = 0; + current_dynamic_spanner_ = 0; } -ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic); -ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column); -ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic); void -Dynamic_align_engraver::create_line_spanner (Stream_event* event) +Dynamic_align_engraver::create_line_spanner (Grob *cause) { if (!line_) - line_ = make_spanner ("DynamicLineSpanner", - event ? event->self_scm() : SCM_EOL); + line_ = make_spanner ("DynamicLineSpanner", cause->self_scm ()); } void Dynamic_align_engraver::acknowledge_end_dynamic (Grob_info info) { - if (Spanner::has_interface(info.grob())) + if (has_interface (info.grob ())) ended_.push_back (info.spanner ()); + + /* If the break flag is set, store the current spanner and let new dynamics + * create a new spanner + */ + bool spanner_broken = current_dynamic_spanner_ == info.spanner () + && to_boolean (current_dynamic_spanner_->get_property ("spanner-broken")); + if (spanner_broken && line_) + { + if (ended_line_) + programming_error ("already have a force-ended DynamicLineSpanner."); + ended_line_ = line_; + line_ = 0; + current_dynamic_spanner_ = 0; + } +} + +void +Dynamic_align_engraver::acknowledge_footnote_spanner (Grob_info info) +{ + Grob *parent = info.grob ()->get_parent (Y_AXIS); + if (line_ && parent + && parent->internal_has_interface (ly_symbol2scm ("dynamic-interface"))) + Axis_group_interface::add_element (line_, info.grob ()); } void -Dynamic_align_engraver::acknowledge_note_column (Grob_info info) +Dynamic_align_engraver::acknowledge_rhythmic_head (Grob_info info) +{ + support_.push_back (info.grob ()); +} + +void +Dynamic_align_engraver::acknowledge_stem (Grob_info info) { support_.push_back (info.grob ()); } @@ -76,89 +119,135 @@ void Dynamic_align_engraver::acknowledge_dynamic (Grob_info info) { Stream_event *cause = info.event_cause (); - create_line_spanner (cause); - if (Spanner::has_interface(info.grob())) - started_.push_back (info.spanner ()); - else if (info.item()) - scripts_.push_back (info.item()); + // Check whether an existing line spanner has the same direction + if (line_ && cause) + { + Direction line_dir = get_grob_direction (line_); + Direction grob_dir = to_dir (cause->get_property ("direction")); + + // If we have an explicit direction for the new dynamic grob + // that differs from the current line spanner, break the spanner + if (grob_dir && (line_dir != grob_dir)) + { + if (!ended_line_) + ended_line_ = line_; + line_ = 0; + current_dynamic_spanner_ = 0; + } + } + + create_line_spanner (info.grob ()); + if (has_interface (info.grob ())) + { + started_.push_back (info.spanner ()); + current_dynamic_spanner_ = info.spanner (); + } + else if (info.item ()) + scripts_.push_back (info.item ()); else - info.grob ()->programming_error ("Unknown dynamic grob."); + info.grob ()->programming_error ("unknown dynamic grob"); Axis_group_interface::add_element (line_, info.grob ()); if (cause) { if (Direction d = to_dir (cause->get_property ("direction"))) - set_grob_direction (line_, d); + set_grob_direction (line_, d); + } +} + +void +Dynamic_align_engraver::set_spanner_bounds (Spanner *line, bool end) +{ + if (!line) + return; + + for (LEFT_and_RIGHT (d)) + { + if ((d == LEFT && !line->get_bound (LEFT)) + || (end && d == RIGHT && !line->get_bound (RIGHT))) + { + vector const &spanners + = (d == LEFT) ? started_ : ended_; + + Grob *bound = 0; + if (scripts_.size ()) + bound = scripts_[0]; + else if (spanners.size ()) + bound = spanners[0]->get_bound (d); + else + { + bound = unsmob (get_property ("currentMusicalColumn")); + programming_error ("started DynamicLineSpanner but have no left bound"); + } + + line->set_bound (d, bound); + } } } void Dynamic_align_engraver::stop_translation_timestep () { - for (vsize i = 0; i < started_.size(); i++) + for (vsize i = 0; i < started_.size (); i++) running_.insert (started_[i]); - for (vsize i = 0; i < ended_.size(); i++) + for (vsize i = 0; i < ended_.size (); i++) { Spanner *sp = ended_[i]; - set::iterator it = running_.find (sp); - if (it != running_.end()) - running_.erase (it); + set::iterator it = running_.find (sp); + if (it != running_.end ()) + running_.erase (it); else - started_[i]->programming_error ("Lost track of this dynamic spanner."); + started_[i]->programming_error ("lost track of this dynamic spanner"); } bool end = line_ && running_.empty (); - Direction d = LEFT; - do - { - if (line_ - && ((d == LEFT && !line_->get_bound (LEFT)) - || (end && d == RIGHT && !line_->get_bound (RIGHT)))) - { - vector const &spanners = - (d == LEFT) ? started_ : ended_; - - Grob *bound = 0; - if (scripts_.size()) - bound = scripts_[0]; - else if (spanners.size()) - bound = spanners[0]->get_bound (d); - else - { - programming_error ("Started DynamicLineSpanner but have no left bound."); - bound = unsmob_grob (get_property ("currentMusicalColumn")); - } - - line_->set_bound (d, bound); - } - } - while (flip (&d) != LEFT); - for (vsize i = 0; line_ && i < support_.size (); i++) + // Set the proper bounds for the current spanner and for a spanner that + // is ended now + set_spanner_bounds (ended_line_, true); + set_spanner_bounds (line_, end); + // If the flag is set to break the spanner after the current child, don't + // add any more support points (needed e.g. for style=none, where the + // invisible spanner should NOT be shifted since we don't have a line). + bool spanner_broken = current_dynamic_spanner_ + && to_boolean (current_dynamic_spanner_->get_property ("spanner-broken")); + for (vsize i = 0; line_ && !spanner_broken && i < support_.size (); i++) Side_position_interface::add_support (line_, support_[i]); - if (end) - line_ = 0; + if (end) + { + line_ = 0; + } + ended_line_ = 0; ended_.clear (); started_.clear (); scripts_.clear (); support_.clear (); } +void +Dynamic_align_engraver::boot () +{ + ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic); + ADD_ACKNOWLEDGER (Dynamic_align_engraver, rhythmic_head); + ADD_ACKNOWLEDGER (Dynamic_align_engraver, stem); + ADD_ACKNOWLEDGER (Dynamic_align_engraver, footnote_spanner); + ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic); +} ADD_TRANSLATOR (Dynamic_align_engraver, - /* doc */ - "Align hairpins and dynamic texts on a horizontal line", + /* doc */ + "Align hairpins and dynamic texts on a horizontal line.", - /* create */ - "DynamicLineSpanner ", + /* create */ + "DynamicLineSpanner ", - /* read */ - "currentMusicalColumn ", + /* read */ + "currentMusicalColumn ", - /* write */ - "" - ); + /* write */ + "" + );