]> git.donarmstrong.com Git - lilypond.git/blob - lily/rest.cc
Merge branch '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   return scm_from_double (amount);
58 }
59
60 /* A rest might lie under a beam, in which case it should be cross-staff if
61    the beam is cross-staff because the rest's position depends on the
62    formatting of the beam. */
63 MAKE_SCHEME_CALLBACK (Rest, calc_cross_staff, 1);
64 SCM
65 Rest::calc_cross_staff (SCM smob)
66 {
67   Grob *me = unsmob_grob (smob);
68   Grob *stem = unsmob_grob (me->get_object ("stem"));
69
70   if (!stem)
71     return SCM_BOOL_F;
72
73   return stem->get_property ("cross-staff");
74 }
75
76 /*
77   make this function easily usable in C++
78 */
79 string
80 Rest::glyph_name (Grob *me, int balltype, string style, bool try_ledgers)
81 {
82   bool is_ledgered = false;
83   if (try_ledgers && (balltype == -1 || balltype == 0 || balltype == 1))
84     {
85       Real rad = Staff_symbol_referencer::staff_radius (me) * 2.0;
86       Real pos = Staff_symbol_referencer::get_position (me);
87
88       /*
89         Figure out when the rest is far enough outside the staff. This
90         could bemore generic, but hey, we understand this even after
91         dinner.
92       */
93       is_ledgered |= (balltype == -1) && (pos <= -rad - 3 || pos >= +rad + 1);
94       is_ledgered |= (balltype == 0) && (pos >= +rad + 2 || pos < -rad);
95       is_ledgered |= (balltype == 1) && (pos <= -rad - 2 || pos > +rad);
96     }
97
98   string actual_style (style.c_str ());
99
100   if ((style == "mensural") || (style == "neomensural"))
101     {
102
103       /*
104         FIXME: Currently, ancient font does not provide ledgered rests;
105         hence the "o" suffix in the glyph name is bogus.  But do we need
106         ledgered rests at all now that we can draw ledger lines with
107         variable width, length and blotdiameter? -- jr
108       */
109       is_ledgered = 0;
110
111       /*
112         There are no 32th/64th/128th mensural/neomensural rests.  In
113         these cases, revert back to default style.
114       */
115       if (balltype > 4)
116         actual_style = "";
117     }
118
119   if ((style == "classical") && (balltype != 2))
120     {
121       /*
122         classical style: revert back to default style for any rest other
123         than quarter rest
124       */
125       actual_style = "";
126     }
127
128   if (style == "default")
129     {
130       /*
131         Some parts of lily still prefer style "default" over "".
132         Correct this here. -- jr
133       */
134       actual_style = "";
135     }
136
137   return ("rests." + to_string (balltype) + (is_ledgered ? "o" : "")
138           + actual_style);
139 }
140
141 MAKE_SCHEME_CALLBACK (Rest, print, 1);
142 SCM
143 Rest::brew_internal_stencil (Grob *me, bool ledgered)
144 {
145   SCM balltype_scm = me->get_property ("duration-log");
146   if (!scm_is_number (balltype_scm))
147     return Stencil ().smobbed_copy ();
148
149   int balltype = scm_to_int (balltype_scm);
150
151   string style;
152   SCM style_scm = me->get_property ("style");
153   if (scm_is_symbol (style_scm))
154     style = ly_scm2string (scm_symbol_to_string (style_scm));
155
156   Font_metric *fm = Font_interface::get_default_font (me);
157   string font_char = glyph_name (me, balltype, style, ledgered);
158   Stencil out = fm->find_by_name (font_char);
159   if (out.is_empty ())
160     me->warning (_f ("rest `%s' not found", font_char.c_str ()));
161
162   return out.smobbed_copy ();
163 }
164
165 /**
166    translate the rest vertically by amount DY, but only if
167    it doesn't have staff-position set.
168 */
169 void
170 Rest::translate (Grob *me, int dy)
171 {
172   if (!scm_is_number (me->get_property ("staff-position")))
173     {
174       me->translate_axis (dy * Staff_symbol_referencer::staff_space (me) / 2.0, Y_AXIS);
175       Grob *p = me->get_parent (Y_AXIS);
176       p->flush_extent_cache (Y_AXIS);
177     }
178 }
179
180 SCM
181 Rest::print (SCM smob)
182 {
183   return brew_internal_stencil (unsmob_grob (smob), true);
184 }
185
186 MAKE_SCHEME_CALLBACK (Rest, width, 1);
187 /*
188   We need the callback. The real stencil has ledgers depending on
189   Y-position. The Y-position is known only after line breaking.  */
190 SCM
191 Rest::width (SCM smob)
192 {
193   return generic_extent_callback (unsmob_grob (smob), X_AXIS);
194 }
195
196 MAKE_SCHEME_CALLBACK (Rest, height, 1);
197 SCM
198 Rest::height (SCM smob)
199 {
200   return generic_extent_callback (unsmob_grob (smob), Y_AXIS);
201 }
202
203 /*
204   We need the callback. The real stencil has ledgers depending on
205   Y-position. The Y-position is known only after line breaking.  */
206 SCM
207 Rest::generic_extent_callback (Grob *me, Axis a)
208 {
209   /*
210     Don't want ledgers: ledgers depend on Y position, which depends on
211     rest collision, which depends on stem size which depends on beam
212     slop of opposite note column.
213
214     consequence: we get too small extents and potential collisions
215     with ledgered rests.
216   */
217   SCM m = brew_internal_stencil (me, a != X_AXIS);
218   return ly_interval2scm (unsmob_stencil (m)->extent (a));
219 }
220
221 MAKE_SCHEME_CALLBACK (Rest, pure_height, 3);
222 SCM
223 Rest::pure_height (SCM smob,
224                    SCM /* start */,
225                    SCM /* end */)
226 {
227   Grob *me = unsmob_grob (smob);
228   SCM m = brew_internal_stencil (me, false);
229   return ly_interval2scm (unsmob_stencil (m)->extent (Y_AXIS));
230 }
231
232 ADD_INTERFACE (Rest,
233                "A rest symbol.  The property @code{style} can be"
234                " @code{default}, @code{mensural}, @code{neomensural} or"
235                " @code{classical}.",
236
237                /* properties */
238                "direction "
239                "minimum-distance "
240                "style "
241               );
242