X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbreak-alignment-interface.cc;h=76d1e48ca4c7ee88d1bc7baf8c4a21415f49320c;hb=5bbfc22fce036b9b69df5e420de93e11da23c05e;hp=7b19d75fdc33eeff6b1ebadf7cdb04e661773b6f;hpb=474c8729dc274a30558102a015a01fa5882673db;p=lilypond.git diff --git a/lily/break-alignment-interface.cc b/lily/break-alignment-interface.cc index 7b19d75fdc..76d1e48ca4 100644 --- a/lily/break-alignment-interface.cc +++ b/lily/break-alignment-interface.cc @@ -1,11 +1,21 @@ /* - break-align-interface.cc -- implement Break_alignment_interface + This file is part of LilyPond, the GNU music typesetter. - source file of the GNU LilyPond music typesetter + Copyright (C) 1997--2014 Han-Wen Nienhuys - (c) 1997--2007 Han-Wen Nienhuys -*/ + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ #include "break-align-interface.hh" @@ -16,12 +26,9 @@ #include "output-def.hh" #include "paper-column.hh" #include "pointer-group-interface.hh" -#include "self-alignment-interface.hh" #include "side-position-interface.hh" #include "warn.hh" - - /* This is tricky: we cannot modify 'elements, since callers are iterating the same list. Reordering the list in-place, or resetting @@ -38,43 +45,40 @@ Break_alignment_interface::break_align_order (Item *me) return SCM_BOOL_F; SCM order = scm_vector_ref (order_vec, - scm_from_int (me->break_status_dir () + 1)); - + scm_from_int (me->break_status_dir () + 1)); return order; } - -vector +vector Break_alignment_interface::ordered_elements (Grob *grob) { Item *me = dynamic_cast (grob); extract_grob_set (me, "elements", elts); - SCM order = break_align_order (me); if (order == SCM_BOOL_F) return elts; - - vector writable_elts (elts); - /* - Copy in order specified in BREAK-ALIGN-ORDER. + + vector writable_elts (elts); + /* + Copy in order specified in BREAK-ALIGN-ORDER. */ - vector new_elts; + vector new_elts; for (; scm_is_pair (order); order = scm_cdr (order)) { SCM sym = scm_car (order); for (vsize i = writable_elts.size (); i--;) - { - Grob *g = writable_elts[i]; - if (g && sym == g->get_property ("break-align-symbol")) - { - new_elts.push_back (g); - writable_elts.erase (writable_elts.begin () + i); - } - } + { + Grob *g = writable_elts[i]; + if (g && sym == g->get_property ("break-align-symbol")) + { + new_elts.push_back (g); + writable_elts.erase (writable_elts.begin () + i); + } + } } return new_elts; @@ -86,23 +90,22 @@ Break_alignment_interface::add_element (Grob *me, Grob *toadd) Align_interface::add_element (me, toadd); } -MAKE_SCHEME_CALLBACK(Break_alignment_interface, calc_positioning_done, 1) +MAKE_SCHEME_CALLBACK (Break_alignment_interface, calc_positioning_done, 1) SCM Break_alignment_interface::calc_positioning_done (SCM smob) { - Grob *grob = unsmob_grob (smob); + Grob *grob = Grob::unsmob (smob); Item *me = dynamic_cast (grob); - vector elems = ordered_elements (me); + me->set_property ("positioning-done", SCM_BOOL_T); + + vector elems = ordered_elements (me); vector extents; - int last_nonempty = -1; for (vsize i = 0; i < elems.size (); i++) { Interval y = elems[i]->extent (elems[i], X_AXIS); extents.push_back (y); - if (!y.is_empty ()) - last_nonempty = i; } vsize idx = 0; @@ -111,7 +114,7 @@ Break_alignment_interface::calc_positioning_done (SCM smob) vector offsets; offsets.resize (elems.size ()); - for (vsize i = 0; i < offsets.size ();i++) + for (vsize i = 0; i < offsets.size (); i++) offsets[i] = 0.0; Real extra_right_space = 0.0; @@ -120,106 +123,106 @@ Break_alignment_interface::calc_positioning_done (SCM smob) { vsize next_idx = idx + 1; while (next_idx < elems.size () - && extents[next_idx].is_empty ()) - next_idx++; + && extents[next_idx].is_empty ()) + next_idx++; Grob *l = elems[idx]; Grob *r = 0; if (next_idx < elems.size ()) - r = elems[next_idx]; + r = elems[next_idx]; SCM alist = SCM_EOL; /* - Find the first grob with a space-alist entry. + Find the first grob with a space-alist entry. */ extract_grob_set (l, "elements", elts); for (vsize i = elts.size (); i--;) - { - Grob *elt = elts[i]; - - if (edge_idx == VPOS - && (elt->get_property ("break-align-symbol") - == ly_symbol2scm ("left-edge"))) - edge_idx = idx; - - SCM l = elt->get_property ("space-alist"); - if (scm_is_pair (l)) - { - alist = l; - break; - } - } + { + Grob *elt = elts[i]; + + if (edge_idx == VPOS + && (elt->get_property ("break-align-symbol") + == ly_symbol2scm ("left-edge"))) + edge_idx = idx; + + SCM l = elt->get_property ("space-alist"); + if (scm_is_pair (l)) + { + alist = l; + break; + } + } SCM rsym = r ? SCM_EOL : ly_symbol2scm ("right-edge"); /* - We used to use #'cause to find out the symbol and the spacing - table, but that gets icky when that grob is suicided for some - reason. + We used to use #'cause to find out the symbol and the spacing + table, but that gets icky when that grob is suicided for some + reason. */ if (r) - { - extract_grob_set (r, "elements", elts); - for (vsize i = elts.size (); - !scm_is_symbol (rsym) && i--;) - { - Grob *elt = elts[i]; - rsym = elt->get_property ("break-align-symbol"); - } - } + { + extract_grob_set (r, "elements", elts); + for (vsize i = elts.size (); + !scm_is_symbol (rsym) && i--;) + { + Grob *elt = elts[i]; + rsym = elt->get_property ("break-align-symbol"); + } + } if (rsym == ly_symbol2scm ("left-edge")) - edge_idx = next_idx; + edge_idx = next_idx; SCM entry = SCM_EOL; if (scm_is_symbol (rsym)) - entry = scm_assq (rsym, alist); + entry = scm_assq (rsym, alist); bool entry_found = scm_is_pair (entry); if (!entry_found) - { - string sym_string; - if (scm_is_symbol (rsym)) - sym_string = ly_symbol2string (rsym); + { + string sym_string; + if (scm_is_symbol (rsym)) + sym_string = ly_symbol2string (rsym); - string orig_string; - if (unsmob_grob (l->get_property ("cause"))) - orig_string = unsmob_grob (l->get_property ("cause"))->name (); + string orig_string; + if (Grob::unsmob (l->get_property ("cause"))) + orig_string = Grob::unsmob (l->get_property ("cause"))->name (); - programming_error (_f ("No spacing entry from %s to `%s'", - orig_string.c_str (), - sym_string.c_str ())); - } + programming_error (to_string ("No spacing entry from %s to `%s'", + orig_string.c_str (), + sym_string.c_str ())); + } Real distance = 1.0; SCM type = ly_symbol2scm ("extra-space"); if (entry_found) - { - entry = scm_cdr (entry); + { + entry = scm_cdr (entry); - distance = scm_to_double (scm_cdr (entry)); - type = scm_car (entry); - } + distance = scm_to_double (scm_cdr (entry)); + type = scm_car (entry); + } if (r) - { - if (type == ly_symbol2scm ("extra-space")) - offsets[next_idx] = extents[idx][RIGHT] + distance - - extents[next_idx][LEFT]; - /* should probably junk minimum-space */ - else if (type == ly_symbol2scm ("minimum-space")) - offsets[next_idx] = max (extents[idx][RIGHT], distance); - } + { + if (type == ly_symbol2scm ("extra-space")) + offsets[next_idx] = extents[idx][RIGHT] + distance + - extents[next_idx][LEFT]; + /* should probably junk minimum-space */ + else if (type == ly_symbol2scm ("minimum-space")) + offsets[next_idx] = max (extents[idx][RIGHT], distance); + } else - { - extra_right_space = distance; - if (idx < offsets.size() - 1) - offsets[idx+1] = extents[idx][RIGHT] + distance; - } + { + extra_right_space = distance; + if (idx + 1 < offsets.size ()) + offsets[idx + 1] = extents[idx][RIGHT] + distance; + } idx = next_idx; } @@ -232,7 +235,7 @@ Break_alignment_interface::calc_positioning_done (SCM smob) { here += offsets[i]; if (i == edge_idx) - alignment_off = -here; + alignment_off = -here; total_extent.unite (extents[i] + here); } @@ -254,92 +257,159 @@ Break_alignment_interface::calc_positioning_done (SCM smob) return SCM_BOOL_T; } - - -MAKE_SCHEME_CALLBACK(Break_alignable_interface, self_align_callback, 1) +MAKE_SCHEME_CALLBACK (Break_alignable_interface, self_align_callback, 1) SCM Break_alignable_interface::self_align_callback (SCM grob) { - Grob *me = unsmob_grob (grob); - Item *alignment = dynamic_cast (me->get_parent (X_AXIS)); + Grob *me = Grob::unsmob (grob); + Item *alignment = dynamic_cast (me->get_parent (X_AXIS)); if (!Break_alignment_interface::has_interface (alignment)) return scm_from_int (0); - SCM my_align = me->get_property ("break-align-symbol"); - SCM order = Break_alignment_interface::break_align_order (alignment); - - vector elements = Break_alignment_interface::ordered_elements (alignment); + SCM symbol_list = me->get_property ("break-align-symbols"); + vector elements = Break_alignment_interface::ordered_elements (alignment); if (elements.size () == 0) return scm_from_int (0); - - int last_idx_found = -1; - vsize i = 0; - for (SCM s = order; scm_is_pair (s); s = scm_cdr (s)) + + int break_aligned_grob = -1; + for (; scm_is_pair (symbol_list); symbol_list = scm_cdr (symbol_list)) { - if (i < elements.size () - && elements[i]->get_property ("break-align-symbol") == scm_car (s)) - { - last_idx_found = i; - i ++; - } - - if (scm_car (s) == my_align) - break ; - } - - Direction which_edge = LEFT; - if (vsize (last_idx_found + 1) < elements.size()) - last_idx_found ++; - else - which_edge = RIGHT; - - Grob *common = me->common_refpoint (elements[last_idx_found], X_AXIS); - - return scm_from_double (robust_relative_extent (elements[last_idx_found], common, X_AXIS)[which_edge] - - me->relative_coordinate (common, X_AXIS)); + SCM sym = scm_car (symbol_list); + for (vsize i = 0; i < elements.size (); i++) + { + if (elements[i]->get_property ("break-align-symbol") == sym) + { + if (Item::break_visible (elements[i]) + && !elements[i]->extent (elements[i], X_AXIS).is_empty ()) + { + break_aligned_grob = i; + goto found_break_aligned_grob; /* ugh. need to break out of 2 loops */ + } + else if (break_aligned_grob == -1) + break_aligned_grob = i; + } + } + } + +found_break_aligned_grob: + if (break_aligned_grob == -1) + return scm_from_int (0); + + Grob *alignment_parent = elements[break_aligned_grob]; + Grob *common = me->common_refpoint (alignment_parent, X_AXIS); + Real anchor = robust_scm2double (alignment_parent->get_property ("break-align-anchor"), 0); + + return scm_from_double (alignment_parent->relative_coordinate (common, X_AXIS) + - me->relative_coordinate (common, X_AXIS) + + anchor); } -ADD_INTERFACE (Break_alignable_interface, - "Object that is aligned on a break aligment. ", +MAKE_SCHEME_CALLBACK (Break_aligned_interface, calc_average_anchor, 1) +SCM +Break_aligned_interface::calc_average_anchor (SCM grob) +{ + Grob *me = Grob::unsmob (grob); + Real avg = 0.0; + int count = 0; + + /* average the anchors of those children that have it set */ + extract_grob_set (me, "elements", elts); + for (vsize i = 0; i < elts.size (); i++) + { + SCM anchor = elts[i]->get_property ("break-align-anchor"); + if (scm_is_number (anchor)) + { + count++; + avg += scm_to_double (anchor); + } + } + + return scm_from_double (count > 0 ? avg / count : 0); +} + +MAKE_SCHEME_CALLBACK (Break_aligned_interface, calc_extent_aligned_anchor, 1) +SCM +Break_aligned_interface::calc_extent_aligned_anchor (SCM smob) +{ + Grob *me = Grob::unsmob (smob); + Real alignment = robust_scm2double (me->get_property ("break-align-anchor-alignment"), 0.0); + Interval iv = me->extent (me, X_AXIS); - /* properties */ - "break-align-symbol " - ) + if (isinf (iv[LEFT]) && isinf (iv[RIGHT])) /* avoid NaN */ + return scm_from_double (0.0); + return scm_from_double (iv.linear_combination (alignment)); +} + +MAKE_SCHEME_CALLBACK (Break_aligned_interface, calc_break_visibility, 1) +SCM +Break_aligned_interface::calc_break_visibility (SCM smob) +{ + /* a BreakAlignGroup is break-visible if it has one element that is break-visible */ + Grob *me = Grob::unsmob (smob); + SCM ret = scm_c_make_vector (3, SCM_EOL); + extract_grob_set (me, "elements", elts); + for (int dir = 0; dir <= 2; dir++) + { + bool visible = false; + for (vsize i = 0; i < elts.size (); i++) + { + SCM vis = elts[i]->get_property ("break-visibility"); + if (scm_is_vector (vis) && to_boolean (scm_c_vector_ref (vis, dir))) + visible = true; + } + scm_c_vector_set_x (ret, dir, scm_from_bool (visible)); + } + return ret; +} + +ADD_INTERFACE (Break_alignable_interface, + "Object that is aligned on a break alignment.", + /* properties */ + "break-align-symbols " + "non-break-align-symbols " + ); ADD_INTERFACE (Break_aligned_interface, - "Items that are aligned in prefatory matter.\n" - "\n" - "The spacing of these items is controlled by the @code{space-alist}\n" - "property. It contains a list @code{break-align-symbol}s with a specification\n" - "of the associated space. The space specification can be " - "@table @code\n" - "@item (minimum-space . @var{spc}))\n" - " Pad space until the distance is @var{spc}\n" - "@item (fixed-space . @var{spc})\n" - " Set a fixed space\n" - "@item (semi-fixed-space . @var{spc})\n" - " Set a space. Half of it is fixed and half is stretchable. \n" - "(does not work at start of line. fixme)\n" - "@item (extra-space . @var{spc})\n" - " Add @var{spc} amount of space.\n" - "@end table\n" - "\n" - "Special keys for the alist are @code{first-note} and @code{next-note}, signifying\n" - "the first note on a line, and the next note halfway a line.\n" - "\n" - "Rules for this spacing are much more complicated than this. \n" - "See [Wanske] page 126 -- 134, [Ross] pg 143 -- 147\n", - - /* properties */ - "break-align-symbol " - "space-alist " - ); + "Items that are aligned in prefatory matter.\n" + "\n" + "The spacing of these items is controlled by the" + " @code{space-alist} property. It contains a list" + " @code{break-align-symbol}s with a specification of the" + " associated space. The space specification can be\n" + "\n" + "@table @code\n" + "@item (minimum-space . @var{spc}))\n" + "Pad space until the distance is @var{spc}.\n" + "@item (fixed-space . @var{spc})\n" + "Set a fixed space.\n" + "@item (semi-fixed-space . @var{spc})\n" + "Set a space. Half of it is fixed and half is stretchable." + " (does not work at start of line. fixme)\n" + "@item (extra-space . @var{spc})\n" + "Add @var{spc} amount of space.\n" + "@end table\n" + "\n" + "Special keys for the alist are @code{first-note} and" + " @code{next-note}, signifying the first note on a line, and" + " the next note halfway a line.\n" + "\n" + "Rules for this spacing are much more complicated than this." + " See [Wanske] page 126--134, [Ross] page 143--147.", + + /* properties */ + "break-align-anchor " + "break-align-anchor-alignment " + "break-align-symbol " + "space-alist " + ); ADD_INTERFACE (Break_alignment_interface, - "The object that performs break aligment. See @ref{break-aligned-interface}.", + "The object that performs break alignment. See" + " @ref{break-aligned-interface}.", - /* properties */ - "positioning-done " - "break-align-orders"); + /* properties */ + "positioning-done " + "break-align-orders " + );