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