Fix InstrumentSwitch grob definition.
[lilypond.git] / lily / arpeggio.cc
blob22351d3b13f3d56a8d640dc730737d2b39d58b31
1 /*
2 arpeggio.cc -- implement Arpeggio
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2007 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 Interval heads = robust_scm2interval (me->get_property ("positions"),
157 Interval())
158 * Staff_symbol_referencer::staff_space (me);
160 Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
161 Real dy = heads.length ();
163 Real height_limit = 1.5;
164 Real ratio = .33;
165 Bezier curve = slur_shape (dy, height_limit, ratio);
166 curve.rotate (M_PI / 2);
168 Stencil mol (Lookup::slur (curve, lt, lt));
169 mol.translate_axis (heads[LEFT], Y_AXIS);
170 return mol.smobbed_copy ();
174 We have to do a callback, because print () triggers a
175 vertical alignment if it is cross-staff.
177 MAKE_SCHEME_CALLBACK (Arpeggio, width, 1);
179 Arpeggio::width (SCM smob)
181 Grob *me = unsmob_grob (smob);
182 Stencil arpeggio = Font_interface::get_default_font (me)->find_by_name ("scripts.arpeggio");
184 return ly_interval2scm (arpeggio.extent (X_AXIS));
187 MAKE_SCHEME_CALLBACK (Arpeggio, height, 1);
189 Arpeggio::height (SCM smob)
191 return Grob::stencil_height (smob);
194 MAKE_SCHEME_CALLBACK (Arpeggio, pure_height, 3);
196 Arpeggio::pure_height (SCM smob, SCM, SCM)
198 Grob *me = unsmob_grob (smob);
199 if (to_boolean (me->get_property ("cross-staff")))
200 return ly_interval2scm (Interval ());
202 return height (smob);
205 ADD_INTERFACE (Arpeggio,
206 "Functions and settings for drawing an arpeggio symbol (a"
207 " wavy line left to noteheads.",
209 /* properties */
210 "arpeggio-direction "
211 "positions "
212 "script-priority " // TODO: make around-note-interface
213 "stems "