]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/dynamic-engraver.cc
release: 1.3.49
[lilypond.git] / lily / dynamic-engraver.cc
index d36142c8e2931fc84477c6b03b6c050e0c4e6c74..019ef105db37ec8af9743e597e07154bab966aca 100644 (file)
@@ -7,6 +7,7 @@
 */
 #include "debug.hh"
 #include "dimensions.hh"
+#include "dimension-cache.hh"
 #include "crescendo.hh"
 #include "musical-request.hh"
 #include "lookup.hh"
 #include "directional-element-interface.hh"
 #include "staff-symbol-referencer.hh"
 #include "translator-group.hh"
+#include "axis-group-interface.hh"
+
 
 /*
- Wat mij betreft wel DYN_LINE
- */
-#define DYN_LINE
+  TODO:
 
+  * direction of text-dynamic-request if not equalt to direction
+  of line-spanner
+
+  * FIXME: this has gotten a bit too hairy.
+ */
 
-#ifdef DYN_LINE
 class Dynamic_line_spanner : public Spanner
 {
 public:
   Dynamic_line_spanner ();
-  
+  VIRTUAL_COPY_CONS(Score_element);
   void add_column (Note_column*);
-  Direction get_default_dir () const;
-protected:
-  virtual void do_post_processing ();
+  void add_element (Score_element*);
 };
 
 Dynamic_line_spanner::Dynamic_line_spanner ()
 {
   set_elt_property ("transparent", SCM_BOOL_T);
   side_position (this).set_axis (Y_AXIS);
+  Axis_group_interface (this).set_interface ();
+  Axis_group_interface (this).set_axes (X_AXIS, Y_AXIS);
 }
 
 void
 Dynamic_line_spanner::add_column (Note_column* n)
 {
-  if (!spanned_drul_[LEFT])
-    set_bounds (LEFT, n);
-  set_bounds (RIGHT, n);
+  if (!get_bound (LEFT))
+    set_bound (LEFT, n);
+  else
+    set_bound (RIGHT, n);
 
   add_dependency (n);
 }
 
-Direction
-Dynamic_line_spanner::get_default_dir () const
-{
-  return DOWN;
-}
 
 void
-Dynamic_line_spanner::do_post_processing ()
+Dynamic_line_spanner::add_element (Score_element* e)
 {
-  Spanner::do_post_processing ();
-  Direction dir = directional_element (this).get ();
-  if (!dir)
-    dir = get_default_dir ();
-
-  /*
-    Hier is ook vast iets voor?
-   */
-  Staff_symbol_referencer_interface si (this);
-  Real above_staff = si.line_count () + 2;
-
-#if 0
-  // Aargh, nu snap ik waarom ik het niet snap
-  // zie Staff_symbol_referencer_interface::set_position 
-
-  if (si.position_f () * dir < above_staff)
-    si.set_position (above_staff * (int)dir);
-
-  SCM s = get_elt_property ("padding");
-  if (gh_number_p (s))
-    {
-      si.set_position (si.position_f () + gh_scm2double (s) * (int) dir);
-    }
-#else
-  Real dy = 0;
-  Real pos = si.position_f () * dir;
-  if (pos * dir < above_staff)
-    dy = above_staff;
-
-  SCM s = get_elt_property ("padding");
-  if (gh_number_p (s))
-    dy += gh_scm2double (s);
-  
-  Real half_space = si.staff_space () / 2;
-  translate_axis (dy*half_space*dir, Y_AXIS);
-#endif
-  
+  e->set_parent (this, Y_AXIS);
+  Axis_group_interface (this).add_element (e); 
 }
 
-#endif
-/*
-  TODO:
-    Baseline alignment / character metrics of dynamic symbols.
- */
-
 /**
    print text & hairpin dynamics.
  */
@@ -125,12 +85,12 @@ class Dynamic_engraver : public Engraver
   Span_req * span_start_req_l_;
   Drul_array<Span_req*> span_req_l_drul_;
 
-#ifdef DYN_LINE
   Dynamic_line_spanner* line_spanner_;
-#else
-  Spanner* line_spanner_;
-#endif
+  Dynamic_line_spanner* finished_line_spanner_;
   Moment last_request_mom_;
+
+  Array<Note_column*> pending_column_arr_;
+  Link_array<Score_element> pending_element_arr_;
   
   void  typeset_all ();
 
@@ -144,7 +104,7 @@ protected:
   virtual void do_removal_processing ();
   virtual void acknowledge_element (Score_element_info);
   virtual bool do_try_music (Music *req_l);
-  virtual void do_process_requests ();
+  virtual void do_process_music ();
   virtual void do_pre_move_processing ();
   virtual void do_post_move_processing ();
 };
@@ -165,6 +125,7 @@ Dynamic_engraver::Dynamic_engraver ()
   text_p_ = 0;
   finished_cresc_p_ = 0;
   line_spanner_ = 0;
+  finished_line_spanner_ = 0;
   span_start_req_l_ = 0;
   cresc_p_ =0;
 
@@ -205,54 +166,98 @@ Dynamic_engraver::do_try_music (Music * m)
 }
 
 void
-Dynamic_engraver::do_process_requests ()
+Dynamic_engraver::do_process_music ()
 {
-  if ((span_req_l_drul_[START] || text_req_l_) && !line_spanner_)
+  if ((span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
+      && !line_spanner_
+      && pending_element_arr_.size ())
     {
-#ifdef DYN_LINE
       line_spanner_ = new Dynamic_line_spanner;
-#else
-      line_spanner_ = new Spanner;
-      line_spanner_->set_elt_property ("transparent", SCM_BOOL_T);
-      side_position (line_spanner_).set_axis (Y_AXIS);
-#endif
+      for (int i = 0; i < pending_column_arr_.size (); i++)
+       line_spanner_->add_column (pending_column_arr_[i]);
+      pending_column_arr_.clear ();
       announce_element (Score_element_info
                        (line_spanner_,
                         text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
 
     }
-         
-  if (span_req_l_drul_[START] || text_req_l_)
-    last_request_mom_ = now_mom ();
-  
-#ifndef DYN_LINE
-  if (line_spanner_)
+
+  if (line_spanner_ && pending_element_arr_.size ())
+    {
+      for (int i = 0; i < pending_element_arr_.size (); i++)
+       line_spanner_->add_element (pending_element_arr_[i]);
+      pending_element_arr_.clear ();
+    }
+
+  /*
+    TODO: This should be optionised:
+      * break when group of dynamic requests ends
+      * break now  (only if no cresc. in progress)
+      * continue through piece */
+  if (span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
+    {
+      last_request_mom_ = now_mom ();
+    }
+  else
     {
       /*
-       Generic property will handle this for a Dynamic_line_spanner
+       During a (de)crescendo, pending request will not be cleared,
+       and a line-spanner will always be created, as \< \! are already
+       two requests.
+
+       Maybe always creating a line-spanner for a (de)crescendo (see
+       below) is not a good idea:
+
+            a\< b\p \!c
+
+       the \p will be centred on the line-spanner, and thus clash
+       with the hairpin.  When axis-group code is in place, the \p
+       should move below the hairpin, which is probably better?
+
+       Urg, but line-spanner must always have at least same duration
+       as (de)crecsendo, b.o. line-breaking.
        */
-      Direction dir = DOWN;
-      SCM s = get_property ("dynamicDirection");
-      if (!isdir_b (s))
+      if (now_mom () > last_request_mom_ && !span_start_req_l_)
        {
-         s = get_property ("verticalDirection");
+         for (int i = 0; i < pending_element_arr_.size (); i++)
+           {
+             Score_element* e = pending_element_arr_[i];
+             side_position (e).set_axis (Y_AXIS);
+             side_position (e).add_staff_support ();
+
+             /*
+               UGH UGH 
+             */
+             Direction d = directional_element (e).get ();
+             if (!d)
+               {
+                 SCM s = get_property ("dynamicDirection");
+                 if (!isdir_b (s))
+                   s = get_property ("verticalDirection");
+                 if (isdir_b (s))
+                   d = to_dir (s);
+                 directional_element (e).set (d);
+               }
+         
+             SCM s = get_property ("dynamicPadding");
+             if (gh_number_p (s))
+               e->set_elt_property ("padding", s);
+             s = get_property ("dynamicMinimumSpace");
+             if (gh_number_p (s))
+               e->set_elt_property ("minimum-space", s);
+           }
+         pending_element_arr_.clear ();
+         if (line_spanner_)
+           {
+             for (int i = 0; i < pending_column_arr_.size (); i++)
+               line_spanner_->add_column (pending_column_arr_[i]);
+             pending_column_arr_.clear ();
+             finished_line_spanner_ = line_spanner_;
+             line_spanner_ = 0;
+           }
        }
-      
-      if (isdir_b (s) && to_dir (s))
-       dir = to_dir (s);
-      
-      line_spanner_->set_elt_property ("direction", gh_int2scm ((int)dir));
-
-      s = get_property ("dynamicPadding");
-      Real padding;
-      if (gh_number_p (s))
-       padding = gh_scm2double (s);
-      else
-       padding = 2;
-      line_spanner_->set_elt_property ("padding", gh_double2scm (padding));
-    }
-#endif 
-  
+    } 
+
   if (text_req_l_)
     {
       String loud = text_req_l_->text_str_;
@@ -263,9 +268,12 @@ Dynamic_engraver::do_process_requests ()
       text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
       text_p_->set_elt_property ("script-priority",
                                          gh_int2scm (100));
-         
-      assert (line_spanner_);
-      text_p_->set_parent (line_spanner_, Y_AXIS);
+      if (Direction d=text_req_l_->get_direction ())
+       directional_element (text_p_).set (d);
+      pending_element_arr_.push (text_p_);
+      text_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
+      text_p_->add_offset_callback (Side_position_interface::aligned_on_self,
+                                   Y_AXIS);
       announce_element (Score_element_info (text_p_, text_req_l_));
     }
 
@@ -279,7 +287,7 @@ Dynamic_engraver::do_process_requests ()
       else
        {
          assert (!finished_cresc_p_);
-         cresc_p_->set_bounds(RIGHT, get_staff_info ().musical_pcol_l ());
+         cresc_p_->set_bound (RIGHT, get_staff_info ().musical_pcol_l ());
          finished_cresc_p_ = cresc_p_;
          cresc_p_ = 0;
          span_start_req_l_ = 0;
@@ -314,6 +322,11 @@ Dynamic_engraver::do_process_requests ()
            }
 
          s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
+
+
+         /*
+           TODO: Use symbols.
+          */
          if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
            {
              cresc_p_->set_elt_property ("spanner", s);
@@ -321,10 +334,25 @@ Dynamic_engraver::do_process_requests ()
                                            + "Spanner", SCM_UNDEFINED);
            }
 
-         cresc_p_->set_bounds(LEFT, get_staff_info ().musical_pcol_l ());
-         cresc_p_->set_bounds(RIGHT, get_staff_info ().musical_pcol_l ());
+         cresc_p_->set_bound (LEFT, get_staff_info ().musical_pcol_l ());
+
 
-         // arrragh, brr, urg: we know how wide text is, no?
+         /* 
+             We know how wide the text is, if we can be sure that the
+             text already has relevant pointers into the paperdef,
+             and it has its font-size property set.
+
+             Since font-size may be set by a context higher up, we
+             can not be sure of the size.
+
+
+             We shouldn't try to do this stuff here, the Item should
+             do it when the score is finished.  We could maybe
+             set a callback to have the Item do the alignment if
+             it is not a special symbol, like Crescendo.
+         */
+
+            
          if (text_p_)
            {
              index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
@@ -333,9 +361,10 @@ Dynamic_engraver::do_process_requests ()
                index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
                                RIGHT, SCM_BOOL_T);
            }
-
-         assert (line_spanner_);
-         cresc_p_->set_parent (line_spanner_, Y_AXIS);
+         pending_element_arr_.push (cresc_p_);
+         cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
+         cresc_p_->add_offset_callback
+           (Side_position_interface::aligned_on_self, Y_AXIS);
          announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
        }
     }
@@ -359,24 +388,17 @@ Dynamic_engraver::do_removal_processing ()
   typeset_all ();
   if (line_spanner_)
     {
-#ifndef DYN_LINE
-      Direction dir = directional_element (line_spanner_).get ();
-      Real staff_space = Staff_symbol_referencer_interface (line_spanner_).staff_space ();
-      SCM s = line_spanner_->get_elt_property ("padding");
-      line_spanner_->translate_axis (gh_scm2double (s) * staff_space * (int)dir, Y_AXIS);
-#endif
+      side_position (line_spanner_).add_staff_support ();
       typeset_element (line_spanner_);
       line_spanner_ = 0;
     }
 }
 
-
 void
 Dynamic_engraver::typeset_all ()
 {  
   if (finished_cresc_p_)
     {
-      finished_cresc_p_->set_bounds (RIGHT, get_staff_info ().musical_pcol_l ());
       typeset_element (finished_cresc_p_);
       finished_cresc_p_ =0;
     }
@@ -386,43 +408,27 @@ Dynamic_engraver::typeset_all ()
       typeset_element (text_p_);
       text_p_ = 0;
     }
-
-  /*
-    TODO: This should be optionised:
-      * break when group of dynamic requests ends
-      * break now 
-      * continue through piece
-   */
-  if (line_spanner_ && last_request_mom_ < now_mom ())
+  if (finished_line_spanner_)
     {
-#ifndef DYN_LINE
-      Direction dir = directional_element (line_spanner_).get ();
-      Real staff_space = Staff_symbol_referencer_interface (line_spanner_).staff_space ();
-      SCM s = line_spanner_->get_elt_property ("padding");
-      line_spanner_->translate_axis (gh_scm2double (s) * staff_space * (int)dir, Y_AXIS);
-#endif
-      typeset_element (line_spanner_);
-      line_spanner_ = 0;
+      side_position (finished_line_spanner_).add_staff_support ();
+      typeset_element (finished_line_spanner_);
+      finished_line_spanner_ = 0;
     }
 }
 
 void
 Dynamic_engraver::acknowledge_element (Score_element_info i)
 {
-  if (line_spanner_)
+  if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
     {
-      if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
+      if (line_spanner_)
        {
          side_position (line_spanner_).add_support (n);
-#ifdef DYN_LINE
          line_spanner_->add_column (n);
-#else
-         if (!line_spanner_->spanned_drul_[LEFT])
-           line_spanner_->set_bounds (LEFT, n);
-         line_spanner_->set_bounds (RIGHT, n);
-         
-         line_spanner_->add_dependency (n);
-#endif
+       }
+      else
+       {
+         pending_column_arr_.push (n);
        }
     }
 }