]> git.donarmstrong.com Git - lilypond.git/blob - lily/arpeggio.cc
Merge branch 'lilypond/translation' of ssh://jomand@git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / lily / arpeggio.cc
1 /*
2   arpeggio.cc -- implement Arpeggio
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2000--2009 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "arpeggio.hh"
10
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"
21
22 Grob *
23 Arpeggio::get_common_y (Grob *me)
24 {
25   Grob *common = me;
26
27   extract_grob_set (me, "stems", stems);
28   for (vsize i = 0; i < stems.size (); i++)
29     {
30       Grob *stem = stems[i];
31       common = common->common_refpoint (Staff_symbol_referencer::get_staff_symbol (stem),
32                                         Y_AXIS);
33     }
34
35   return common;
36 }
37
38 MAKE_SCHEME_CALLBACK(Arpeggio, calc_positions, 1);
39 SCM
40 Arpeggio::calc_positions (SCM grob)
41 {
42   Grob *me = unsmob_grob (grob);
43   Grob *common = get_common_y (me);
44   
45   /*
46     TODO:
47
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.
51   */
52   Interval heads;
53   Real my_y = me->relative_coordinate (common, Y_AXIS);
54
55   extract_grob_set (me, "stems", stems);
56   for (vsize i = 0; i < stems.size (); i++)
57     {
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;
62
63       heads.unite (iv + ss->relative_coordinate (common, Y_AXIS)
64                    - my_y);
65     }
66
67   heads *= 1/Staff_symbol_referencer::staff_space(me);
68
69   return ly_interval2scm (heads);
70 }
71
72 MAKE_SCHEME_CALLBACK (Arpeggio, print, 1);
73 SCM
74 Arpeggio::print (SCM smob)
75 {
76   Grob *me = unsmob_grob (smob);
77   Interval heads = robust_scm2interval (me->get_property ("positions"),
78                                         Interval())
79     * Staff_symbol_referencer::staff_space (me);
80   
81   if (heads.is_empty () || heads.length () < 0.5)
82     {
83       if (!to_boolean (me->get_property ("transparent")))
84         {
85           me->warning ("no heads for arpeggio found?");
86           me->suicide ();
87         }
88       return SCM_EOL;
89     }
90
91   SCM ad = me->get_property ("arpeggio-direction");
92   Direction dir = CENTER;
93   if (is_direction (ad))
94     dir = to_dir (ad);
95
96   Stencil mol;
97   Font_metric *fm = Font_interface::get_default_font (me);
98   Stencil squiggle = fm->find_by_name ("scripts.arpeggio");
99
100   /*
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.
107   */
108   const Real epsilon = 1e-3;
109
110   Stencil arrow;
111   if (dir)
112     {
113       arrow = fm->find_by_name ("scripts.arpeggio.arrow." + to_string (dir));
114       heads[dir] -= dir * arrow.extent (Y_AXIS).length ();
115     }
116
117   while (mol.extent (Y_AXIS).length () + epsilon < heads.length ())
118     {
119       mol.add_at_edge (Y_AXIS, UP, squiggle, 0.0);
120     }
121
122   mol.translate_axis (heads[LEFT], Y_AXIS);
123   if (dir)
124     mol.add_at_edge (Y_AXIS, dir, arrow, 0);
125
126   return mol.smobbed_copy ();
127 }
128
129 /* Draws a vertical bracket to the left of a chord
130    Chris Jackson <chris@fluffhouse.org.uk> */
131
132 MAKE_SCHEME_CALLBACK (Arpeggio, brew_chord_bracket, 1);
133 SCM
134 Arpeggio::brew_chord_bracket (SCM smob)
135 {
136   Grob *me = unsmob_grob (smob);
137   Interval heads = robust_scm2interval (me->get_property ("positions"),
138                                         Interval())
139     * Staff_symbol_referencer::staff_space (me);
140
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;
145
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 ();
149 }
150
151 MAKE_SCHEME_CALLBACK (Arpeggio, brew_chord_slur, 1);
152 SCM
153 Arpeggio::brew_chord_slur (SCM smob)
154 {
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);
160
161   Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
162   Real dy = heads.length ();
163
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);
168
169   Stencil mol (Lookup::slur (curve, lt, lt, dash_definition));
170   mol.translate_axis (heads[LEFT], Y_AXIS);
171   return mol.smobbed_copy ();
172 }
173
174 /*
175   We have to do a callback, because print () triggers a
176   vertical alignment if it is cross-staff.
177 */
178 MAKE_SCHEME_CALLBACK (Arpeggio, width, 1);
179 SCM
180 Arpeggio::width (SCM smob)
181 {
182   Grob *me = unsmob_grob (smob);
183   Stencil arpeggio = Font_interface::get_default_font (me)->find_by_name ("scripts.arpeggio");
184
185   return ly_interval2scm (arpeggio.extent (X_AXIS));
186 }
187
188 MAKE_SCHEME_CALLBACK (Arpeggio, height, 1);
189 SCM
190 Arpeggio::height (SCM smob)
191 {
192   return Grob::stencil_height (smob);
193 }
194
195 MAKE_SCHEME_CALLBACK (Arpeggio, pure_height, 3);
196 SCM
197 Arpeggio::pure_height (SCM smob, SCM, SCM)
198 {
199   Grob *me = unsmob_grob (smob);
200   if (to_boolean (me->get_property ("cross-staff")))
201     return ly_interval2scm (Interval ());
202
203   return height (smob);
204 }
205
206 ADD_INTERFACE (Arpeggio,
207                "Functions and settings for drawing an arpeggio symbol.",
208
209                /* properties */
210                "arpeggio-direction "
211                "positions "
212                "script-priority " // TODO: make around-note-interface
213                "stems "
214                "dash-definition " // TODO: make apply to non-slur arpeggios
215                );
216