]> git.donarmstrong.com Git - lilypond.git/blob - lily/rest.cc
Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/lilypond
[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;
153   SCM style_scm = me->get_property ("style");
154   if (scm_is_symbol (style_scm))
155     style = ly_scm2string (scm_symbol_to_string (style_scm));
156
157   Font_metric *fm = Font_interface::get_default_font (me);
158   string font_char = glyph_name (me, balltype, style, ledgered);
159   Stencil out = fm->find_by_name (font_char);
160   if (out.is_empty ())
161     me->warning (_f ("rest `%s' not found", font_char.c_str ()));
162
163   return out.smobbed_copy ();
164 }
165
166 /**
167    translate the rest vertically by amount DY, but only if
168    it doesn't have staff-position set.
169 */
170 void
171 Rest::translate (Grob *me, int dy)
172 {
173   if (!scm_is_number (me->get_property ("staff-position")))
174     {
175       me->translate_axis (dy * Staff_symbol_referencer::staff_space (me) / 2.0, Y_AXIS);
176       Grob *p = me->get_parent (Y_AXIS);
177       p->flush_extent_cache (Y_AXIS);
178     }
179 }
180
181 SCM
182 Rest::print (SCM smob)
183 {
184   return brew_internal_stencil (unsmob_grob (smob), true);
185 }
186
187 MAKE_SCHEME_CALLBACK (Rest, width, 1);
188 /*
189   We need the callback. The real stencil has ledgers depending on
190   Y-position. The Y-position is known only after line breaking.  */
191 SCM
192 Rest::width (SCM smob)
193 {
194   return generic_extent_callback (unsmob_grob (smob), X_AXIS);
195 }
196
197 MAKE_SCHEME_CALLBACK (Rest, height, 1);
198 SCM
199 Rest::height (SCM smob)
200 {
201   return generic_extent_callback (unsmob_grob (smob), Y_AXIS);
202 }
203
204 /*
205   We need the callback. The real stencil has ledgers depending on
206   Y-position. The Y-position is known only after line breaking.  */
207 SCM
208 Rest::generic_extent_callback (Grob *me, Axis a)
209 {
210   /*
211     Don't want ledgers: ledgers depend on Y position, which depends on
212     rest collision, which depends on stem size which depends on beam
213     slop of opposite note column.
214
215     consequence: we get too small extents and potential collisions
216     with ledgered rests.
217   */
218   SCM m = brew_internal_stencil (me, a != X_AXIS);
219   return ly_interval2scm (unsmob_stencil (m)->extent (a));
220 }
221
222 MAKE_SCHEME_CALLBACK (Rest, pure_height, 3);
223 SCM
224 Rest::pure_height (SCM smob,
225                    SCM /* start */,
226                    SCM /* end */)
227 {
228   Grob *me = unsmob_grob (smob);
229   SCM m = brew_internal_stencil (me, false);
230   return ly_interval2scm (unsmob_stencil (m)->extent (Y_AXIS));
231 }
232
233 ADD_INTERFACE (Rest,
234                "A rest symbol.  The property @code{style} can be"
235                " @code{default}, @code{mensural}, @code{neomensural} or"
236                " @code{classical}.",
237
238                /* properties */
239                "direction "
240                "minimum-distance "
241                "style "
242               );
243