]> git.donarmstrong.com Git - lilypond.git/commitdiff
add support for custom ledgers, using two new staff-symbol properties
authorPiers Titus van der Torren <pierstitus@gmail.com>
Thu, 26 May 2011 00:44:14 +0000 (02:44 +0200)
committerJanek Warchol <lemniskata.bernoullego@gmail.com>
Sun, 25 Sep 2011 14:35:10 +0000 (16:35 +0200)
input/regression/staff-ledger-positions.ly [new file with mode: 0644]
lily/include/staff-symbol.hh
lily/ledger-line-spanner.cc
lily/staff-symbol.cc
scm/define-grob-properties.scm

diff --git a/input/regression/staff-ledger-positions.ly b/input/regression/staff-ledger-positions.ly
new file mode 100644 (file)
index 0000000..67233d1
--- /dev/null
@@ -0,0 +1,17 @@
+\header {
+
+  texidoc = "The vertical positions of ledger lines may be customised
+by setting the @code{ledger-positions} property of the StaffSymbol.
+The given pattern is repeated.  Bracketed groups are always shown together:
+either all or none are shown.  Ledger lines can be set to appear sooner or
+later by setting the @code{ledger-extra} property."
+}
+
+\version "2.15.12"
+
+\new Staff \relative c' {
+  \override Staff.StaffSymbol #'line-positions = #'(-5 -2 -1 2 5 6)
+  \override Staff.StaffSymbol #'ledger-positions = #'(-5 (-2 -1) 2)
+  \override Staff.StaffSymbol #'ledger-extra = #1
+  g,4 c e b' c'' e g
+}
index 9aee969f49533b141ede35799b10229c3eade3ca..0a3ef80d642b03efc1ba74829869922a167b29d0 100644 (file)
@@ -33,7 +33,8 @@ public:
   static Real get_line_thickness (Grob *);
   static Real get_ledger_line_thickness (Grob *);
 
-  static int get_steps (Grob *);
+  static vector<Real> line_positions (Grob *);
+  static vector<Real> ledger_positions (Grob *me, int pos);
   static int line_count (Grob *);
   static bool on_line (Grob *me, int pos);
   static Interval line_span (Grob *);
index 01238222147c9afbf4f33a2e6b62ac2018a46c9f..0e46e0d5b8f51b1013af8a2d6cefe1b59d6eb7e6 100644 (file)
@@ -32,61 +32,9 @@ struct Ledger_line_spanner
 {
   DECLARE_SCHEME_CALLBACK (print, (SCM));
   DECLARE_SCHEME_CALLBACK (set_spacing_rods, (SCM));
-  static Stencil brew_ledger_lines (Grob *me,
-                                    int pos,
-                                    Interval,
-                                    Real, Real,
-                                    Interval x_extent,
-                                    Real left_shorten);
-
   DECLARE_GROB_INTERFACE ();
 };
 
-Stencil
-Ledger_line_spanner::brew_ledger_lines (Grob *staff,
-                                        int pos,
-                                        Interval staff_extent,
-                                        Real halfspace,
-                                        Real ledgerlinethickness,
-                                        Interval x_extent,
-                                        Real left_shorten)
-{
-  int line_count = (staff_extent.contains (pos)
-                    ? 0
-                    : sign (pos) * int (rint (pos - staff_extent[Direction (sign (pos))])) / 2);
-  Stencil stencil;
-  if (line_count)
-    {
-      Real blotdiameter = ledgerlinethickness;
-      Interval y_extent
-        = Interval (-0.5 * (ledgerlinethickness),
-                    +0.5 * (ledgerlinethickness));
-      Stencil proto_ledger_line
-        = Lookup::round_filled_box (Box (x_extent, y_extent), blotdiameter);
-
-      x_extent[LEFT] += left_shorten;
-      Stencil proto_first_line
-        = Lookup::round_filled_box (Box (x_extent, y_extent), blotdiameter);
-
-      Direction dir = (Direction)sign (pos);
-      Real offs = (Staff_symbol_referencer::on_line (staff, pos))
-                  ? 0.0
-                  : -dir * halfspace;
-
-      offs += pos * halfspace;
-      for (int i = 0; i < line_count; i++)
-        {
-          Stencil ledger_line ((i == 0)
-                               ? proto_first_line
-                               : proto_ledger_line);
-          ledger_line.translate_axis (-dir * halfspace * i * 2 + offs, Y_AXIS);
-          stencil.add_stencil (ledger_line);
-        }
-    }
-
-  return stencil;
-}
-
 static void
 set_rods (Drul_array<Interval> const &current_extents,
           Drul_array<Interval> const &previous_extents,
@@ -236,7 +184,6 @@ Ledger_line_spanner::print (SCM smob)
     = robust_scm2double (me->get_property ("length-fraction"), 0.25);
 
   Stencil ledgers;
-  Stencil default_ledger;
 
   Grob *common[NO_AXES];
 
@@ -320,38 +267,56 @@ Ledger_line_spanner::print (SCM smob)
       Item *h = dynamic_cast<Item *> (heads[i]);
 
       int pos = Staff_symbol_referencer::get_rounded_position (h);
-      if (!staff_extent.contains (pos - sign (pos)) && !staff_extent.is_empty ())
+      vector<Real> ledger_positions = Staff_symbol::ledger_positions (staff, pos);
+      if (!ledger_positions.empty ())
         {
+          int ledger_count = ledger_positions.size ();
           Interval head_size = h->extent (common[X_AXIS], X_AXIS);
           Interval ledger_size = head_size;
           ledger_size.widen (ledger_size.length () * length_fraction);
 
-          Interval max_size = reqs[h->get_column ()->get_rank ()]
-                              [Direction (sign (pos))].ledger_extent_;
-
-          ledger_size.intersect (max_size);
-          Real left_shorten = 0.0;
-          if (Grob *g = unsmob_grob (h->get_object ("accidental-grob")))
+          if (pos && !staff_extent.contains (pos))
             {
-              Interval accidental_size = g->extent (common[X_AXIS], X_AXIS);
-              Real d
-                = linear_combination (Drul_array<Real> (accidental_size[RIGHT],
-                                                        head_size[LEFT]),
-                                      0.0);
-
-              left_shorten = max (-ledger_size[LEFT] + d, 0.0);
-
-              /*
-                TODO: shorten 2 ledger lines for the case natural +
-                downstem.
-              */
+              Interval max_size = reqs[h->get_column ()->get_rank ()]
+                                  [Direction (sign (pos))].ledger_extent_;
+
+              if (!max_size.is_empty ())
+                ledger_size.intersect (max_size);
             }
 
-          ledgers.add_stencil (brew_ledger_lines (staff, pos, staff_extent,
-                                                  halfspace,
-                                                  ledgerlinethickness,
-                                                  ledger_size,
-                                                  left_shorten));
+          for (int i = 0; i < ledger_count; i++)
+            {
+              Real lpos = ledger_positions[i];
+              Interval x_extent = ledger_size;
+
+              if (i == 0)
+                if (Grob *g = unsmob_grob (h->get_object ("accidental-grob")))
+                  {
+                    Interval accidental_size = g->extent (common[X_AXIS], X_AXIS);
+                    Real d
+                      = linear_combination (Drul_array<Real> (accidental_size[RIGHT],
+                                                            head_size[LEFT]),
+                                          0.0);
+
+                    Real left_shorten = max (-ledger_size[LEFT] + d, 0.0);
+
+                    x_extent[LEFT] += left_shorten;
+                    /*
+                      TODO: shorten 2 ledger lines for the case natural +
+                      downstem.
+                    */
+                  }
+
+              Real blotdiameter = ledgerlinethickness;
+              Interval y_extent
+                = Interval (-0.5 * (ledgerlinethickness),
+                            +0.5 * (ledgerlinethickness));
+              Stencil ledger_line
+                = Lookup::round_filled_box (Box (x_extent, y_extent), blotdiameter);
+
+              ledger_line.translate_axis ( lpos * halfspace, Y_AXIS);
+              ledgers.add_stencil (ledger_line);
+            }
         }
     }
 
index f80a5c57741dfc1c2523f403fa809149c370d8d3..abfbe0ef0dc25848c265af1ce4f0c350f4b7098f 100644 (file)
@@ -78,52 +78,172 @@ Staff_symbol::print (SCM smob)
 
   Stencil m;
 
-  SCM line_positions = me->get_property ("line-positions");
+  vector<Real> line_positions = Staff_symbol::line_positions (me);
+  int line_count = line_positions.size ();
+
   Stencil line
     = Lookup::horizontal_line (span_points
                                - me->relative_coordinate (common, X_AXIS),
                                t);
 
   Real space = staff_space (me);
+  for (int i = 0; i < line_count; i++)
+    {
+      Stencil b (line);
+      b.translate_axis (line_positions[i] * 0.5 * space, Y_AXIS);
+      m.add_stencil (b);
+    }
+  return m.smobbed_copy ();
+}
+
+vector<Real>
+Staff_symbol::line_positions (Grob *me)
+{
+  SCM line_positions = me->get_property ("line-positions");
   if (scm_is_pair (line_positions))
     {
+      int line_count = scm_ilength (line_positions);
+      vector<Real> values (line_count);
+      int i = 0;
       for (SCM s = line_positions; scm_is_pair (s);
            s = scm_cdr (s))
         {
-          Stencil b (line);
-          b.translate_axis (scm_to_double (scm_car (s))
-                            * 0.5 * space, Y_AXIS);
-          m.add_stencil (b);
+          values[i++] = scm_to_double (scm_car (s));
         }
+      return values;
     }
   else
     {
-      int l = Staff_symbol::line_count (me);
-      Real height = (l - 1) * staff_space (me) / 2;
-      for (int i = 0; i < l; i++)
+      int line_count = Staff_symbol::line_count (me);
+      Real height = line_count - 1;
+      vector<Real> values (line_count);
+      for (int i = 0; i < line_count; i++)
         {
-          Stencil b (line);
-          b.translate_axis (height - i * space, Y_AXIS);
-          m.add_stencil (b);
+          values[i] = height - i * 2;
         }
+      return values;
     }
-  return m.smobbed_copy ();
 }
 
-int
-Staff_symbol::get_steps (Grob *me)
+vector<Real>
+Staff_symbol::ledger_positions (Grob *me, int pos)
 {
-  return line_count (me) * 2;
+  SCM ledger_positions = me->get_property ("ledger-positions");
+  Real ledger_extra = robust_scm2double (me->get_property ("ledger-extra"), 0);
+  vector<Real> line_positions = Staff_symbol::line_positions (me);
+  vector<Real> values;
+
+  if (line_positions.empty ())
+    return values;
+
+  int line_count = line_positions.size ();
+
+  // find the staff line nearest to note position
+  Real nearest_line = line_positions[0];
+  Real line_dist = abs (line_positions[0] - pos);
+  for (int i = 1; i < line_count; i++)
+    {
+      if (abs (line_positions[i] - pos) < line_dist)
+        {
+          nearest_line = line_positions[i];
+          line_dist = abs (line_positions[i] - pos);
+        }
+    }
+
+  if (line_dist < .5)
+    return values;
+
+  Direction dir = (Direction)sign (pos - nearest_line);
+
+  if (scm_is_pair (ledger_positions))
+    {
+      Real min_pos = HUGE_VAL;
+      Real max_pos = -HUGE_VAL;
+      SCM s2;
+
+      // find the extent of the ledger pattern
+      for (SCM s = ledger_positions; scm_is_pair (s); s = scm_cdr (s))
+        {
+          s2 = scm_car (s);
+          if (!scm_is_number (s2))
+            s2 = scm_car (s2);
+          Real current_ledger = scm_to_double (s2);
+          if (current_ledger > max_pos)
+            max_pos = current_ledger;
+          if (current_ledger < min_pos)
+            min_pos = current_ledger;
+        }
+
+      Real cycle = max_pos - min_pos;
+
+      Interval ledger_fill;
+      ledger_fill.add_point (nearest_line + 0.5 * dir);
+      ledger_fill.add_point (pos + 0.5 * dir + ledger_extra * dir);
+
+      // fill the Interval ledger_fill with ledger lines
+      int n = floor ((ledger_fill[DOWN] - min_pos) / cycle);
+      Real current;
+      SCM s = scm_cdr (ledger_positions);
+      do
+        {
+          s2 = scm_car (s);
+          if (scm_is_number (s2))
+            {
+              current = scm_to_double (s2) + n * cycle;
+              if (ledger_fill.contains (current))
+                values.push_back (current);
+            }
+          else
+            // grouped ledger lines, either add all or none
+            {
+              do
+                {
+                  current = scm_to_double (scm_car (s2)) + n * cycle;
+                  if (ledger_fill.contains (current))
+                    {
+                      s2 = scm_car (s);
+                      do
+                        {
+                          current = scm_to_double (scm_car (s2)) + n * cycle;
+                          values.push_back (current);
+                          s2 = scm_cdr (s2);
+                        }
+                      while (scm_is_pair (s2));
+                    }
+                  else
+                    s2 = scm_cdr (s2);
+                }
+              while (scm_is_pair (s2));
+            }
+          s = scm_cdr (s);
+          if (!scm_is_pair (s))
+            {
+              s = scm_cdr (ledger_positions);
+              n++;
+            }
+        }
+      while (current <= ledger_fill[UP]);
+    }
+  else
+    {
+      int ledger_count = floor ((abs (nearest_line - pos) + ledger_extra) / 2);
+      values.resize (ledger_count);
+      for (int i = 0; i < ledger_count; i++)
+        {
+          values[i] = nearest_line + dir * (ledger_count - i) * 2;
+        }
+    }
+  return values;
 }
 
 int
 Staff_symbol::line_count (Grob *me)
 {
-  SCM c = me->get_property ("line-count");
-  if (scm_is_number (c))
-    return scm_to_int (c);
+  SCM line_positions = me->get_property ("line-positions");
+  if (scm_is_pair (line_positions))
+    return scm_ilength (line_positions);
   else
-    return 0;
+    return robust_scm2int (me->get_property ("line-count"), 0);
 }
 
 Real
@@ -234,7 +354,9 @@ ADD_INTERFACE (Staff_symbol,
                " @code{width} property.",
 
                /* properties */
+               "ledger-extra "
                "ledger-line-thickness "
+               "ledger-positions "
                "line-count "
                "line-positions "
                "staff-space "
index ec0ff1e37f7e05d15c9a998b7ba10aad58563c17..a78ce0e9bb4d894d3ce8364e8ed4857bec1ae819 100644 (file)
@@ -498,10 +498,14 @@ objects.  Objects with the lowest value of layer are drawn first, then
 objects with progressively higher values are drawn, so objects with
 higher values overwrite objects with lower values.  By default most
 objects are assigned a layer value of 1.")
+     (ledger-extra ,ly:dimension? "Extra distance from staff line to draw ledger
+lines for.")
      (ledger-line-thickness ,number-pair? "The thickness of ledger
 lines.  It is the sum of 2@tie{}numbers: The first is the factor for
 line thickness, and the second for staff space.  Both contributions
 are added.")
+     (ledger-positions ,list? "Repeating pattern for the vertical positions
+of ledger lines.  Bracketed groups are always shown together.")
      (left-bound-info ,list? "An alist of properties for determining
 attachments of spanners to edges.")
      (left-padding ,ly:dimension? "The amount of space that is put