Start pictograms branch.
[lilypond/mpolesky.git] / lily / spanner.cc
blob32e0d21201c4bdd2fa8b32870176e0c5d24d6f59
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1996--2010 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"
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"
29 Grob *
30 Spanner::clone () const
32 return new Spanner (*this);
35 void
36 Spanner::do_break_processing ()
38 //break_into_pieces
39 Item *left = spanned_drul_[LEFT];
40 Item *right = spanned_drul_[RIGHT];
42 if (!left || !right)
43 return;
46 if (get_system () || is_broken ())
47 return;
49 if (left == right)
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;
57 Item *bound = left->find_prebroken_piece (d);
58 if (!bound)
59 programming_error ("no broken bound");
60 else if (bound->get_system ())
62 Spanner *span = dynamic_cast<Spanner *> (clone ());
63 span->set_bound (LEFT, bound);
64 span->set_bound (RIGHT, bound);
66 assert (span->get_system ());
67 span->get_system ()->typeset_grob (span);
68 broken_intos_.push_back (span);
71 while ((flip (&d)) != LEFT);
73 else
75 System *root = get_root_system (this);
76 vector<Item*> break_points = root->broken_col_range (left, right);
78 break_points.insert (break_points.begin () + 0, left);
79 break_points.push_back (right);
81 Slice parent_rank_slice;
82 parent_rank_slice.set_full ();
85 Check if our parent in X-direction spans equally wide
86 or wider than we do.
88 for (int a = X_AXIS; a < NO_AXES; a++)
90 if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
91 parent_rank_slice.intersect (parent->spanned_rank_interval ());
94 for (vsize i = 1; i < break_points.size (); i++)
96 Drul_array<Item *> bounds;
97 bounds[LEFT] = break_points[i - 1];
98 bounds[RIGHT] = break_points[i];
99 Direction d = LEFT;
102 if (!bounds[d]->get_system ())
103 bounds[d] = bounds[d]->find_prebroken_piece (- d);
105 while ((flip (&d)) != LEFT);
107 if (!bounds[LEFT] || ! bounds[RIGHT])
109 programming_error ("bounds of this piece aren't breakable. ");
110 continue;
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 ());
116 if (!ok)
118 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner. Ignoring orphaned part",
119 name ().c_str ()));
120 continue;
124 Spanner *span = dynamic_cast<Spanner *> (clone ());
125 span->set_bound (LEFT, bounds[LEFT]);
126 span->set_bound (RIGHT, bounds[RIGHT]);
128 if (!bounds[LEFT]->get_system ()
129 || !bounds[RIGHT]->get_system ()
130 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
132 programming_error ("bounds of spanner are invalid");
133 span->suicide ();
135 else
137 bounds[LEFT]->get_system ()->typeset_grob (span);
138 broken_intos_.push_back (span);
142 vector_sort (broken_intos_, Spanner::less);
143 for (vsize i = broken_intos_.size (); i--;)
144 broken_intos_[i]->break_index_ = i;
147 vsize
148 Spanner::get_break_index () const
150 return break_index_;
153 void
154 Spanner::set_my_columns ()
156 Direction i = (Direction) LEFT;
159 if (!spanned_drul_[i]->get_system ())
160 set_bound (i, spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
162 while (flip (&i) != LEFT);
165 Interval_t<int>
166 Spanner::spanned_rank_interval () const
168 Interval_t<int> iv (0, 0);
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;
177 Interval_t<Moment>
178 Spanner::spanned_time () const
180 return spanned_time_interval (spanned_drul_[LEFT],
181 spanned_drul_[RIGHT]);
185 Item *
186 Spanner::get_bound (Direction d) const
188 return spanned_drul_[d];
192 Set the items that this spanner spans. If D == LEFT, we also set the
193 X-axis parent of THIS to S.
195 void
196 Spanner::set_bound (Direction d, Grob *s)
198 Item *i = dynamic_cast<Item *> (s);
199 if (!i)
201 programming_error ("must have Item for spanner bound of " + name());
202 return;
205 spanned_drul_[d] = i;
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);
214 Signal that this column needs to be kept alive. They need to be
215 kept alive to have meaningful position and linebreaking.
217 [maybe we should try keeping all columns alive?, and perhaps
218 inherit position from their (non-)musical brother]
220 if (dynamic_cast<Paper_column *> (i))
221 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
224 Spanner::Spanner (SCM s)
225 : Grob (s)
227 break_index_ = 0;
228 spanned_drul_.set (0, 0);
231 Spanner::Spanner (Spanner const &s)
232 : Grob (s)
234 spanned_drul_.set (0, 0);
237 Real
238 Spanner::spanner_length () const
240 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
241 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
243 if (r < l)
244 programming_error ("spanner with negative length");
246 return r - l;
249 System *
250 Spanner::get_system () const
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 ();
259 Grob *
260 Spanner::find_broken_piece (System *l) const
262 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
263 if (idx != VPOS)
264 return broken_intos_ [idx];
265 return 0;
268 Spanner *
269 Spanner::broken_neighbor (Direction d) const
271 if (!original_)
272 return 0;
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;
280 return orig->broken_intos_[j];
284 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
286 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
289 bool
290 Spanner::less (Spanner *const &a, Spanner *const &b)
292 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
295 bool
296 Spanner::is_broken () const
298 return broken_intos_.size ();
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.
307 Real
308 Spanner::get_broken_left_end_align () const
310 Paper_column *sc = dynamic_cast<Paper_column *> (spanned_drul_[LEFT]->get_column ());
312 // Relevant only if left span point is first column in line
313 if (sc != NULL
314 && sc->break_status_dir () == RIGHT)
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.
321 return sc->extent (sc, X_AXIS)[RIGHT];
324 return 0.0;
327 void
328 Spanner::derived_mark () const
330 Direction d = LEFT;
332 if (spanned_drul_[d])
333 scm_gc_mark (spanned_drul_[d]->self_scm ());
334 while (flip (&d) != LEFT)
337 for (vsize i = broken_intos_.size (); i--;)
338 scm_gc_mark (broken_intos_[i]->self_scm ());
342 Set left or right bound to IT.
344 Warning: caller should ensure that subsequent calls put in ITems
345 that are left-to-right ordered.
347 void
348 add_bound_item (Spanner *sp, Grob *it)
350 if (!sp->get_bound (LEFT))
351 sp->set_bound (LEFT, it);
352 else
353 sp->set_bound (RIGHT, it);
356 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
358 Spanner::set_spacing_rods (SCM smob)
360 Grob *me = unsmob_grob (smob);
361 SCM num_length = me->get_property ("minimum-length");
362 if (scm_is_number (num_length))
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;
372 vector<Item*> cols (root->broken_col_range (bounds[LEFT]->get_column (),
373 bounds[RIGHT]->get_column ()));
375 if (cols.size ())
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 ();
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 ();
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 ();
394 return SCM_UNSPECIFIED;
398 Return I such that SP == SP->ORIGINAL ()->BROKEN_INTOS_[I].
401 broken_spanner_index (Spanner const *sp)
403 Spanner *parent = dynamic_cast<Spanner *> (sp->original ());
404 /* ugh: casting */
405 return find (parent->broken_intos_, (Spanner*) sp) - parent->broken_intos_.begin ();
408 Spanner *
409 unsmob_spanner (SCM s)
411 return dynamic_cast<Spanner *> (unsmob_grob (s));
414 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
416 Spanner::bounds_width (SCM grob)
418 Spanner *me = unsmob_spanner (grob);
420 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
422 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
423 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
425 w -= me->relative_coordinate (common, X_AXIS);
427 return ly_interval2scm (w);
430 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
432 Spanner::kill_zero_spanned_time (SCM grob)
434 Spanner *me = unsmob_spanner (grob);
435 Interval_t<Moment> moments = me->spanned_time ();
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.
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.
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.
448 --hwn.
451 if (moments.length () == Moment (0, 0))
452 me->suicide ();
454 return SCM_UNSPECIFIED;
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.",
465 /* properties */
466 "minimum-length "
467 "to-barline "