]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/spacing-interface.cc
Run grand-replace (issue 3765)
[lilypond.git] / lily / spacing-interface.cc
index 33a4e14d399c1d679fe2e4cbf99b091759f52299..9e11cfa73a3545b3329c62f03ed22a7aa48585dc 100644 (file)
@@ -1,10 +1,20 @@
 /*
-  spacing-interface.cc -- functionality that is shared between Note_spacing
-  and Staff_spacing
+  This file is part of LilyPond, the GNU music typesetter.
 
-  source file of the GNU LilyPond music typesetter
+  Copyright (C) 2007--2014 Joe Neeman <joeneeman@gmail.com>
 
-  (c) 2007 Joe Neeman <joeneeman@gmail.com>
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "spacing-interface.hh"
 #include "paper-column.hh"
 #include "separation-item.hh"
 #include "skyline.hh"
-
-/* return the minimum distance between the left-items and the right-items of
-   this spacing object */
-Real
-Spacing_interface::minimum_distance (Grob *me)
+#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
+   ret[LEFT]) */
+Drul_array<Skyline>
+Spacing_interface::skylines (Grob *me, Grob *right_col)
 {
   /* the logic here is a little convoluted.
-     A {Staff,Note}_spacing doesn't copy {left-,right-}items when it clones,
+     A {Staff,Note}_spacing doesn't copy left-items when it clones,
      so in order to find the separation items, we need to use the original
      spacing grob. But once we find the separation items, we need to get back
      the broken piece.
-
-     FIXME: this only works for the left column. There is only one spacing
-     grob for the original and non-original right column and we have no way
-     to tell which one we need */
+  */
 
   Grob *orig = me->original () ? me->original () : me;
-  Direction break_dir = dynamic_cast<Item*> (me)->break_status_dir ();
+  Drul_array<Direction> break_dirs (dynamic_cast<Item *> (me)->break_status_dir (),
+                                    dynamic_cast<Item *> (right_col)->break_status_dir ());
   Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
-  Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
-                                   ly_scm2link_array (orig->get_object ("right-items")));
+  Drul_array<vector<Grob *> > items (ly_scm2link_array (orig->get_object ("left-items")),
+                                     ly_scm2link_array (orig->get_object ("right-items")));
 
-  Direction d = LEFT;
-  do
+  Grob *system = me->get_system ();
+  Grob *left_col = dynamic_cast<Item *> (me)->get_column ();
+
+  Drul_array<Grob *> columns (left_col, right_col);
+
+  for (LEFT_and_RIGHT (d))
     {
       for (vsize i = 0; i < items[d].size (); i++)
-       {
-         Grob *g = items[d][i];
-         if (d == LEFT)
-           if (Item *it = dynamic_cast<Item*> (g))
-             if (Grob *piece = it->find_prebroken_piece (break_dir))
-               g = piece;
-
-         if (Separation_item::has_interface (g))
-           {
-             SCM sky_scm = g->get_property ("horizontal-skylines");
-             Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
-             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]));
-           }
-       }
+        {
+          Item *g = dynamic_cast<Item *> (items[d][i]);
+          if (g)
+            if (Item *piece = g->find_prebroken_piece (break_dirs[d]))
+              g = piece;
+
+          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);
+            }
+        }
     }
-  while (flip (&d) != LEFT);
+
+  return skylines;
+}
+
+Real
+Spacing_interface::minimum_distance (Grob *me, Grob *right)
+{
+  Drul_array<Skyline> skylines = Spacing_interface::skylines (me, right);
 
   return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
 }
 
 /*
-  Compute the column of the right-items.  This is a big function,
-  since RIGHT-ITEMS may span more columns (eg. if a clef is inserted,
-  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.
+  Compute the left-most column of the right-items.
 */
 Item *
 Spacing_interface::right_column (Grob *me)
@@ -85,7 +111,6 @@ Spacing_interface::right_column (Grob *me)
   Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
   Item *mincol = 0;
   int min_rank = INT_MAX;
-  bool prune = false;
   for (vsize i = 0; a && i < a->size (); i++)
     {
       Item *ri = a->item (i);
@@ -94,23 +119,10 @@ Spacing_interface::right_column (Grob *me)
       int rank = Paper_column::get_rank (col);
 
       if (rank < min_rank)
-       {
-         min_rank = rank;
-         if (mincol)
-           prune = true;
-
-         mincol = col;
-       }
-    }
-
-  if (prune && a)
-    {
-      vector<Grob*> &right = a->array_reference ();
-      for (vsize i = right.size (); i--;)
-       {
-         if (dynamic_cast<Item *> (right[i])->get_column () != mincol)
-           right.erase (right.begin () + i);
-       }
+        {
+          min_rank = rank;
+          mincol = col;
+        }
     }
 
   return mincol;
@@ -125,35 +137,91 @@ Spacing_interface::left_column (Grob *me)
   return dynamic_cast<Item *> (me)->get_column ();
 }
 
-static vector<Item*>
-get_note_columns (vector<Grob*> const &elts)
+static vector<Item *>
+get_note_columns (vector<Grob *> const &elts)
 {
-  vector<Item*> ret;
+  vector<Item *> ret;
 
   for (vsize i = 0; i < elts.size (); i++)
-    if (Note_column::has_interface (elts[i]))
-      ret.push_back (dynamic_cast<Item*> (elts[i]));
+    {
+      if (Note_column::has_interface (elts[i]))
+        ret.push_back (dynamic_cast<Item *> (elts[i]));
+      else if (Separation_item::has_interface (elts[i]))
+        {
+          extract_grob_set (elts[i], "elements", more_elts);
+          vector<Item *> ncs = get_note_columns (more_elts);
+
+          ret.insert (ret.end (), ncs.begin (), ncs.end ());
+        }
+    }
 
   return ret;
 }
 
-vector<Item*>
+vector<Item *>
 Spacing_interface::right_note_columns (Grob *me)
 {
   extract_grob_set (me, "right-items", elts);
   return get_note_columns (elts);
 }
 
-vector<Item*>
+vector<Item *>
 Spacing_interface::left_note_columns (Grob *me)
 {
   extract_grob_set (me, "left-items", elts);
   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.",
 
-              "left-items "
-              "right-items "
-              );
+               /* properties */
+               "left-items "
+               "right-items "
+              );