]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
Docs-hu: Translated Community Updated macro translations Fixed some translations...
[lilypond.git] / lily / spanner.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2009 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 "libc-extension.hh"
21 #include "moment.hh"
22 #include "paper-column.hh"
23 #include "paper-score.hh"
24 #include "pointer-group-interface.hh"
25 #include "stencil.hh"
26 #include "system.hh"
27 #include "warn.hh"
28
29 Grob *
30 Spanner::clone () const
31 {
32   return new Spanner (*this);
33 }
34
35 void
36 Spanner::do_break_processing ()
37 {
38   //break_into_pieces
39   Item *left = spanned_drul_[LEFT];
40   Item *right = spanned_drul_[RIGHT];
41
42   if (!left || !right)
43     return;
44
45
46   if (get_system () || is_broken ())
47     return;
48
49   if (left == right)
50     {
51       /*
52         If we have a spanner spanning one column, we must break it
53         anyway because it might provide a parent for another item.  */
54       Direction d = LEFT;
55       do
56         {
57           Item *bound = left->find_prebroken_piece (d);
58           if (!bound)
59             programming_error ("no broken bound");
60           else if (bound->get_system ())
61             {
62               Spanner *span = dynamic_cast<Spanner *> (clone ());
63               span->set_bound (LEFT, bound);
64               span->set_bound (RIGHT, bound);
65
66               assert (span->get_system ());
67               span->get_system ()->typeset_grob (span);
68               broken_intos_.push_back (span);
69             }
70         }
71       while ((flip (&d)) != LEFT);
72     }
73   else
74     {
75       System *root  = get_root_system (this);
76       vector<Item*> break_points = root->broken_col_range (left, right);
77
78       break_points.insert (break_points.begin () + 0, left);
79       break_points.push_back (right);
80
81       Slice parent_rank_slice;
82       parent_rank_slice.set_full ();
83       
84       /*
85         Check if our parent in X-direction spans equally wide
86         or wider than we do.
87       */
88       for (int a = X_AXIS; a < NO_AXES; a++)
89         {
90           if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
91             parent_rank_slice.intersect (parent->spanned_rank_interval ());
92         }
93   
94       for (vsize i = 1; i < break_points.size (); i++)
95         {
96           Drul_array<Item *> bounds;
97           bounds[LEFT] = break_points[i - 1];
98           bounds[RIGHT] = break_points[i];
99           Direction d = LEFT;
100           do
101             {
102               if (!bounds[d]->get_system ())
103                 bounds[d] = bounds[d]->find_prebroken_piece (- d);
104             }
105           while ((flip (&d)) != LEFT);
106
107           if (!bounds[LEFT] || ! bounds[RIGHT])
108             {
109               programming_error ("bounds of this piece aren't breakable. ");
110               continue;
111             }
112
113           bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
114           ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
115           
116           if (!ok)
117             {
118               programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner. Ignoring orphaned part",
119                                             name ().c_str ()));
120               continue;
121             }
122             
123           
124           Spanner *span = dynamic_cast<Spanner *> (clone ());
125           span->set_bound (LEFT, bounds[LEFT]);
126           span->set_bound (RIGHT, bounds[RIGHT]);
127
128           if (!bounds[LEFT]->get_system ()
129               || !bounds[RIGHT]->get_system ()
130               || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
131             {
132               programming_error ("bounds of spanner are invalid");
133               span->suicide ();
134             }
135           else
136             {
137               bounds[LEFT]->get_system ()->typeset_grob (span);
138               broken_intos_.push_back (span);
139             }
140         }
141     }
142   vector_sort (broken_intos_, Spanner::less);
143   for (vsize i = broken_intos_.size (); i--;)
144     broken_intos_[i]->break_index_ = i;
145 }
146
147 vsize
148 Spanner::get_break_index () const
149 {
150   return break_index_;
151 }
152
153 void
154 Spanner::set_my_columns ()
155 {
156   Direction i = (Direction) LEFT;
157   do
158     {
159       if (!spanned_drul_[i]->get_system ())
160         set_bound (i, spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
161     }
162   while (flip (&i) != LEFT);
163 }
164
165 Interval_t<int>
166 Spanner::spanned_rank_interval () const
167 {
168   Interval_t<int> iv (0, 0);
169
170   if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
171     iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
172   if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
173     iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
174   return iv;
175 }
176
177 Interval_t<Moment>
178 Spanner::spanned_time () const
179 {
180   return spanned_time_interval (spanned_drul_[LEFT],
181                                 spanned_drul_[RIGHT]);
182 }
183
184
185 Item *
186 Spanner::get_bound (Direction d) const
187 {
188   return spanned_drul_[d];
189 }
190
191 /*
192   Set the items that this spanner spans. If D == LEFT, we also set the
193   X-axis parent of THIS to S.
194 */
195 void
196 Spanner::set_bound (Direction d, Grob *s)
197 {
198   Item *i = dynamic_cast<Item *> (s);
199   if (!i)
200     {
201       programming_error ("must have Item for spanner bound of " + name());
202       return;
203     }
204
205   spanned_drul_[d] = i;
206
207   /**
208      We check for System to prevent the column -> line_of_score
209      -> column -> line_of_score -> etc situation */
210   if (d == LEFT && !dynamic_cast<System *> (this))
211     set_parent (i, X_AXIS);
212
213   /*
214     Signal that this column needs to be kept alive. They need to be
215     kept alive to have meaningful position and linebreaking.
216
217     [maybe we should try keeping all columns alive?, and perhaps
218     inherit position from their (non-)musical brother]
219   */
220   if (dynamic_cast<Paper_column *> (i))
221     Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
222 }
223
224 Spanner::Spanner (SCM s)
225   : Grob (s)
226 {
227   break_index_ = 0;
228   spanned_drul_.set (0, 0);
229 }
230
231 Spanner::Spanner (Spanner const &s)
232   : Grob (s)
233 {
234   spanned_drul_.set (0, 0);
235 }
236
237 Real
238 Spanner::spanner_length () const
239 {
240   Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
241   Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
242
243   if (r < l)
244     programming_error ("spanner with negative length");
245
246   return r - l;
247 }
248
249 System *
250 Spanner::get_system () const
251 {
252   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
253     return 0;
254   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
255     return 0;
256   return spanned_drul_[LEFT]->get_system ();
257 }
258
259 Grob *
260 Spanner::find_broken_piece (System *l) const
261 {
262   vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
263   if (idx != VPOS)
264     return broken_intos_ [idx];
265   return 0;
266 }
267
268 Spanner *
269 Spanner::broken_neighbor (Direction d) const
270 {
271   if (!original_)
272     return 0;
273
274   vsize k = broken_spanner_index (this);
275   Spanner *orig = dynamic_cast<Spanner*> (original_);
276   int j = int (k) + d;
277   if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
278     return 0;
279
280   return orig->broken_intos_[j];
281 }
282
283 int
284 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
285 {
286   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
287 }
288
289 bool
290 Spanner::less (Spanner *const &a, Spanner *const &b)
291 {
292   return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
293 }
294
295 bool
296 Spanner::is_broken () const
297 {
298   return broken_intos_.size ();
299 }
300
301 /*
302   If this is a broken spanner, return the amount the left end is to be
303   shifted horizontally so that the spanner starts after the initial
304   clef and key on the staves. This is necessary for ties, slurs,
305   crescendo and decrescendo signs, for example.
306 */
307 Real
308 Spanner::get_broken_left_end_align () const
309 {
310   Paper_column *sc = dynamic_cast<Paper_column *> (spanned_drul_[LEFT]->get_column ());
311
312   // Relevant only if left span point is first column in line
313   if (sc != NULL
314       && sc->break_status_dir () == RIGHT)
315     {
316       /*
317         We used to do a full search for the Break_align_item.
318         But that doesn't make a difference, since the Paper_column
319         is likely to contain only a Break_align_item.
320       */
321       return sc->extent (sc, X_AXIS)[RIGHT];
322     }
323
324   return 0.0;
325 }
326
327 void
328 Spanner::derived_mark () const
329 {
330   Direction d = LEFT;
331   do
332     if (spanned_drul_[d])
333       scm_gc_mark (spanned_drul_[d]->self_scm ());
334   while (flip (&d) != LEFT)
335     ;
336
337   for (vsize i = broken_intos_.size (); i--;)
338     scm_gc_mark (broken_intos_[i]->self_scm ());
339 }
340
341 /*
342   Set left or right bound to IT.
343
344   Warning: caller should ensure that subsequent calls put in ITems
345   that are left-to-right ordered.
346 */
347 void
348 add_bound_item (Spanner *sp, Grob *it)
349 {
350   if (!sp->get_bound (LEFT))
351     sp->set_bound (LEFT, it);
352   else
353     sp->set_bound (RIGHT, it);
354 }
355
356 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
357 SCM
358 Spanner::set_spacing_rods (SCM smob)
359 {
360   Grob *me = unsmob_grob (smob);
361   SCM num_length = me->get_property ("minimum-length");
362   if (scm_is_number (num_length))
363     {
364       Rod r;
365       Spanner *sp = dynamic_cast<Spanner *> (me);
366       System *root = get_root_system (me);
367       Drul_array<Item*> bounds (sp->get_bound (LEFT),
368                                 sp->get_bound (RIGHT));
369       if (!bounds[LEFT] || !bounds[RIGHT])
370         return SCM_UNSPECIFIED;
371       
372       vector<Item*> cols (root->broken_col_range (bounds[LEFT]->get_column (),
373                                                   bounds[RIGHT]->get_column ()));
374
375       if (cols.size ())
376         {
377           Rod r ;
378           r.item_drul_[LEFT] = sp->get_bound (LEFT);
379           r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
380           r.distance_ = robust_scm2double (num_length, 0);
381           r.add_to_cols ();
382           
383           r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
384           r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
385           r.add_to_cols ();
386         }
387            
388       r.distance_ = robust_scm2double (num_length, 0);
389       r.item_drul_[LEFT] = sp->get_bound (LEFT);
390       r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
391       r.add_to_cols ();
392     }
393   
394   return SCM_UNSPECIFIED;
395 }
396
397 /*
398   Return I such that SP == SP->ORIGINAL ()->BROKEN_INTOS_[I].
399 */
400 int
401 broken_spanner_index (Spanner const *sp)
402 {
403   Spanner *parent = dynamic_cast<Spanner *> (sp->original ());
404   /* ugh: casting */
405   return find (parent->broken_intos_, (Spanner*) sp) - parent->broken_intos_.begin ();
406 }
407
408 Spanner *
409 unsmob_spanner (SCM s)
410 {
411   return dynamic_cast<Spanner *> (unsmob_grob (s));
412 }
413
414 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
415 SCM
416 Spanner::bounds_width (SCM grob)
417 {
418   Spanner *me = unsmob_spanner (grob);
419
420   Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
421
422   Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
423               me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
424               
425   w -= me->relative_coordinate (common, X_AXIS);
426
427   return ly_interval2scm (w);
428 }
429
430 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
431 SCM
432 Spanner::kill_zero_spanned_time (SCM grob)
433 {
434   Spanner *me = unsmob_spanner (grob);
435   Interval_t<Moment> moments = me->spanned_time ();
436   /*
437     Remove the line or hairpin at the start of the line.  For
438     piano voice indicators, it makes no sense to have them at
439     the start of the line.
440
441     I'm not sure what the official rules for glissandi are, but
442     usually the 2nd note of the glissando is "exact", so when playing
443     from the start of the line, there is no need to glide.
444
445     From a typographical p.o.v. this makes sense, since the amount of
446     space left of a note at the start of a line is very small.
447
448     --hwn.
449
450   */
451   if (moments.length () == Moment (0, 0))
452     me->suicide ();
453
454   return SCM_UNSPECIFIED;
455 }
456
457 ADD_INTERFACE (Spanner,
458                "Some objects are horizontally spanned between objects.  For"
459                " example, slurs, beams, ties, etc.  These grobs form a subtype"
460                " called @code{Spanner}.  All spanners have two span points"
461                " (these must be @code{Item} objects), one on the left and one"
462                " on the right.  The left bound is also the X@tie{}reference"
463                " point of the spanner.",
464
465                /* properties */
466                "minimum-length "
467                "to-barline "
468                );
469