]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/tuplet-bracket.cc
Fix some bugs in the dynamic engraver and PostScript backend
[lilypond.git] / lily / tuplet-bracket.cc
index ab19c15abce1a858694f536a5dc0cc4718df5fe2..4ca50328295c88d6319b39f69706925bff100a27 100644 (file)
@@ -3,7 +3,7 @@
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 1997--2005 Jan Nieuwenhuizen <janneke@gnu.org>
+  (c) 1997--2006 Jan Nieuwenhuizen <janneke@gnu.org>
   Han-Wen Nienhuys <hanwen@xs4all.nl>
 */
 
@@ -34,8 +34,8 @@
 #include "line-interface.hh"
 #include "beam.hh"
 #include "warn.hh"
-#include "font-interface.hh"
 #include "output-def.hh"
+#include "font-interface.hh"
 #include "text-interface.hh"
 #include "stem.hh"
 #include "note-column.hh"
@@ -44,6 +44,8 @@
 #include "spanner.hh"
 #include "staff-symbol-referencer.hh"
 #include "lookup.hh"
+#include "paper-column.hh"
+#include "moment.hh"
 
 static Item *
 get_x_bound_item (Grob *me_grob, Direction hdir, Direction my_dir)
@@ -58,8 +60,22 @@ get_x_bound_item (Grob *me_grob, Direction hdir, Direction my_dir)
   return g;
 }
 
+
+void
+flatten_number_pair_property (Grob *me,
+                             Direction xdir,  SCM sym)
+{
+  Drul_array<Real> zero (0, 0);
+  Drul_array<Real> pair
+    = robust_scm2drul (me->internal_get_property (sym), zero);
+  pair[xdir] = 0.0;
+  
+  me->internal_set_property (sym, ly_interval2scm (pair));
+}
+
+
 Grob *
-Tuplet_bracket::parallel_beam (Grob *me_grob, Link_array<Grob> const &cols, bool *equally_long)
+Tuplet_bracket::parallel_beam (Grob *me_grob, vector<Grob*> const &cols, bool *equally_long)
 {
   Spanner *me = dynamic_cast<Spanner *> (me_grob);
 
@@ -68,7 +84,7 @@ Tuplet_bracket::parallel_beam (Grob *me_grob, Link_array<Grob> const &cols, bool
     return 0;
 
   Drul_array<Grob*> stems (Note_column::get_stem (cols[0]),
-                          Note_column::get_stem (cols.top ()));
+                          Note_column::get_stem (cols.back ()));
 
   if (dynamic_cast<Item*> (stems[RIGHT])->get_column ()
       != me->get_bound (RIGHT)->get_column())
@@ -92,70 +108,31 @@ Tuplet_bracket::parallel_beam (Grob *me_grob, Link_array<Grob> const &cols, bool
       return 0;
     }
 
-  *equally_long = (beam_stems[0] == stems[LEFT] && beam_stems.top () == stems[RIGHT]);
+  *equally_long =
+    (beam_stems[0] == stems[LEFT] && beam_stems.back () == stems[RIGHT]);
   return beams[LEFT];
 }
 
-/*
-  TODO:
 
-  in the case that there is no bracket, but there is a (single) beam,
-  follow beam precisely for determining tuplet number location.
-*/
-MAKE_SCHEME_CALLBACK (Tuplet_bracket, print, 1);
+MAKE_SCHEME_CALLBACK(Tuplet_bracket,calc_connect_to_neighbors,1);
 SCM
-Tuplet_bracket::print (SCM smob)
+Tuplet_bracket::calc_connect_to_neighbors (SCM smob)
 {
   Spanner *me = unsmob_spanner (smob);
-  Stencil mol;
-  extract_grob_set (me, "note-columns", columns);
 
-  Drul_array<Real> positions
-    = ly_scm2realdrul (me->get_property ("positions"));
-  Real dy = positions[RIGHT] - positions[LEFT];
-  bool equally_long = false;
-  Grob *par_beam = parallel_beam (me, columns, &equally_long);
-  Spanner *sp = dynamic_cast<Spanner *> (me);
-
-  bool bracket_visibility = !(par_beam && equally_long);
-  bool number_visibility = true;
-
-  /*
-    Fixme: the type of this prop is sucky.
-  */
-  SCM bracket = me->get_property ("bracket-visibility");
-  if (scm_is_bool (bracket))
-    bracket_visibility = ly_scm2bool (bracket);
-  else if (bracket == ly_symbol2scm ("if-no-beam"))
-    bracket_visibility = !par_beam;
-
-  SCM numb = me->get_property ("number-visibility");
-  if (scm_is_bool (numb))
-    number_visibility = ly_scm2bool (numb);
-  else if (numb == ly_symbol2scm ("if-no-beam"))
-    number_visibility = !par_beam;
-
-  Grob *commonx = common_refpoint_of_array (columns, me, X_AXIS);
-  commonx = commonx->common_refpoint (sp->get_bound (LEFT), X_AXIS);
-  commonx = commonx->common_refpoint (sp->get_bound (RIGHT), X_AXIS);
-
-  Direction dir = get_grob_direction (me);
-
-  Drul_array<Item *> bounds;
-  bounds[LEFT] = get_x_bound_item (me, LEFT, dir);
-  bounds[RIGHT] = get_x_bound_item (me, RIGHT, dir);
-
-  Drul_array<bool> connect_to_other;
-  Interval x_span;
+  Direction dir = get_grob_direction (me); 
+  Drul_array<Item *> bounds (get_x_bound_item (me, LEFT, dir),
+                            get_x_bound_item (me, RIGHT, dir));
+  
+  Drul_array<bool> connect_to_other (false, false);
   Direction d = LEFT;
   do
     {
-      x_span[d] = robust_relative_extent (bounds[d], commonx, X_AXIS)[d];
       Direction break_dir = bounds[d]->break_status_dir ();
-      Spanner *orig_spanner = dynamic_cast<Spanner *> (me->original ());
-
-      int neighbor_idx = me->get_break_index () - break_dir;
+      
+      Spanner *orig_spanner = dynamic_cast<Spanner*> (me->original ());
 
+      vsize neighbor_idx = me->get_break_index () - break_dir;
       if (break_dir
          && d == RIGHT
          && neighbor_idx < orig_spanner->broken_intos_.size ())
@@ -168,10 +145,66 @@ Tuplet_bracket::print (SCM smob)
 
       connect_to_other[d]
        = (break_dir
-          && (neighbor_idx < orig_spanner->broken_intos_.size ()
-              && neighbor_idx >= 0)
+          && neighbor_idx < orig_spanner->broken_intos_.size ()
           && orig_spanner->broken_intos_[neighbor_idx]->is_live ());
-          
+    }
+  while (flip (&d) != LEFT);
+
+
+  if (connect_to_other[LEFT] || connect_to_other[RIGHT])
+    return scm_cons (scm_from_bool (connect_to_other[LEFT]),
+                    scm_from_bool (connect_to_other[RIGHT]));
+                    
+  return SCM_EOL;
+}
+
+Grob* 
+Tuplet_bracket::get_common_x (Spanner *me)
+{
+  extract_grob_set (me, "note-columns", columns);
+
+  Grob * commonx = common_refpoint_of_array (columns, me, X_AXIS);
+  commonx = commonx->common_refpoint (me->get_bound (LEFT), X_AXIS);
+  commonx = commonx->common_refpoint (me->get_bound (RIGHT), X_AXIS);
+
+  return commonx;
+}
+  
+MAKE_SCHEME_CALLBACK(Tuplet_bracket,calc_control_points,1)
+SCM
+Tuplet_bracket::calc_control_points (SCM smob)
+{
+  Spanner *me = unsmob_spanner (smob);
+
+  extract_grob_set (me, "note-columns", columns);
+
+  SCM scm_positions = me->get_property ("positions");
+  if (!me->is_live ())
+    return SCM_EOL;
+  
+  if (!scm_is_pair (scm_positions))
+    programming_error ("Positions should be number pair");
+    
+  Drul_array<Real> positions
+    = robust_scm2drul (scm_positions, Drul_array<Real> (0,0));
+
+  Grob *commonx = get_common_x (me);
+  Direction dir = get_grob_direction (me);
+
+  Drul_array<Item *> bounds;
+  bounds[LEFT] = get_x_bound_item (me, LEFT, dir);
+  bounds[RIGHT] = get_x_bound_item (me, RIGHT, dir);
+
+  Drul_array<bool> connect_to_other =
+    robust_scm2booldrul (me->get_property ("connect-to-neighbor"),
+                        Drul_array<bool> (false, false));
+  
+    
+  Interval x_span;
+  Direction d = LEFT;
+  do
+    {
+      x_span[d] = robust_relative_extent (bounds[d], commonx, X_AXIS)[d];
 
       if (connect_to_other[d])
        {
@@ -184,12 +217,16 @@ Tuplet_bracket::print (SCM smob)
            x_span[d] = robust_relative_extent (bounds[d], commonx, X_AXIS)[RIGHT]
              - overshoot[LEFT];
        }
+      
       else if (d == RIGHT
-              && (columns.is_empty ()
+              && (columns.empty ()
                   || (bounds[d]->get_column ()
-                      != dynamic_cast<Item *> (columns.top ())->get_column ())))
+                      != dynamic_cast<Item *> (columns.back ())->get_column ())))
        {
          /*
+           We're connecting to a column, for the last bit of a broken
+           fullLength bracket.
+           
            TODO: make padding tunable?
          */
          Real padding = 1.0;
@@ -197,42 +234,82 @@ Tuplet_bracket::print (SCM smob)
          if (bounds[d]->break_status_dir ())
            padding = 0.0;
          
-         x_span[d] = robust_relative_extent (bounds[d], commonx, X_AXIS) [LEFT] - padding;
+         x_span[d]
+           = robust_relative_extent (bounds[d], commonx, X_AXIS) [LEFT]
+           - padding;
        }
     }
   while (flip (&d) != LEFT);
 
-  Real w = x_span.length ();
-  SCM number = me->get_property ("text");
+  
+  
+  x_span -= me->get_bound (LEFT)->relative_coordinate (commonx, X_AXIS);
+  return scm_list_2 (ly_offset2scm (Offset (x_span[LEFT], positions[LEFT])),
+                    ly_offset2scm (Offset (x_span[RIGHT], positions[RIGHT])));
+}
 
-  Output_def *pap = me->layout ();
-  Stencil num;
-  if (scm_is_string (number) && number_visibility)
-    {
-      SCM properties = Font_interface::text_font_alist_chain (me);
-      SCM snum = Text_interface::interpret_markup (pap->self_scm (),
-                                                  properties, number);
-      num = *unsmob_stencil (snum);
-      num.align_to (X_AXIS, CENTER);
-      num.translate_axis (w / 2, X_AXIS);
-      num.align_to (Y_AXIS, CENTER);
+/*
+  TODO:
 
-      num.translate_axis (dy / 2, Y_AXIS);
+  in the case that there is no bracket, but there is a (single) beam,
+  follow beam precisely for determining tuplet number location.
+*/
+MAKE_SCHEME_CALLBACK (Tuplet_bracket, print, 1);
+SCM
+Tuplet_bracket::print (SCM smob)
+{
+  Spanner *me = unsmob_spanner (smob);
+  Stencil mol;
+
+  extract_grob_set (me, "note-columns", columns);
+  bool equally_long = false;
+  Grob *par_beam = parallel_beam (me, columns, &equally_long);
+  
+  bool bracket_visibility = !(par_beam && equally_long);
+  /*
+    Fixme: the type of this prop is sucky.
+  */
+  SCM bracket = me->get_property ("bracket-visibility");
+  if (scm_is_bool (bracket))
+    bracket_visibility = ly_scm2bool (bracket);
+  else if (bracket == ly_symbol2scm ("if-no-beam"))
+    bracket_visibility = !par_beam;
 
-      mol.add_stencil (num);
+  
+  SCM cpoints =  me->get_property ("control-points");
+  if (scm_ilength (cpoints) < 2)
+    {
+      me->suicide ();
+      return SCM_EOL;
     }
+  
+  Drul_array<Offset> points;
+  points[LEFT] = ly_scm2offset (scm_car (cpoints));
+  points[RIGHT] = ly_scm2offset (scm_cadr (cpoints));
+  
+  Interval x_span (points[LEFT][X_AXIS], points[RIGHT][X_AXIS]);
+  Drul_array<Real> positions (points[LEFT][Y_AXIS], points[RIGHT][Y_AXIS]);
+
 
+
+  Output_def *pap = me->layout ();
+
+  Grob *number_grob = unsmob_grob (me->get_object ("tuplet-number"));
+  
   /*
     No bracket when it would be smaller than the number.
   */
   Real gap = 0.;
-  if (bracket_visibility && number_visibility)
+  if (bracket_visibility && number_grob)
     {
-      if (!num.extent (X_AXIS).is_empty ())
-       gap = num.extent (X_AXIS).length () + 1.0;
+      Interval ext = number_grob->extent (number_grob, X_AXIS);
+      if (!ext.is_empty ())
+       {
+         gap = ext.length () + 1.0;
       
-      if (w - gap < w / 4.0)
-       bracket_visibility = false;
+         if (0.75 * x_span.length () < gap)
+           bracket_visibility = false;
+       }
     }
 
   if (bracket_visibility)
@@ -247,9 +324,17 @@ Tuplet_bracket::print (SCM smob)
        = robust_scm2drul (me->get_property ("shorten-pair"), zero);
       Drul_array<Stencil> edge_stencils;
 
+      Direction dir = get_grob_direction (me);
+      
       scale_drul (&height, -ss * dir);
       scale_drul (&flare, ss);
       scale_drul (&shorten, ss);
+
+      Drul_array<bool> connect_to_other =
+       robust_scm2booldrul (me->get_property ("connect-to-neighbor"),
+                            Drul_array<bool> (false, false));
+
+      Direction d = LEFT;
       do
        {
          if (connect_to_other[d])
@@ -279,7 +364,7 @@ Tuplet_bracket::print (SCM smob)
       while (flip (&d) != LEFT);
 
       Stencil brack = make_bracket (me, Y_AXIS,
-                                   Offset (w, dy),
+                                   points[RIGHT] - points[LEFT],
                                    height,
                                    /*
                                      0.1 = more space at right due to italics
@@ -298,9 +383,7 @@ Tuplet_bracket::print (SCM smob)
       mol.add_stencil (brack);
     }
 
-  mol.translate_axis (positions[LEFT], Y_AXIS);
-  mol.translate_axis (x_span[LEFT]
-                     - sp->get_bound (LEFT)->relative_coordinate (commonx, X_AXIS), X_AXIS);
+  mol.translate (points[LEFT]);
   return mol.smobbed_copy ();
 }
 
@@ -368,20 +451,20 @@ void
 Tuplet_bracket::get_bounds (Grob *me, Grob **left, Grob **right)
 {
   extract_grob_set (me, "note-columns", columns);
-  int l = 0;
+  vsize l = 0;
   while (l < columns.size () && Note_column::has_rests (columns[l]))
     l++;
 
-  int r = columns.size ()- 1;
-  while (r >= l && Note_column::has_rests (columns[r]))
+  vsize r = columns.size ();
+  while (r > l && Note_column::has_rests (columns[r-1]))
     r--;
 
   *left = *right = 0;
 
-  if (l <= r)
+  if (l < r)
     {
       *left = columns[l];
-      *right = columns[r];
+      *right = columns[r-1];
     }
 }
 
@@ -401,17 +484,18 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
   if (Grob *st = Staff_symbol_referencer::get_staff_symbol (me))
     commony = st->common_refpoint (commony, Y_AXIS);
 
-  Grob *commonx = common_refpoint_of_array (columns, me, X_AXIS);
+  Grob *commonx = get_common_x (me);
   commonx = common_refpoint_of_array (tuplets, commonx, Y_AXIS);
-  commonx = commonx->common_refpoint (me->get_bound (LEFT), X_AXIS);
-  commonx = commonx->common_refpoint (me->get_bound (RIGHT), X_AXIS);
 
   Interval staff;
   if (Grob *st = Staff_symbol_referencer::get_staff_symbol (me))
     {
-      staff = st->extent (commony, Y_AXIS);
-      Real pad = robust_scm2double (me->get_property ("staff-padding"), 0.5);
-      staff.widen (pad);
+      Real pad = robust_scm2double (me->get_property ("staff-padding"), -1.0);
+      if  (pad >= 0.0)
+       {
+         staff = st->extent (commony, Y_AXIS);
+         staff.widen (pad);
+       }
     }
   
   Direction dir = get_grob_direction (me);
@@ -453,17 +537,17 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
   Real x0 = robust_relative_extent (lgr, commonx, X_AXIS)[LEFT];
   Real x1 = robust_relative_extent (rgr, commonx, X_AXIS)[RIGHT];
 
-  Array<Offset> points;
-  points.push (Offset (x0 - x0, staff[dir]));
-  points.push (Offset (x1 - x0, staff[dir]));
+  vector<Offset> points;
+  points.push_back (Offset (x0 - x0, staff[dir]));
+  points.push_back (Offset (x1 - x0, staff[dir]));
 
-  for (int i = 0; i < columns.size (); i++)
+  for (vsize i = 0; i < columns.size (); i++)
     {
       Interval note_ext = columns[i]->extent (commony, Y_AXIS);
       Real notey = note_ext[dir] - me->relative_coordinate (commony, Y_AXIS);
 
       Real x = columns[i]->relative_coordinate (commonx, X_AXIS) - x0;
-      points.push (Offset (x, notey));
+      points.push_back (Offset (x, notey));
     }
 
   /*
@@ -473,7 +557,7 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
     We assume that the smaller bracket is 1.0 space high.
   */
   Real ss = Staff_symbol_referencer::staff_space (me);
-  for (int i = 0; i < tuplets.size (); i++)
+  for (vsize i = 0; i < tuplets.size (); i++)
     {
       Interval tuplet_x (tuplets[i]->extent (commonx, X_AXIS));
       Interval tuplet_y (tuplets[i]->extent (commony, Y_AXIS));
@@ -489,27 +573,19 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
          Real y
            = tuplet_y.linear_combination (d * sign (other_dy));
 
-#if 0
          /*
-           Let's not take padding into account for nested tuplets.
+           We don't take padding into account for nested tuplets.
            the edges can come very close to the stems, likewise for
            nested tuplets?
          */
-         Drul_array<Real> my_height
-           = robust_scm2drul (me->get_property ("edge-height"),
-                              Interval (0, 0));
-         if (dynamic_cast<Spanner *> (tuplets[i])->get_bound (d)
-             == me->get_bound (d))
-           y += dir * my_height[d];
-#endif
-
-         points.push (Offset (tuplet_x[d] - x0, y));
+
+         points.push_back (Offset (tuplet_x[d] - x0, y));
        }
       while (flip (&d) != LEFT);
     }
 
   Real factor = (columns.size () > 1) ? 1 / (x1 - x0) : 1.0;
-  for (int i = 0; i < points.size (); i++)
+  for (vsize i = 0; i < points.size (); i++)
     {
       Real x = points[i][X_AXIS];
       Real tuplety = (*dy) * x * factor;
@@ -534,7 +610,7 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
       *offset *= 2 / ss;
 
       *offset = rint (*offset);
-      if (Staff_symbol_referencer::on_staffline (me, (int) rint (*offset)))
+      if (Staff_symbol_referencer::on_line (me, (int) rint (*offset)))
        *offset += dir;
 
       *offset *= 0.5 * ss;
@@ -555,15 +631,19 @@ MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_positions, 1);
 SCM
 Tuplet_bracket::calc_positions (SCM smob)
 {
-  Grob *me = unsmob_grob (smob);
+  Spanner *me = unsmob_spanner (smob);
   extract_grob_set (me, "note-columns", columns);
 
-  if (columns.is_empty())
+  /*
+    Don't print if it doesn't span time.
+   */
+  if (robust_scm2moment (me->get_bound (LEFT)->get_column ()->get_property ("when"), Moment (0))
+      == robust_scm2moment (me->get_bound (RIGHT)->get_column ()->get_property ("when"), Moment (0)))
     {
       me->suicide ();
-      return scm_cons (scm_from_double (0),
-                      scm_from_double (0));
+      return SCM_EOL;
     }
+
   
   Direction dir = get_grob_direction (me);
   bool equally_long = false;
@@ -584,11 +664,13 @@ Tuplet_bracket::calc_positions (SCM smob)
       Real lp = scm_to_double (scm_car (ps));
       Real rp = scm_to_double (scm_cdr (ps));
 
-      /*
-       duh. magic.
-      */
+      Real ss = Staff_symbol_referencer::staff_space (me);
+      
       offset = lp + dir * (0.5 + scm_to_double (me->get_property ("padding")));
-      dy = rp - lp;
+      dy = (rp - lp);
+
+      dy *= ss;
+      offset *= ss;    
     }
 
   
@@ -606,7 +688,7 @@ Tuplet_bracket::get_default_dir (Grob *me)
 {
   Drul_array<int> dirs (0, 0);
   extract_grob_set (me, "note-columns", columns);
-  for (int i = 0; i < columns.size (); i++)
+  for (vsize i = 0; i < columns.size (); i++)
     {
       Grob *nc = columns[i];
       Direction d = Note_column::dir (nc);
@@ -644,15 +726,19 @@ ADD_INTERFACE (Tuplet_bracket,
               "bracket-flare "
               "bracket-visibility "
               "break-overshoot "
+              "connect-to-neighbor "
+              "control-points "
               "direction "
               "edge-height "
               "edge-text "
+              "gap "
               "positions "
               "note-columns "
-              "number-visibility "
               "padding "
+              "tuplet-number "
               "shorten-pair "
               "staff-padding "
               "thickness "
               "tuplets ");
 
+