]> git.donarmstrong.com Git - lilypond.git/blob - lily/rest.cc
Merge branch 'master' into lilypond/translation
[lilypond.git] / lily / rest.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "rest.hh"
21
22 #include "directional-element-interface.hh"
23 #include "dots.hh"
24 #include "font-interface.hh"
25 #include "international.hh"
26 #include "output-def.hh"
27 #include "paper-score.hh"
28 #include "staff-symbol-referencer.hh"
29 #include "stencil.hh"
30 #include "grob.hh"
31
32 // -> offset callback
33 MAKE_SCHEME_CALLBACK (Rest, y_offset_callback, 1);
34 SCM
35 Rest::y_offset_callback (SCM smob)
36 {
37   Grob *me = unsmob_grob (smob);
38   int duration_log = scm_to_int (me->get_property ("duration-log"));
39   int line_count = Staff_symbol_referencer::line_count (me);
40   Real ss = Staff_symbol_referencer::staff_space (me);
41
42   bool position_override = scm_is_number (me->get_property ("staff-position"));
43   Real amount = robust_scm2double (me->get_property ("staff-position"), 0)
44                 * 0.5 * ss;
45
46   if (line_count % 2)
47     {
48       if (duration_log == 0 && line_count > 1)
49         amount += ss;
50     }
51   else
52     amount += ss / 2;
53
54   if (!position_override)
55     amount += 2 * ss * get_grob_direction (me);
56
57
58   return scm_from_double (amount);
59 }
60
61 /* A rest might lie under a beam, in which case it should be cross-staff if
62    the beam is cross-staff because the rest's position depends on the
63    formatting of the beam. */
64 MAKE_SCHEME_CALLBACK (Rest, calc_cross_staff, 1);
65 SCM
66 Rest::calc_cross_staff (SCM smob)
67 {
68   Grob *me = unsmob_grob (smob);
69   Grob *stem = unsmob_grob (me->get_object ("stem"));
70
71   if (!stem)
72     return SCM_BOOL_F;
73
74   return stem->get_property ("cross-staff");
75 }
76
77 /*
78   make this function easily usable in C++
79 */
80 string
81 Rest::glyph_name (Grob *me, int balltype, string style, bool try_ledgers)
82 {
83   bool is_ledgered = false;
84   if (try_ledgers && (balltype == -1 || balltype == 0 || balltype == 1))
85     {
86       Real rad = Staff_symbol_referencer::staff_radius (me) * 2.0;
87       Real pos = Staff_symbol_referencer::get_position (me);
88
89       /*
90         Figure out when the rest is far enough outside the staff. This
91         could bemore generic, but hey, we understand this even after
92         dinner.
93       */
94       is_ledgered |= (balltype == -1) && (pos <= -rad - 3 || pos >= +rad + 1);
95       is_ledgered |= (balltype == 0) && (pos >= +rad + 2 || pos < -rad);
96       is_ledgered |= (balltype == 1) && (pos <= -rad - 2 || pos > +rad);
97     }
98
99   string actual_style (style.c_str ());
100
101   if ((style == "mensural") || (style == "neomensural"))
102     {
103
104       /*
105         FIXME: Currently, ancient font does not provide ledgered rests;
106         hence the "o" suffix in the glyph name is bogus.  But do we need
107         ledgered rests at all now that we can draw ledger lines with
108         variable width, length and blotdiameter? -- jr
109       */
110       is_ledgered = 0;
111
112       /*
113         There are no 32th/64th/128th mensural/neomensural rests.  In
114         these cases, revert back to default style.
115       */
116       if (balltype > 4)
117         actual_style = "";
118     }
119
120   if ((style == "classical") && (balltype != 2))
121     {
122       /*
123         classical style: revert back to default style for any rest other
124         than quarter rest
125       */
126       actual_style = "";
127     }
128
129   if (style == "default")
130     {
131       /*
132         Some parts of lily still prefer style "default" over "".
133         Correct this here. -- jr
134       */
135       actual_style = "";
136     }
137
138   return ("rests." + to_string (balltype) + (is_ledgered ? "o" : "")
139           + actual_style);
140 }
141
142 MAKE_SCHEME_CALLBACK (Rest, print, 1);
143 SCM
144 Rest::brew_internal_stencil (Grob *me, bool ledgered)
145 {
146   SCM balltype_scm = me->get_property ("duration-log");
147   if (!scm_is_number (balltype_scm))
148     return Stencil ().smobbed_copy ();
149
150   int balltype = scm_to_int (balltype_scm);
151
152   string style = robust_symbol2string (me->get_property ("style"), "default");
153
154   Font_metric *fm = Font_interface::get_default_font (me);
155   string font_char = glyph_name (me, balltype, style, ledgered);
156   Stencil out = fm->find_by_name (font_char);
157   if (out.is_empty ())
158     me->warning (_f ("rest `%s' not found", font_char.c_str ()));
159
160   return out.smobbed_copy ();
161 }
162
163 /**
164    translate the rest vertically by amount DY, but only if
165    it doesn't have staff-position set.
166 */
167 void
168 Rest::translate (Grob *me, int dy)
169 {
170   if (!scm_is_number (me->get_property ("staff-position")))
171     {
172       me->translate_axis (dy * Staff_symbol_referencer::staff_space (me) / 2.0, Y_AXIS);
173       Grob *p = me->get_parent (Y_AXIS);
174       p->flush_extent_cache (Y_AXIS);
175     }
176 }
177
178 SCM
179 Rest::print (SCM smob)
180 {
181   return brew_internal_stencil (unsmob_grob (smob), true);
182 }
183
184 MAKE_SCHEME_CALLBACK (Rest, width, 1);
185 /*
186   We need the callback. The real stencil has ledgers depending on
187   Y-position. The Y-position is known only after line breaking.  */
188 SCM
189 Rest::width (SCM smob)
190 {
191   return generic_extent_callback (unsmob_grob (smob), X_AXIS);
192 }
193
194 MAKE_SCHEME_CALLBACK (Rest, height, 1);
195 SCM
196 Rest::height (SCM smob)
197 {
198   return generic_extent_callback (unsmob_grob (smob), Y_AXIS);
199 }
200
201 /*
202   We need the callback. The real stencil has ledgers depending on
203   Y-position. The Y-position is known only after line breaking.  */
204 SCM
205 Rest::generic_extent_callback (Grob *me, Axis a)
206 {
207   /*
208     Don't want ledgers: ledgers depend on Y position, which depends on
209     rest collision, which depends on stem size which depends on beam
210     slop of opposite note column.
211
212     consequence: we get too small extents and potential collisions
213     with ledgered rests.
214   */
215   SCM m = brew_internal_stencil (me, a != X_AXIS);
216   return ly_interval2scm (unsmob_stencil (m)->extent (a));
217 }
218
219 MAKE_SCHEME_CALLBACK (Rest, pure_height, 3);
220 SCM
221 Rest::pure_height (SCM smob,
222                    SCM /* start */,
223                    SCM /* end */)
224 {
225   Grob *me = unsmob_grob (smob);
226   SCM m = brew_internal_stencil (me, false);
227   return ly_interval2scm (unsmob_stencil (m)->extent (Y_AXIS));
228 }
229
230 ADD_INTERFACE (Rest,
231                "A rest symbol.  The property @code{style} can be"
232                " @code{default}, @code{mensural}, @code{neomensural} or"
233                " @code{classical}.",
234
235                /* properties */
236                "direction "
237                "minimum-distance "
238                "style "
239               );
240