X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fhairpin.cc;h=399b5d995e8876f37aec2622a947435bcdc35507;hb=068eadf4ad2d70a0eec8589921ed6a12742b6c63;hp=723244c025d14682bff1e75a3845cb68974afe50;hpb=e8936ee66fdd3e7ebe30556590e8dc913908a533;p=lilypond.git diff --git a/lily/hairpin.cc b/lily/hairpin.cc index 723244c025..399b5d995e 100644 --- a/lily/hairpin.cc +++ b/lily/hairpin.cc @@ -1,138 +1,265 @@ /* - hairpin.cc -- implement Hairpin + This file is part of LilyPond, the GNU music typesetter. - source file of the GNU LilyPond music typesetter + Copyright (C) 1997--2011 Han-Wen Nienhuys - (c) 1997--2003 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 "molecule.hh" #include "hairpin.hh" -#include "spanner.hh" -#include "font-interface.hh" + #include "dimensions.hh" -#include "paper-def.hh" -#include "warn.hh" +#include "international.hh" +#include "line-interface.hh" +#include "output-def.hh" #include "paper-column.hh" -#include "lookup.hh" +#include "pointer-group-interface.hh" +#include "spanner.hh" +#include "staff-symbol-referencer.hh" +#include "text-interface.hh" +#include "note-column.hh" +#include "warn.hh" + +MAKE_SCHEME_CALLBACK (Hairpin, pure_height, 3); +SCM +Hairpin::pure_height (SCM smob, SCM, SCM) +{ + Grob *me = unsmob_grob (smob); + Real height = robust_scm2double (me->get_property ("height"), 0.0) + * Staff_symbol_referencer::staff_space (me); + + Real thickness = robust_scm2double (me->get_property ("thickness"), 1) + * Staff_symbol_referencer::line_thickness (me); -MAKE_SCHEME_CALLBACK (Hairpin, brew_molecule, 1); + height += thickness / 2; + return ly_interval2scm (Interval (-height, height)); +} +MAKE_SCHEME_CALLBACK (Hairpin, print, 1); SCM -Hairpin::brew_molecule (SCM smob) +Hairpin::print (SCM smob) { - Grob *me= unsmob_grob (smob); - Spanner *spanner = dynamic_cast (me); + Spanner *me = unsmob_spanner (smob); - Real line = me->get_paper ()->get_realvar (ly_symbol2scm ("linethickness")); - - SCM s = me->get_grob_property ("grow-direction"); - if (!ly_dir_p (s)) + SCM s = me->get_property ("grow-direction"); + if (!is_direction (s)) { me->suicide (); return SCM_EOL; } - - Direction grow_dir = to_dir (s); - - /* Ugh, must be same as Text_spanner::brew_molecule. */ + Direction grow_dir = to_dir (s); + Real padding = robust_scm2double (me->get_property ("bound-padding"), 0.5); - /* - Ugh. property name is not general. - */ - Real padding = gh_scm2double (me->get_grob_property ("if-text-padding")); - Drul_array broken; - Drul_array bounds ; + Drul_array bounds; Direction d = LEFT; do { - bounds[d] =spanner->get_bound (d); + bounds[d] = me->get_bound (d); broken[d] = bounds[d]->break_status_dir () != CENTER; } while (flip (&d) != LEFT); + broken[RIGHT] = broken[RIGHT] && me->broken_neighbor (RIGHT); + broken[RIGHT] = broken[RIGHT] && me->broken_neighbor (RIGHT)->is_live (); + + if (broken[RIGHT]) + { + Spanner *next = me->broken_neighbor (RIGHT); + Stencil *s = next->get_stencil (); + if (!s || s->is_empty ()) + broken[RIGHT] = false; + } + Grob *common = bounds[LEFT]->common_refpoint (bounds[RIGHT], X_AXIS); - Drul_array x_points ; - + Drul_array x_points; + + /* + Use the height and thickness of the hairpin when making a circled tip + */ + bool circled_tip = ly_scm2bool (me->get_property ("circled-tip")); + Real height = robust_scm2double (me->get_property ("height"), 0.2) + * Staff_symbol_referencer::staff_space (me); + /* + FIXME: 0.525 is still just a guess... + */ + Real rad = height * 0.525; + Real thick = 1.0; + if (circled_tip) + thick = robust_scm2double (me->get_property ("thickness"), 1.0) + * Staff_symbol_referencer::line_thickness (me); + do { Item *b = bounds[d]; - x_points[d] = b->relative_coordinate (common, X_AXIS); + x_points[d] = b->relative_coordinate (common, X_AXIS); if (broken [d]) { if (d == LEFT) - x_points[d] = b->extent (common,X_AXIS)[RIGHT] ; + x_points[d] = b->extent (common, X_AXIS)[RIGHT]; } else { - if (dynamic_cast (b)) + if (Text_interface::has_interface (b)) { - /* - If we're hung on a paper column, that means we're not - adjacent to a text-dynamic, and we may move closer. We - make the padding a little smaller, here. - */ - Interval e =b->extent (common, X_AXIS); - if (e.empty_b ()) - e = Interval (0,0) + b->relative_coordinate (common, X_AXIS); - - x_points[d] = e.center () - d * padding /3; // ugh. + Interval e = b->extent (common, X_AXIS); + if (!e.is_empty ()) + x_points[d] = e[-d] - d * padding; } else { - Interval e =b->extent (common, X_AXIS); - if (!e.empty_b ()) - x_points[d] = e[-d] - d*padding; + bool neighbor_found = false; + Spanner *adjacent; + extract_grob_set (me, "adjacent-spanners", neighbors); + for (vsize i = 0; i < neighbors.size (); i++) + { + /* + FIXME: this will fuck up in case of polyphonic + notes in other voices. Need to look at note-columns + in the current staff/voice. + */ + adjacent = dynamic_cast (neighbors[i]); + if (adjacent + && (adjacent->get_bound (-d)->get_column () + == b->get_column ())) + { + neighbor_found = true; + break; + } + } + + Interval e = robust_relative_extent (b, common, X_AXIS); + if (neighbor_found) + { + if (Hairpin::has_interface (adjacent)) + { + /* + Handle back-to-back hairpins with a circle in the middle + */ + if (circled_tip && (grow_dir != d)) + x_points[d] = e.center () + d * (rad - thick / 2.0); + /* + If we're hung on a paper column, that means we're not + adjacent to a text-dynamic, and we may move closer. We + make the padding a little smaller, here. + */ + else + x_points[d] = e.center () - d * padding / 3; + } + // Our neighbor is a dynamic text spanner, so add the + // same amount of padding as for text dynamics + else + x_points[d] = e[-d] - d * padding; + } + else + { + if (Note_column::has_interface (b) + && Note_column::has_rests (b)) + x_points[d] = e[-d]; + else + x_points[d] = e[d]; + + Item *bound = me->get_bound (d); + if (bound->is_non_musical (bound)) + x_points[d] -= d * padding; + } } } } while (flip (&d) != LEFT); - Real width = x_points[RIGHT] - x_points[LEFT]; - if (width < 0) { me->warning (_ ((grow_dir < 0) ? "decrescendo too small" - : "crescendo too small")); + : "crescendo too small")); width = 0; } bool continued = broken[Direction (-grow_dir)]; - Real height = gh_scm2double (me->get_grob_property ("height")); - Real thick = line * gh_scm2double (me->get_grob_property ("thickness")); - Real starth, endh; + Real starth = 0; + Real endh = 0; if (grow_dir < 0) { starth = height; - endh = continued ? height/2 : 0.0; + endh = continued ? height / 2 : 0.0; } else { - starth = continued ? height/2 : 0.0; + starth = continued ? height / 2 : 0.0; endh = height; } - Molecule mol = Lookup::line (thick, - Offset (0, starth), - Offset (width, endh)); - mol.add_molecule (Lookup::line (thick, - Offset (0, -starth), - Offset (width, -endh))); - + /* + should do relative to staff-symbol staff-space? + */ + Stencil mol; + Real x = 0.0; + + /* + Compensate for size of circle + */ + Direction tip_dir = -grow_dir; + if (circled_tip && !broken[tip_dir]) + { + if (grow_dir > 0) + x = rad * 2.0; + else if (grow_dir < 0) + width -= rad *2.0; + } + mol = Line_interface::line (me, Offset (x, starth), Offset (width, endh)); + mol.add_stencil (Line_interface::line (me, + Offset (x, -starth), + Offset (width, -endh))); + + /* + Support al/del niente notation by putting a circle at the + tip of the (de)crescendo. + */ + if (circled_tip) + { + Box extent (Interval (-rad, rad), Interval (-rad, rad)); + + /* Hmmm, perhaps we should have a Lookup::circle () method? */ + Stencil circle (extent, + scm_list_4 (ly_symbol2scm ("circle"), + scm_from_double (rad), + scm_from_double (thick), + SCM_BOOL_F)); + + /* + don't add another circle if the hairpin is broken + */ + if (!broken[tip_dir]) + mol.add_at_edge (X_AXIS, tip_dir, Stencil (circle), 0); + } + mol.translate_axis (x_points[LEFT] - bounds[LEFT]->relative_coordinate (common, X_AXIS), X_AXIS); - return mol.smobbed_copy (); } +ADD_INTERFACE (Hairpin, + "A hairpin crescendo or decrescendo.", - -ADD_INTERFACE (Hairpin, "hairpin-interface", - "hairpin crescendo.", - "grow-direction thickness height if-text-padding"); - + /* properties */ + "adjacent-spanners " + "circled-tip " + "bound-padding " + "grow-direction " + "height " + );