]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/side-position-interface.cc
*** empty log message ***
[lilypond.git] / lily / side-position-interface.cc
index 7c15bdb86e835b18440b1a86b0c42e163cfea250..a974a4495844c270bd6a41c0437ff1216ff1f781 100644 (file)
   
   source file of the GNU LilyPond music typesetter
   
   
   source file of the GNU LilyPond music typesetter
   
-  (c) 1998--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c) 1998--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
   
  */
 #include <math.h>              // ceil.
 
 #include "side-position-interface.hh"
   
  */
 #include <math.h>              // ceil.
 
 #include "side-position-interface.hh"
-#include "debug.hh"
+#include "warn.hh"
 #include "warn.hh"
 #include "dimensions.hh"
 #include "staff-symbol-referencer.hh"
 #include "group-interface.hh"
 #include "warn.hh"
 #include "dimensions.hh"
 #include "staff-symbol-referencer.hh"
 #include "group-interface.hh"
+#include "directional-element-interface.hh"
+#include "staff-symbol-referencer.hh"
 
 void
 
 void
-Side_position::add_support (Grob*me, Grob*e)
+Side_position_interface::add_support (Grob*me, Grob*e)
 {
 {
-  Pointer_group_interface::add_element (me, "side-support-elements",e);
+  Pointer_group_interface::add_grob (me, ly_symbol2scm ("side-support-elements"), e);
 }
 
 }
 
-
-
 Direction
 Direction
-Side_position::get_direction (Grob*me)
+Side_position_interface::get_direction (Grob*me)
 {
   SCM d = me->get_grob_property ("direction");
 {
   SCM d = me->get_grob_property ("direction");
-  if (isdir_b (d))
-    return to_dir (d) ? to_dir (d) : DOWN;
+  if (is_direction (d) && to_dir (d))
+    return to_dir (d);
 
 
-  Direction relative_dir = UP;
+  Direction relative_dir = Direction (1);
   SCM reldir = me->get_grob_property ("side-relative-direction");      // should use a lambda.
   SCM reldir = me->get_grob_property ("side-relative-direction");      // should use a lambda.
-  if (isdir_b (reldir))
+  if (is_direction (reldir))
     {
       relative_dir = to_dir (reldir);
     }
   
   SCM other_elt = me->get_grob_property ("direction-source");
     {
       relative_dir = to_dir (reldir);
     }
   
   SCM other_elt = me->get_grob_property ("direction-source");
-  Grob * e = unsmob_element(other_elt);
+  Grob * e = unsmob_grob (other_elt);
   if (e)
     {
   if (e)
     {
-      return (Direction)(relative_dir * Side_position::get_direction (e));
+      return (Direction) (relative_dir * get_grob_direction (e));
     }
   
     }
   
-  return DOWN;
+  return CENTER;
 }
   
 }
   
-/*
-   Callback that does the aligning. Puts the element next to the support
- */
 
 
-MAKE_SCHEME_CALLBACK(Side_position,side_position,2);
+MAKE_SCHEME_CALLBACK (Side_position_interface,aligned_on_support_extents, 2);
 SCM
 SCM
-Side_position::side_position (SCM element_smob, SCM axis)
+Side_position_interface::aligned_on_support_extents (SCM element_smob, SCM axis)
 {
 {
-  Grob *me = unsmob_element (element_smob);
+  Grob *me = unsmob_grob (element_smob);
   Axis a = (Axis) gh_scm2int (axis);
 
   Axis a = (Axis) gh_scm2int (axis);
 
-  Grob *common = me->parent_l (a);
+  return general_side_position (me, a, true);
+}
+
+
+/*
+ Puts the element next to the support, optionally taking in
+ account the extent of the support.
+*/
+SCM
+Side_position_interface::general_side_position (Grob * me, Axis a, bool use_extents)
+{
+  Real ss = Staff_symbol_referencer::staff_space (me);
   SCM support = me->get_grob_property ("side-support-elements");
   SCM support = me->get_grob_property ("side-support-elements");
-  for (SCM s = support; s != SCM_EOL; s = gh_cdr (s))
+  Grob *common = common_refpoint_of_list (support, me->get_parent (a), a);
+  Grob * st = Staff_symbol_referencer::get_staff_symbol (me);
+  bool include_staff = (st
+                       && a == Y_AXIS
+                       && gh_number_p (me->get_grob_property ("staff-padding")));
+
+  Interval dim;
+  if (include_staff)
     {
     {
-      Grob * e  = unsmob_element (gh_car (s));
-      if (e)
-       common = common->common_refpoint (e, a);
+      common = st->common_refpoint (common, Y_AXIS);
+      dim = st->extent (common, Y_AXIS);
     }
     }
-  
-  Interval dim;
-  for (SCM s = support; s != SCM_EOL; s = gh_cdr (s))
+    
+  for (SCM s = support; s != SCM_EOL; s = ly_cdr (s))
     {
     {
-
-      Grob * e  = unsmob_element ( gh_car (s));
+      Grob * e  = unsmob_grob (ly_car (s));
       if (e)
       if (e)
-       {
+       if (use_extents)
          dim.unite (e->extent (common, a));
          dim.unite (e->extent (common, a));
-       }
+       else
+         {
+           Real x = e->relative_coordinate (common, a);
+           dim.unite (Interval (x,x));
+         }
     }
 
     }
 
-  if (dim.empty_b ())
+  if (dim.is_empty ())
     {
     {
-      dim = Interval(0,0);
+      dim = Interval (0,0);
     }
 
     }
 
-  Direction dir = Side_position::get_direction (me);
+  Direction dir = Side_position_interface::get_direction (me);
     
     
-  Real off =  me->parent_l (a)->relative_coordinate (common, a);
-  SCM minimum = me->remove_grob_property ("minimum-space");
+  Real off =  me->get_parent (a)->relative_coordinate (common, a);
+  Real  minimum_space = ss * robust_scm2double (me->get_grob_property ("minimum-space"),  -1);
 
 
-  Real total_off = dim[dir] + off;
-  SCM padding = me->remove_grob_property ("padding");
-  if (gh_number_p (padding))
-    {
-      total_off += gh_scm2double (padding) * dir;
-    }
-  if (gh_number_p (minimum) && total_off * dir < gh_scm2double (minimum))
+  Real total_off = dim.linear_combination (dir) - off;
+  total_off += dir * ss * robust_scm2double (me->get_grob_property ("padding"), 0);
+
+  if (minimum_space >= 0
+      && dir
+      && total_off * dir < minimum_space)
     {
     {
-      total_off = gh_scm2double (minimum) * dir;
+      total_off = minimum_space * dir;
     }
     }
+
   if (fabs (total_off) > 100 CM)
     programming_error ("Huh ? Improbable staff side dim.");
 
   if (fabs (total_off) > 100 CM)
     programming_error ("Huh ? Improbable staff side dim.");
 
+
+  
+  
   return gh_double2scm (total_off);
 }
 
   return gh_double2scm (total_off);
 }
 
-/**
-  callback that centers the element on itself
+/*
+  Cut & paste (ugh.)
  */
  */
-MAKE_SCHEME_CALLBACK(Side_position,aligned_on_self,2);
+MAKE_SCHEME_CALLBACK (Side_position_interface,aligned_on_support_refpoints,2);
 SCM
 SCM
-Side_position::aligned_on_self (SCM element_smob, SCM axis)
+Side_position_interface::aligned_on_support_refpoints (SCM smob, SCM axis)
 {
 {
-  Grob *me = unsmob_element (element_smob);
+  Grob *me = unsmob_grob (smob);
   Axis a = (Axis) gh_scm2int (axis);
   Axis a = (Axis) gh_scm2int (axis);
-  String s ("self-alignment-");
 
 
-  s +=  (a == X_AXIS) ? "X" : "Y";
-
-  SCM align (me->get_grob_property (s.ch_C()));
-  if (gh_number_p (align))
-    {
-      Interval ext(me->extent (me,a));
-
-      if (ext.empty_b ())
-       {
-         programming_error ("I'm empty. Can't align on self");
-         return gh_double2scm (0.0);
-       }
-      else
-       {
-         return gh_double2scm (- ext.linear_combination (gh_scm2double (align)));
-       }
-    }
-  else if (unsmob_element (align))
-    {
-      return gh_double2scm (- unsmob_element (align)->relative_coordinate (me,  a));
-    }
-    return gh_double2scm (0.0);
+  return general_side_position (me, a, false); 
 }
 
 
 
 }
 
 
 
+
 Real
 directed_round (Real f, Direction d)
 {
 Real
 directed_round (Real f, Direction d)
 {
@@ -155,24 +153,24 @@ directed_round (Real f, Direction d)
   of the elements "direction" elt property.
 
   Only rounds when we're inside the staff, as determined by
   of the elements "direction" elt property.
 
   Only rounds when we're inside the staff, as determined by
-  Staff_symbol_referencer::staff_radius() */
-MAKE_SCHEME_CALLBACK(Side_position,quantised_position,2);
+  Staff_symbol_referencer::staff_radius () */
+MAKE_SCHEME_CALLBACK (Side_position_interface,quantised_position,2);
 SCM
 SCM
-Side_position::quantised_position (SCM element_smob, SCM )
+Side_position_interface::quantised_position (SCM element_smob, SCM)
 {
 {
-  Grob *me = unsmob_element (element_smob);
-  
+  Grob *me = unsmob_grob (element_smob);
   
   
-  Direction d = Side_position::get_direction (me);
+  Direction d = Side_position_interface::get_direction (me);
 
 
-  if (Staff_symbol_referencer::has_interface (me))
+  Grob * stsym = Staff_symbol_referencer::get_staff_symbol (me);
+  if (stsym)
     {
     {
-      Real p = Staff_symbol_referencer::position_f (me);
+      Real p = Staff_symbol_referencer::get_position (me);
       Real rp = directed_round (p, d);
       Real rad = Staff_symbol_referencer::staff_radius (me) *2 ;
       Real rp = directed_round (p, d);
       Real rad = Staff_symbol_referencer::staff_radius (me) *2 ;
-      int ip = int  (rp);
+      int ip = int (rp);
 
 
-      if (abs (ip) < rad && Staff_symbol_referencer::on_staffline (me,ip))
+      if (abs (ip) <= rad && Staff_symbol_referencer::on_staffline (me,ip))
        {
          ip += d;
          rp += d;
        {
          ip += d;
          rp += d;
@@ -186,103 +184,83 @@ Side_position::quantised_position (SCM element_smob, SCM )
 /*
   Position next to support, taking into account my own dimensions and padding.
  */
 /*
   Position next to support, taking into account my own dimensions and padding.
  */
-MAKE_SCHEME_CALLBACK(Side_position,aligned_side,2);
+MAKE_SCHEME_CALLBACK (Side_position_interface,aligned_side,2);
 SCM
 SCM
-Side_position::aligned_side (SCM element_smob, SCM axis)
+Side_position_interface::aligned_side (SCM element_smob, SCM axis)
 {
 {
-  Grob *me = unsmob_element (element_smob);
+  Grob *me = unsmob_grob (element_smob);
   Axis a = (Axis) gh_scm2int (axis);
   
   Axis a = (Axis) gh_scm2int (axis);
   
-  Direction d = Side_position::get_direction (me);
-  Real o = gh_scm2double (side_position (element_smob,axis));
+  Direction d = Side_position_interface::get_direction (me);
+  
+  Real o = gh_scm2double (aligned_on_support_extents (element_smob,axis));
 
   Interval iv =  me->extent (me, a);
 
 
   Interval iv =  me->extent (me, a);
 
-  if (!iv.empty_b ())
+  if (!iv.is_empty ())
     {
     {
+      if (!d)
+       {
+         programming_error ("Direction unknown, but aligned-side wanted.");
+         d = DOWN;
+       }
       o += - iv[-d];
       o += - iv[-d];
-
-      SCM pad = me->get_grob_property ("padding");
-      if (gh_number_p (pad))
-       o += d *gh_scm2double (pad) ; 
     }
     }
-  return gh_double2scm (o);
-}
 
 
-/*
-  Position centered on parent.
+  /*
+  Maintain a minimum distance to the staff. This is similar to side
+  position with padding, but it will put adjoining objects on a row if
+  stuff sticks out of the staff a little.
  */
  */
-MAKE_SCHEME_CALLBACK(Side_position,centered_on_parent,2);
-SCM
-Side_position::centered_on_parent (SCM element_smob, SCM axis)
-{
-  Grob *me = unsmob_element (element_smob);
-  Axis a = (Axis) gh_scm2int (axis);
-  Grob *him = me->parent_l (a);
-
-  return gh_double2scm (him->extent (him,a).center ());  
-}
-
-
-void
-Side_position::add_staff_support (Grob*me)
-{
-  Grob* st = Staff_symbol_referencer::staff_symbol_l (me);
-  if (st)
+  Grob * st = Staff_symbol_referencer::get_staff_symbol (me);
+  if (st && a == Y_AXIS
+      && gh_number_p (me->get_grob_property ("staff-padding")))
     {
     {
-      add_support (me,st);
+      Real padding=
+      Staff_symbol_referencer::staff_space (me)
+      * gh_scm2double (me->get_grob_property ("staff-padding"));
+  
+      Grob *common = me->common_refpoint (st, Y_AXIS);
+      
+      Interval staff_size = st->extent (common, Y_AXIS);
+      Interval me_ext = me->extent (common, a);
+      Real diff =  d*staff_size[d] + padding - d*(o + iv[-d]);
+      o += (d*  (diff >? 0));
     }
     }
+      
+  return gh_double2scm (o);
 }
 
 }
 
+
 void
 void
-Side_position::set_axis (Grob*me, Axis a)
+Side_position_interface::set_axis (Grob*me, Axis a)
 {
 {
-  me->add_offset_callback (Side_position::aligned_side_proc, a);
+  me->add_offset_callback (Side_position_interface::aligned_side_proc, a);
 }
 
 
 
 }
 
 
 
-// ugh. doesn't cactch all variants. 
+// ugh. doesn't catch all variants. 
 Axis
 Axis
-Side_position::get_axis (Grob*me)
+Side_position_interface::get_axis (Grob*me)
 {
 {
-  if (me->has_offset_callback_b (Side_position::aligned_side_proc, X_AXIS)
-      || me->has_offset_callback_b (Side_position::aligned_side_proc , X_AXIS))
+  if (me->has_offset_callback_b (Side_position_interface::aligned_side_proc, X_AXIS)
+      || me->has_offset_callback_b (Side_position_interface::aligned_side_proc , X_AXIS))
     return X_AXIS;
 
   
   return Y_AXIS;
 }
 
     return X_AXIS;
 
   
   return Y_AXIS;
 }
 
-void
-Side_position::set_direction (Grob*me, Direction d)
-{
-  me->set_grob_property ("direction", gh_int2scm (d));
-}
-
-void
-Side_position::set_minimum_space (Grob*me, Real m)
-{
-  me->set_grob_property ("minimum-space", gh_double2scm (m));
-}
 
 
-void
-Side_position::set_padding (Grob*me, Real p)
-{
-  me->set_grob_property ("padding", gh_double2scm (p));
-}
-
-bool
-Side_position::has_interface (Grob*me) 
-{
-  return me->has_interface (ly_symbol2scm ("side-position-interface"));
-}
-
-bool
-Side_position::supported_b (Grob*me) 
-{
-  SCM s = me->get_grob_property  ("side-support-elements"); 
-  return gh_pair_p(s);
-}
 
 
 
 
+ADD_INTERFACE (Side_position_interface,"side-position-interface",
+              "Position a victim object (this one) next to other objects (the "
+              "support).  In this case, the property @code{direction} signifies where to put the  "
+              "victim object relative to the support (left or right, up or down?)\n\n "
+              "The routine also takes the size the staff into account if "
+              "@code{staff-padding} is set. If undefined, the staff symbol is ignored." 
+              ,
+              "staff-padding side-support-elements direction-source "
+              "direction side-relative-direction minimum-space padding");