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