*** empty log message ***
[lilypond.git] / lily / spanner.cc
blob69ed46231cda14c17bdaea4c96df82a980ff11f7
1 /*
2 spanner.cc -- implement Spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include <math.h>
9 #include <libc-extension.hh>
12 #include "warn.hh"
13 #include "spanner.hh"
14 #include "paper-column.hh"
15 #include "paper-score.hh"
16 #include "stencil.hh"
17 #include "paper-outputter.hh"
18 #include "paper-column.hh"
19 #include "system.hh"
20 #include "group-interface.hh"
22 void
23 Spanner::do_break_processing ()
25 //break_into_pieces
26 Item * left = spanned_drul_[LEFT];
27 Item * right = spanned_drul_[RIGHT];
29 if (!left || !right)
30 return;
33 Check if our parent in X-direction spans equally wide
34 or wider than we do.
36 for (int a = X_AXIS; a < NO_AXES; a ++)
38 if (Spanner* parent = dynamic_cast<Spanner*> (get_parent ((Axis)a)))
40 if (!parent->spanned_rank_iv ().superset (this->spanned_rank_iv ()))
42 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner `%s'.",
43 name ().to_str0 (),
44 parent->name ().to_str0 ()));
49 if (get_system () || is_broken ())
50 return;
52 if (left == right)
55 If we have a spanner spanning one column, we must break it
56 anyway because it might provide a parent for another item. */
57 Direction d = LEFT;
60 Item* bound = left->find_prebroken_piece (d);
61 if (!bound)
62 programming_error ("no broken bound");
63 else if (bound->get_system ())
65 Spanner * span = dynamic_cast<Spanner*> (clone ());
66 span->set_bound (LEFT, bound);
67 span->set_bound (RIGHT, bound);
69 assert (span->get_system ());
70 span->get_system ()->typeset_grob (span);
71 broken_intos_.push (span);
74 while ((flip (&d))!= LEFT);
76 else
78 Link_array<Item> break_points = pscore_->system_->broken_col_range (left,right);
80 break_points.insert (left,0);
81 break_points.push (right);
83 for (int 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 Spanner *span = dynamic_cast<Spanner*> (clone ());
103 span->set_bound (LEFT,bounds[LEFT]);
104 span->set_bound (RIGHT,bounds[RIGHT]);
106 if (!bounds[LEFT]->get_system ()
108 || !bounds[RIGHT]->get_system ()
109 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
111 programming_error ("bounds of spanner are invalid");
112 span->suicide ();
114 else
116 bounds[LEFT]->get_system ()->typeset_grob (span);
117 broken_intos_.push (span);
121 broken_intos_.sort (Spanner::compare);
122 for (int i= broken_intos_.size ();i--;)
123 broken_intos_[i]->break_index_ = i;
127 Spanner::get_break_index ()const
129 return break_index_;
132 void
133 Spanner::set_my_columns ()
135 Direction i = (Direction) LEFT;
138 if (!spanned_drul_[i]->get_system ())
139 set_bound (i,spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
141 while (flip (&i) != LEFT);
144 Interval_t<int>
145 Spanner::spanned_rank_iv ()
147 Interval_t<int> iv (0, 0);
149 if (spanned_drul_[LEFT])
151 iv[LEFT] = Paper_column::get_rank (spanned_drul_[LEFT]->get_column ());
153 if (spanned_drul_[RIGHT])
155 iv[RIGHT] = Paper_column::get_rank (spanned_drul_[RIGHT]->get_column ());
157 return iv;
161 Item*
162 Spanner::get_bound (Direction d) const
164 return spanned_drul_ [d];
168 Set the items that this spanner spans. If D == LEFT, we also set the
169 X-axis parent of THIS to S.
171 void
172 Spanner::set_bound (Direction d, Grob*s)
174 Item * i = dynamic_cast<Item*> (s);
175 if (!i)
177 programming_error ("Must have Item for spanner bound.");
178 return;
181 spanned_drul_[d] =i;
184 We check for System to prevent the column -> line_of_score
185 -> column -> line_of_score -> etc situation */
186 if (d== LEFT && !dynamic_cast<System*> (this))
188 set_parent (i, X_AXIS);
192 Signal that this column needs to be kept alive. They need to be
193 kept alive to have meaningful position and linebreaking.
195 [maybe we should try keeping all columns alive?, and perhaps
196 inherit position from their (non-)musical brother]
199 if (dynamic_cast<Paper_column*> (i))
201 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
205 Spanner::Spanner (SCM s)
206 : Grob (s)
208 break_index_ = 0;
209 spanned_drul_[LEFT]=0;
210 spanned_drul_[RIGHT]=0;
212 Group_interface::add_thing (this, ly_symbol2scm ("interfaces"), ly_symbol2scm ("spanner-interface"));
215 Spanner::Spanner (Spanner const &s)
216 : Grob (s)
218 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
221 Real
222 Spanner::spanner_length () const
224 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
225 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
227 if (r< l)
228 programming_error ("spanner with negative length");
230 return r-l;
233 System *
234 Spanner::get_system () const
236 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
237 return 0;
238 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
239 return 0;
240 return spanned_drul_[LEFT]->get_system ();
244 Grob*
245 Spanner::find_broken_piece (System*l) const
247 int idx = binsearch_links (broken_intos_, (Spanner*)l, Spanner::compare);
249 if (idx < 0)
250 return 0;
251 else
252 return broken_intos_ [idx];
257 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
259 return p1->get_system ()->rank_ - p2->get_system ()->rank_;
262 bool
263 Spanner::is_broken () const
265 return broken_intos_.size ();
270 If this is a broken spanner, return the amount the left end is to be
271 shifted horizontally so that the spanner starts after the initial
272 clef and key on the staves. This is necessary for ties, slurs,
273 crescendo and decrescendo signs, for example.
275 Real
276 Spanner::get_broken_left_end_align () const
278 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->get_column ());
280 // Relevant only if left span point is first column in line
281 if (sc != NULL &&
282 sc->break_status_dir () == RIGHT)
286 We used to do a full search for the Break_align_item.
287 But that doesn't make a difference, since the Paper_column
288 is likely to contain only a Break_align_item.
290 return sc->extent (sc, X_AXIS)[RIGHT];
293 return 0.0;
297 Spanner::do_derived_mark () const
300 We'd be fucked if this is called before spanned_drul_[] is inited. */
301 if (status_ == ORPHAN)
302 return SCM_EOL;
304 Direction d = LEFT;
306 if (spanned_drul_[d])
307 scm_gc_mark (spanned_drul_[d]->self_scm ());
308 while (flip (&d) != LEFT);
310 for (int i= broken_intos_.size () ; i--;)
311 scm_gc_mark (broken_intos_[i]->self_scm ());
313 return SCM_EOL;
318 Set left or right bound to IT.
320 Warning: caller should ensure that subsequent calls put in ITems
321 that are left-to-right ordered.
323 void
324 add_bound_item (Spanner* sp, Grob*it)
326 if (!sp->get_bound (LEFT))
327 sp->set_bound (LEFT, it);
328 else
329 sp->set_bound (RIGHT, it);
333 MAKE_SCHEME_CALLBACK (Spanner,set_spacing_rods,1);
335 Spanner::set_spacing_rods (SCM smob)
337 Grob*me = unsmob_grob (smob);
339 Rod r;
340 Spanner*sp = dynamic_cast<Spanner*> (me);
341 r.item_l_drul_[LEFT] = sp->get_bound (LEFT);
342 r.item_l_drul_[RIGHT] = sp->get_bound (RIGHT);
343 r.distance_ =
344 robust_scm2double (me->get_property ("minimum-length"), 0);
346 r.add_to_cols ();
347 return SCM_UNSPECIFIED;
352 Return I such that SP == SP->ORIGINAL_->BROKEN_INTOS_[I].
355 broken_spanner_index (Spanner * sp)
357 Spanner * parent = dynamic_cast<Spanner*> (sp->original_);
358 return parent->broken_intos_.find_index (sp);
362 Spanner*
363 unsmob_spanner (SCM s )
365 return dynamic_cast<Spanner*> (unsmob_grob (s));
368 ADD_INTERFACE (Spanner,
369 "spanner-interface",
370 "Some objects are horizontally spanned between objects. For\n"
371 "example, slur, beam, tie, etc. These grobs form a subtype called\n"
372 "@code{Spanner}. All spanners have two span-points (these must be\n"
373 "@code{Item} objects), one on the left and one on the right. The left bound is\n"
374 "also the X-reference point of the spanner.\n"
376 "minimum-length");