]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/spacing-spanner.cc
Merge branch 'master' of ssh+git://hanwen@git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / lily / spacing-spanner.cc
index 3e6ca278994f674bc83bd373c9fe743a450df7b8..512bfe4166a71565a5464b42d1a42630ebf05d5b 100644 (file)
@@ -11,8 +11,6 @@
 #include <math.h>
 #include <cstdio>
 
-using namespace std;
-
 #include "spacing-options.hh"
 #include "international.hh"
 #include "main.hh"
@@ -22,6 +20,7 @@ using namespace std;
 #include "paper-column.hh"
 #include "paper-score.hh"
 #include "pointer-group-interface.hh"
+#include "separation-item.hh"
 #include "spaceable-grob.hh"
 #include "spacing-interface.hh"
 #include "staff-spacing.hh"
@@ -209,22 +208,101 @@ Spacing_spanner::generate_pair_spacing (Grob *me,
     }
 }
 
+static void
+set_column_rods (vector<Grob*> const &cols, Real padding)
+{
+  /* distances[i] will be the minimum distance between column i and column i+1 */
+  vector<Real> distances;
+
+  for (vsize i = 1; i < cols.size (); i++)
+    {
+      assert (distances.size () == i-1);
+
+      Item *r = dynamic_cast<Item*> (cols[i]);
+      Item *rb = r->find_prebroken_piece (LEFT);
+
+      if (Separation_item::is_empty (r) && (!rb || Separation_item::is_empty (rb)))
+       {
+         distances.push_back (0);
+         continue;
+       }
+
+      Skyline_pair *skys = Skyline_pair::unsmob (r->get_property ("horizontal-skylines"));
+      Real right_stickout = skys ? (*skys)[LEFT].max_height () : 0.0;
+
+      /* min rather than max because right-stickout will be negative if the right-hand column
+        sticks out a lot to the left */
+      right_stickout = min (right_stickout,
+                           Separation_item::conditional_skyline (r, cols[i-1]).max_height ());
+
+      Drul_array<Item*> r_cols (r, rb);
+      Drul_array<Real> cur_dist (0.0, 0.0);
+
+      /* This is an inner loop and hence it is potentially quadratic. However, we only continue
+        as long as there is a rod to insert. Therefore, this loop will usually only execute
+        a constant number of times per iteration of the outer loop. */
+      for (vsize j = i; j--;)
+       {
+         Item *l = dynamic_cast<Item*> (cols[j]);
+         Item *lb = l->find_prebroken_piece (RIGHT);
+         Skyline_pair *skys = Skyline_pair::unsmob (l->get_property ("horizontal-skylines"));
+         Real left_stickout = skys ? (*skys)[RIGHT].max_height () : 0.0;
+         bool done = true;
+
+         Direction d = LEFT;
+         do
+           {
+             if (j < i-1)
+               cur_dist[d] += distances[j];
+
+             Item *r_col = r_cols[d];
+             bool touches = right_stickout - left_stickout + cur_dist[d] < 0.0;
+             Real dist = 0.0;
+
+             /* we set a distance for the line-starter column even if it's non-broken counterpart
+                doesn't touch the right column. */
+             if (lb)
+               Separation_item::set_distance (lb, r_col, padding);
+
+             if (touches || j == i-1)
+               dist = Separation_item::set_distance (l, r_col, padding);
+
+             if (j == i-1 && d == LEFT)
+               distances.push_back (dist);
+
+             if (j == i-1)
+               cur_dist[d] = distances[j];
+
+             done = done && !touches;
+           }
+         while (flip (&d) != LEFT && rb);
+
+         /* we need the empty check for gregorian notation, where there are a lot of
+            extraneous paper-columns that we need to skip over */
+         if (done && !Separation_item::is_empty (l))
+           break;
+       }
+    }
+}
+
+
 void
 Spacing_spanner::generate_springs (Grob *me,
                                   vector<Grob*> const &cols,
                                   Spacing_options const *options)
 {
-  Paper_column *prev = 0;
-  for (vsize i = 0; i < cols.size (); i++)
+  Paper_column *prev = dynamic_cast<Paper_column*> (cols[0]);
+  for (vsize i = 1; i < cols.size (); i++)
     {
       Paper_column *col = dynamic_cast<Paper_column *> (cols[i]);
       Paper_column *next = (i + 1 < cols.size ()) ? dynamic_cast<Paper_column *> (cols[i+1]) : 0;
       
-      if (i > 0)
-       generate_pair_spacing (me, prev, col, next, options);
+      generate_pair_spacing (me, prev, col, next, options);
 
       prev = col;
     }
+
+  set_column_rods (cols, 0.1); // FIXME: padding
 }
 
 /*
@@ -259,7 +337,16 @@ Spacing_spanner::musical_column_spacing (Grob *me,
            This is probably a waste of time in the case of polyphonic
            music.  */
          if (Note_spacing::has_interface (wish))
-           springs.push_back (Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_));
+           {
+             Real inc = options->increment_;
+             if (Grob *gsp = unsmob_grob (left_col->get_object ("grace-spacing")))
+               {
+                 Spacing_options grace_opts;
+                 grace_opts.init_from_grob (gsp);
+                 inc = grace_opts.increment_;
+               }
+             springs.push_back (Note_spacing::get_spacing (wish, right_col, base_note_space, inc));
+           }
        }
 
       if (springs.empty ())