2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1996--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
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.
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.
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/>.
20 #include "libc-extension.hh"
22 #include "paper-column.hh"
23 #include "paper-score.hh"
24 #include "pointer-group-interface.hh"
30 Spanner::clone () const
32 return new Spanner (*this);
36 Spanner::do_break_processing ()
39 Item *left = spanned_drul_[LEFT];
40 Item *right = spanned_drul_[RIGHT];
45 if (get_system () || is_broken ())
51 If we have a spanner spanning one column, we must break it
52 anyway because it might provide a parent for another item. */
56 Item *bound = left->find_prebroken_piece (d);
58 programming_error ("no broken bound");
59 else if (bound->get_system ())
61 Spanner *span = dynamic_cast<Spanner *> (clone ());
62 span->set_bound (LEFT, bound);
63 span->set_bound (RIGHT, bound);
65 assert (span->get_system ());
66 span->get_system ()->typeset_grob (span);
67 broken_intos_.push_back (span);
70 while ((flip (&d)) != LEFT);
74 System *root = get_root_system (this);
75 vector<Item *> break_points = root->broken_col_range (left, right);
77 break_points.insert (break_points.begin () + 0, left);
78 break_points.push_back (right);
80 Slice parent_rank_slice;
81 parent_rank_slice.set_full ();
84 Check if our parent in X-direction spans equally wide
87 for (int a = X_AXIS; a < NO_AXES; a++)
89 if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
90 parent_rank_slice.intersect (parent->spanned_rank_interval ());
93 for (vsize i = 1; i < break_points.size (); i++)
95 Drul_array<Item *> bounds;
96 bounds[LEFT] = break_points[i - 1];
97 bounds[RIGHT] = break_points[i];
101 if (!bounds[d]->get_system ())
102 bounds[d] = bounds[d]->find_prebroken_piece (- d);
104 while ((flip (&d)) != LEFT);
106 if (!bounds[LEFT] || ! bounds[RIGHT])
108 programming_error ("bounds of this piece aren't breakable. ");
112 bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
113 ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
117 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner. Ignoring orphaned part",
122 Spanner *span = dynamic_cast<Spanner *> (clone ());
123 span->set_bound (LEFT, bounds[LEFT]);
124 span->set_bound (RIGHT, bounds[RIGHT]);
126 if (!bounds[LEFT]->get_system ()
127 || !bounds[RIGHT]->get_system ()
128 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
130 programming_error ("bounds of spanner are invalid");
135 bounds[LEFT]->get_system ()->typeset_grob (span);
136 broken_intos_.push_back (span);
140 vector_sort (broken_intos_, Spanner::less);
141 for (vsize i = broken_intos_.size (); i--;)
142 broken_intos_[i]->break_index_ = i;
146 Spanner::get_break_index () const
152 Spanner::set_my_columns ()
154 Direction i = (Direction) LEFT;
157 if (!spanned_drul_[i]->get_system ())
158 set_bound (i, spanned_drul_[i]->find_prebroken_piece ((Direction) - i));
160 while (flip (&i) != LEFT);
164 Spanner::spanned_rank_interval () const
166 Interval_t<int> iv (0, 0);
168 if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
169 iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
170 if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
171 iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
176 Spanner::spanned_time () const
178 return spanned_time_interval (spanned_drul_[LEFT],
179 spanned_drul_[RIGHT]);
183 Spanner::get_bound (Direction d) const
185 return spanned_drul_[d];
189 Set the items that this spanner spans. If D == LEFT, we also set the
190 X-axis parent of THIS to S.
193 Spanner::set_bound (Direction d, Grob *s)
195 Item *i = dynamic_cast<Item *> (s);
198 programming_error ("must have Item for spanner bound of " + name ());
202 spanned_drul_[d] = i;
205 We check for System to prevent the column -> line_of_score
206 -> column -> line_of_score -> etc situation */
207 if (d == LEFT && !dynamic_cast<System *> (this))
208 set_parent (i, X_AXIS);
211 Signal that this column needs to be kept alive. They need to be
212 kept alive to have meaningful position and linebreaking.
214 [maybe we should try keeping all columns alive?, and perhaps
215 inherit position from their (non-)musical brother]
217 if (dynamic_cast<Paper_column *> (i))
218 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
221 Spanner::Spanner (SCM s)
225 spanned_drul_.set (0, 0);
226 pure_property_cache_ = SCM_UNDEFINED;
229 Spanner::Spanner (Spanner const &s)
232 spanned_drul_.set (0, 0);
233 pure_property_cache_ = SCM_UNDEFINED;
237 Certain spanners have pre-computed X values that lie either in
238 X-positions or the X key of the alists returned for left-bound-info
239 and right-bound-info. These are calculated to give the real length
240 of a spanner (which, because of various padding or overhang properties,
241 can extend pass or arrive short of a given bound). If possible, we
242 use these to calculate the spanner's length, and otherwise, we use
245 For those writing a new spanner, DO NOT use both X-positions and
246 left-bound-info/right-bound-info.
249 Spanner::spanner_length () const
251 Interval lr = robust_scm2interval (get_property ("X-positions"),
256 Drul_array<SCM> bounds (get_property ("left-bound-info"),
257 get_property ("right-bound-info"));
261 lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
262 bounds[d], SCM_BOOL_F), -d);
263 while (flip (&d) != LEFT);
270 lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
271 while (flip (&d) != LEFT);
275 programming_error ("spanner with negative length");
281 Spanner::get_system () const
283 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
285 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
287 return spanned_drul_[LEFT]->get_system ();
291 Spanner::find_broken_piece (System *l) const
293 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
295 return broken_intos_ [idx];
300 Spanner::broken_neighbor (Direction d) const
305 vsize k = get_break_index ();
306 Spanner *orig = dynamic_cast<Spanner *> (original_);
308 if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
311 return orig->broken_intos_[j];
315 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
317 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
321 Spanner::less (Spanner *const &a, Spanner *const &b)
323 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
327 Spanner::is_broken () const
329 return broken_intos_.size ();
333 If this is a broken spanner, return the amount the left end is to be
334 shifted horizontally so that the spanner starts after the initial
335 clef and key on the staves. This is necessary for ties, slurs,
336 crescendo and decrescendo signs, for example.
339 Spanner::get_broken_left_end_align () const
341 Paper_column *sc = dynamic_cast<Paper_column *> (spanned_drul_[LEFT]->get_column ());
343 // Relevant only if left span point is first column in line
345 && sc->break_status_dir () == RIGHT)
348 We used to do a full search for the Break_align_item.
349 But that doesn't make a difference, since the Paper_column
350 is likely to contain only a Break_align_item.
352 return sc->extent (sc, X_AXIS)[RIGHT];
359 Spanner::derived_mark () const
361 scm_gc_mark (pure_property_cache_);
365 if (spanned_drul_[d])
366 scm_gc_mark (spanned_drul_[d]->self_scm ());
367 while (flip (&d) != LEFT)
370 for (vsize i = broken_intos_.size (); i--;)
371 scm_gc_mark (broken_intos_[i]->self_scm ());
375 Set left or right bound to IT.
377 Warning: caller should ensure that subsequent calls put in ITems
378 that are left-to-right ordered.
381 add_bound_item (Spanner *sp, Grob *it)
383 if (!sp->get_bound (LEFT))
384 sp->set_bound (LEFT, it);
386 sp->set_bound (RIGHT, it);
389 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
391 Spanner::set_spacing_rods (SCM smob)
393 Grob *me = unsmob_grob (smob);
394 SCM num_length = me->get_property ("minimum-length");
395 if (scm_is_number (num_length))
398 Spanner *sp = dynamic_cast<Spanner *> (me);
399 System *root = get_root_system (me);
400 Drul_array<Item *> bounds (sp->get_bound (LEFT),
401 sp->get_bound (RIGHT));
402 if (!bounds[LEFT] || !bounds[RIGHT])
403 return SCM_UNSPECIFIED;
405 vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
406 bounds[RIGHT]->get_column ()));
411 r.item_drul_[LEFT] = sp->get_bound (LEFT);
412 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
413 r.distance_ = robust_scm2double (num_length, 0);
416 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
417 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
421 r.distance_ = robust_scm2double (num_length, 0);
422 r.item_drul_[LEFT] = sp->get_bound (LEFT);
423 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
427 return SCM_UNSPECIFIED;
430 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
432 Spanner::calc_normalized_endpoints (SCM smob)
434 Spanner *me = unsmob_spanner (smob);
435 SCM result = SCM_EOL;
437 Spanner *orig = dynamic_cast<Spanner *> (me->original ());
439 orig = orig ? orig : me;
441 if (orig->is_broken ())
443 Real total_width = 0.0;
444 vector<Real> span_data;
446 if (!orig->is_broken ())
447 span_data.push_back (orig->spanner_length ());
449 for (vsize i = 0; i < orig->broken_intos_.size (); i++)
450 span_data.push_back (orig->broken_intos_[i]->spanner_length ());
452 vector<Interval> unnormalized_endpoints;
454 for (vsize i = 0; i < span_data.size (); i++)
456 unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
457 total_width += span_data[i];
460 for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
462 SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
463 orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
464 if (me->get_break_index () == i)
470 result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
471 orig->set_property ("normalized-endpoints", result);
478 unsmob_spanner (SCM s)
480 return dynamic_cast<Spanner *> (unsmob_grob (s));
483 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
485 Spanner::bounds_width (SCM grob)
487 Spanner *me = unsmob_spanner (grob);
489 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
491 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
492 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
494 w -= me->relative_coordinate (common, X_AXIS);
496 return ly_interval2scm (w);
499 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
501 Spanner::kill_zero_spanned_time (SCM grob)
503 Spanner *me = unsmob_spanner (grob);
505 Remove the line or hairpin at the start of the line. For
506 piano voice indicators, it makes no sense to have them at
507 the start of the line.
509 I'm not sure what the official rules for glissandi are, but
510 usually the 2nd note of the glissando is "exact", so when playing
511 from the start of the line, there is no need to glide.
513 From a typographical p.o.v. this makes sense, since the amount of
514 space left of a note at the start of a line is very small.
519 if (me->get_bound (LEFT)->break_status_dir ())
521 Interval_t<Moment> moments = me->spanned_time ();
522 moments [LEFT].grace_part_ = 0;
523 if (moments.length () == Moment (0, 0))
527 return SCM_UNSPECIFIED;
531 Spanner::get_cached_pure_property (SCM sym, int start, int end)
533 // The pure property cache is indexed by (name start . end), where name is
534 // a symbol, and start and end are numbers referring to the starting and
535 // ending column ranks of the current line.
536 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
537 return SCM_UNDEFINED;
539 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
540 return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
544 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
546 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
547 pure_property_cache_ = scm_c_make_hash_table (17);
549 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
550 scm_hash_set_x (pure_property_cache_, key, val);
553 ADD_INTERFACE (Spanner,
554 "Some objects are horizontally spanned between objects. For"
555 " example, slurs, beams, ties, etc. These grobs form a subtype"
556 " called @code{Spanner}. All spanners have two span points"
557 " (these must be @code{Item} objects), one on the left and one"
558 " on the right. The left bound is also the X@tie{}reference"
559 " point of the spanner.",
562 "normalized-endpoints "