]> git.donarmstrong.com Git - lilypond.git/blob - lily/rest.cc
Merge branch 'fixedmerge' into HEAD
[lilypond.git] / lily / rest.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2012 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 "staff-symbol.hh"
30 #include "stencil.hh"
31 #include "grob.hh"
32
33 // -> offset callback
34 MAKE_SCHEME_CALLBACK (Rest, y_offset_callback, 1);
35 SCM
36 Rest::y_offset_callback (SCM smob)
37 {
38   Grob *me = unsmob_grob (smob);
39   int duration_log = scm_to_int (me->get_property ("duration-log"));
40   int line_count = Staff_symbol_referencer::line_count (me);
41   Real ss = Staff_symbol_referencer::staff_space (me);
42
43   bool position_override = scm_is_number (me->get_property ("staff-position"));
44   Real amount;
45
46   if (position_override)
47     {
48       amount =
49         robust_scm2double (me->get_property ("staff-position"), 0) * 0.5 * ss;
50
51       /*
52         semibreve rests are positioned one staff line off
53       */
54       if (duration_log == 0)
55         amount += ss;
56
57       /*
58         trust the client on good positioning;
59         would be tempting to adjust position of rests longer than a quarter
60         to be properly aligned to staff lines,
61         but custom rest shapes may not need that sort of care.
62       */
63     }
64   else
65     {
66       int pos = 4 * get_grob_direction (me);
67
68       /*
69         make a semibreve rest hang from the next line,
70         except for a single line staff
71       */
72       if (duration_log == 0 && line_count > 1)
73         pos += 2;
74
75       /*
76         make sure rest is aligned to a staff line
77       */
78       if (Grob *staff = Staff_symbol_referencer::get_staff_symbol(me))
79         {
80           std::vector<Real> linepos = Staff_symbol::line_positions (staff);
81           std::sort(linepos.begin(), linepos.end());
82           std::vector<Real>::const_iterator it
83             = std::lower_bound(linepos.begin(), linepos.end(), pos);
84           if (it != linepos.end())
85             {
86               pos = (int)ceil(*it);
87             }
88         }
89
90       amount = ss * 0.5 * pos;
91     }
92
93   return scm_from_double (amount);
94 }
95
96 /* A rest might lie under a beam, in which case it should be cross-staff if
97    the beam is cross-staff because the rest's position depends on the
98    formatting of the beam. */
99 MAKE_SCHEME_CALLBACK (Rest, calc_cross_staff, 1);
100 SCM
101 Rest::calc_cross_staff (SCM smob)
102 {
103   Grob *me = unsmob_grob (smob);
104   Grob *stem = unsmob_grob (me->get_object ("stem"));
105
106   if (!stem)
107     return SCM_BOOL_F;
108
109   return stem->get_property ("cross-staff");
110 }
111
112 /*
113   make this function easily usable in C++
114 */
115 string
116 Rest::glyph_name (Grob *me, int durlog, string style, bool try_ledgers)
117 {
118   bool is_ledgered = false;
119   if (try_ledgers && (durlog == -1 || durlog == 0 || durlog == 1))
120     {
121       int const pos = int (Staff_symbol_referencer::get_position (me));
122
123       /*
124         half rests need ledger if not lying on a staff line,
125         whole rests need ledger if not hanging from a staff line,
126         breve rests need ledger if neither lying on nor hanging from a staff line
127       */
128       if (-1 <= durlog && durlog <= 1)
129         is_ledgered = !Staff_symbol_referencer::on_staff_line (me, pos)
130           && !(durlog == -1
131                && Staff_symbol_referencer::on_staff_line (me, pos + 2));
132     }
133
134   string actual_style (style.c_str ());
135
136   if ((style == "mensural") || (style == "neomensural"))
137     {
138
139       /*
140         FIXME: Currently, ancient font does not provide ledgered rests;
141         hence the "o" suffix in the glyph name is bogus.  But do we need
142         ledgered rests at all now that we can draw ledger lines with
143         variable width, length and blotdiameter? -- jr
144       */
145       is_ledgered = 0;
146
147       /*
148         There are no 32th/64th/128th mensural/neomensural rests.  In
149         these cases, revert back to default style.
150       */
151       if (durlog > 4)
152         actual_style = "";
153     }
154
155   if ((style == "classical") && (durlog != 2))
156     {
157       /*
158         classical style: revert back to default style for any rest other
159         than quarter rest
160       */
161       actual_style = "";
162     }
163
164   if (style == "default")
165     {
166       /*
167         Some parts of lily still prefer style "default" over "".
168         Correct this here. -- jr
169       */
170       actual_style = "";
171     }
172
173   return ("rests." + to_string (durlog) + (is_ledgered ? "o" : "")
174           + actual_style);
175 }
176
177 MAKE_SCHEME_CALLBACK (Rest, print, 1);
178 SCM
179 Rest::brew_internal_stencil (Grob *me, bool ledgered)
180 {
181   SCM durlog_scm = me->get_property ("duration-log");
182   if (!scm_is_number (durlog_scm))
183     return Stencil ().smobbed_copy ();
184
185   int durlog = scm_to_int (durlog_scm);
186
187   string style = robust_symbol2string (me->get_property ("style"), "default");
188
189   Font_metric *fm = Font_interface::get_default_font (me);
190   string font_char = glyph_name (me, durlog, style, ledgered);
191   Stencil out = fm->find_by_name (font_char);
192   if (out.is_empty ())
193     me->warning (_f ("rest `%s' not found", font_char.c_str ()));
194
195   return out.smobbed_copy ();
196 }
197
198 /**
199    translate the rest vertically by amount DY, but only if
200    it doesn't have staff-position set.
201 */
202 void
203 Rest::translate (Grob *me, int dy)
204 {
205   if (!scm_is_number (me->get_property ("staff-position")))
206     {
207       me->translate_axis (dy * Staff_symbol_referencer::staff_space (me) / 2.0, Y_AXIS);
208       Grob *p = me->get_parent (Y_AXIS);
209       p->flush_extent_cache (Y_AXIS);
210     }
211 }
212
213 SCM
214 Rest::print (SCM smob)
215 {
216   return brew_internal_stencil (unsmob_grob (smob), true);
217 }
218
219 MAKE_SCHEME_CALLBACK (Rest, width, 1);
220 /*
221   We need the callback. The real stencil has ledgers depending on
222   Y-position. The Y-position is known only after line breaking.  */
223 SCM
224 Rest::width (SCM smob)
225 {
226   return generic_extent_callback (unsmob_grob (smob), X_AXIS);
227 }
228
229 MAKE_SCHEME_CALLBACK (Rest, height, 1);
230 SCM
231 Rest::height (SCM smob)
232 {
233   return generic_extent_callback (unsmob_grob (smob), Y_AXIS);
234 }
235
236 /*
237   We need the callback. The real stencil has ledgers depending on
238   Y-position. The Y-position is known only after line breaking.  */
239 SCM
240 Rest::generic_extent_callback (Grob *me, Axis a)
241 {
242   /*
243     Don't want ledgers: ledgers depend on Y position, which depends on
244     rest collision, which depends on stem size which depends on beam
245     slop of opposite note column.
246
247     consequence: we get too small extents and potential collisions
248     with ledgered rests.
249   */
250   SCM m = brew_internal_stencil (me, a != X_AXIS);
251   return ly_interval2scm (unsmob_stencil (m)->extent (a));
252 }
253
254 MAKE_SCHEME_CALLBACK (Rest, pure_height, 3);
255 SCM
256 Rest::pure_height (SCM smob,
257                    SCM /* start */,
258                    SCM /* end */)
259 {
260   Grob *me = unsmob_grob (smob);
261   SCM m = brew_internal_stencil (me, false);
262   return ly_interval2scm (unsmob_stencil (m)->extent (Y_AXIS));
263 }
264
265 ADD_INTERFACE (Rest,
266                "A rest symbol.  The property @code{style} can be"
267                " @code{default}, @code{mensural}, @code{neomensural} or"
268                " @code{classical}.",
269
270                /* properties */
271                "direction "
272                "minimum-distance "
273                "style "
274               );