]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/new-dynamic-engraver.cc
Merge branch 'master' of git://git.savannah.gnu.org/lilypond.git
[lilypond.git] / lily / new-dynamic-engraver.cc
index af943c4aa8583c7d64965de3dab8c6d01a800e9c..331d6056168363eb84aac48861b21aa7ec2a2360 100644 (file)
@@ -1,7 +1,7 @@
 /*
   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
@@ -36,6 +36,7 @@ class New_dynamic_engraver : public Engraver
   DECLARE_ACKNOWLEDGER (note_column);
   DECLARE_TRANSLATOR_LISTENER (absolute_dynamic);
   DECLARE_TRANSLATOR_LISTENER (span_dynamic);
+  DECLARE_TRANSLATOR_LISTENER (break_span);
 
 protected:
   virtual void process_music ();
@@ -54,6 +55,7 @@ private:
   Item *script_;
   Stream_event *script_event_;
   Stream_event *current_span_event_;
+  bool end_new_spanner_;
 };
 
 New_dynamic_engraver::New_dynamic_engraver ()
@@ -64,6 +66,7 @@ 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);
@@ -82,6 +85,22 @@ New_dynamic_engraver::listen_span_dynamic (Stream_event *ev)
   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,
@@ -132,6 +151,13 @@ New_dynamic_engraver::process_music ()
                                           (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
        {
@@ -144,6 +170,12 @@ New_dynamic_engraver::process_music ()
          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_))
@@ -186,6 +218,7 @@ New_dynamic_engraver::stop_translation_timestep ()
   script_event_ = 0;
   accepted_spanevents_drul_.set (0, 0);
   finished_spanner_ = 0;
+  end_new_spanner_ = false;
 }
 
 void
@@ -227,10 +260,16 @@ New_dynamic_engraver::acknowledge_note_column (Grob_info info)
   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);
        }
     }
@@ -244,10 +283,7 @@ New_dynamic_engraver::acknowledge_note_column (Grob_info info)
 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 "