]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/axis-group-interface.cc
Run `make grand-replace'.
[lilypond.git] / lily / axis-group-interface.cc
index da08f53526eb4f1fa333df1126cd3ccdb77478c1..cc6ff24fc7d6a30fda4f7764b83cb9695bcface8 100644 (file)
@@ -3,7 +3,7 @@
 
   source file of the GNU LilyPond music typesetter
 
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 2000--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
+  (c) 2000--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
 */
 
 #include "axis-group-interface.hh"
 */
 
 #include "axis-group-interface.hh"
@@ -18,6 +18,7 @@
 #include "paper-column.hh"
 #include "paper-score.hh"
 #include "separation-item.hh"
 #include "paper-column.hh"
 #include "paper-score.hh"
 #include "separation-item.hh"
+#include "skyline-pair.hh"
 #include "stencil.hh"
 #include "system.hh"
 #include "warn.hh"
 #include "stencil.hh"
 #include "system.hh"
 #include "warn.hh"
@@ -90,11 +91,14 @@ Axis_group_interface::cached_pure_height (Grob *me, int start, int end)
 
   SCM extents = me->get_property ("adjacent-pure-heights");
 
 
   SCM extents = me->get_property ("adjacent-pure-heights");
 
+  if (!scm_is_vector (extents))
+    return Interval (0, 0);
+
   Interval ext;
   for (vsize i = 0; i + 1 < breaks.size (); i++)
     {
       int r = Paper_column::get_rank (cols[breaks[i]]);
   Interval ext;
   for (vsize i = 0; i + 1 < breaks.size (); i++)
     {
       int r = Paper_column::get_rank (cols[breaks[i]]);
-      if (r > end)
+      if (r >= end)
        break;
 
       if (r >= start)
        break;
 
       if (r >= start)
@@ -131,7 +135,8 @@ Axis_group_interface::adjacent_pure_heights (SCM smob)
          Item *it = dynamic_cast<Item*> (items[j]);
          int rank = it->get_column ()->get_rank ();
 
          Item *it = dynamic_cast<Item*> (items[j]);
          int rank = it->get_column ()->get_rank ();
 
-         if (rank <= end && it->pure_is_visible (start, end))
+         if (rank <= end && it->pure_is_visible (start, end)
+             && !to_boolean (it->get_property ("cross-staff")))
            {
              Interval dims = items[j]->pure_height (common, start, end);
              if (!dims.is_empty ())
            {
              Interval dims = items[j]->pure_height (common, start, end);
              if (!dims.is_empty ())
@@ -147,7 +152,8 @@ Axis_group_interface::adjacent_pure_heights (SCM smob)
       for (vsize j = 0; j < spanners.size (); j++)
        {
          Interval_t<int> rank_span = spanners[j]->spanned_rank_interval ();
       for (vsize j = 0; j < spanners.size (); j++)
        {
          Interval_t<int> rank_span = spanners[j]->spanned_rank_interval ();
-         if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start)
+         if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start
+             && !to_boolean (spanners[j]->get_property ("cross-staff")))
            {
              Interval dims = spanners[j]->pure_height (common, start, end);
              if (!dims.is_empty ())
            {
              Interval dims = spanners[j]->pure_height (common, start, end);
              if (!dims.is_empty ())
@@ -189,7 +195,8 @@ Axis_group_interface::relative_pure_height (Grob *me, int start, int end)
 
       if (rank > end)
        break;
 
       if (rank > end)
        break;
-      else if (rank >= start && it->pure_is_visible (start, end))
+      else if (rank >= start && it->pure_is_visible (start, end)
+              && !to_boolean (it->get_property ("cross-staff")))
        {
          Interval dims = it->pure_height (common, start, end);
          if (!dims.is_empty ())
        {
          Interval dims = it->pure_height (common, start, end);
          if (!dims.is_empty ())
@@ -200,7 +207,8 @@ Axis_group_interface::relative_pure_height (Grob *me, int start, int end)
   for (vsize i = 0; i < spanners.size (); i++)
     {
       Interval_t<int> rank_span = spanners[i]->spanned_rank_interval ();
   for (vsize i = 0; i < spanners.size (); i++)
     {
       Interval_t<int> rank_span = spanners[i]->spanned_rank_interval ();
-      if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start)
+      if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start
+         && !to_boolean (spanners[i]->get_property ("cross-staff")))
        {
          Interval dims = spanners[i]->pure_height (common, start, end);
          if (!dims.is_empty ())
        {
          Interval dims = spanners[i]->pure_height (common, start, end);
          if (!dims.is_empty ())
@@ -256,13 +264,6 @@ Axis_group_interface::calc_skylines (SCM smob)
   extract_grob_set (me, "elements", elts);
   Skyline_pair skylines = skyline_spacing (me, elts);
 
   extract_grob_set (me, "elements", elts);
   Skyline_pair skylines = skyline_spacing (me, elts);
 
-  /* add a minimum-Y-extent-sized box to the skyline */
-  SCM min_y_extent = me->get_property ("minimum-Y-extent");
-  if (is_number_pair (min_y_extent))
-    {
-      Box b (me->extent (me, X_AXIS), ly_scm2interval (min_y_extent));
-      skylines.insert (b, 0, X_AXIS);
-    }
   return skylines.smobbed_copy ();
 }
 
   return skylines.smobbed_copy ();
 }
 
@@ -279,8 +280,10 @@ Axis_group_interface::combine_skylines (SCM smob)
   Grob *me = unsmob_grob (smob);
   extract_grob_set (me, "elements", elements);
   Grob *y_common = common_refpoint_of_array (elements, me, Y_AXIS);
   Grob *me = unsmob_grob (smob);
   extract_grob_set (me, "elements", elements);
   Grob *y_common = common_refpoint_of_array (elements, me, Y_AXIS);
+  Grob *x_common = common_refpoint_of_array (elements, me, X_AXIS);
 
 
-  assert (y_common == me);
+  if (y_common != me)
+    programming_error ("combining skylines that don't belong to me");
 
   Skyline_pair ret;
   for (vsize i = 0; i < elements.size (); i++)
 
   Skyline_pair ret;
   for (vsize i = 0; i < elements.size (); i++)
@@ -291,6 +294,7 @@ Axis_group_interface::combine_skylines (SCM smob)
          Real offset = elements[i]->relative_coordinate (y_common, Y_AXIS);
          Skyline_pair other = *Skyline_pair::unsmob (skyline_scm);
          other.raise (offset);
          Real offset = elements[i]->relative_coordinate (y_common, Y_AXIS);
          Skyline_pair other = *Skyline_pair::unsmob (skyline_scm);
          other.raise (offset);
+         other.shift (elements[i]->relative_coordinate (x_common, X_AXIS));
          ret.merge (other);
        }
     }
          ret.merge (other);
        }
     }
@@ -313,6 +317,22 @@ Axis_group_interface::generic_group_extent (Grob *me, Axis a)
   return ly_interval2scm (r - my_coord);
 }
 
   return ly_interval2scm (r - my_coord);
 }
 
+/* This is like generic_group_extent, but it only counts the grobs that
+   are children of some other axis-group. This is uncached; if it becomes
+   commonly used, it may be necessary to cache it somehow. */
+Interval
+Axis_group_interface::staff_extent (Grob *me, Grob *refp, Axis ext_a, Grob *staff, Axis parent_a)
+{
+  extract_grob_set (me, "elements", elts);
+  vector<Grob*> new_elts;
+
+  for (vsize i = 0; i < elts.size (); i++)
+    if (elts[i]->common_refpoint (staff, parent_a) == staff)
+      new_elts.push_back (elts[i]);
+
+  return relative_group_extent (new_elts, refp, ext_a);
+}
+
 
 Grob *
 Axis_group_interface::calc_pure_elts_and_common (Grob *me)
 
 Grob *
 Axis_group_interface::calc_pure_elts_and_common (Grob *me)
@@ -366,26 +386,33 @@ Axis_group_interface::calc_pure_elts_and_common (Grob *me)
   return common;
 }
 
   return common;
 }
 
-MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_x_common, 1);
 SCM
 SCM
-Axis_group_interface::calc_x_common (SCM grob)
+Axis_group_interface::calc_common (Grob *me, Axis axis)
 {
 {
-  Grob *me = unsmob_grob (grob);
-
   extract_grob_set (me, "elements", elts);
   extract_grob_set (me, "elements", elts);
-  Grob *common = common_refpoint_of_array (elts, me, X_AXIS);
+  Grob *common = common_refpoint_of_array (elts, me, axis);
+  if (!common)
+    {
+      me->programming_error ("No common parent found in calc_common axis.");
+      return SCM_EOL;
+    }
+  
   return common->self_scm ();
 }
 
   return common->self_scm ();
 }
 
+
+MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_x_common, 1);
+SCM
+Axis_group_interface::calc_x_common (SCM grob)
+{
+  return calc_common (unsmob_grob (grob), X_AXIS);
+}
+
 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_y_common, 1);
 SCM
 Axis_group_interface::calc_y_common (SCM grob)
 {
 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_y_common, 1);
 SCM
 Axis_group_interface::calc_y_common (SCM grob)
 {
-  Grob *me = unsmob_grob (grob);
-
-  extract_grob_set (me, "elements", elts);
-  Grob *common = common_refpoint_of_array (elts, me, Y_AXIS);
-  return common->self_scm ();
+  return calc_common (unsmob_grob (grob), Y_AXIS);
 }
 
 Interval
 }
 
 Interval
@@ -478,7 +505,7 @@ add_boxes (Grob *me, Grob *x_common, Grob *y_common, vector<Box> *const boxes, S
    positions, one for above the staff, one for below).
 
    In each pass, we loop through the unplaced grobs from left to right.
    positions, one for above the staff, one for below).
 
    In each pass, we loop through the unplaced grobs from left to right.
-   If the grob overlaps the right-most affected position, we place it
+   If the grob doesn't overlap the right-most affected position, we place it
    (and then update the right-most affected position to point to the right
    edge of the just-placed grob).  Otherwise, we skip it until the next pass.
 */
    (and then update the right-most affected position to point to the right
    edge of the just-placed grob).  Otherwise, we skip it until the next pass.
 */
@@ -540,9 +567,27 @@ add_grobs_of_one_priority (Skyline_pair *const skylines,
     }
 }
 
     }
 }
 
+// TODO: it is tricky to correctly handle skyline placement of cross-staff grobs.
+// For example, cross-staff beams cannot be formatted until the distance between
+// staves is known and therefore any grobs that depend on the beam cannot be placed
+// until the skylines are known. On the other hand, the distance between staves should
+// really depend on position of the cross-staff grobs that lie between them.
+// Currently, we just leave cross-staff grobs out of the
+// skyline altogether, but this could mean that staves are placed so close together
+// that there is no room for the cross-staff grob. It also means, of course, that
+// we don't get the benefits of skyline placement for cross-staff grobs.
 Skyline_pair
 Axis_group_interface::skyline_spacing (Grob *me, vector<Grob*> elements)
 {
 Skyline_pair
 Axis_group_interface::skyline_spacing (Grob *me, vector<Grob*> elements)
 {
+  /* For grobs with an outside-staff-priority, the sorting function might
+     call extent and cause suicide. This breaks the contract that is required
+     for the STL sort function. To avoid this, we make sure that any suicides
+     are triggered beforehand.
+  */
+  for (vsize i = 0; i < elements.size (); i++)
+    if (scm_is_number (elements[i]->get_property ("outside-staff-priority")))
+      elements[i]->extent (elements[i], X_AXIS);
+
   vector_sort (elements, staff_priority_less);
   Grob *x_common = common_refpoint_of_array (elements, me, X_AXIS);
   Grob *y_common = common_refpoint_of_array (elements, me, Y_AXIS);
   vector_sort (elements, staff_priority_less);
   Grob *x_common = common_refpoint_of_array (elements, me, X_AXIS);
   Grob *y_common = common_refpoint_of_array (elements, me, Y_AXIS);
@@ -555,13 +600,17 @@ Axis_group_interface::skyline_spacing (Grob *me, vector<Grob*> elements)
   Skyline_pair skylines;
   for (i = 0; i < elements.size ()
         && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++)
   Skyline_pair skylines;
   for (i = 0; i < elements.size ()
         && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++)
-    add_boxes (elements[i], x_common, y_common, &boxes, &skylines);
+    if (!to_boolean (elements[i]->get_property ("cross-staff")))
+      add_boxes (elements[i], x_common, y_common, &boxes, &skylines);
 
   SCM padding_scm = me->get_property ("skyline-horizontal-padding");
   Real padding = robust_scm2double (padding_scm, 0.1);
   skylines.merge (Skyline_pair (boxes, padding, X_AXIS));
   for (; i < elements.size (); i++)
     {
 
   SCM padding_scm = me->get_property ("skyline-horizontal-padding");
   Real padding = robust_scm2double (padding_scm, 0.1);
   skylines.merge (Skyline_pair (boxes, padding, X_AXIS));
   for (; i < elements.size (); i++)
     {
+      if (to_boolean (elements[i]->get_property ("cross-staff")))
+       continue;
+
       SCM priority = elements[i]->get_property ("outside-staff-priority");
       vector<Grob*> current_elts;
       current_elts.push_back (elements[i]);
       SCM priority = elements[i]->get_property ("outside-staff-priority");
       vector<Grob*> current_elts;
       current_elts.push_back (elements[i]);
@@ -590,7 +639,6 @@ Axis_group_interface::calc_max_stretch (SCM smob)
   return scm_from_double (ret);
 }
 
   return scm_from_double (ret);
 }
 
-extern bool debug_skylines;
 MAKE_SCHEME_CALLBACK (Axis_group_interface, print, 1)
 SCM
 Axis_group_interface::print (SCM smob)
 MAKE_SCHEME_CALLBACK (Axis_group_interface, print, 1)
 SCM
 Axis_group_interface::print (SCM smob)
@@ -602,14 +650,15 @@ Axis_group_interface::print (SCM smob)
   Stencil ret;
   if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("vertical-skylines")))
     {
   Stencil ret;
   if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("vertical-skylines")))
     {
-      ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[UP].to_points (X_AXIS)).in_color (255, 0, 255));
-      ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[DOWN].to_points (X_AXIS)).in_color (0, 255, 255));
+      ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[UP].to_points (X_AXIS))
+                      .in_color (255, 0, 255));
+      ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[DOWN].to_points (X_AXIS))
+                      .in_color (0, 255, 255));
     }
   return ret.smobbed_copy ();
 }
 
 ADD_INTERFACE (Axis_group_interface,
     }
   return ret.smobbed_copy ();
 }
 
 ADD_INTERFACE (Axis_group_interface,
-
               "An object that groups other layout objects.",
 
               /* properties */
               "An object that groups other layout objects.",
 
               /* properties */
@@ -620,6 +669,7 @@ ADD_INTERFACE (Axis_group_interface,
               "elements "
               "keep-fixed-while-stretching "
               "max-stretch "
               "elements "
               "keep-fixed-while-stretching "
               "max-stretch "
+              "no-alignment "
               "pure-Y-common "
               "pure-relevant-items "
               "pure-relevant-spanners "
               "pure-Y-common "
               "pure-relevant-items "
               "pure-relevant-spanners "