]> git.donarmstrong.com Git - lilypond.git/commitdiff
Issue 3307: Rest positions incorrect with non-standard line count
authorDavid Kastrup <dak@gnu.org>
Tue, 9 Apr 2013 17:17:25 +0000 (19:17 +0200)
committerDavid Kastrup <dak@gnu.org>
Tue, 30 Apr 2013 10:57:03 +0000 (12:57 +0200)
lily/include/rest.hh
lily/multi-measure-rest.cc
lily/rest.cc

index 208da0499ae195377b055afda7f154756ef471c7..5463574751d01b1a6ce0ac8bed8a867eeaf84d1f 100644 (file)
@@ -31,6 +31,8 @@ public:
   DECLARE_SCHEME_CALLBACK (calc_cross_staff, (SCM));
   DECLARE_GROB_INTERFACE ();
   static string glyph_name (Grob *, int, string, bool);
+  static Real staff_position_internal (Grob *, int /* duration_log */,
+                                       int /* dir */);
   static SCM brew_internal_stencil (Grob *, bool);
   static SCM generic_extent_callback (Grob *, Axis);
   static void translate (Grob *me, int dy);
index 36e462653238fbfc62d4cb1db2fd4d808aa3efc8..34f6bb6e687b2649a77c750d55b14010521c8475 100644 (file)
@@ -32,6 +32,7 @@
 #include "separation-item.hh"
 #include "spacing-options.hh"
 #include "spanner.hh"
+#include "staff-symbol.hh"
 #include "staff-symbol-referencer.hh"
 #include "system.hh"
 #include "text-interface.hh"
@@ -225,10 +226,8 @@ Multi_measure_rest::symbol_stencil (Grob *me, Real space)
     {
       if (mdl == 0 && me->get_property ("staff-position") == SCM_EOL)
         {
-          if (Staff_symbol_referencer::on_staff_line (me, 2))
-            me->set_property ("staff-position", scm_from_int (2));
-          else if (Staff_symbol_referencer::on_staff_line (me, 3))
-            me->set_property ("staff-position", scm_from_int (3));
+          Real pos = Rest::staff_position_internal (me, mdl, 0);
+          me->set_property ("staff-position", scm_from_double (pos));
         }
 
       Stencil s = musfont->find_by_name (Rest::glyph_name (me, mdl, "", true));
index 8e45405de278dbd4ea5040dfc3259c6a2164a112..4a46b7312aa8feab0946a83fa6ad17552a8601e6 100644 (file)
@@ -39,19 +39,28 @@ Rest::y_offset_callback (SCM smob)
   int duration_log = scm_to_int (me->get_property ("duration-log"));
   Real ss = Staff_symbol_referencer::staff_space (me);
 
+  return scm_from_double (ss * 0.5 * Rest::staff_position_internal (me, duration_log, get_grob_direction (me)));
+}
+
+Real
+Rest::staff_position_internal (Grob *me, int duration_log, int dir)
+{
+  if (!me)
+    return 0;
+
   bool position_override = scm_is_number (me->get_property ("staff-position"));
-  Real amount;
+  Real pos;
 
   if (position_override)
     {
-      amount
-        = robust_scm2double (me->get_property ("staff-position"), 0) * 0.5 * ss;
+      pos
+        = robust_scm2double (me->get_property ("staff-position"), 0);
 
       /*
         semibreve rests are positioned one staff line off
       */
       if (duration_log == 0)
-        amount += ss;
+        return pos + 2;
 
       /*
         trust the client on good positioning;
@@ -59,37 +68,75 @@ Rest::y_offset_callback (SCM smob)
         to be properly aligned to staff lines,
         but custom rest shapes may not need that sort of care.
       */
+
+      return pos;
     }
-  else
-    {
-      int pos = 4 * get_grob_direction (me);
 
+  pos = 4 * dir;
+
+  if (duration_log > 1)
+    /* Only half notes or longer want alignment with staff lines */
+    return pos;
+      
+  /*
+    We need a staff symbol for actually aligning anything
+  */
+  Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
+  if (!staff)
+    return pos;
+
+  std::vector<Real> linepos = Staff_symbol::line_positions (staff);
+
+  if (linepos.empty ())
+    return pos;
+      
+  std::sort (linepos.begin (), linepos.end ());
+          
+  if (duration_log == 0)
+    {
       /*
-        make a semibreve rest hang from the next line,
-        except for a single line staff
+        lower voice semibreve rests generally hang a line lower
       */
-      if (duration_log == 0 && Staff_symbol_referencer::line_count (me) > 1)
-        pos += 2;
+
+      if (dir < 0)
+        pos -= 2;
 
       /*
-        make sure rest is aligned to a staff line
+        make a semibreve rest hang from the next available line,
+        except when there is none.
       */
-      if (Grob *staff = Staff_symbol_referencer::get_staff_symbol (me))
-        {
-          std::vector<Real> linepos = Staff_symbol::line_positions (staff);
-          std::sort (linepos.begin (), linepos.end ());
-          std::vector<Real>::const_iterator it
-            = std::lower_bound (linepos.begin (), linepos.end (), pos);
-          if (it != linepos.end ())
-            {
-              pos = (int)ceil (*it);
-            }
-        }
-
-      amount = ss * 0.5 * pos;
+      
+      std::vector<Real>::const_iterator it
+        = std::upper_bound (linepos.begin (), linepos.end (), pos);
+      if (it != linepos.end ())
+        pos = *it;
+      else
+        pos = linepos.back ();
+    }
+  else
+    {
+      std::vector<Real>::const_iterator it
+        = std::upper_bound (linepos.begin (), linepos.end (), pos);
+      if (it != linepos.begin ())
+        --it;
+      pos = *it;
     }
 
-  return scm_from_double (amount);
+  /* Finished for neutral position */
+  if (!dir)
+    return pos;
+
+  /* If we have a voiced position, make sure that it's on the
+     proper side of neutral before using it.  If it isn't, we fall
+     back to a constant offset from neutral position.
+  */
+
+  Real neutral = staff_position_internal (me, duration_log, 0);
+
+  if (dir * (pos - neutral) > 0)
+    return pos;
+
+  return neutral + 4 * dir;
 }
 
 /* A rest might lie under a beam, in which case it should be cross-staff if