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