-/*
- dynamic-align-engraver.cc -- implement Dynamic_align_engraver
-
- source file of the GNU LilyPond music typesetter
-
- (c) 2008--2009 Han-Wen Nienhuys <hanwen@lilypond.org>
-
+/*
+ This file is part of LilyPond, the GNU music typesetter.
+
+ Copyright (C) 2008--2011 Han-Wen Nienhuys <hanwen@lilypond.org>
+
+
+ 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 <http://www.gnu.org/licenses/>.
*/
#include <set>
TRANSLATOR_DECLARATIONS (Dynamic_align_engraver);
DECLARE_ACKNOWLEDGER (note_column);
DECLARE_ACKNOWLEDGER (dynamic);
+ DECLARE_ACKNOWLEDGER (footnote_spanner);
DECLARE_END_ACKNOWLEDGER (dynamic);
protected:
private:
void create_line_spanner (Stream_event *cause);
- Spanner* line_;
-
- vector<Spanner*> ended_;
- vector<Spanner*> started_;
- vector<Grob*> scripts_;
- vector<Grob*> support_;
-
- set<Spanner*> running_;
+ 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<Spanner *> ended_;
+ vector<Spanner *> started_;
+ vector<Grob *> scripts_;
+ vector<Grob *> support_;
+
+ set<Spanner *> running_;
};
Dynamic_align_engraver::Dynamic_align_engraver ()
{
line_ = 0;
+ ended_line_ = 0;
+ current_dynamic_spanner_ = 0;
}
ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column);
+ADD_ACKNOWLEDGER (Dynamic_align_engraver, footnote_spanner);
ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
void
-Dynamic_align_engraver::create_line_spanner (Stream_event* event)
+Dynamic_align_engraver::create_line_spanner (Stream_event *event)
{
if (!line_)
line_ = make_spanner ("DynamicLineSpanner",
- event ? event->self_scm() : SCM_EOL);
+ event ? event->self_scm () : SCM_EOL);
}
void
Dynamic_align_engraver::acknowledge_end_dynamic (Grob_info info)
{
- if (Spanner::has_interface(info.grob()))
+ if (Spanner::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_dynamic (Grob_info info)
{
Stream_event *cause = info.event_cause ();
+ // 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 (cause);
- if (Spanner::has_interface(info.grob()))
- started_.push_back (info.spanner ());
- else if (info.item())
- scripts_.push_back (info.item());
+ if (Spanner::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 ());
}
void
-Dynamic_align_engraver::stop_translation_timestep ()
+Dynamic_align_engraver::set_spanner_bounds (Spanner *line, bool end)
{
- for (vsize i = 0; i < started_.size(); i++)
- running_.insert (started_[i]);
- for (vsize i = 0; i < ended_.size(); i++)
- {
- Spanner *sp = ended_[i];
-
- set<Spanner*>::iterator it = running_.find (sp);
- if (it != running_.end())
- running_.erase (it);
- else
- started_[i]->programming_error ("Lost track of this dynamic spanner.");
- }
-
- bool end = line_ && running_.empty ();
+ if (!line)
+ return;
Direction d = LEFT;
do
{
- if (line_
- && ((d == LEFT && !line_->get_bound (LEFT))
- || (end && d == RIGHT && !line_->get_bound (RIGHT))))
+ if ((d == LEFT && !line->get_bound (LEFT)) ||
+ (end && d == RIGHT && !line->get_bound (RIGHT)))
{
- vector<Spanner*> const &spanners =
- (d == LEFT) ? started_ : ended_;
-
+ vector<Spanner *> const &spanners
+ = (d == LEFT) ? started_ : ended_;
+
Grob *bound = 0;
- if (scripts_.size())
+ if (scripts_.size ())
bound = scripts_[0];
- else if (spanners.size())
+ 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"));
+ programming_error ("started DynamicLineSpanner but have no left bound");
}
- line_->set_bound (d, bound);
+ line->set_bound (d, bound);
}
}
while (flip (&d) != LEFT);
+}
+
+void
+Dynamic_align_engraver::stop_translation_timestep ()
+{
+ for (vsize i = 0; i < started_.size (); i++)
+ running_.insert (started_[i]);
+ for (vsize i = 0; i < ended_.size (); i++)
+ {
+ Spanner *sp = ended_[i];
+
+ set<Spanner *>::iterator it = running_.find (sp);
+ if (it != running_.end ())
+ running_.erase (it);
+ else
+ started_[i]->programming_error ("lost track of this dynamic spanner");
+ }
- for (vsize i = 0; line_ && i < support_.size (); i++)
+ bool end = line_ && running_.empty ();
+
+ // 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 ();
}
-
ADD_TRANSLATOR (Dynamic_align_engraver,
/* doc */
- "Align hairpins and dynamic texts on a horizontal line",
+ "Align hairpins and dynamic texts on a horizontal line.",
/* create */
"DynamicLineSpanner ",