--- /dev/null
+\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
+}
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 *);
{
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 ¤t_extents,
Drul_array<Interval> const &previous_extents,
= robust_scm2double (me->get_property ("length-fraction"), 0.25);
Stencil ledgers;
- Stencil default_ledger;
Grob *common[NO_AXES];
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);
+ }
}
}
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
" @code{width} property.",
/* properties */
+ "ledger-extra "
"ledger-line-thickness "
+ "ledger-positions "
"line-count "
"line-positions "
"staff-space "
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