]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/spacing-interface.cc
Run `make grand-replace'.
[lilypond.git] / lily / spacing-interface.cc
index dbfe4e43c6dd1e4dc9cea9cf7632de16aacc7cc5..c5a7e000c1cc6199af743260142262b92ff0ad1e 100644 (file)
@@ -4,7 +4,7 @@
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 2007 Joe Neeman <joeneeman@gmail.com>
+  (c) 2007--2008 Joe Neeman <joeneeman@gmail.com>
 */
 
 #include "spacing-interface.hh"
@@ -17,6 +17,8 @@
 #include "paper-column.hh"
 #include "separation-item.hh"
 #include "skyline.hh"
+#include "skyline-pair.hh"
+#include "system.hh"
 
 /* return the right-pointing skyline of the left-items and the left-pointing
    skyline of the right-items (with the skyline of the left-items in
@@ -38,29 +40,41 @@ Spacing_interface::skylines (Grob *me, Grob *right_col)
   Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
                                    ly_scm2link_array (orig->get_object ("right-items")));
 
+  Grob *system = me->get_system ();
+  Grob *left_col = dynamic_cast<Item*> (me)->get_column ();
+
+  Drul_array<Grob*> columns (left_col, right_col);
+
   Direction d = LEFT;
   do
     {
-      skylines[d].set_minimum_height (0.0);
-
       for (vsize i = 0; i < items[d].size (); i++)
        {
-         Grob *g = items[d][i];
-         if (Item *it = dynamic_cast<Item*> (g))
-           if (Grob *piece = it->find_prebroken_piece (break_dirs[d]))
+         Item *g = dynamic_cast<Item*> (items[d][i]);
+         if (g)
+           if (Item *piece = g->find_prebroken_piece (break_dirs[d]))
              g = piece;
 
-         if (Separation_item::has_interface (g))
+         if (g && Separation_item::has_interface (g) && g->get_column () == columns[d])
            {
              SCM sky_scm = g->get_property ("horizontal-skylines");
              Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
+
+             extract_grob_set (g, "elements", elts);
+             Grob *ycommon = common_refpoint_of_array (elts, g, Y_AXIS);
+             Real shift = ycommon->pure_relative_y_coordinate (system, 0, INT_MAX);
+
+             skylines[d].shift (-shift);
+
              if (sky)
                skylines[d].merge ((*sky)[-d]);
              else
                programming_error ("separation item has no skyline");
-           
+
              if (d == RIGHT && items[LEFT].size ())
                skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
+
+             skylines[d].shift (shift);
            }
        }
     }
@@ -83,6 +97,15 @@ Spacing_interface::minimum_distance (Grob *me, Grob *right)
   this will add a new column to RIGHT-ITEMS. Here we look at the
   columns, and return the left-most. If there are multiple columns, we
   prune RIGHT-ITEMS.
+
+  If we end up pruning, we add a left-neighbor to every column that
+  gets pruned. This ensures that loose columns in cross-staff music
+  do indeed get marked as loose. The problem situation is when a voice
+  passes from staff 1 to staff 2 and a clef appears later on in staff 1.
+  Then the NoteSpacing attached to the last note in staff 1 has two
+  right-items: one pointing to the next note in staff 2 and one pointing
+  to the clef. We will prune the clef right-item here and, unless we add
+  a left-neighbor to the clef, it won't get marked as loose.
 */
 Item *
 Spacing_interface::right_column (Grob *me)
@@ -109,6 +132,8 @@ Spacing_interface::right_column (Grob *me)
 
          mincol = col;
        }
+      else if (rank > min_rank)
+       prune = true;
     }
 
   if (prune && a)
@@ -117,7 +142,15 @@ Spacing_interface::right_column (Grob *me)
       for (vsize i = right.size (); i--;)
        {
          if (dynamic_cast<Item *> (right[i])->get_column () != mincol)
-           right.erase (right.begin () + i);
+           {
+             extract_grob_set (right[i], "left-neighbors", lns);
+             if (lns.empty ())
+               Pointer_group_interface::add_grob (right[i],
+                                                  ly_symbol2scm ("left-neighbors"),
+                                                  dynamic_cast<Item*> (me)->get_column ());
+
+             right.erase (right.begin () + i);
+           }
        }
     }
 
@@ -168,9 +201,57 @@ Spacing_interface::left_note_columns (Grob *me)
   return get_note_columns (elts);
 }
 
+/*
+  Try to find the break-aligned symbol that belongs on the D-side
+  of ME, sticking out in direction -D. The x size is put in LAST_EXT
+*/
+Grob *
+Spacing_interface::extremal_break_aligned_grob (Grob *me,
+                                               Direction d,
+                                               Direction break_dir,
+                                               Interval *last_ext)
+{
+  Grob *col = 0;
+  last_ext->set_empty ();
+  Grob *last_grob = 0;
+
+  extract_grob_set (me, d == LEFT ? "left-break-aligned" : "right-break-aligned", elts);
+
+  for (vsize i = elts.size (); i--;)
+    {
+      Item *break_item = dynamic_cast<Item*> (elts[i]);
+
+      if (break_item->break_status_dir () != break_dir)
+       break_item = break_item->find_prebroken_piece (break_dir);
+
+      if (!break_item || !scm_is_pair (break_item->get_property ("space-alist")))
+       continue;
+
+      if (!col)
+       col = dynamic_cast<Item*> (elts[0])->get_column ()->find_prebroken_piece (break_dir);
+
+      Interval ext = break_item->extent (col, X_AXIS);
+
+      if (ext.is_empty ())
+       continue;
+
+      if (!last_grob
+         || (last_grob && d * (ext[-d]- (*last_ext)[-d]) < 0))
+       {
+         *last_ext = ext;
+         last_grob = break_item;
+       }
+    }
+
+  return last_grob;
+}
+
+
 ADD_INTERFACE (Spacing_interface,
-              "This object calculates the desired and minimum distances between two columns.",
+              "This object calculates the desired and minimum distances"
+              " between two columns.",
 
+              /* properties */
               "left-items "
               "right-items "
               );