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