]> git.donarmstrong.com Git - lilypond.git/blob - lily/multi-measure-rest.cc
0ea2cf13f3c568312dcc312342598836f9dc8546
[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--2001 Jan Nieuwenhuizen <janneke@gnu.org>
7   
8  */
9
10 #include "multi-measure-rest.hh"
11 #include "debug.hh"
12 #include "paper-def.hh"
13 #include "paper-column.hh" // urg
14 #include "font-interface.hh"
15 #include "rest.hh"
16 #include "molecule.hh"
17 #include "misc.hh"
18 #include "group-interface.hh"
19 #include "spanner.hh"
20 #include "staff-symbol-referencer.hh"
21 #include "text-item.hh"
22 #include "percent-repeat-item.hh"
23
24
25 void
26 Multi_measure_rest::set_interface (Grob*me)
27 {
28   me->set_interface (ly_symbol2scm ("multi-measure-rest-interface"));
29 }
30
31 bool
32 Multi_measure_rest::has_interface (Grob*me)
33 {
34   return me->has_interface (ly_symbol2scm ("multi-measure-rest-interface"));
35 }
36
37 MAKE_SCHEME_CALLBACK (Multi_measure_rest,percent,1);
38 SCM
39 Multi_measure_rest::percent (SCM smob)
40 {
41   
42   Grob *me = unsmob_grob (smob);
43   Spanner *sp = dynamic_cast<Spanner*> (me);
44   
45   Molecule r = Percent_repeat_item_interface::x_percent (me, 1,  0.75, 1.6);
46
47   // ugh copy & paste.
48   
49   Interval sp_iv;
50   Direction d = LEFT;
51   do
52     {
53       Item * col = sp->get_bound (d)->column_l ();
54
55       Interval coldim = col->extent (0, X_AXIS);
56
57       sp_iv[d] = coldim[-d]  ;
58     }
59   while ((flip (&d)) != LEFT);
60   Real x_off = 0.0;
61
62   Real rx  = sp->get_bound (LEFT)->relative_coordinate (0, X_AXIS);
63   /*
64     we gotta stay clear of sp_iv, so move a bit to the right if
65     needed.
66    */
67   x_off += (sp_iv[LEFT] -  rx) >? 0;
68
69   /*
70     center between stuff.
71    */
72   x_off += sp_iv.length ()/ 2;
73
74   r.translate_axis (x_off,X_AXIS);
75
76   
77   return r.smobbed_copy ();
78 }
79
80
81 /*
82    [TODO]                                      17
83    variable-sized multi-measure rest symbol: |====| ??
84 */
85 MAKE_SCHEME_CALLBACK (Multi_measure_rest,brew_molecule,1);
86 SCM
87 Multi_measure_rest::brew_molecule (SCM smob) 
88 {
89   Grob *me = unsmob_grob (smob);
90   if (to_boolean (me->get_grob_property ("skip-timestep")))
91     {
92       me->set_grob_property ("skip-timestep", SCM_EOL);
93       return SCM_EOL;
94     }
95   
96   Spanner * sp = dynamic_cast<Spanner*> (me);
97
98   SCM alist_chain = Font_interface::font_alist_chain (me);
99
100   
101   SCM style_chain =
102     Font_interface::add_style (me, ly_symbol2scm ("mmrest-symbol"),
103                                alist_chain);
104
105   Font_metric *musfont
106     = Font_interface::get_font (me,style_chain);
107                         
108   Real staff_space = Staff_symbol_referencer::staff_space (me);
109
110   Interval sp_iv;
111   Direction d = LEFT;
112   do
113     {
114       Item * col = sp->get_bound (d)->column_l ();
115
116       Interval coldim = col->extent (0, X_AXIS);
117
118       sp_iv[d] = coldim[-d]  ;
119     }
120   while ((flip (&d)) != LEFT);
121   Molecule mol;
122   Real x_off = 0.0;
123
124   Real rx  = sp->get_bound (LEFT)->relative_coordinate (0, X_AXIS);
125   /*
126     we gotta stay clear of sp_iv, so move a bit to the right if
127     needed.
128    */
129   x_off += (sp_iv[LEFT] -  rx) >? 0;
130
131   /*
132     center between stuff.
133    */
134   x_off += sp_iv.length ()/ 2;
135
136   
137   Molecule s;
138
139   int measures = 0;
140   SCM m (me->get_grob_property ("measure-count"));
141   if (gh_number_p (m))
142     {
143       measures = gh_scm2int (m);
144     }
145   
146
147   SCM limit = me->get_grob_property ("expand-limit");
148   if (measures <= 0)
149     return SCM_EOL;
150   if (measures == 1)
151     {
152       s = musfont->find_by_name (Rest::glyph_name (me, 0, ""));
153
154       /*
155         ugh.
156        */
157       if (Staff_symbol_referencer::position_f (me) == 0.0)
158         s.translate_axis (Staff_symbol_referencer::staff_space (me), Y_AXIS);
159     }
160   else if (measures <= gh_scm2int (limit))
161     {
162       /*
163         Build a rest from smaller parts. Distances inbetween are
164         really variable, see Wanske pp. 125 */
165
166       int l = measures;
167       while (l)
168         {
169           int k;
170           if (l >= 4)
171             {
172               l-=4;
173               k = -2;
174             }
175           else if (l>= 2)
176             {
177               l -= 2;
178               k = -1;
179             }
180           else
181             {
182               k = 0;
183               l --;
184             }
185
186           Real pad = s.empty_b ()
187             ? 0.0 : gh_scm2double (me->get_grob_property ("padding")) * staff_space;
188
189           Molecule r (musfont->find_by_name ("rests-" + to_str (k)));
190           if (k == 0)
191             r.translate_axis (staff_space, Y_AXIS);
192           
193           s.add_at_edge (X_AXIS, RIGHT, r, pad);
194         }
195
196
197       s.align_to (X_AXIS, CENTER);
198     }
199   else 
200     {
201       String idx = ("rests-") + to_str (-4);
202       s = musfont->find_by_name (idx);
203     }
204   
205   mol.add_molecule (s);
206
207   if (measures > 1)
208     {
209       Molecule s = Text_item::text2molecule (me,
210                                              ly_str02scm (to_str (measures).ch_C ()),
211                                              alist_chain);
212       s.align_to (X_AXIS, CENTER);
213       s.translate_axis (3.0 * staff_space, Y_AXIS);
214       mol.add_molecule (s);
215     }
216   mol.translate_axis (x_off, X_AXIS);
217   return mol.smobbed_copy ();
218 }
219
220 /*
221   UGH. JUNKME elt prop "columns" isn't really needed. 
222  */
223 void
224 Multi_measure_rest::add_column (Grob*me,Item* c)
225 {
226   Pointer_group_interface::add_grob (me, ly_symbol2scm ("columns"),c);
227
228   add_bound_item (dynamic_cast<Spanner*> (me),c);
229 }
230
231
232 MAKE_SCHEME_CALLBACK (Multi_measure_rest, set_spacing_rods,1);
233
234 SCM
235 Multi_measure_rest::set_spacing_rods (SCM smob)
236 {
237   Grob*me = unsmob_grob (smob);
238
239   Spanner*sp = dynamic_cast<Spanner*> (me);
240   if (! (sp->get_bound (LEFT) && sp->get_bound (RIGHT)))
241     {
242       programming_error ("Multi_measure_rest::get_rods (): I am not spanned!");
243       return SCM_UNSPECIFIED;
244     }
245
246   Item * l = sp->get_bound (LEFT)->column_l ();
247   Item * r = sp->get_bound (RIGHT)->column_l ();
248   Item * lb = l->find_prebroken_piece (RIGHT);
249   Item * rb = r->find_prebroken_piece (LEFT);      
250   
251   Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
252   Real staff_space = Staff_symbol_referencer::staff_space (me);
253   for (int i=0; i < 4; i++)
254     {
255       Item * l =  combinations[i][0];
256       Item *r = combinations[i][1];
257
258       if (!l || !r)
259         continue;
260
261       Rod rod;
262       rod.item_l_drul_[LEFT] = l;
263       rod.item_l_drul_[RIGHT] = r;
264
265         /*
266           should do something more advanced.
267          */
268       rod.distance_f_ = l->extent (l, X_AXIS)[BIGGER] - r->extent (r, X_AXIS)[SMALLER]
269         + gh_scm2double (me->get_grob_property ("minimum-width")) * staff_space;
270   
271       rod.add_to_cols ();
272     }
273   return SCM_UNSPECIFIED;
274 }
275