Nitpick: ly:spanner-bound grob name slur -> spanner.
[lilypond.git] / lily / spanner.cc
blob12346042df772cbb88f0b4380470ba0a1fe14391
1 /*
2 spanner.cc -- implement Spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
9 #include "libc-extension.hh"
10 #include "moment.hh"
11 #include "paper-column.hh"
12 #include "paper-score.hh"
13 #include "pointer-group-interface.hh"
14 #include "stencil.hh"
15 #include "system.hh"
16 #include "warn.hh"
18 Grob *
19 Spanner::clone () const
21 return new Spanner (*this);
24 void
25 Spanner::do_break_processing ()
27 //break_into_pieces
28 Item *left = spanned_drul_[LEFT];
29 Item *right = spanned_drul_[RIGHT];
31 if (!left || !right)
32 return;
35 if (get_system () || is_broken ())
36 return;
38 if (left == right)
41 If we have a spanner spanning one column, we must break it
42 anyway because it might provide a parent for another item. */
43 Direction d = LEFT;
46 Item *bound = left->find_prebroken_piece (d);
47 if (!bound)
48 programming_error ("no broken bound");
49 else if (bound->get_system ())
51 Spanner *span = dynamic_cast<Spanner *> (clone ());
52 span->set_bound (LEFT, bound);
53 span->set_bound (RIGHT, bound);
55 assert (span->get_system ());
56 span->get_system ()->typeset_grob (span);
57 broken_intos_.push_back (span);
60 while ((flip (&d)) != LEFT);
62 else
64 System *root = get_root_system (this);
65 vector<Item*> break_points = root->broken_col_range (left, right);
67 break_points.insert (break_points.begin () + 0, left);
68 break_points.push_back (right);
70 Slice parent_rank_slice;
71 parent_rank_slice.set_full ();
74 Check if our parent in X-direction spans equally wide
75 or wider than we do.
77 for (int a = X_AXIS; a < NO_AXES; a++)
79 if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
80 parent_rank_slice.intersect (parent->spanned_rank_interval ());
83 for (vsize i = 1; i < break_points.size (); i++)
85 Drul_array<Item *> bounds;
86 bounds[LEFT] = break_points[i - 1];
87 bounds[RIGHT] = break_points[i];
88 Direction d = LEFT;
91 if (!bounds[d]->get_system ())
92 bounds[d] = bounds[d]->find_prebroken_piece (- d);
94 while ((flip (&d)) != LEFT);
96 if (!bounds[LEFT] || ! bounds[RIGHT])
98 programming_error ("bounds of this piece aren't breakable. ");
99 continue;
102 bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
103 ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
105 if (!ok)
107 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner. Ignoring orphaned part",
108 name ().c_str ()));
109 continue;
113 Spanner *span = dynamic_cast<Spanner *> (clone ());
114 span->set_bound (LEFT, bounds[LEFT]);
115 span->set_bound (RIGHT, bounds[RIGHT]);
117 if (!bounds[LEFT]->get_system ()
118 || !bounds[RIGHT]->get_system ()
119 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
121 programming_error ("bounds of spanner are invalid");
122 span->suicide ();
124 else
126 bounds[LEFT]->get_system ()->typeset_grob (span);
127 broken_intos_.push_back (span);
131 vector_sort (broken_intos_, Spanner::less);
132 for (vsize i = broken_intos_.size (); i--;)
133 broken_intos_[i]->break_index_ = i;
136 vsize
137 Spanner::get_break_index () const
139 return break_index_;
142 void
143 Spanner::set_my_columns ()
145 Direction i = (Direction) LEFT;
148 if (!spanned_drul_[i]->get_system ())
149 set_bound (i, spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
151 while (flip (&i) != LEFT);
154 Interval_t<int>
155 Spanner::spanned_rank_interval () const
157 Interval_t<int> iv (0, 0);
159 if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
160 iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
161 if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
162 iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
163 return iv;
166 Interval_t<Moment>
167 Spanner::spanned_time () const
169 return spanned_time_interval (spanned_drul_[LEFT],
170 spanned_drul_[RIGHT]);
174 Item *
175 Spanner::get_bound (Direction d) const
177 return spanned_drul_[d];
181 Set the items that this spanner spans. If D == LEFT, we also set the
182 X-axis parent of THIS to S.
184 void
185 Spanner::set_bound (Direction d, Grob *s)
187 Item *i = dynamic_cast<Item *> (s);
188 if (!i)
190 programming_error ("must have Item for spanner bound of " + name());
191 return;
194 spanned_drul_[d] = i;
197 We check for System to prevent the column -> line_of_score
198 -> column -> line_of_score -> etc situation */
199 if (d == LEFT && !dynamic_cast<System *> (this))
200 set_parent (i, X_AXIS);
203 Signal that this column needs to be kept alive. They need to be
204 kept alive to have meaningful position and linebreaking.
206 [maybe we should try keeping all columns alive?, and perhaps
207 inherit position from their (non-)musical brother]
209 if (dynamic_cast<Paper_column *> (i))
210 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
213 Spanner::Spanner (SCM s)
214 : Grob (s)
216 break_index_ = 0;
217 spanned_drul_.set (0, 0);
220 Spanner::Spanner (Spanner const &s)
221 : Grob (s)
223 spanned_drul_.set (0, 0);
226 Real
227 Spanner::spanner_length () const
229 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
230 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
232 if (r < l)
233 programming_error ("spanner with negative length");
235 return r - l;
238 System *
239 Spanner::get_system () const
241 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
242 return 0;
243 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
244 return 0;
245 return spanned_drul_[LEFT]->get_system ();
248 Grob *
249 Spanner::find_broken_piece (System *l) const
251 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
252 if (idx != VPOS)
253 return broken_intos_ [idx];
254 return 0;
257 Spanner *
258 Spanner::broken_neighbor (Direction d) const
260 if (!original_)
261 return 0;
263 vsize k = broken_spanner_index (this);
264 Spanner *orig = dynamic_cast<Spanner*> (original_);
265 int j = int (k) + d;
266 if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
267 return 0;
269 return orig->broken_intos_[j];
273 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
275 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
278 bool
279 Spanner::less (Spanner *const &a, Spanner *const &b)
281 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
284 bool
285 Spanner::is_broken () const
287 return broken_intos_.size ();
291 If this is a broken spanner, return the amount the left end is to be
292 shifted horizontally so that the spanner starts after the initial
293 clef and key on the staves. This is necessary for ties, slurs,
294 crescendo and decrescendo signs, for example.
296 Real
297 Spanner::get_broken_left_end_align () const
299 Paper_column *sc = dynamic_cast<Paper_column *> (spanned_drul_[LEFT]->get_column ());
301 // Relevant only if left span point is first column in line
302 if (sc != NULL
303 && sc->break_status_dir () == RIGHT)
306 We used to do a full search for the Break_align_item.
307 But that doesn't make a difference, since the Paper_column
308 is likely to contain only a Break_align_item.
310 return sc->extent (sc, X_AXIS)[RIGHT];
313 return 0.0;
316 void
317 Spanner::derived_mark () const
319 Direction d = LEFT;
321 if (spanned_drul_[d])
322 scm_gc_mark (spanned_drul_[d]->self_scm ());
323 while (flip (&d) != LEFT)
326 for (vsize i = broken_intos_.size (); i--;)
327 scm_gc_mark (broken_intos_[i]->self_scm ());
331 Set left or right bound to IT.
333 Warning: caller should ensure that subsequent calls put in ITems
334 that are left-to-right ordered.
336 void
337 add_bound_item (Spanner *sp, Grob *it)
339 if (!sp->get_bound (LEFT))
340 sp->set_bound (LEFT, it);
341 else
342 sp->set_bound (RIGHT, it);
345 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
347 Spanner::set_spacing_rods (SCM smob)
349 Grob *me = unsmob_grob (smob);
350 SCM num_length = me->get_property ("minimum-length");
351 if (scm_is_number (num_length))
353 Rod r;
354 Spanner *sp = dynamic_cast<Spanner *> (me);
355 System *root = get_root_system (me);
356 Drul_array<Item*> bounds (sp->get_bound (LEFT),
357 sp->get_bound (RIGHT));
358 if (!bounds[LEFT] || !bounds[RIGHT])
359 return SCM_UNSPECIFIED;
361 vector<Item*> cols (root->broken_col_range (bounds[LEFT]->get_column (),
362 bounds[RIGHT]->get_column ()));
364 if (cols.size ())
366 Rod r ;
367 r.item_drul_[LEFT] = sp->get_bound (LEFT);
368 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
369 r.distance_ = robust_scm2double (num_length, 0);
370 r.add_to_cols ();
372 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
373 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
374 r.add_to_cols ();
377 r.distance_ = robust_scm2double (num_length, 0);
378 r.item_drul_[LEFT] = sp->get_bound (LEFT);
379 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
380 r.add_to_cols ();
383 return SCM_UNSPECIFIED;
387 Return I such that SP == SP->ORIGINAL ()->BROKEN_INTOS_[I].
390 broken_spanner_index (Spanner const *sp)
392 Spanner *parent = dynamic_cast<Spanner *> (sp->original ());
393 /* ugh: casting */
394 return find (parent->broken_intos_, (Spanner*) sp) - parent->broken_intos_.begin ();
397 Spanner *
398 unsmob_spanner (SCM s)
400 return dynamic_cast<Spanner *> (unsmob_grob (s));
403 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
405 Spanner::bounds_width (SCM grob)
407 Spanner *me = unsmob_spanner (grob);
409 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
411 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
412 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
414 w -= me->relative_coordinate (common, X_AXIS);
416 return ly_interval2scm (w);
419 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
421 Spanner::kill_zero_spanned_time (SCM grob)
423 Spanner *me = unsmob_spanner (grob);
424 Interval_t<Moment> moments = me->spanned_time ();
426 Remove the line or hairpin at the start of the line. For
427 piano voice indicators, it makes no sense to have them at
428 the start of the line.
430 I'm not sure what the official rules for glissandi are, but
431 usually the 2nd note of the glissando is "exact", so when playing
432 from the start of the line, there is no need to glide.
434 From a typographical p.o.v. this makes sense, since the amount of
435 space left of a note at the start of a line is very small.
437 --hwn.
440 if (moments.length () == Moment (0, 0))
441 me->suicide ();
443 return SCM_UNSPECIFIED;
446 ADD_INTERFACE (Spanner,
447 "Some objects are horizontally spanned between objects. For"
448 " example, slurs, beams, ties, etc. These grobs form a subtype"
449 " called @code{Spanner}. All spanners have two span points"
450 " (these must be @code{Item} objects), one on the left and one"
451 " on the right. The left bound is also the X@tie{}reference"
452 " point of the spanner.",
454 /* properties */
455 "minimum-length "
456 "to-barline "