From d10ec4f5a95d5b205da1bd73102697f8cc03b5b6 Mon Sep 17 00:00:00 2001 From: Piers Titus van der Torren Date: Thu, 26 May 2011 02:44:14 +0200 Subject: [PATCH] add support for custom ledgers, using two new staff-symbol properties --- input/regression/staff-ledger-positions.ly | 17 +++ lily/include/staff-symbol.hh | 3 +- lily/ledger-line-spanner.cc | 119 ++++++--------- lily/staff-symbol.cc | 160 ++++++++++++++++++--- scm/define-grob-properties.scm | 4 + 5 files changed, 206 insertions(+), 97 deletions(-) create mode 100644 input/regression/staff-ledger-positions.ly diff --git a/input/regression/staff-ledger-positions.ly b/input/regression/staff-ledger-positions.ly new file mode 100644 index 0000000000..67233d1060 --- /dev/null +++ b/input/regression/staff-ledger-positions.ly @@ -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 +} diff --git a/lily/include/staff-symbol.hh b/lily/include/staff-symbol.hh index 9aee969f49..0a3ef80d64 100644 --- a/lily/include/staff-symbol.hh +++ b/lily/include/staff-symbol.hh @@ -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 line_positions (Grob *); + static vector ledger_positions (Grob *me, int pos); static int line_count (Grob *); static bool on_line (Grob *me, int pos); static Interval line_span (Grob *); diff --git a/lily/ledger-line-spanner.cc b/lily/ledger-line-spanner.cc index 0123822214..0e46e0d5b8 100644 --- a/lily/ledger-line-spanner.cc +++ b/lily/ledger-line-spanner.cc @@ -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 const ¤t_extents, Drul_array 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 (heads[i]); int pos = Staff_symbol_referencer::get_rounded_position (h); - if (!staff_extent.contains (pos - sign (pos)) && !staff_extent.is_empty ()) + vector 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 (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 (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); + } } } diff --git a/lily/staff-symbol.cc b/lily/staff-symbol.cc index f80a5c5774..abfbe0ef0d 100644 --- a/lily/staff-symbol.cc +++ b/lily/staff-symbol.cc @@ -78,52 +78,172 @@ Staff_symbol::print (SCM smob) Stencil m; - SCM line_positions = me->get_property ("line-positions"); + vector 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 +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 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 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 +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 line_positions = Staff_symbol::line_positions (me); + vector 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 " diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index ec0ff1e37f..a78ce0e9bb 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -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 -- 2.39.2