2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1996--2012 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. */
53 for (LEFT_and_RIGHT (d))
55 Item *bound = left->find_prebroken_piece (d);
57 programming_error ("no broken bound");
58 else if (bound->get_system ())
60 Spanner *span = dynamic_cast<Spanner *> (clone ());
61 span->set_bound (LEFT, bound);
62 span->set_bound (RIGHT, bound);
64 assert (span->get_system ());
65 span->get_system ()->typeset_grob (span);
66 broken_intos_.push_back (span);
72 System *root = get_root_system (this);
73 vector<Item *> break_points = root->broken_col_range (left, right);
75 break_points.insert (break_points.begin () + 0, left);
76 break_points.push_back (right);
78 Slice parent_rank_slice;
79 parent_rank_slice.set_full ();
82 Check if our parent in X-direction spans equally wide
85 for (int a = X_AXIS; a < NO_AXES; a++)
87 if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
88 parent_rank_slice.intersect (parent->spanned_rank_interval ());
91 for (vsize i = 1; i < break_points.size (); i++)
93 Drul_array<Item *> bounds;
94 bounds[LEFT] = break_points[i - 1];
95 bounds[RIGHT] = break_points[i];
96 for (LEFT_and_RIGHT (d))
98 if (!bounds[d]->get_system ())
99 bounds[d] = bounds[d]->find_prebroken_piece (- d);
102 if (!bounds[LEFT] || ! bounds[RIGHT])
104 programming_error ("bounds of this piece aren't breakable. ");
108 bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
109 ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
113 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner. Ignoring orphaned part",
118 Spanner *span = dynamic_cast<Spanner *> (clone ());
119 span->set_bound (LEFT, bounds[LEFT]);
120 span->set_bound (RIGHT, bounds[RIGHT]);
122 if (!bounds[LEFT]->get_system ()
123 || !bounds[RIGHT]->get_system ()
124 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
126 programming_error ("bounds of spanner are invalid");
131 bounds[LEFT]->get_system ()->typeset_grob (span);
132 broken_intos_.push_back (span);
136 vector_sort (broken_intos_, Spanner::less);
137 for (vsize i = broken_intos_.size (); i--;)
138 broken_intos_[i]->break_index_ = i;
142 Spanner::get_break_index () const
148 Spanner::set_my_columns ()
150 for (LEFT_and_RIGHT (d))
152 if (!spanned_drul_[d]->get_system ())
153 set_bound (d, spanned_drul_[d]->find_prebroken_piece ((Direction) - d));
158 Spanner::spanned_rank_interval () const
160 Interval_t<int> iv (0, 0);
162 if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
163 iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
164 if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
165 iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
170 Spanner::spanned_time () const
172 return spanned_time_interval (spanned_drul_[LEFT],
173 spanned_drul_[RIGHT]);
177 Spanner::get_bound (Direction d) const
179 return spanned_drul_[d];
183 Set the items that this spanner spans. If D == LEFT, we also set the
184 X-axis parent of THIS to S.
187 Spanner::set_bound (Direction d, Grob *s)
189 Item *i = dynamic_cast<Item *> (s);
192 programming_error ("must have Item for spanner bound of " + name ());
196 spanned_drul_[d] = i;
199 We check for System to prevent the column -> line_of_score
200 -> column -> line_of_score -> etc situation */
201 if (d == LEFT && !dynamic_cast<System *> (this))
202 set_parent (i, X_AXIS);
205 Signal that this column needs to be kept alive. They need to be
206 kept alive to have meaningful position and linebreaking.
208 [maybe we should try keeping all columns alive?, and perhaps
209 inherit position from their (non-)musical brother]
211 if (dynamic_cast<Paper_column *> (i))
212 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
215 Spanner::Spanner (SCM s)
219 spanned_drul_.set (0, 0);
220 pure_property_cache_ = SCM_UNDEFINED;
223 Spanner::Spanner (Spanner const &s)
226 spanned_drul_.set (0, 0);
227 pure_property_cache_ = SCM_UNDEFINED;
231 Certain spanners have pre-computed X values that lie either in
232 X-positions or the X key of the alists returned for left-bound-info
233 and right-bound-info. These are calculated to give the real length
234 of a spanner (which, because of various padding or overhang properties,
235 can extend pass or arrive short of a given bound). If possible, we
236 use these to calculate the spanner's length, and otherwise, we use
239 For those writing a new spanner, DO NOT use both X-positions and
240 left-bound-info/right-bound-info.
243 Spanner::spanner_length () const
245 Interval lr = robust_scm2interval (get_property ("X-positions"),
250 Drul_array<SCM> bounds (get_property ("left-bound-info"),
251 get_property ("right-bound-info"));
253 for (LEFT_and_RIGHT (d))
254 lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
255 bounds[d], SCM_BOOL_F), -d);
260 for (LEFT_and_RIGHT (d))
261 lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
265 programming_error ("spanner with negative length");
271 Spanner::get_system () const
273 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
275 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
277 return spanned_drul_[LEFT]->get_system ();
281 Spanner::find_broken_piece (System *l) const
283 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
285 return broken_intos_ [idx];
290 Spanner::broken_neighbor (Direction d) const
295 vsize k = get_break_index ();
296 Spanner *orig = dynamic_cast<Spanner *> (original_);
298 if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
301 return orig->broken_intos_[j];
305 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
307 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
311 Spanner::less (Spanner *const &a, Spanner *const &b)
313 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
317 Spanner::is_broken () const
319 return broken_intos_.size ();
323 If this is a broken spanner, return the amount the left end is to be
324 shifted horizontally so that the spanner starts after the initial
325 clef and key on the staves. This is necessary for ties, slurs,
326 crescendo and decrescendo signs, for example.
329 Spanner::get_broken_left_end_align () const
331 Paper_column *sc = dynamic_cast<Paper_column *> (spanned_drul_[LEFT]->get_column ());
333 // Relevant only if left span point is first column in line
335 && sc->break_status_dir () == RIGHT)
338 We used to do a full search for the Break_align_item.
339 But that doesn't make a difference, since the Paper_column
340 is likely to contain only a Break_align_item.
342 return sc->extent (sc, X_AXIS)[RIGHT];
349 Spanner::derived_mark () const
351 scm_gc_mark (pure_property_cache_);
353 for (LEFT_and_RIGHT (d))
354 if (spanned_drul_[d])
355 scm_gc_mark (spanned_drul_[d]->self_scm ());
358 for (vsize i = broken_intos_.size (); i--;)
359 scm_gc_mark (broken_intos_[i]->self_scm ());
363 Set left or right bound to IT.
365 Warning: caller should ensure that subsequent calls put in ITems
366 that are left-to-right ordered.
369 add_bound_item (Spanner *sp, Grob *it)
371 if (!sp->get_bound (LEFT))
372 sp->set_bound (LEFT, it);
374 sp->set_bound (RIGHT, it);
377 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
379 Spanner::set_spacing_rods (SCM smob)
381 Grob *me = unsmob_grob (smob);
382 SCM num_length = me->get_property ("minimum-length");
383 if (scm_is_number (num_length))
386 Spanner *sp = dynamic_cast<Spanner *> (me);
387 System *root = get_root_system (me);
388 Drul_array<Item *> bounds (sp->get_bound (LEFT),
389 sp->get_bound (RIGHT));
390 if (!bounds[LEFT] || !bounds[RIGHT])
391 return SCM_UNSPECIFIED;
393 vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
394 bounds[RIGHT]->get_column ()));
399 r.item_drul_[LEFT] = sp->get_bound (LEFT);
400 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
401 r.distance_ = robust_scm2double (num_length, 0);
404 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
405 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
409 r.distance_ = robust_scm2double (num_length, 0);
410 r.item_drul_[LEFT] = sp->get_bound (LEFT);
411 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
415 return SCM_UNSPECIFIED;
418 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
420 Spanner::calc_normalized_endpoints (SCM smob)
422 Spanner *me = unsmob_spanner (smob);
423 SCM result = SCM_EOL;
425 Spanner *orig = dynamic_cast<Spanner *> (me->original ());
427 orig = orig ? orig : me;
429 if (orig->is_broken ())
431 Real total_width = 0.0;
432 vector<Real> span_data;
434 if (!orig->is_broken ())
435 span_data.push_back (orig->spanner_length ());
437 for (vsize i = 0; i < orig->broken_intos_.size (); i++)
438 span_data.push_back (orig->broken_intos_[i]->spanner_length ());
440 vector<Interval> unnormalized_endpoints;
442 for (vsize i = 0; i < span_data.size (); i++)
444 unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
445 total_width += span_data[i];
448 for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
450 SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
451 orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
452 if (me->get_break_index () == i)
458 result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
459 orig->set_property ("normalized-endpoints", result);
466 unsmob_spanner (SCM s)
468 return dynamic_cast<Spanner *> (unsmob_grob (s));
471 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
473 Spanner::bounds_width (SCM grob)
475 Spanner *me = unsmob_spanner (grob);
477 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
479 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
480 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
482 w -= me->relative_coordinate (common, X_AXIS);
484 return ly_interval2scm (w);
487 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
489 Spanner::kill_zero_spanned_time (SCM grob)
491 Spanner *me = unsmob_spanner (grob);
493 Remove the line or hairpin at the start of the line. For
494 piano voice indicators, it makes no sense to have them at
495 the start of the line.
497 I'm not sure what the official rules for glissandi are, but
498 usually the 2nd note of the glissando is "exact", so when playing
499 from the start of the line, there is no need to glide.
501 From a typographical p.o.v. this makes sense, since the amount of
502 space left of a note at the start of a line is very small.
507 if (me->get_bound (LEFT)->break_status_dir ())
509 Interval_t<Moment> moments = me->spanned_time ();
510 moments [LEFT].grace_part_ = 0;
511 if (moments.length () == Moment (0, 0))
515 return SCM_UNSPECIFIED;
519 Spanner::get_cached_pure_property (SCM sym, int start, int end)
521 // The pure property cache is indexed by (name start . end), where name is
522 // a symbol, and start and end are numbers referring to the starting and
523 // ending column ranks of the current line.
524 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
525 return SCM_UNDEFINED;
527 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
528 return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
532 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
534 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
535 pure_property_cache_ = scm_c_make_hash_table (17);
537 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
538 scm_hash_set_x (pure_property_cache_, key, val);
541 ADD_INTERFACE (Spanner,
542 "Some objects are horizontally spanned between objects. For"
543 " example, slurs, beams, ties, etc. These grobs form a subtype"
544 " called @code{Spanner}. All spanners have two span points"
545 " (these must be @code{Item} objects), one on the left and one"
546 " on the right. The left bound is also the X@tie{}reference"
547 " point of the spanner.",
550 "normalized-endpoints "