X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;ds=sidebyside;f=lily%2Ftuplet-bracket.cc;h=a70c46ef6d6ff6379e869a17977ac4db19e9be4c;hb=be83f044fb3dad53417d9183a25af6ce642ef1b5;hp=a73c06dec4f7c0e2c1cc52e5fa072d79c583723a;hpb=bdf4ab13203502e7ec7cf9cf5896527643a07c1f;p=lilypond.git diff --git a/lily/tuplet-bracket.cc b/lily/tuplet-bracket.cc index a73c06dec4..a70c46ef6d 100644 --- a/lily/tuplet-bracket.cc +++ b/lily/tuplet-bracket.cc @@ -37,48 +37,58 @@ #include "warn.hh" #include "font-interface.hh" #include "output-def.hh" -#include "text-item.hh" +#include "text-interface.hh" #include "stem.hh" #include "note-column.hh" -#include "group-interface.hh" +#include "pointer-group-interface.hh" #include "directional-element-interface.hh" #include "spanner.hh" #include "staff-symbol-referencer.hh" #include "lookup.hh" -static Grob * -get_x_bound_grob (Grob *g, Direction my_dir) +static Item * +get_x_bound_item (Grob *me_grob, Direction hdir, Direction my_dir) { - if (Note_column::get_stem (g) + Spanner *me = dynamic_cast (me_grob); + Item *g = me->get_bound (hdir); + if (Note_column::has_interface (g) + && Note_column::get_stem (g) && Note_column::dir (g) == my_dir) { g = Note_column::get_stem (g); } + return g; } Grob * -Tuplet_bracket::parallel_beam (Grob *me, Link_array const &cols, bool *equally_long) +Tuplet_bracket::parallel_beam (Grob *me_grob, Link_array const &cols, bool *equally_long) { - /* - ugh: code dup. - */ + Spanner *me = dynamic_cast (me_grob); + + if (me->get_bound (LEFT)->break_status_dir () + || me->get_bound (RIGHT)->break_status_dir ()) + return 0; + Grob *s1 = Note_column::get_stem (cols[0]); Grob *s2 = Note_column::get_stem (cols.top ()); + + if (s2 != me->get_bound (RIGHT)) + return 0; + Grob *b1 = s1 ? Stem::get_beam (s1) : 0; Grob *b2 = s2 ? Stem::get_beam (s2) : 0; - Spanner *sp = dynamic_cast (me); *equally_long = false; - if (! (b1 && (b1 == b2) && !sp->is_broken ())) + if (! (b1 && (b1 == b2) && !me->is_broken ())) return 0; - Link_array beam_stems = extract_grob_array (b1, ly_symbol2scm ("stems")); + extract_grob_set (b1, "stems", beam_stems); if (beam_stems.size () == 0) { - programming_error ("Beam under tuplet bracket has no stems!"); + programming_error ("beam under tuplet bracket has no stems"); *equally_long = 0; return 0; } @@ -97,20 +107,25 @@ MAKE_SCHEME_CALLBACK (Tuplet_bracket, print, 1); SCM Tuplet_bracket::print (SCM smob) { - Grob *me = unsmob_grob (smob); + Spanner *me = unsmob_spanner (smob); Stencil mol; - Link_array columns - = extract_grob_array (me, ly_symbol2scm ("note-columns")); - - if (!columns.size ()) - return mol.smobbed_copy (); + extract_grob_set (me, "note-columns", columns); { SCM lp = me->get_property ("left-position"); SCM rp = me->get_property ("right-position"); if (!scm_is_number (rp) || !scm_is_number (lp)) - after_line_breaking (smob); + { + /* + UGH. dependency tracking! + */ + extract_grob_set (me, "tuplets", tuplets); + for (int i = 0; i < tuplets.size (); i++) + Tuplet_bracket::print (tuplets[i]->self_scm()); + + after_line_breaking (smob); + } } Real ly = robust_scm2double (me->get_property ("left-position"), 0); @@ -143,24 +158,53 @@ Tuplet_bracket::print (SCM smob) else if (numb == ly_symbol2scm ("if-no-beam")) number_visibility = !par_beam; - Grob *commonx = columns[0]->common_refpoint (columns.top (), X_AXIS); - - /* - Tuplet brackets are normally not broken, but we shouldn't crash if - they are. - */ + Grob *commonx = common_refpoint_of_array (columns, me, X_AXIS); commonx = commonx->common_refpoint (sp->get_bound (LEFT), X_AXIS); commonx = commonx->common_refpoint (sp->get_bound (RIGHT), X_AXIS); Direction dir = get_grob_direction (me); - Grob *lgr = get_x_bound_grob (columns[0], dir); - Grob *rgr = get_x_bound_grob (columns.top (), dir); + Drul_array bounds; + bounds[LEFT] = get_x_bound_item (me, LEFT, dir); + bounds[RIGHT] = get_x_bound_item (me, RIGHT, dir); - Real x0 = robust_relative_extent (lgr, commonx, X_AXIS)[LEFT]; - Real x1 = robust_relative_extent (rgr, commonx, X_AXIS)[RIGHT]; - Real w = x1 -x0; + Drul_array connect_to_other; + Interval x_span; + Direction d = LEFT; + do + { + x_span[d] = robust_relative_extent (bounds[d], commonx, X_AXIS)[d]; + Direction break_dir = bounds[d]->break_status_dir (); + Spanner *orig_spanner = dynamic_cast (me->original_); + connect_to_other[d] + = (break_dir + && (me->get_break_index() - break_dir < orig_spanner->broken_intos_.size())); + + if (connect_to_other[d]) + { + Interval overshoot (robust_scm2drul (me->get_property ("break-overshoot"), + Interval (-0.5, 1.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]; + } + else if (d == RIGHT && + (columns.is_empty () + || bounds[d] != columns.top())) + + { + /* + TODO: make padding tunable? + */ + x_span[d] = robust_relative_extent (bounds[d], commonx, X_AXIS) [LEFT] - 1.0; + } + } + while (flip (&d) != LEFT); + Real w = x_span.length(); SCM number = me->get_property ("text"); Output_def *pap = me->get_layout (); @@ -192,30 +236,50 @@ Tuplet_bracket::print (SCM smob) if (bracket_visibility) { - Real ss = Staff_symbol_referencer::staff_space (me); Real gap = 0.; if (!num.extent (X_AXIS).is_empty ()) gap = num.extent (X_AXIS).length () + 1.0; - SCM fl = me->get_property ("bracket-flare"); - SCM eh = me->get_property ("edge-height"); - SCM sp = me->get_property ("shorten-pair"); - - Direction d = LEFT; - Drul_array height, flare, shorten; + Drul_array zero (0,0); + Real ss = Staff_symbol_referencer::staff_space (me); + Drul_array height + = robust_scm2drul (me->get_property ("edge-height"), zero); + Drul_array flare + = robust_scm2drul (me->get_property ("bracket-flare"), zero); + Drul_array shorten + = robust_scm2drul (me->get_property ("shorten-pair"), zero); + Drul_array edge_stencils; + + scale_drul (&height, -ss * dir); + scale_drul (&flare, ss); + scale_drul (&shorten, ss); do { - flare[d] = height[d] = shorten[d] = 0.0; - if (is_number_pair (fl)) - flare[d] += ss * scm_to_double (index_get_cell (fl, d)); - if (is_number_pair (eh)) - height[d] += -dir * ss * scm_to_double (index_get_cell (eh, d)); - if (is_number_pair (sp)) - shorten[d] += ss * scm_to_double (index_get_cell (sp, d)); + if (connect_to_other[d]) + { + height[d] = 0.0; + flare[d] = 0.0; + shorten[d] = 0.0; + + SCM properties = Font_interface::text_font_alist_chain (me); + SCM edge_text = me->get_property ("edge-text"); + + 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); + Stencil brack = make_bracket (me, Y_AXIS, Offset (w, ry - ly), height, @@ -225,11 +289,21 @@ Tuplet_bracket::print (SCM smob) */ 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); + + mol.add_stencil (brack); } mol.translate_axis (ly, Y_AXIS); - mol.translate_axis (x0 - sp->get_bound (LEFT)->relative_coordinate (commonx, X_AXIS), X_AXIS); + mol.translate_axis (x_span[LEFT] + - sp->get_bound (LEFT)->relative_coordinate (commonx, X_AXIS), X_AXIS); return mol.smobbed_copy (); } @@ -295,18 +369,50 @@ Tuplet_bracket::make_bracket (Grob *me, // for line properties. return m; } +void +Tuplet_bracket::get_bounds (Grob *me, Grob **left, Grob **right) +{ + extract_grob_set (me, "note-columns", columns); + int l = 0; + while (l < columns.size () && Note_column::has_rests (columns[l])) + l++; + + int r = columns.size ()- 1; + while (r >= l && Note_column::has_rests (columns[r])) + r--; + + *left = *right = 0; + + if (l <= r) + { + *left = columns[l]; + *right = columns[r]; + } +} + + /* use first -> last note for slope, and then correct for disturbing notes in between. */ void -Tuplet_bracket::calc_position_and_height (Grob *me, Real *offset, Real *dy) +Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy) { - Link_array columns - = extract_grob_array (me, ly_symbol2scm ("note-columns")); + Spanner *me = dynamic_cast (me_grob); + + extract_grob_set (me, "note-columns", columns); + extract_grob_set (me, "tuplets", tuplets); + + Grob *commony = common_refpoint_of_array (columns, me, Y_AXIS); + commony = common_refpoint_of_array (tuplets, commony, Y_AXIS); + if (Grob *st = Staff_symbol_referencer::get_staff_symbol (me)) + { + commony = st->common_refpoint (commony, Y_AXIS); + } - SCM cols = me->get_property ("note-columns"); - Grob *commony = common_refpoint_of_list (cols, me, Y_AXIS); - Grob *commonx = common_refpoint_of_list (cols, me, X_AXIS); + Grob *commonx = common_refpoint_of_array (columns, me, X_AXIS); + commonx = common_refpoint_of_array (tuplets, commonx, Y_AXIS); + commonx = commonx->common_refpoint (me->get_bound (LEFT), X_AXIS); + commonx = commonx->common_refpoint (me->get_bound (RIGHT), X_AXIS); Interval staff; if (Grob *st = Staff_symbol_referencer::get_staff_symbol (me)) @@ -317,24 +423,19 @@ Tuplet_bracket::calc_position_and_height (Grob *me, Real *offset, Real *dy) /* Use outer non-rest columns to determine slope */ - int l = 0; - while (l < columns.size () && Note_column::has_rests (columns[l])) - l++; - - int r = columns.size ()- 1; - while (r >= l && Note_column::has_rests (columns[r])) - r--; - - if (l < r) + Grob *left_col = 0; + Grob *right_col = 0; + get_bounds (me, &left_col, &right_col); + if (left_col && right_col) { - Interval rv = columns[r]->extent (commony, Y_AXIS); - Interval lv = columns[l]->extent (commony, Y_AXIS); + Interval rv = right_col->extent (commony, Y_AXIS); + Interval lv = left_col->extent (commony, Y_AXIS); rv.unite (staff); lv.unite (staff); Real graphical_dy = rv[dir] - lv[dir]; - Slice ls = Note_column::head_positions_interval (columns[l]); - Slice rs = Note_column::head_positions_interval (columns[r]); + 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]; @@ -347,45 +448,95 @@ Tuplet_bracket::calc_position_and_height (Grob *me, Real *offset, Real *dy) *dy = graphical_dy; } else - * dy = 0; + *dy = 0; *offset = -dir * infinity_f; - if (!columns.size ()) - return; - - Grob *lgr = get_x_bound_grob (columns[0], dir); - Grob *rgr = get_x_bound_grob (columns.top (), dir); + Item *lgr = get_x_bound_item (me, LEFT, dir); + Item *rgr = get_x_bound_item (me, RIGHT, dir); Real x0 = robust_relative_extent (lgr, commonx, X_AXIS)[LEFT]; Real x1 = robust_relative_extent (rgr, commonx, X_AXIS)[RIGHT]; /* - Slope. + offset */ Real factor = columns.size () > 1 ? 1 / (x1 - x0) : 1.0; + Array points; + points.push (Offset (x0, staff[dir])); + points.push (Offset (x1, staff[dir])); + for (int i = 0; i < columns.size (); i++) { Interval note_ext = columns[i]->extent (commony, Y_AXIS); - note_ext.unite (staff); Real notey = note_ext[dir] - me->relative_coordinate (commony, Y_AXIS); Real x = columns[i]->relative_coordinate (commonx, X_AXIS) - x0; - Real tuplety = *dy * x * factor; + points.push (Offset (x, notey)); + } + + /* + 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. + */ + Real ss = Staff_symbol_referencer::staff_space (me); + for (int i = 0; i < tuplets.size (); i++) + { + Interval tuplet_x (tuplets[i]->extent (commonx, X_AXIS)); + Interval tuplet_y (tuplets[i]->extent (commony, Y_AXIS)); - if (notey * dir > (*offset + tuplety) * dir) - *offset = notey - tuplety; + Direction d = LEFT; + Real lp = scm_to_double (tuplets[i]->get_property ("left-position")); + Real rp = scm_to_double (tuplets[i]->get_property ("right-position")); + Real other_dy = rp - lp; + + do + { + Real y = + tuplet_y.linear_combination (d * sign (other_dy)); + +#if 0 + /* + Let's not take padding into account for nested tuplets. + the edges can come very close to the stems, likewise for + nested tuplets? + */ + Drul_array my_height + = robust_scm2drul (me->get_property ("edge-height"), Interval (0,0)); + if (dynamic_cast (tuplets[i])->get_bound (d) + == me->get_bound (d)) + { + y += dir * my_height[d]; + } +#endif + + points.push (Offset (tuplet_x[d] - x0, y)); + } + while (flip (&d) != LEFT); } - // padding + for (int i = 0; i < points.size (); i++) + { + Real x = points[i][X_AXIS]; + Real tuplety = *dy * x * factor; + + if (points[i][Y_AXIS] * dir > (*offset + tuplety) * dir) + *offset = points[i][Y_AXIS] - tuplety; + } + *offset += scm_to_double (me->get_property ("padding")) * dir; /* 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. */ - Real ss = Staff_symbol_referencer::staff_space (me); - if (*dy == 0 && fabs (*offset) < ss * Staff_symbol_referencer::staff_radius (me)) + if (*dy == 0 && + fabs (*offset) < ss * Staff_symbol_referencer::staff_radius (me)) { // quantize, then do collision check. *offset *= 2 / ss; @@ -406,8 +557,7 @@ SCM Tuplet_bracket::before_line_breaking (SCM smob) { Grob *me = unsmob_grob (smob); - Link_array columns - = extract_grob_array (me, ly_symbol2scm ("note-columns")); + extract_grob_set (me, "note-columns", columns); for (int i = columns.size (); i--;) { @@ -425,20 +575,7 @@ SCM Tuplet_bracket::after_line_breaking (SCM smob) { Grob *me = unsmob_grob (smob); - Link_array columns - = extract_grob_array (me, ly_symbol2scm ("note-columns")); - - if (!columns.size ()) - { - me->suicide (); - return SCM_UNSPECIFIED; - } - if (dynamic_cast (me)->is_broken ()) - { - me->warning (_ ("Killing tuplet bracket across linebreak.")); - me->suicide (); - return SCM_UNSPECIFIED; - } + extract_grob_set (me, "note-columns", columns); Direction dir = get_grob_direction (me); if (!dir) @@ -453,7 +590,8 @@ Tuplet_bracket::after_line_breaking (SCM smob) /* We follow the beam only if there is one, and we are next to it. */ - Real dy, offset; + Real dy = 0.0; + Real offset = 0.0; if (!par_beam || get_grob_direction (par_beam) != dir) { @@ -478,16 +616,16 @@ Tuplet_bracket::after_line_breaking (SCM smob) if (scm_is_number (lp) && !scm_is_number (rp)) { - rp = scm_make_real (scm_to_double (lp) + dy); + rp = scm_from_double (scm_to_double (lp) + dy); } else if (scm_is_number (rp) && !scm_is_number (lp)) { - lp = scm_make_real (scm_to_double (rp) - dy); + lp = scm_from_double (scm_to_double (rp) - dy); } else if (!scm_is_number (rp) && !scm_is_number (lp)) { - lp = scm_make_real (offset); - rp = scm_make_real (offset + dy); + lp = scm_from_double (offset); + rp = scm_from_double (offset + dy); } me->set_property ("left-position", lp); @@ -503,9 +641,10 @@ Direction Tuplet_bracket::get_default_dir (Grob *me) { Drul_array dirs (0, 0); - for (SCM s = me->get_property ("note-columns"); scm_is_pair (s); s = scm_cdr (s)) + extract_grob_set (me, "note-columns", columns); + for (int i = 0 ; i < columns.size (); i++) { - Grob *nc = unsmob_grob (scm_car (s)); + Grob *nc = columns[i]; Direction d = Note_column::dir (nc); if (d) dirs[d]++; @@ -523,11 +662,26 @@ Tuplet_bracket::add_column (Grob *me, Item *n) add_bound_item (dynamic_cast (me), n); } +void +Tuplet_bracket::add_tuplet_bracket (Grob *me, Grob *bracket) +{ + Pointer_group_interface::add_grob (me, ly_symbol2scm ("tuplets"), bracket); + me->add_dependency (bracket); +} + + + ADD_INTERFACE (Tuplet_bracket, "tuplet-bracket-interface", - "A bracket with a number in the middle, used for 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. ", "note-columns bracket-flare edge-height shorten-pair " + "tuplets edge-text break-overshoot " "padding left-position right-position bracket-visibility " "number-visibility thickness direction");