]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/side-position-interface.cc
* lily/text-item.cc (interpret_string): new file, select font with
[lilypond.git] / lily / side-position-interface.cc
index b1d3923d3f8435991718300f078afff5a1d0fa4a..82b1ff44ba5a4c12dc87b1fb146e52ff8ec74e66 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 <math.h>              // ceil.
 
+#include "note-head.hh"
 #include "side-position-interface.hh"
 #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");
-  if (isdir_b (d) && to_dir (d))
+  SCM d = me->get_property ("direction");
+  if (is_direction (d) && to_dir (d))
     return to_dir (d);
 
   Direction relative_dir = Direction (1);
     return to_dir (d);
 
   Direction relative_dir = Direction (1);
-  SCM reldir = me->get_grob_property ("side-relative-direction");      // should use a lambda.
-  if (isdir_b (reldir))
+  SCM reldir = me->get_property ("side-relative-direction");   // should use a lambda.
+  if (is_direction (reldir))
     {
       relative_dir = to_dir (reldir);
     }
   
     {
       relative_dir = to_dir (reldir);
     }
   
-  SCM other_elt = me->get_grob_property ("direction-source");
-  Grob * e = unsmob_grob(other_elt);
+  SCM other_elt = me->get_property ("direction-source");
+  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_grob (element_smob);
 {
   Grob *me = unsmob_grob (element_smob);
-  Axis a = (Axis) gh_scm2int (axis);
+  Axis a = (Axis) ly_scm2int (axis);
+
+  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_property ("side-support-elements");
+  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
+                       && is_number (me->get_property ("staff-padding")));
 
 
-  Grob *common = me->parent_l (a);
-  SCM support = me->get_grob_property ("side-support-elements");
-  for (SCM s = support; s != SCM_EOL; s = gh_cdr (s))
+  Interval dim;
+  if (include_staff)
     {
     {
-      Grob * e  = unsmob_grob (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_grob ( 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_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_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 scm_make_real (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_grob (element_smob);
-  Axis a = (Axis) gh_scm2int (axis);
-  String s ("self-alignment-");
+  Grob *me = unsmob_grob (smob);
+  Axis a = (Axis) ly_scm2int (axis);
 
 
-  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_grob (align))
-    {
-      return gh_double2scm (- unsmob_grob (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,134 +154,121 @@ 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_grob (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);
-
-      if (abs (ip) < rad && Staff_symbol_referencer::on_staffline (me,ip))
+      int ip = int (rp);
+
+      Grob *head = me->get_parent (X_AXIS);
+       
+      if (Staff_symbol_referencer::on_staffline (me,ip)
+         && ((abs (ip) <= rad)
+             || (Note_head::has_interface (head)
+                 && sign (Staff_symbol_referencer::get_position (head))
+                 == -d)
+             ))
        {
          ip += d;
          rp += d;
        }
        {
          ip += d;
          rp += d;
        }
-
-      return gh_double2scm ((rp - p) * Staff_symbol_referencer::staff_space (me) / 2.0);
+      
+      return scm_make_real ((rp - p) * Staff_symbol_referencer::staff_space (me) / 2.0);
     }
     }
-  return gh_double2scm (0.0);
+  return scm_make_real (0.0);
 }
 
 /*
   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_grob (element_smob);
 {
   Grob *me = unsmob_grob (element_smob);
-  Axis a = (Axis) gh_scm2int (axis);
+  Axis a = (Axis) ly_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 = ly_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_grob (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
+      && is_number (me->get_property ("staff-padding")))
     {
     {
-      add_support (me,st);
+      Real padding=
+      Staff_symbol_referencer::staff_space (me)
+      * ly_scm2double (me->get_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 scm_make_real (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 (Side_position_interface::aligned_side_proc, X_AXIS)
+      || me->has_offset_callback (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).   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");