]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/tuplet-bracket.cc
Run grand replace for 2015.
[lilypond.git] / lily / tuplet-bracket.cc
index abc559ab051b3942c941988e9cae856fc2bc94da..c926966e9c05afa81c7a989312c0d54a8c4fb4ad 100644 (file)
@@ -1,7 +1,7 @@
 /*
   This file is part of LilyPond, the GNU music typesetter.
 
 /*
   This file is part of LilyPond, the GNU music typesetter.
 
-  Copyright (C) 1997--2010 Jan Nieuwenhuizen <janneke@gnu.org>
+  Copyright (C) 1997--2015 Jan Nieuwenhuizen <janneke@gnu.org>
   Han-Wen Nienhuys <hanwen@xs4all.nl>
 
   LilyPond is free software: you can redistribute it and/or modify
   Han-Wen Nienhuys <hanwen@xs4all.nl>
 
   LilyPond is free software: you can redistribute it and/or modify
@@ -41,6 +41,7 @@
 */
 
 #include "tuplet-bracket.hh"
 */
 
 #include "tuplet-bracket.hh"
+#include "axis-group-interface.hh"
 #include "line-interface.hh"
 #include "beam.hh"
 #include "warn.hh"
 #include "line-interface.hh"
 #include "beam.hh"
 #include "warn.hh"
@@ -51,6 +52,7 @@
 #include "note-column.hh"
 #include "pointer-group-interface.hh"
 #include "directional-element-interface.hh"
 #include "note-column.hh"
 #include "pointer-group-interface.hh"
 #include "directional-element-interface.hh"
+#include "skyline.hh"
 #include "spanner.hh"
 #include "staff-symbol-referencer.hh"
 #include "lookup.hh"
 #include "spanner.hh"
 #include "staff-symbol-referencer.hh"
 #include "lookup.hh"
@@ -75,7 +77,7 @@ flatten_number_pair_property (Grob *me, Direction xdir, SCM sym)
 {
   Drul_array<Real> zero (0, 0);
   Drul_array<Real> pair
 {
   Drul_array<Real> zero (0, 0);
   Drul_array<Real> pair
-    = robust_scm2drul (me->internal_get_property (sym), zero);
+    = robust_scm2drul (me->get_property (sym), zero);
   pair[xdir] = 0.0;
 
   me->set_property (sym, ly_interval2scm (pair));
   pair[xdir] = 0.0;
 
   me->set_property (sym, ly_interval2scm (pair));
@@ -86,28 +88,28 @@ flatten_number_pair_property (Grob *me, Direction xdir, SCM sym)
 */
 Grob *
 Tuplet_bracket::parallel_beam (Grob *me_grob, vector<Grob *> const &cols,
 */
 Grob *
 Tuplet_bracket::parallel_beam (Grob *me_grob, vector<Grob *> const &cols,
-                              bool *equally_long)
+                               bool *equally_long)
 {
   Spanner *me = dynamic_cast<Spanner *> (me_grob);
 
 {
   Spanner *me = dynamic_cast<Spanner *> (me_grob);
 
-  if (me->get_bound (LEFT)->break_status_dir ()
-      || me->get_bound (RIGHT)->break_status_dir ())
+  Item *left = me->get_bound (LEFT);
+  Item *right = me->get_bound (RIGHT);
+  if (!left || left->break_status_dir ()
+      || !right || right->break_status_dir ())
     return 0;
 
   Drul_array<Grob *> stems (Note_column::get_stem (cols[0]),
     return 0;
 
   Drul_array<Grob *> stems (Note_column::get_stem (cols[0]),
-                           Note_column::get_stem (cols.back ()));
+                            Note_column::get_stem (cols.back ()));
 
   if (!stems[RIGHT]
       || !stems[LEFT]
       || (dynamic_cast<Item *> (stems[RIGHT])->get_column ()
 
   if (!stems[RIGHT]
       || !stems[LEFT]
       || (dynamic_cast<Item *> (stems[RIGHT])->get_column ()
-         != me->get_bound (RIGHT)->get_column ()))
+          != me->get_bound (RIGHT)->get_column ()))
     return 0;
 
   Drul_array<Grob *> beams;
     return 0;
 
   Drul_array<Grob *> beams;
-  Direction d = LEFT;
-  do
+  for (LEFT_and_RIGHT (d))
     beams[d] = stems[d] ? Stem::get_beam (stems[d]) : 0;
     beams[d] = stems[d] ? Stem::get_beam (stems[d]) : 0;
-  while (flip (&d) != LEFT);
 
   *equally_long = false;
   if (! (beams[LEFT] && (beams[LEFT] == beams[RIGHT]) && !me->is_broken ()))
 
   *equally_long = false;
   if (! (beams[LEFT] && (beams[LEFT] == beams[RIGHT]) && !me->is_broken ()))
@@ -131,39 +133,37 @@ MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_connect_to_neighbors, 1);
 SCM
 Tuplet_bracket::calc_connect_to_neighbors (SCM smob)
 {
 SCM
 Tuplet_bracket::calc_connect_to_neighbors (SCM smob)
 {
-  Spanner *me = unsmob_spanner (smob);
+  Spanner *me = Spanner::unsmob (smob);
 
   Direction dir = get_grob_direction (me);
   Drul_array<Item *> bounds (get_x_bound_item (me, LEFT, dir),
 
   Direction dir = get_grob_direction (me);
   Drul_array<Item *> bounds (get_x_bound_item (me, LEFT, dir),
-                            get_x_bound_item (me, RIGHT, dir));
+                             get_x_bound_item (me, RIGHT, dir));
 
   Drul_array<bool> connect_to_other (false, false);
 
   Drul_array<bool> connect_to_other (false, false);
-  Direction d = LEFT;
-  do
+  for (LEFT_and_RIGHT (d))
     {
       Direction break_dir = bounds[d]->break_status_dir ();
       Spanner *orig_spanner = dynamic_cast<Spanner *> (me->original ());
       vsize neighbor_idx = me->get_break_index () - break_dir;
       if (break_dir
     {
       Direction break_dir = bounds[d]->break_status_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 ())
-       {
-         Grob *neighbor = orig_spanner->broken_intos_[neighbor_idx];
+          && d == RIGHT
+          && neighbor_idx < orig_spanner->broken_intos_.size ())
+        {
+          Grob *neighbor = orig_spanner->broken_intos_[neighbor_idx];
 
 
-         /* trigger possible suicide*/
-         (void) neighbor->get_property ("positions");
-       }
+          /* trigger possible suicide*/
+          (void) neighbor->get_property ("positions");
+        }
 
       connect_to_other[d]
 
       connect_to_other[d]
-       = (break_dir
-          && neighbor_idx < orig_spanner->broken_intos_.size ()
-          && orig_spanner->broken_intos_[neighbor_idx]->is_live ());
+        = (break_dir
+           && 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]),
 
   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]));
+                     scm_from_bool (connect_to_other[RIGHT]));
 
   return SCM_EOL;
 }
 
   return SCM_EOL;
 }
@@ -180,24 +180,13 @@ Tuplet_bracket::get_common_x (Spanner *me)
   return commonx;
 }
 
   return commonx;
 }
 
-MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_control_points, 1)
+MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_x_positions, 1)
 SCM
 SCM
-Tuplet_bracket::calc_control_points (SCM smob)
+Tuplet_bracket::calc_x_positions (SCM smob)
 {
 {
-  Spanner *me = unsmob_spanner (smob);
-
+  Spanner *me = Spanner::unsmob (smob);
   extract_grob_set (me, "note-columns", columns);
 
   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);
 
   Grob *commonx = get_common_x (me);
   Direction dir = get_grob_direction (me);
 
@@ -207,56 +196,53 @@ Tuplet_bracket::calc_control_points (SCM smob)
 
   Drul_array<bool> connect_to_other
     = robust_scm2booldrul (me->get_property ("connect-to-neighbor"),
 
   Drul_array<bool> connect_to_other
     = robust_scm2booldrul (me->get_property ("connect-to-neighbor"),
-                          Drul_array<bool> (false, false));
+                           Drul_array<bool> (false, false));
 
   Interval x_span;
 
   Interval x_span;
-  Direction d = LEFT;
-  do
+  for (LEFT_and_RIGHT (d))
     {
     {
-      x_span[d] = robust_relative_extent (bounds[d], commonx, X_AXIS)[d];
+      x_span[d] = Axis_group_interface::generic_bound_extent (bounds[d], commonx, X_AXIS)[d];
 
       if (connect_to_other[d])
 
       if (connect_to_other[d])
-       {
-         Interval overshoot (robust_scm2drul (me->get_property ("break-overshoot"),
-                                              Interval (-0.5, 0.0)));
-
-         if (d == RIGHT)
-           x_span[d] += d * overshoot[d];
-         else
-           x_span[d] = robust_relative_extent (bounds[d],
-                                               commonx, X_AXIS)[RIGHT]
-             - overshoot[LEFT];
-       }
+        {
+          Interval overshoot (robust_scm2drul (me->get_property ("break-overshoot"),
+                                               Interval (-0.5, 0.0)));
+
+          if (d == RIGHT)
+            x_span[d] += d * overshoot[d];
+          else
+            x_span[d] = (bounds[d]->break_status_dir ()
+                         ? Axis_group_interface::generic_bound_extent (bounds[d], commonx, X_AXIS)[-d]
+                         : robust_relative_extent (bounds[d], commonx, X_AXIS)[-d])
+                        - overshoot[LEFT];
+        }
 
       else if (d == RIGHT
 
       else if (d == RIGHT
-              && (columns.empty ()
-                  || (bounds[d]->get_column ()
-                      != dynamic_cast<Item *> (columns.back ())->get_column ())))
-       {
-         /*
-           We're connecting to a column, for the last bit of a broken
-           fullLength bracket.
-         */
-         Real padding
-           = robust_scm2double (me->get_property ("full-length-padding"), 1.0);
-
-         if (bounds[d]->break_status_dir ())
-           padding = 0.0;
-
-         Real coord = bounds[d]->relative_coordinate (commonx, X_AXIS);
-         if (to_boolean (me->get_property ("full-length-to-extent")))
-           coord = robust_relative_extent (bounds[d], commonx, X_AXIS)[LEFT];
-
-         coord = max (coord, x_span[LEFT]);
-
-         x_span[d] = coord - padding;
-       }
+               && (columns.empty ()
+                   || (bounds[d]->get_column ()
+                       != dynamic_cast<Item *> (columns.back ())->get_column ())))
+        {
+          /*
+            We're connecting to a column, for the last bit of a broken
+            fullLength bracket.
+          */
+          Real padding
+            = robust_scm2double (me->get_property ("full-length-padding"), 1.0);
+
+          if (bounds[d]->break_status_dir ())
+            padding = 0.0;
+
+          Real coord = bounds[d]->relative_coordinate (commonx, X_AXIS);
+          if (to_boolean (me->get_property ("full-length-to-extent")))
+            coord = robust_relative_extent (bounds[d], commonx, X_AXIS)[LEFT];
+
+          coord = max (coord, x_span[LEFT]);
+
+          x_span[d] = coord - padding;
+        }
     }
     }
-  while (flip (&d) != LEFT);
 
 
-  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])));
+  return ly_interval2scm (x_span - me->get_bound (LEFT)->relative_coordinate (commonx, X_AXIS));
 }
 
 /*
 }
 
 /*
@@ -269,31 +255,32 @@ MAKE_SCHEME_CALLBACK (Tuplet_bracket, print, 1);
 SCM
 Tuplet_bracket::print (SCM smob)
 {
 SCM
 Tuplet_bracket::print (SCM smob)
 {
-  Spanner *me = unsmob_spanner (smob);
+  Spanner *me = Spanner::unsmob (smob);
   Stencil mol;
 
   extract_grob_set (me, "note-columns", columns);
   bool equally_long = false;
   Grob *par_beam = parallel_beam (me, columns, &equally_long);
 
   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); // Flag, print/don't print tuplet bracket.
+  bool bracket_visibility = !(par_beam && equally_long); // Flag, print/don't print tuplet bracket.
   /*
     FIXME: The type of this prop is sucky.
   */
   SCM bracket_vis_prop = me->get_property ("bracket-visibility");
   /*
     FIXME: The type of this prop is sucky.
   */
   SCM bracket_vis_prop = me->get_property ("bracket-visibility");
-  bool bracket_prop = to_boolean (bracket_vis_prop); // Flag, user has set bracket-visibility prop.
+  bool bracket_prop = ly_scm2bool (bracket_vis_prop); // Flag, user has set bracket-visibility prop.
   bool bracket = (bracket_vis_prop == ly_symbol2scm ("if-no-beam"));
   bool bracket = (bracket_vis_prop == ly_symbol2scm ("if-no-beam"));
-  if (bracket_prop)
-    bracket_visibility = true;
+  if (scm_is_bool (bracket_vis_prop))
+    bracket_visibility = bracket_prop;
   else if (bracket)
     bracket_visibility = !par_beam;
 
   /*
     Don't print a tuplet bracket and number if
   else if (bracket)
     bracket_visibility = !par_beam;
 
   /*
     Don't print a tuplet bracket and number if
-    no control-points were calculated
+    no X or Y positions were calculated.
   */
   */
-  SCM cpoints = me->get_property ("control-points");
-  if (scm_ilength (cpoints) < 2)
+  SCM scm_x_span = me->get_property ("X-positions");
+  SCM scm_positions = me->get_property ("positions");
+  if (!scm_is_pair (scm_x_span) || !scm_is_pair (scm_positions))
     {
       me->suicide ();
       return SCM_EOL;
     {
       me->suicide ();
       return SCM_EOL;
@@ -302,37 +289,37 @@ Tuplet_bracket::print (SCM smob)
       the bracket, but still let the number be displayed.
       Only do this if the user has not explicitly specified bracket-visibility = #t.
   */
       the bracket, but still let the number be displayed.
       Only do this if the user has not explicitly specified bracket-visibility = #t.
   */
-  if (!bracket_prop
+  if (!to_boolean (bracket_vis_prop)
       && (robust_scm2moment (me->get_bound (LEFT)->get_column ()->get_property ("when"), Moment (0))
       && (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))))
+          == robust_scm2moment (me->get_bound (RIGHT)->get_column ()->get_property ("when"), Moment (0))))
     bracket_visibility = false;
 
     bracket_visibility = false;
 
-  Drul_array<Offset> points;
-  points[LEFT] = ly_scm2offset (scm_car (cpoints));
-  points[RIGHT] = ly_scm2offset (scm_cadr (cpoints));
+  Interval x_span = robust_scm2interval (scm_x_span, Interval (0.0, 0.0));
+  Interval positions = robust_scm2interval (scm_positions, Interval (0.0, 0.0));
 
 
-  Interval x_span (points[LEFT][X_AXIS], points[RIGHT][X_AXIS]);
-  Drul_array<Real> positions (points[LEFT][Y_AXIS], points[RIGHT][Y_AXIS]);
+  Drul_array<Offset> points;
+  for (LEFT_and_RIGHT (d))
+    points[d] = Offset (x_span[d], positions[d]);
 
   Output_def *pap = me->layout ();
 
 
   Output_def *pap = me->layout ();
 
-  Grob *number_grob = unsmob_grob (me->get_object ("tuplet-number"));
+  Grob *number_grob = Grob::unsmob (me->get_object ("tuplet-number"));
 
   /*
     Don't print the bracket when it would be smaller than the number.
     ...Unless the user has coded bracket-visibility = #t, that is.
   */
 
   /*
     Don't print the bracket when it would be smaller than the number.
     ...Unless the user has coded bracket-visibility = #t, that is.
   */
-  Real gap = 0.0;
+  Real gap = 0.;
   if (bracket_visibility && number_grob)
     {
       Interval ext = number_grob->extent (number_grob, X_AXIS);
       if (!ext.is_empty ())
   if (bracket_visibility && number_grob)
     {
       Interval ext = number_grob->extent (number_grob, X_AXIS);
       if (!ext.is_empty ())
-       {
-         gap = ext.length () + 1.0;
+        {
+          gap = ext.length () + 1.0;
 
 
-         if ((0.75 * x_span.length () < gap) && !bracket_prop)
-           bracket_visibility = false;
-       }
+          if ((0.75 * x_span.length () < gap) && !bracket_prop)
+            bracket_visibility = false;
+        }
     }
 
   if (bracket_visibility)
     }
 
   if (bracket_visibility)
@@ -340,11 +327,11 @@ Tuplet_bracket::print (SCM smob)
       Drul_array<Real> zero (0, 0);
       Real ss = Staff_symbol_referencer::staff_space (me);
       Drul_array<Real> height
       Drul_array<Real> zero (0, 0);
       Real ss = Staff_symbol_referencer::staff_space (me);
       Drul_array<Real> height
-       = robust_scm2drul (me->get_property ("edge-height"), zero);
+        = robust_scm2drul (me->get_property ("edge-height"), zero);
       Drul_array<Real> flare
       Drul_array<Real> flare
-       = robust_scm2drul (me->get_property ("bracket-flare"), zero);
+        = robust_scm2drul (me->get_property ("bracket-flare"), zero);
       Drul_array<Real> shorten
       Drul_array<Real> shorten
-       = robust_scm2drul (me->get_property ("shorten-pair"), zero);
+        = robust_scm2drul (me->get_property ("shorten-pair"), zero);
       Drul_array<Stencil> edge_stencils;
 
       Direction dir = get_grob_direction (me);
       Drul_array<Stencil> edge_stencils;
 
       Direction dir = get_grob_direction (me);
@@ -354,56 +341,53 @@ Tuplet_bracket::print (SCM smob)
       scale_drul (&shorten, ss);
 
       Drul_array<bool> connect_to_other
       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])
-           {
-             height[d] = 0.0;
-             flare[d] = 0.0;
-             shorten[d] = 0.0;
-
-             SCM edge_text = me->get_property ("edge-text");
-
-             if (scm_is_pair (edge_text))
-               {
-                 SCM properties = Font_interface::text_font_alist_chain (me);
-                 SCM text = index_get_cell (edge_text, d);
-                 if (Text_interface::is_markup (text))
-                   {
-                     SCM t
-                       = Text_interface::interpret_markup (pap->self_scm (),
-                                                           properties, text);
-
-                     Stencil *edge_text = unsmob_stencil (t);
-                     edge_text->translate_axis (x_span[d] - x_span[LEFT],
-                                                X_AXIS);
-                     edge_stencils[d] = *edge_text;
-                   }
-               }
-           }
-       }
-      while (flip (&d) != LEFT);
+        = robust_scm2booldrul (me->get_property ("connect-to-neighbor"),
+                               Drul_array<bool> (false, false));
+
+      for (LEFT_and_RIGHT (d))
+        {
+          if (connect_to_other[d])
+            {
+              height[d] = 0.0;
+              flare[d] = 0.0;
+              shorten[d] = 0.0;
+
+              SCM edge_text = me->get_property ("edge-text");
+
+              if (scm_is_pair (edge_text))
+                {
+                  SCM properties = Font_interface::text_font_alist_chain (me);
+                  SCM text = index_get_cell (edge_text, d);
+                  if (Text_interface::is_markup (text))
+                    {
+                      SCM t
+                        = Text_interface::interpret_markup (pap->self_scm (),
+                                                            properties, text);
+
+                      Stencil *edge_text = Stencil::unsmob (t);
+                      edge_text->translate_axis (x_span[d] - x_span[LEFT],
+                                                 X_AXIS);
+                      edge_stencils[d] = *edge_text;
+                    }
+                }
+            }
+        }
 
       Stencil brack = make_bracket (me, Y_AXIS,
 
       Stencil brack = make_bracket (me, Y_AXIS,
-                                   points[RIGHT] - points[LEFT],
-                                   height,
-                                   /*
-                                     0.1 = more space at right due to italics
-                                     TODO: use italic correction of font.
-                                   */
-                                   Interval (-0.5, 0.5) * gap + 0.1,
-                                   flare, shorten);
-
-      do
-       {
-         if (!edge_stencils[d].is_empty ())
-           brack.add_stencil (edge_stencils[d]);
-       }
-      while (flip (&d) != LEFT);
+                                    points[RIGHT] - points[LEFT],
+                                    height,
+                                    /*
+                                      0.1 = more space at right due to italics
+                                      TODO: use italic correction of font.
+                                    */
+                                    Interval (-0.5, 0.5) * gap + 0.1,
+                                    flare, shorten);
+
+      for (LEFT_and_RIGHT (d))
+        {
+          if (!edge_stencils[d].is_empty ())
+            brack.add_stencil (edge_stencils[d]);
+        }
 
       mol.add_stencil (brack);
     }
 
       mol.add_stencil (brack);
     }
@@ -420,12 +404,12 @@ Tuplet_bracket::print (SCM smob)
 */
 Stencil
 Tuplet_bracket::make_bracket (Grob *me, // for line properties.
 */
 Stencil
 Tuplet_bracket::make_bracket (Grob *me, // for line properties.
-                             Axis protrusion_axis,
-                             Offset dz,
-                             Drul_array<Real> height,
-                             Interval gap,
-                             Drul_array<Real> flare,
-                             Drul_array<Real> shorten)
+                              Axis protrusion_axis,
+                              Offset dz,
+                              Drul_array<Real> height,
+                              Interval gap,
+                              Drul_array<Real> flare,
+                              Drul_array<Real> shorten)
 {
   Drul_array<Offset> corners (Offset (0, 0), dz);
 
 {
   Drul_array<Offset> corners (Offset (0, 0), dz);
 
@@ -436,44 +420,37 @@ Tuplet_bracket::make_bracket (Grob *me, // for line properties.
 
   Drul_array<Offset> straight_corners = corners;
 
 
   Drul_array<Offset> straight_corners = corners;
 
-  Direction d = LEFT;
-  do
+  for (LEFT_and_RIGHT (d))
     straight_corners[d] += -d * shorten[d] / length * dz;
     straight_corners[d] += -d * shorten[d] / length * dz;
-  while (flip (&d) != LEFT);
 
   if (!gap.is_empty ())
     {
 
   if (!gap.is_empty ())
     {
-      do
-       gap_corners[d] = (dz * 0.5) + gap[d] / length * dz;
-      while (flip (&d) != LEFT);
+      for (LEFT_and_RIGHT (d))
+        gap_corners[d] = (dz * 0.5) + gap[d] / length * dz;
     }
 
   Drul_array<Offset> flare_corners = straight_corners;
     }
 
   Drul_array<Offset> flare_corners = straight_corners;
-  do
+  for (LEFT_and_RIGHT (d))
     {
       flare_corners[d][bracket_axis] = straight_corners[d][bracket_axis];
       flare_corners[d][protrusion_axis] += height[d];
       straight_corners[d][bracket_axis] += -d * flare[d];
     }
     {
       flare_corners[d][bracket_axis] = straight_corners[d][bracket_axis];
       flare_corners[d][protrusion_axis] += height[d];
       straight_corners[d][bracket_axis] += -d * flare[d];
     }
-  while (flip (&d) != LEFT);
 
   Stencil m;
 
   Stencil m;
-  do
-    {
-      if (!gap.is_empty ())
-       m.add_stencil (Line_interface::line (me, straight_corners[d],
-                                            gap_corners[d]));
-
+  if (!gap.is_empty ())
+    for (LEFT_and_RIGHT (d))
       m.add_stencil (Line_interface::line (me, straight_corners[d],
       m.add_stencil (Line_interface::line (me, straight_corners[d],
-                                          flare_corners[d]));
-    }
-
-  while (flip (&d) != LEFT);
-
-  if (gap.is_empty ())
+                                           gap_corners[d]));
+  else
     m.add_stencil (Line_interface::line (me, straight_corners[LEFT],
     m.add_stencil (Line_interface::line (me, straight_corners[LEFT],
-                                        straight_corners[RIGHT]));
+                                         straight_corners[RIGHT]));
 
 
+  if (scm_is_number (me->get_property ("dash-fraction")))
+    me->set_property ("dash-fraction", scm_from_double (1.0));
+  for (LEFT_and_RIGHT (d))
+    m.add_stencil (Line_interface::line (me, straight_corners[d],
+                                         flare_corners[d]));
   return m;
 }
 
   return m;
 }
 
@@ -500,8 +477,7 @@ Tuplet_bracket::get_bounds (Grob *me, Grob **left, Grob **right)
 
 /*
   use first -> last note for slope, and then correct for disturbing
 
 /*
   use first -> last note for slope, and then correct for disturbing
-  notes in between.
-*/
+  notes in between.  */
 void
 Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
 {
 void
 Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
 {
@@ -522,19 +498,17 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
   Interval staff;
   Grob *st = Staff_symbol_referencer::get_staff_symbol (me);
 
   Interval staff;
   Grob *st = Staff_symbol_referencer::get_staff_symbol (me);
 
-  /*
-    staff-padding doesn't work correctly on cross-staff tuplets
-    because it only considers one staff symbol. Until this works,
-    disable it.
-  */
+  /* staff-padding doesn't work correctly on cross-staff tuplets
+     because it only considers one staff symbol. Until this works,
+     disable it. */
   if (st && !to_boolean (me->get_property ("cross-staff")))
     {
       Real pad = robust_scm2double (me->get_property ("staff-padding"), -1.0);
       if (pad >= 0.0)
   if (st && !to_boolean (me->get_property ("cross-staff")))
     {
       Real pad = robust_scm2double (me->get_property ("staff-padding"), -1.0);
       if (pad >= 0.0)
-       {
-         staff = st->extent (commony, Y_AXIS) - my_offset;
-         staff.widen (pad);
-       }
+        {
+          staff = st->extent (commony, Y_AXIS) - my_offset;
+          staff.widen (pad);
+        }
     }
 
   Direction dir = get_grob_direction (me);
     }
 
   Direction dir = get_grob_direction (me);
@@ -547,8 +521,8 @@ 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];
   bool follow_beam = par_beam
   Real x0 = robust_relative_extent (lgr, commonx, X_AXIS)[LEFT];
   Real x1 = robust_relative_extent (rgr, commonx, X_AXIS)[RIGHT];
   bool follow_beam = par_beam
-    && get_grob_direction (par_beam) == dir
-    && ! to_boolean (par_beam->get_property ("knee"));
+                     && get_grob_direction (par_beam) == dir
+                     && !Beam::is_knee (par_beam);
 
   vector<Offset> points;
   if (columns.size ()
 
   vector<Offset> points;
   if (columns.size ()
@@ -556,65 +530,64 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
       && Note_column::get_stem (columns[0])
       && Note_column::get_stem (columns.back ()))
     {
       && Note_column::get_stem (columns[0])
       && Note_column::get_stem (columns.back ()))
     {
-      /*
-       trigger set_stem_ends
-      */
-      (void) par_beam->get_property ("quantized-positions");
-
       Drul_array<Grob *> stems (Note_column::get_stem (columns[0]),
       Drul_array<Grob *> stems (Note_column::get_stem (columns[0]),
-                               Note_column::get_stem (columns.back ()));
-
-      Real ss = 0.5 * Staff_symbol_referencer::staff_space (me);
-      Real lp = ss * robust_scm2double (stems[LEFT]->get_property ("stem-end-position"), 0.0)
-       + stems[LEFT]->get_parent (Y_AXIS)->relative_coordinate (commony, Y_AXIS);
-      Real rp = ss * robust_scm2double (stems[RIGHT]->get_property ("stem-end-position"), 0.0)
-       + stems[RIGHT]->get_parent (Y_AXIS)->relative_coordinate (commony, Y_AXIS);
-
-      *dy = rp - lp;
-      points.push_back (Offset (stems[LEFT]->relative_coordinate (commonx, X_AXIS) - x0, lp));
-      points.push_back (Offset (stems[RIGHT]->relative_coordinate (commonx, X_AXIS) - x0, rp));
+                                Note_column::get_stem (columns.back ()));
+
+      Interval poss;
+      for (LEFT_and_RIGHT (side))
+        {
+          // Trigger setting of stem lengths if necessary.
+          if (Grob *beam = Stem::get_beam (stems[side]))
+            (void) beam->get_property ("quantized-positions");
+          poss[side] = stems[side]->extent (stems[side], Y_AXIS)[get_grob_direction (stems[side])]
+                       + stems[side]->get_parent (Y_AXIS)->relative_coordinate (commony, Y_AXIS);
+        }
+
+      *dy = poss[RIGHT] - poss[LEFT];
+      points.push_back (Offset (stems[LEFT]->relative_coordinate (commonx, X_AXIS) - x0, poss[LEFT]));
+      points.push_back (Offset (stems[RIGHT]->relative_coordinate (commonx, X_AXIS) - x0, poss[RIGHT]));
     }
   else
     {
       /*
     }
   else
     {
       /*
-       Use outer non-rest columns to determine slope
+        Use outer non-rest columns to determine slope
       */
       Grob *left_col = 0;
       Grob *right_col = 0;
       get_bounds (me, &left_col, &right_col);
       if (left_col && right_col)
       */
       Grob *left_col = 0;
       Grob *right_col = 0;
       get_bounds (me, &left_col, &right_col);
       if (left_col && right_col)
-       {
-         Interval rv = Note_column::cross_staff_extent (right_col, commony);
-         Interval lv = Note_column::cross_staff_extent (left_col, commony);
-         rv.unite (staff);
-         lv.unite (staff);
-
-         Real graphical_dy = rv[dir] - lv[dir];
-
-         Slice ls = Note_column::head_positions_interval (left_col);
-         Slice rs = Note_column::head_positions_interval (right_col);
-
-         Interval musical_dy;
-         musical_dy[UP] = rs[UP] - ls[UP];
-         musical_dy[DOWN] = rs[DOWN] - ls[DOWN];
-         if (sign (musical_dy[UP]) != sign (musical_dy[DOWN]))
-           *dy = 0.0;
-         else if (sign (graphical_dy) != sign (musical_dy[DOWN]))
-           *dy = 0.0;
-         else
-           *dy = graphical_dy;
-       }
+        {
+          Interval rv = Note_column::cross_staff_extent (right_col, commony);
+          Interval lv = Note_column::cross_staff_extent (left_col, commony);
+          rv.unite (staff);
+          lv.unite (staff);
+
+          Real graphical_dy = rv[dir] - lv[dir];
+
+          Slice ls = Note_column::head_positions_interval (left_col);
+          Slice rs = Note_column::head_positions_interval (right_col);
+
+          Interval musical_dy;
+          musical_dy[UP] = rs[UP] - ls[UP];
+          musical_dy[DOWN] = rs[DOWN] - ls[DOWN];
+          if (sign (musical_dy[UP]) != sign (musical_dy[DOWN]))
+            *dy = 0.0;
+          else if (sign (graphical_dy) != sign (musical_dy[DOWN]))
+            *dy = 0.0;
+          else
+            *dy = graphical_dy;
+        }
       else
       else
-       *dy = 0;
+        *dy = 0;
 
       for (vsize i = 0; i < columns.size (); i++)
 
       for (vsize i = 0; i < columns.size (); i++)
-       {
-         Interval note_ext = Note_column::cross_staff_extent (columns[i],
-                                                              commony);
-         Real x = columns[i]->relative_coordinate (commonx, X_AXIS) - x0;
+        {
+          Interval note_ext = Note_column::cross_staff_extent (columns[i],
+                                                               commony);
+          Real x = columns[i]->relative_coordinate (commonx, X_AXIS) - x0;
 
 
-         points.push_back (Offset (x, note_ext[dir]));
-       }
+          points.push_back (Offset (x, note_ext[dir]));
+        }
     }
 
   if (!follow_beam)
     }
 
   if (!follow_beam)
@@ -624,7 +597,7 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
     }
 
   /*
     }
 
   /*
-    This is a slight hack.  We compute two encompass points from the
+    This is a slight hack. We compute two encompass points from the
     bbox of the smaller tuplets.
 
     We assume that the smaller bracket is 1.0 space high.
     bbox of the smaller tuplets.
 
     We assume that the smaller bracket is 1.0 space high.
@@ -636,29 +609,57 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
       Interval tuplet_y (tuplets[i]->extent (commony, Y_AXIS));
 
       if (!tuplets[i]->is_live ())
       Interval tuplet_y (tuplets[i]->extent (commony, Y_AXIS));
 
       if (!tuplets[i]->is_live ())
-       continue;
+        continue;
 
 
-      Direction d = LEFT;
       Drul_array<Real> positions
       Drul_array<Real> positions
-       = robust_scm2interval (tuplets[i]->get_property ("positions"),
-                              Interval (0,0));
+        = robust_scm2interval (tuplets[i]->get_property ("positions"),
+                               Interval (0, 0));
 
       Real other_dy = positions[RIGHT] - positions[LEFT];
 
 
       Real other_dy = positions[RIGHT] - positions[LEFT];
 
-      do
-       {
-         Real y
-           = tuplet_y.linear_combination (d * sign (other_dy));
-
-         /*
-           We don't take padding into account for nested tuplets.
-           the edges can come very close to the stems, likewise for
-           nested tuplets?
-         */
+      for (LEFT_and_RIGHT (d))
+        {
+          Real y
+            = tuplet_y.linear_combination (d * sign (other_dy));
+
+          /*
+            We don't take padding into account for nested tuplets.
+            the edges can come very close to the stems, likewise for
+            nested tuplets?
+          */
+
+          points.push_back (Offset (tuplet_x[d] - x0, y));
+        }
+
+      // Check for number-on-bracket collisions
+      Grob *number = Grob::unsmob (tuplets[i]->get_object ("tuplet-number"));
+      if (number)
+        points.push_back (Offset (number->extent (commonx, X_AXIS).center () - x0,
+                                  number->extent (commony, Y_AXIS)[dir]));
+    }
 
 
-         points.push_back (Offset (tuplet_x[d] - x0, y));
-       }
-      while (flip (&d) != LEFT);
+  if (to_boolean (me->get_property ("avoid-scripts"))
+      && !scm_is_number (me->get_property ("outside-staff-priority")))
+    {
+      extract_grob_set (me, "scripts", scripts);
+      for (vsize i = 0; i < scripts.size (); i++)
+        {
+          if (!scripts[i]->is_live ())
+            continue;
+          if (scm_is_number (scripts[i]->get_property ("outside-staff-priority")))
+            continue;
+
+          // assume that if a script is avoiding slurs, it should not get placed
+          // under a tuplet bracket
+          if (Grob::is_smob (scripts[i]->get_object ("slur")))
+            continue;
+
+          Interval script_x (scripts[i]->extent (commonx, X_AXIS));
+          Interval script_y (scripts[i]->extent (commony, Y_AXIS));
+
+          points.push_back (Offset (script_x.center () - x0,
+                                    script_y[dir]));
+        }
     }
 
   *offset = -dir * infinity_f;
     }
 
   *offset = -dir * infinity_f;
@@ -669,7 +670,7 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
       Real tuplety = (*dy) * x * factor + my_offset;
 
       if (points[i][Y_AXIS] * dir > (*offset + tuplety) * dir)
       Real tuplety = (*dy) * x * factor + my_offset;
 
       if (points[i][Y_AXIS] * dir > (*offset + tuplety) * dir)
-       *offset = points[i][Y_AXIS] - tuplety;
+        *offset = points[i][Y_AXIS] - tuplety;
     }
 
   *offset += scm_to_double (me->get_property ("padding")) * dir;
     }
 
   *offset += scm_to_double (me->get_property ("padding")) * dir;
@@ -677,21 +678,20 @@ Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
   /*
     horizontal brackets should not collide with staff lines.
 
   /*
     horizontal brackets should not collide with staff lines.
 
-    Kind of pointless since we put them outside the staff anyway, but
-    let's leave code for the future when possibly allow them to move
-    into the staff once again.
-
     This doesn't seem to support cross-staff tuplets atm.
   */
     This doesn't seem to support cross-staff tuplets atm.
   */
-  if (*dy == 0
-      && fabs (*offset) < ss * Staff_symbol_referencer::staff_radius (me))
+  if (*dy == 0)
     {
       // quantize, then do collision check.
     {
       // quantize, then do collision check.
-      *offset *= 2 / ss;
+      *offset /= 0.5 * ss;
 
 
-      *offset = rint (*offset);
-      if (Staff_symbol_referencer::on_line (me, (int) rint (*offset)))
-       *offset += dir;
+      Interval staff_span = Staff_symbol_referencer::staff_span (me);
+      if (staff_span.contains (*offset))
+        {
+          *offset = rint (*offset);
+          if (Staff_symbol_referencer::on_line (me, int (*offset)))
+            *offset += dir;
+        }
 
       *offset *= 0.5 * ss;
     }
 
       *offset *= 0.5 * ss;
     }
@@ -701,7 +701,7 @@ MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_direction, 1);
 SCM
 Tuplet_bracket::calc_direction (SCM smob)
 {
 SCM
 Tuplet_bracket::calc_direction (SCM smob)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = Grob::unsmob (smob);
   Direction dir = Tuplet_bracket::get_default_dir (me);
   return scm_from_int (dir);
 }
   Direction dir = Tuplet_bracket::get_default_dir (me);
   return scm_from_int (dir);
 }
@@ -710,14 +710,14 @@ MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_positions, 1);
 SCM
 Tuplet_bracket::calc_positions (SCM smob)
 {
 SCM
 Tuplet_bracket::calc_positions (SCM smob)
 {
-  Spanner *me = unsmob_spanner (smob);
+  Spanner *me = Spanner::unsmob (smob);
 
   Real dy = 0.0;
   Real offset = 0.0;
   calc_position_and_height (me, &offset, &dy);
 
   SCM x = scm_cons (scm_from_double (offset),
 
   Real dy = 0.0;
   Real offset = 0.0;
   calc_position_and_height (me, &offset, &dy);
 
   SCM x = scm_cons (scm_from_double (offset),
-                   scm_from_double (offset + dy));
+                    scm_from_double (offset + dy));
 
   return x;
 }
 
   return x;
 }
@@ -733,12 +733,35 @@ Tuplet_bracket::get_default_dir (Grob *me)
   for (vsize i = 0; i < columns.size (); i++)
     {
       Grob *nc = columns[i];
   for (vsize i = 0; i < columns.size (); i++)
     {
       Grob *nc = columns[i];
+      if (Note_column::has_rests (nc))
+        continue;
       Direction d = Note_column::dir (nc);
       if (d)
       Direction d = Note_column::dir (nc);
       if (d)
-       dirs[d]++;
+        dirs[d]++;
     }
 
     }
 
-  return dirs[UP] >= dirs[DOWN] ? UP : DOWN;
+  if (dirs[UP] == dirs[DOWN])
+    {
+      if (dirs[UP] == 0)
+        return UP;
+      Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
+      if (!staff)
+        return UP;
+      Interval staff_extent = staff->extent (staff, Y_AXIS);
+      Interval extremal_positions;
+      extremal_positions.set_empty ();
+      for (vsize i = 0; i < columns.size (); i++)
+        {
+          Direction d = Note_column::dir (columns[i]);
+          extremal_positions[d] = minmax (d, 1.0 * Note_column::head_positions_interval (columns[i])[d], extremal_positions[d]);
+        }
+      for (LEFT_and_RIGHT (d))
+        extremal_positions[d] = -d * (staff_extent[d] - extremal_positions[d]);
+
+      return extremal_positions[UP] <= extremal_positions[DOWN] ? UP : DOWN;
+    }
+
+  return dirs[UP] > dirs[DOWN] ? UP : DOWN;
 }
 
 void
 }
 
 void
@@ -748,6 +771,12 @@ Tuplet_bracket::add_column (Grob *me, Item *n)
   add_bound_item (dynamic_cast<Spanner *> (me), n);
 }
 
   add_bound_item (dynamic_cast<Spanner *> (me), n);
 }
 
+void
+Tuplet_bracket::add_script (Grob *me, Item *s)
+{
+  Pointer_group_interface::add_grob (me, ly_symbol2scm ("scripts"), s);
+}
+
 void
 Tuplet_bracket::add_tuplet_bracket (Grob *me, Grob *bracket)
 {
 void
 Tuplet_bracket::add_tuplet_bracket (Grob *me, Grob *bracket)
 {
@@ -758,7 +787,7 @@ MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_cross_staff, 1);
 SCM
 Tuplet_bracket::calc_cross_staff (SCM smob)
 {
 SCM
 Tuplet_bracket::calc_cross_staff (SCM smob)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = Grob::unsmob (smob);
   extract_grob_set (me, "note-columns", cols);
   extract_grob_set (me, "tuplets", tuplets);
 
   extract_grob_set (me, "note-columns", cols);
   extract_grob_set (me, "tuplets", tuplets);
 
@@ -777,39 +806,40 @@ Tuplet_bracket::calc_cross_staff (SCM smob)
 
   for (vsize i = 0; i < cols.size (); i++)
     {
 
   for (vsize i = 0; i < cols.size (); i++)
     {
-      Grob *stem = unsmob_grob (cols[i]->get_object ("stem"));
+      Grob *stem = Grob::unsmob (cols[i]->get_object ("stem"));
       if (stem && to_boolean (stem->get_property ("cross-staff")))
       if (stem && to_boolean (stem->get_property ("cross-staff")))
-       return SCM_BOOL_T;
+        return SCM_BOOL_T;
     }
 
   return SCM_BOOL_F;
 }
 
 ADD_INTERFACE (Tuplet_bracket,
     }
 
   return SCM_BOOL_F;
 }
 
 ADD_INTERFACE (Tuplet_bracket,
-              "A bracket with a number in the middle, used for tuplets."
-              "  When the bracket spans a line break, the value of"
-              " @code{break-overshoot} determines how far it extends"
-              " beyond the staff.  At a line break, the markups in the"
-              " @code{edge-text} are printed at the edges.",
-
-              /* properties */
-              "bracket-flare "
-              "bracket-visibility "
-              "break-overshoot "
-              "connect-to-neighbor "
-              "control-points "
-              "direction "
-              "edge-height "
-              "edge-text "
-              "full-length-padding "
-              "full-length-to-extent "
-              "gap "
-              "positions "
-              "note-columns "
-              "padding "
-              "tuplet-number "
-              "shorten-pair "
-              "staff-padding "
-              "thickness "
-              "tuplets "
-              );
+               "A bracket with a number in the middle, used for tuplets."
+               "  When the bracket spans a line break, the value of"
+               " @code{break-overshoot} determines how far it extends"
+               " beyond the staff.  At a line break, the markups in the"
+               " @code{edge-text} are printed at the edges.",
+
+               /* properties */
+               "avoid-scripts "
+               "bracket-flare "
+               "bracket-visibility "
+               "break-overshoot "
+               "connect-to-neighbor "
+               "direction "
+               "edge-height "
+               "edge-text "
+               "full-length-padding "
+               "full-length-to-extent "
+               "gap "
+               "positions "
+               "note-columns "
+               "padding "
+               "tuplet-number "
+               "shorten-pair "
+               "staff-padding "
+               "thickness "
+               "tuplets "
+               "X-positions "
+              );