Nitpick: ly:spanner-bound grob name slur -> spanner.
[lilypond.git] / lily / arpeggio.cc
blob8e6e9c5a3364613eac45c2a216288d1d09421709
1 /*
2 arpeggio.cc -- implement Arpeggio
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2009 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
9 #include "arpeggio.hh"
11 #include "bezier.hh"
12 #include "font-interface.hh"
13 #include "grob.hh"
14 #include "lookup.hh"
15 #include "output-def.hh"
16 #include "pointer-group-interface.hh"
17 #include "staff-symbol-referencer.hh"
18 #include "staff-symbol.hh"
19 #include "stem.hh"
20 #include "warn.hh"
22 Grob *
23 Arpeggio::get_common_y (Grob *me)
25 Grob *common = me;
27 extract_grob_set (me, "stems", stems);
28 for (vsize i = 0; i < stems.size (); i++)
30 Grob *stem = stems[i];
31 common = common->common_refpoint (Staff_symbol_referencer::get_staff_symbol (stem),
32 Y_AXIS);
35 return common;
38 MAKE_SCHEME_CALLBACK(Arpeggio, calc_positions, 1);
39 SCM
40 Arpeggio::calc_positions (SCM grob)
42 Grob *me = unsmob_grob (grob);
43 Grob *common = get_common_y (me);
46 TODO:
48 Using stems here is not very convenient; should store noteheads
49 instead, and also put them into the support. Now we will mess up
50 in vicinity of a collision.
52 Interval heads;
53 Real my_y = me->relative_coordinate (common, Y_AXIS);
55 extract_grob_set (me, "stems", stems);
56 for (vsize i = 0; i < stems.size (); i++)
58 Grob *stem = stems[i];
59 Grob *ss = Staff_symbol_referencer::get_staff_symbol (stem);
60 Interval iv = Stem::head_positions (stem);
61 iv *= Staff_symbol::staff_space (ss) / 2.0;
63 heads.unite (iv + ss->relative_coordinate (common, Y_AXIS)
64 - my_y);
67 heads *= 1/Staff_symbol_referencer::staff_space(me);
69 return ly_interval2scm (heads);
72 MAKE_SCHEME_CALLBACK (Arpeggio, print, 1);
73 SCM
74 Arpeggio::print (SCM smob)
76 Grob *me = unsmob_grob (smob);
77 Interval heads = robust_scm2interval (me->get_property ("positions"),
78 Interval())
79 * Staff_symbol_referencer::staff_space (me);
81 if (heads.is_empty () || heads.length () < 0.5)
83 if (!to_boolean (me->get_property ("transparent")))
85 me->warning ("no heads for arpeggio found?");
86 me->suicide ();
88 return SCM_EOL;
91 SCM ad = me->get_property ("arpeggio-direction");
92 Direction dir = CENTER;
93 if (is_direction (ad))
94 dir = to_dir (ad);
96 Stencil mol;
97 Font_metric *fm = Font_interface::get_default_font (me);
98 Stencil squiggle = fm->find_by_name ("scripts.arpeggio");
101 Compensate for rounding error which may occur when a chord
102 reaches the center line, resulting in an extra squiggle
103 being added to the arpeggio stencil. This value is appreciably
104 larger than the rounding error, which is in the region of 1e-16
105 for a global-staff-size of 20, but small enough that it does not
106 interfere with smaller staff sizes.
108 const Real epsilon = 1e-3;
110 Stencil arrow;
111 if (dir)
113 arrow = fm->find_by_name ("scripts.arpeggio.arrow." + to_string (dir));
114 heads[dir] -= dir * arrow.extent (Y_AXIS).length ();
117 while (mol.extent (Y_AXIS).length () + epsilon < heads.length ())
119 mol.add_at_edge (Y_AXIS, UP, squiggle, 0.0);
122 mol.translate_axis (heads[LEFT], Y_AXIS);
123 if (dir)
124 mol.add_at_edge (Y_AXIS, dir, arrow, 0);
126 return mol.smobbed_copy ();
129 /* Draws a vertical bracket to the left of a chord
130 Chris Jackson <chris@fluffhouse.org.uk> */
132 MAKE_SCHEME_CALLBACK (Arpeggio, brew_chord_bracket, 1);
134 Arpeggio::brew_chord_bracket (SCM smob)
136 Grob *me = unsmob_grob (smob);
137 Interval heads = robust_scm2interval (me->get_property ("positions"),
138 Interval())
139 * Staff_symbol_referencer::staff_space (me);
141 Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
142 Real sp = 1.5 * Staff_symbol_referencer::staff_space (me);
143 Real dy = heads.length () + sp;
144 Real x = 0.7;
146 Stencil mol (Lookup::bracket (Y_AXIS, Interval (0, dy), lt, x, lt));
147 mol.translate_axis (heads[LEFT] - sp / 2.0, Y_AXIS);
148 return mol.smobbed_copy ();
151 MAKE_SCHEME_CALLBACK (Arpeggio, brew_chord_slur, 1);
153 Arpeggio::brew_chord_slur (SCM smob)
155 Grob *me = unsmob_grob (smob);
156 SCM dash_definition = me->get_property ("dash-definition");
157 Interval heads = robust_scm2interval (me->get_property ("positions"),
158 Interval())
159 * Staff_symbol_referencer::staff_space (me);
161 Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
162 Real dy = heads.length ();
164 Real height_limit = 1.5;
165 Real ratio = .33;
166 Bezier curve = slur_shape (dy, height_limit, ratio);
167 curve.rotate (M_PI / 2);
169 Stencil mol (Lookup::slur (curve, lt, lt, dash_definition));
170 mol.translate_axis (heads[LEFT], Y_AXIS);
171 return mol.smobbed_copy ();
175 We have to do a callback, because print () triggers a
176 vertical alignment if it is cross-staff.
178 MAKE_SCHEME_CALLBACK (Arpeggio, width, 1);
180 Arpeggio::width (SCM smob)
182 Grob *me = unsmob_grob (smob);
183 Stencil arpeggio = Font_interface::get_default_font (me)->find_by_name ("scripts.arpeggio");
185 return ly_interval2scm (arpeggio.extent (X_AXIS));
188 MAKE_SCHEME_CALLBACK (Arpeggio, height, 1);
190 Arpeggio::height (SCM smob)
192 return Grob::stencil_height (smob);
195 MAKE_SCHEME_CALLBACK (Arpeggio, pure_height, 3);
197 Arpeggio::pure_height (SCM smob, SCM, SCM)
199 Grob *me = unsmob_grob (smob);
200 if (to_boolean (me->get_property ("cross-staff")))
201 return ly_interval2scm (Interval ());
203 return height (smob);
206 ADD_INTERFACE (Arpeggio,
207 "Functions and settings for drawing an arpeggio symbol (a"
208 " wavy line left to noteheads.",
210 /* properties */
211 "arpeggio-direction "
212 "positions "
213 "script-priority " // TODO: make around-note-interface
214 "stems "
215 "dash-definition " // TODO: make apply to non-slur arpeggios