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 Spanner::spanner_length () const
241 Drul_array<SCM> bounds (get_property ("left-bound-info"),
242 get_property ("right-bound-info"));
246 lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
247 bounds[d], SCM_BOOL_F), -d);
248 while (flip (&d) != LEFT);
253 lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
254 while (flip (&d) != LEFT);
258 programming_error ("spanner with negative length");
264 Spanner::get_system () const
266 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
268 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
270 return spanned_drul_[LEFT]->get_system ();
274 Spanner::find_broken_piece (System *l) const
276 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
278 return broken_intos_ [idx];
283 Spanner::broken_neighbor (Direction d) const
288 vsize k = get_break_index ();
289 Spanner *orig = dynamic_cast<Spanner *> (original_);
291 if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
294 return orig->broken_intos_[j];
298 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
300 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
304 Spanner::less (Spanner *const &a, Spanner *const &b)
306 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
310 Spanner::is_broken () const
312 return broken_intos_.size ();
316 If this is a broken spanner, return the amount the left end is to be
317 shifted horizontally so that the spanner starts after the initial
318 clef and key on the staves. This is necessary for ties, slurs,
319 crescendo and decrescendo signs, for example.
322 Spanner::get_broken_left_end_align () const
324 Paper_column *sc = dynamic_cast<Paper_column *> (spanned_drul_[LEFT]->get_column ());
326 // Relevant only if left span point is first column in line
328 && sc->break_status_dir () == RIGHT)
331 We used to do a full search for the Break_align_item.
332 But that doesn't make a difference, since the Paper_column
333 is likely to contain only a Break_align_item.
335 return sc->extent (sc, X_AXIS)[RIGHT];
342 Spanner::derived_mark () const
344 scm_gc_mark (pure_property_cache_);
348 if (spanned_drul_[d])
349 scm_gc_mark (spanned_drul_[d]->self_scm ());
350 while (flip (&d) != LEFT)
353 for (vsize i = broken_intos_.size (); i--;)
354 scm_gc_mark (broken_intos_[i]->self_scm ());
358 Set left or right bound to IT.
360 Warning: caller should ensure that subsequent calls put in ITems
361 that are left-to-right ordered.
364 add_bound_item (Spanner *sp, Grob *it)
366 if (!sp->get_bound (LEFT))
367 sp->set_bound (LEFT, it);
369 sp->set_bound (RIGHT, it);
372 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
374 Spanner::set_spacing_rods (SCM smob)
376 Grob *me = unsmob_grob (smob);
377 SCM num_length = me->get_property ("minimum-length");
378 if (scm_is_number (num_length))
381 Spanner *sp = dynamic_cast<Spanner *> (me);
382 System *root = get_root_system (me);
383 Drul_array<Item *> bounds (sp->get_bound (LEFT),
384 sp->get_bound (RIGHT));
385 if (!bounds[LEFT] || !bounds[RIGHT])
386 return SCM_UNSPECIFIED;
388 vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
389 bounds[RIGHT]->get_column ()));
394 r.item_drul_[LEFT] = sp->get_bound (LEFT);
395 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
396 r.distance_ = robust_scm2double (num_length, 0);
399 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
400 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
404 r.distance_ = robust_scm2double (num_length, 0);
405 r.item_drul_[LEFT] = sp->get_bound (LEFT);
406 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
410 return SCM_UNSPECIFIED;
413 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
415 Spanner::calc_normalized_endpoints (SCM smob)
417 Spanner *me = unsmob_spanner (smob);
418 SCM result = SCM_EOL;
420 Spanner *orig = dynamic_cast<Spanner *> (me->original ());
422 orig = orig ? orig : me;
424 if (orig->is_broken ())
426 Real total_width = 0.0;
427 vector<Real> span_data;
429 if (!orig->is_broken ())
430 span_data.push_back (orig->spanner_length ());
432 for (vsize i = 0; i < orig->broken_intos_.size (); i++)
433 span_data.push_back (orig->broken_intos_[i]->spanner_length ());
435 vector<Interval> unnormalized_endpoints;
437 for (vsize i = 0; i < span_data.size (); i++)
439 unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
440 total_width += span_data[i];
443 for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
445 SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
446 orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
447 if (me->get_break_index () == i)
453 result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
454 orig->set_property ("normalized-endpoints", result);
461 unsmob_spanner (SCM s)
463 return dynamic_cast<Spanner *> (unsmob_grob (s));
466 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
468 Spanner::bounds_width (SCM grob)
470 Spanner *me = unsmob_spanner (grob);
472 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
474 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
475 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
477 w -= me->relative_coordinate (common, X_AXIS);
479 return ly_interval2scm (w);
482 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
484 Spanner::kill_zero_spanned_time (SCM grob)
486 Spanner *me = unsmob_spanner (grob);
488 Remove the line or hairpin at the start of the line. For
489 piano voice indicators, it makes no sense to have them at
490 the start of the line.
492 I'm not sure what the official rules for glissandi are, but
493 usually the 2nd note of the glissando is "exact", so when playing
494 from the start of the line, there is no need to glide.
496 From a typographical p.o.v. this makes sense, since the amount of
497 space left of a note at the start of a line is very small.
502 if (me->get_bound (LEFT)->break_status_dir ())
504 Interval_t<Moment> moments = me->spanned_time ();
505 moments [LEFT].grace_part_ = 0;
506 if (moments.length () == Moment (0, 0))
510 return SCM_UNSPECIFIED;
514 Spanner::get_cached_pure_property (SCM sym, int start, int end)
516 // The pure property cache is indexed by (name start . end), where name is
517 // a symbol, and start and end are numbers referring to the starting and
518 // ending column ranks of the current line.
519 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
520 return SCM_UNDEFINED;
522 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
523 return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
527 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
529 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
530 pure_property_cache_ = scm_c_make_hash_table (17);
532 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
533 scm_hash_set_x (pure_property_cache_, key, val);
536 ADD_INTERFACE (Spanner,
537 "Some objects are horizontally spanned between objects. For"
538 " example, slurs, beams, ties, etc. These grobs form a subtype"
539 " called @code{Spanner}. All spanners have two span points"
540 " (these must be @code{Item} objects), one on the left and one"
541 " on the right. The left bound is also the X@tie{}reference"
542 " point of the spanner.",
545 "normalized-endpoints "