]> git.donarmstrong.com Git - lilypond.git/blob - lily/multi-measure-rest.cc
Run `make grand-replace'.
[lilypond.git] / lily / multi-measure-rest.cc
1 /*
2   multi-measure-rest.cc -- implement Multi_measure_rest
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2008 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "multi-measure-rest.hh"
10
11 #include "warn.hh"
12 #include "output-def.hh"
13 #include "paper-column.hh" // urg
14 #include "font-interface.hh"
15 #include "rest.hh"
16 #include "misc.hh"
17 #include "spanner.hh"
18 #include "staff-symbol-referencer.hh"
19 #include "system.hh"
20 #include "text-interface.hh"
21 #include "percent-repeat-item.hh"
22 #include "lookup.hh"
23 #include "separation-item.hh"
24
25 Interval
26 Multi_measure_rest::bar_width (Spanner *me)
27 {
28   Interval iv;
29   Direction d = LEFT;
30   do
31     {
32       Item *col = me->get_bound (d)->get_column ();
33
34       Interval coldim = Paper_column::break_align_width (col);
35
36       iv[d] = coldim[-d];
37     }
38   while ((flip (&d)) != LEFT);
39
40   return iv;
41 }
42
43 MAKE_SCHEME_CALLBACK (Multi_measure_rest, percent, 1);
44 SCM
45 Multi_measure_rest::percent (SCM smob)
46 {
47   Grob *me = unsmob_grob (smob);
48   Spanner *sp = dynamic_cast<Spanner *> (me);
49
50   Stencil r = Percent_repeat_item_interface::x_percent (me, 1);
51
52   // ugh copy & paste.
53
54   Grob *common_x = sp->get_bound (LEFT)->common_refpoint (sp->get_bound (RIGHT),
55                                                           X_AXIS);
56   Interval sp_iv = bar_width (sp);
57   Real x_off = 0.0;
58
59   Real rx = sp->get_bound (LEFT)->relative_coordinate (common_x, X_AXIS);
60   /*
61     we gotta stay clear of sp_iv, so move a bit to the right if
62     needed.
63   */
64   x_off += max (sp_iv[LEFT] - rx, 0.0);
65
66   /*
67     center between stuff.
68   */
69   x_off += sp_iv.length () / 2;
70
71   r.translate_axis (x_off, X_AXIS);
72
73   return r.smobbed_copy ();
74 }
75
76 MAKE_SCHEME_CALLBACK (Multi_measure_rest, print, 1);
77 SCM
78 Multi_measure_rest::print (SCM smob)
79 {
80   Grob *me = unsmob_grob (smob);
81   Spanner *sp = dynamic_cast<Spanner *> (me);
82
83   Interval sp_iv = bar_width (sp);
84   Real space = sp_iv.length ();
85
86   Real rx = sp->get_bound (LEFT)->relative_coordinate (0, X_AXIS);
87   /*
88     we gotta stay clear of sp_iv, so move a bit to the right if
89     needed.
90   */
91   Real x_off = max (sp_iv[LEFT] - rx, 0.0);
92
93   Stencil mol;
94   mol.add_stencil (symbol_stencil (me, space));
95
96   int measures = 0;
97   SCM m (me->get_property ("measure-count"));
98   if (scm_is_number (m))
99     measures = scm_to_int (m);
100
101   mol.translate_axis (x_off, X_AXIS);
102   return mol.smobbed_copy ();
103 }
104
105 Stencil
106 Multi_measure_rest::symbol_stencil (Grob *me, Real space)
107 {
108   int measures = 0;
109   SCM m (me->get_property ("measure-count"));
110   if (scm_is_number (m))
111     measures = scm_to_int (m);
112   if (measures <= 0)
113     return Stencil ();
114
115   SCM limit = me->get_property ("expand-limit");
116   if (measures > scm_to_int (limit))
117     {
118       Real padding = 0.15;
119       Stencil s = big_rest (me, (1.0 - 2 * padding) * space);
120       s.translate_axis (padding * space, X_AXIS);
121       return s;
122     }
123
124   SCM alist_chain = Font_interface::music_font_alist_chain (me);
125
126   Real staff_space = Staff_symbol_referencer::staff_space (me);
127   Font_metric *musfont
128     = select_font (me->layout (), alist_chain);
129
130   SCM sml = me->get_property ("use-breve-rest");
131   if (measures == 1)
132     {
133       if (to_boolean (sml))
134         {
135           Stencil s = musfont->find_by_name (Rest::glyph_name (me, -1, "", false));
136
137           s.translate_axis ((space - s.extent (X_AXIS).length ()) / 2, X_AXIS);
138
139           return s;
140         }
141       else
142         {
143           Stencil s = musfont->find_by_name (Rest::glyph_name (me, 0, "", true));
144
145           /*
146             ugh.
147           */
148           if (Staff_symbol_referencer::get_position (me) == 0.0)
149             s.translate_axis (staff_space, Y_AXIS);
150
151           s.translate_axis ((space - s.extent (X_AXIS).length ()) / 2, X_AXIS);
152
153           return s;
154         }
155     }
156   else
157     return church_rest (me, musfont, measures, space);
158 }
159
160 /*
161   WIDTH can also be 0 to determine the minimum size of the object.
162 */
163 Stencil
164 Multi_measure_rest::big_rest (Grob *me, Real width)
165 {
166   Real thick_thick = robust_scm2double (me->get_property ("thick-thickness"), 1.0);
167   Real hair_thick = robust_scm2double (me->get_property ("hair-thickness"), .1);
168
169   Real ss = Staff_symbol_referencer::staff_space (me);
170   Real slt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
171   Real y = slt * thick_thick / 2 * ss;
172   Real ythick = hair_thick * slt * ss;
173   Box b (Interval (0.0, max (0.0, (width - 2 * ythick))), Interval (-y, y));
174
175   Real blot = width ? (.8 * min (y, ythick)) : 0.0;
176
177   Stencil m = Lookup::round_filled_box (b, blot);
178   Stencil yb = Lookup::round_filled_box (Box (Interval (-0.5, 0.5) * ythick, Interval (-ss, ss)), blot);
179
180   m.add_at_edge (X_AXIS, RIGHT, yb, 0);
181   m.add_at_edge (X_AXIS, LEFT, yb, 0);
182
183   m.align_to (X_AXIS, LEFT);
184
185   return m;
186 }
187
188 /*
189   Kirchenpause (?)
190 */
191 Stencil
192 Multi_measure_rest::church_rest (Grob *me, Font_metric *musfont, int measures,
193                                  Real space)
194 {
195   SCM mols = SCM_EOL;
196
197   /* See Wanske pp. 125  */
198   int l = measures;
199   int count = 0;
200   Real symbols_width = 0.0;
201
202   bool use_breve = to_boolean (me->get_property ("use-breve-rest"));
203
204   while (l)
205     {
206       if (use_breve)
207         {
208           int k;
209           if (l >= 2)
210             {
211               l -= 2;
212               k = -2;
213             }
214           else
215             {
216               l -= 1;
217               k = -1;
218             }
219
220           Stencil r (musfont->find_by_name ("rests." + to_string (k)));
221           symbols_width += r.extent (X_AXIS).length ();
222           mols = scm_cons (r.smobbed_copy (), mols);
223         }
224       else
225         {
226           int k;
227           if (l >= 4)
228             {
229               l -= 4;
230               k = -2;
231             }
232           else if (l >= 2)
233             {
234               l -= 2;
235               k = -1;
236             }
237           else
238             {
239               k = 0;
240               l--;
241             }
242
243           Stencil r (musfont->find_by_name ("rests." + to_string (k)));
244           if (k == 0)
245             {
246               Real staff_space = Staff_symbol_referencer::staff_space (me);
247               r.translate_axis (staff_space, Y_AXIS);
248             }
249           symbols_width += r.extent (X_AXIS).length ();
250           mols = scm_cons (r.smobbed_copy (), mols);
251         }
252       count++;
253     }
254
255   /* Make outer padding this much bigger.  */
256   Real outer_padding_factor = 1.5;
257   Real inner_padding = (space - symbols_width)
258     / (2 * outer_padding_factor + (count - 1));
259   if (inner_padding < 0)
260     inner_padding = 1.0;
261
262   Stencil mol;
263   for (SCM s = mols; scm_is_pair (s); s = scm_cdr (s))
264     mol.add_at_edge (X_AXIS, LEFT, *unsmob_stencil (scm_car (s)),
265                      inner_padding);
266   mol.align_to (X_AXIS, LEFT);
267   mol.translate_axis (outer_padding_factor * inner_padding, X_AXIS);
268
269   return mol;
270 }
271
272 void
273 Multi_measure_rest::add_column (Grob *me, Item *c)
274 {
275   add_bound_item (dynamic_cast<Spanner *> (me), c);
276 }
277
278 void
279 Multi_measure_rest::calculate_spacing_rods (Grob *me, Real length)
280 {
281   Spanner *sp = dynamic_cast<Spanner *> (me);
282   if (! (sp->get_bound (LEFT) && sp->get_bound (RIGHT)))
283     {
284       programming_error ("Multi_measure_rest::get_rods (): I am not spanned!");
285       return ;
286     }
287
288   Item *li = sp->get_bound (LEFT)->get_column ();
289   Item *ri = sp->get_bound (RIGHT)->get_column ();
290   Item *lb = li->find_prebroken_piece (RIGHT);
291   Item *rb = ri->find_prebroken_piece (LEFT);
292
293   Item *combinations[4][2] = {{li, ri},
294                               {lb, ri},
295                               {li, rb},
296                               {lb, rb}};
297
298   for (int i = 0; i < 4; i++)
299     {
300       Item *li = combinations[i][0];
301       Item *ri = combinations[i][1];
302
303       if (!li || !ri)
304         continue;
305
306       Rod rod;
307       rod.item_drul_[LEFT] = li;
308       rod.item_drul_[RIGHT] = ri;
309
310       rod.distance_ = Paper_column::minimum_distance (li, ri)
311         + length
312         + 2 * robust_scm2double (me->get_property ("bound-padding"), 1.0);
313
314       Real minlen = robust_scm2double (me->get_property ("minimum-length"), 0);
315       rod.distance_ = max (rod.distance_, minlen);
316       rod.add_to_cols ();
317     }
318 }
319
320 MAKE_SCHEME_CALLBACK (Multi_measure_rest, set_spacing_rods, 1);
321 SCM
322 Multi_measure_rest::set_spacing_rods (SCM smob)
323 {
324   Grob *me = unsmob_grob (smob);
325   Real sym_width = symbol_stencil (me, 0.0).extent (X_AXIS).length ();
326   calculate_spacing_rods (me, sym_width);
327
328   return SCM_UNSPECIFIED;  
329 }
330   
331 MAKE_SCHEME_CALLBACK (Multi_measure_rest, set_text_rods, 1);
332 SCM
333 Multi_measure_rest::set_text_rods (SCM smob)
334 {
335   Grob *me = unsmob_grob (smob);
336   Stencil *stil = me->get_stencil ();
337
338   /* FIXME uncached */
339   Real len = (stil && !stil->extent (X_AXIS).is_empty ())
340     ? stil->extent (X_AXIS).length ()
341     : 0.0;
342   calculate_spacing_rods (me, len);
343
344   return SCM_UNSPECIFIED;
345 }
346
347 ADD_INTERFACE (Multi_measure_rest,
348                "A rest that spans a whole number of measures.",
349
350                /* properties */
351                "expand-limit "
352                "measure-count "
353                "hair-thickness "
354                "thick-thickness "
355                "use-breve-rest "
356                "bound-padding "
357                "minimum-length "
358                );
359