/*
This file is part of LilyPond, the GNU music typesetter.
- Copyright (C) 2008--2009 Han-Wen Nienhuys <hanwen@lilypond.org>
+ 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
DECLARE_ACKNOWLEDGER (note_column);
DECLARE_TRANSLATOR_LISTENER (absolute_dynamic);
DECLARE_TRANSLATOR_LISTENER (span_dynamic);
+ DECLARE_TRANSLATOR_LISTENER (break_span);
protected:
virtual void process_music ();
Item *script_;
Stream_event *script_event_;
Stream_event *current_span_event_;
+ bool end_new_spanner_;
};
New_dynamic_engraver::New_dynamic_engraver ()
finished_spanner_ = 0;
current_spanner_ = 0;
accepted_spanevents_drul_.set (0, 0);
+ end_new_spanner_ = false;
}
IMPLEMENT_TRANSLATOR_LISTENER (New_dynamic_engraver, absolute_dynamic);
ASSIGN_EVENT_ONCE (accepted_spanevents_drul_[d], ev);
}
+IMPLEMENT_TRANSLATOR_LISTENER (New_dynamic_engraver, break_span);
+void
+New_dynamic_engraver::listen_break_span (Stream_event *event)
+{
+ if (event->in_event_class ("break-dynamic-span-event"))
+ {
+ // Case 1: Already have a start dynamic event -> break applies to new
+ // spanner (created later) -> set a flag
+ // Case 2: no new spanner, but spanner already active -> break it now
+ if (accepted_spanevents_drul_[START])
+ end_new_spanner_ = true;
+ else if (current_spanner_)
+ current_spanner_->set_property ("spanner-broken", SCM_BOOL_T);
+ }
+}
+
SCM
New_dynamic_engraver::get_property_setting (Stream_event *evt,
char const *evprop,
(start_type + "Text").c_str ());
if (Text_interface::is_markup (text))
current_spanner_->set_property ("text", text);
+ /*
+ If the line of a text spanner is hidden, end the alignment spanner
+ early: this allows dynamics to be spaced individually instead of
+ being linked together.
+ */
+ if (current_spanner_->get_property ("style") == ly_symbol2scm ("none"))
+ current_spanner_->set_property ("spanner-broken", SCM_BOOL_T);
}
else
{
current_spanner_ = make_spanner ("Hairpin",
current_span_event_->self_scm ());
}
+ // if we have a break-dynamic-span event right after the start dynamic, break the new spanner immediately
+ if (end_new_spanner_)
+ {
+ current_spanner_->set_property ("spanner-broken", SCM_BOOL_T);
+ end_new_spanner_ = false;
+ }
if (finished_spanner_)
{
if (Hairpin::has_interface (finished_spanner_))
if (finished_spanner_)
finished_spanner_->set_bound (RIGHT, script_);
if (current_spanner_)
- {
- current_spanner_->set_bound (LEFT, script_);
-
- if (!Hairpin::has_interface (current_spanner_))
- set_nested_property (current_spanner_,
- scm_list_3 (ly_symbol2scm ("bound-details"),
- ly_symbol2scm ("left"),
- ly_symbol2scm ("attach-dir")),
- scm_from_int (RIGHT));
- }
+ current_spanner_->set_bound (LEFT, script_);
}
}
script_event_ = 0;
accepted_spanevents_drul_.set (0, 0);
finished_spanner_ = 0;
+ end_new_spanner_ = false;
}
void
if (script_ && !script_->get_parent (X_AXIS))
{
extract_grob_set (info.grob (), "note-heads", heads);
- if (heads.size ())
+ /*
+ Spacing constraints may require dynamics to be aligned on rests,
+ so check for a rest if this note column has no note heads.
+ */
+ Grob *x_parent = (heads.size ()
+ ? heads[0]
+ : unsmob_grob (info.grob ()->get_object ("rest")));
+ if (x_parent)
{
- Grob *head = heads[0];
- script_->set_parent (head, X_AXIS);
+ script_->set_parent (x_parent, X_AXIS);
Self_alignment_interface::set_center_parent (script_, X_AXIS);
}
}
ADD_ACKNOWLEDGER (New_dynamic_engraver, note_column);
ADD_TRANSLATOR (New_dynamic_engraver,
/* doc */
- "Create hairpins, dynamic texts, and their vertical"
- " alignments. The symbols are collected onto a"
- " @code{DynamicLineSpanner} grob which takes care of vertical"
- " positioning.",
+ "Create hairpins, dynamic texts and dynamic text spanners.",
/* create */
"DynamicTextSpanner "