2 spanner.cc -- implement Spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include <libc-extension.hh>
14 #include "paper-column.hh"
15 #include "paper-score.hh"
16 #include "molecule.hh"
17 #include "paper-outputter.hh"
18 #include "paper-column.hh"
20 #include "group-interface.hh"
23 MAKE_SCHEME_CALLBACK (Spanner, get_broken_into, 1);
25 Spanner::get_broken_into (SCM smob)
27 if (Spanner *me = dynamic_cast<Spanner*> (unsmob_grob (smob)))
29 return ly_grob_array2scm (me->broken_into_l_arr_);
33 for (int i = me->broken_into_l_arr_.size (); i; i--)
34 s = gh_cons (me->broken_into_l_arr_[i-1]->self_scm (), s);
43 Spanner::do_break_processing ()
46 Item * left = spanned_drul_[LEFT];
47 Item * right = spanned_drul_[RIGHT];
53 Check if our parent in X-direction spans equally wide
56 for (int a = X_AXIS; a < NO_AXES; a ++)
58 if (Spanner* parent = dynamic_cast<Spanner*> (get_parent ((Axis)a)))
60 if (!parent->spanned_rank_iv ().contains_b (this->spanned_rank_iv ()))
62 programming_error (to_str ("Spanner `%s' is not fully contained in parent spanner `%s'.",
64 parent->name ().ch_C ()));
69 if (line_l () || broken_b ())
75 If we have a spanner spanning one column, we must break it
76 anyway because it might provide a parent for another item. */
80 Item* bound = left->find_prebroken_piece (d);
82 programming_error ("no broken bound");
83 else if (bound->line_l ())
85 Spanner * span_p = dynamic_cast<Spanner*> (clone ());
86 span_p->set_bound (LEFT, bound);
87 span_p->set_bound (RIGHT, bound);
89 assert (span_p->line_l ());
90 span_p->line_l ()->typeset_grob (span_p);
91 broken_into_l_arr_.push (span_p);
94 while ((flip (&d))!= LEFT);
98 Link_array<Item> break_points = pscore_l_->line_l_->broken_col_range (left,right);
100 break_points.insert (left,0);
101 break_points.push (right);
103 for (int i=1; i < break_points.size (); i++)
105 Drul_array<Item*> bounds;
106 bounds[LEFT] = break_points[i-1];
107 bounds[RIGHT] = break_points[i];
111 if (!bounds[d]->line_l ())
112 bounds[d] = bounds[d]->find_prebroken_piece (- d);
114 while ((flip (&d))!= LEFT);
116 if (!bounds[LEFT] || ! bounds[RIGHT])
118 programming_error ("bounds of this piece aren't breakable. ");
122 Spanner *span_p = dynamic_cast<Spanner*> (clone ());
123 span_p->set_bound (LEFT,bounds[LEFT]);
124 span_p->set_bound (RIGHT,bounds[RIGHT]);
126 if (!bounds[LEFT]->line_l ()
128 || !bounds[RIGHT]->line_l ()
129 || bounds[LEFT]->line_l () != bounds[RIGHT]->line_l ())
131 programming_error ("bounds of spanner are invalid");
136 bounds[LEFT]->line_l ()->typeset_grob (span_p);
137 broken_into_l_arr_.push (span_p);
141 broken_into_l_arr_.sort (Spanner::compare);
145 Spanner::set_my_columns ()
147 Direction i = (Direction) LEFT;
150 if (!spanned_drul_[i]->line_l ())
151 set_bound (i,spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
153 while (flip (&i) != LEFT);
157 Spanner::spanned_rank_iv ()
159 Interval_t<int> iv (0, 0);
161 if (spanned_drul_[LEFT])
163 iv[LEFT] = Paper_column::rank_i (spanned_drul_[LEFT]->column_l ());
165 if (spanned_drul_[RIGHT])
167 iv[RIGHT] = Paper_column::rank_i (spanned_drul_[RIGHT]->column_l ());
173 Spanner::get_bound (Direction d) const
175 return spanned_drul_ [d];
179 Set the items that this spanner spans. If D == LEFT, we also set the
180 X-axis parent of THIS to S.
183 Spanner::set_bound (Direction d, Grob*s)
185 Item * i = dynamic_cast<Item*> (s);
188 programming_error ("Must have Item for spanner bound.");
195 We check for System to prevent the column -> line_of_score
196 -> column -> line_of_score -> etc situation */
197 if (d== LEFT && !dynamic_cast<System*> (this))
199 set_parent (i, X_AXIS);
203 Signal that this column needs to be kept alive. They need to be
204 kept alive to have meaningful position and linebreaking.
206 [maybe we should try keeping all columns alive?, and perhaps
207 inherit position from their (non-)musical brother]
210 if (dynamic_cast<Paper_column*> (i))
212 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
216 Spanner::Spanner (SCM s)
219 spanned_drul_[LEFT]=0;
220 spanned_drul_[RIGHT]=0;
221 Group_interface::add_thing (this, ly_symbol2scm ("interfaces"), ly_symbol2scm ("spanner-interface"));
226 Spanner::Spanner (Spanner const &s)
229 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
233 Spanner::spanner_length () const
235 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
236 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
239 programming_error ("spanner with negative length");
245 Spanner::line_l () const
247 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
249 if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
251 return spanned_drul_[LEFT]->line_l ();
256 Spanner::find_broken_piece (System*l) const
258 int idx = binsearch_link_array (broken_into_l_arr_, (Spanner*)l, Spanner::compare);
263 return broken_into_l_arr_ [idx];
268 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
270 return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
274 Spanner::broken_b () const
276 return broken_into_l_arr_.size ();
281 If this is a broken spanner, return the amount the left end is to be
282 shifted horizontally so that the spanner starts after the initial
283 clef and key on the staves. This is necessary for ties, slurs,
284 crescendo and decrescendo signs, for example.
287 Spanner::get_broken_left_end_align () const
289 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l ());
291 // Relevant only if left span point is first column in line
293 sc->break_status_dir () == RIGHT)
297 We used to do a full search for the Break_align_item.
298 But that doesn't make a difference, since the Paper_column
299 is likely to contain only a Break_align_item.
301 return sc->extent (sc, X_AXIS)[RIGHT];
308 Spanner::do_derived_mark ()
311 We'd be fucked if this is called before spanned_drul_[] is inited. */
312 if (status_c_ == ORPHAN)
317 if (spanned_drul_[d])
318 scm_gc_mark (spanned_drul_[d]->self_scm ());
319 while (flip (&d) != LEFT);
321 for (int i= broken_into_l_arr_.size () ; i--;)
322 scm_gc_mark (broken_into_l_arr_[i]->self_scm ());
329 Set left or right bound to IT.
331 Warning: caller should ensure that subsequent calls put in ITems
332 that are left-to-right ordered.
335 add_bound_item (Spanner* sp, Grob*it)
337 if (!sp->get_bound (LEFT))
338 sp->set_bound (LEFT, it);
340 sp->set_bound (RIGHT, it);
344 MAKE_SCHEME_CALLBACK (Spanner,set_spacing_rods,1);
346 Spanner::set_spacing_rods (SCM smob)
348 Grob*me = unsmob_grob (smob);
351 Spanner*sp = dynamic_cast<Spanner*> (me);
352 r.item_l_drul_[LEFT] = sp->get_bound (LEFT);
353 r.item_l_drul_[RIGHT] = sp->get_bound (RIGHT);
355 gh_scm2double (me->get_grob_property ("minimum-length"))
359 return SCM_UNSPECIFIED;
364 unsmob_spanner (SCM s )
366 return dynamic_cast<Spanner*> (unsmob_grob (s));
369 ADD_INTERFACE(Spanner,
372 Other grobs have a shape that depends on the horizontal spacing. For
373 example, slur, beam, tie, etc. These grobs form a subtype called
374 @code{Spanner}. All spanners have two span-points (these must be
375 @code{Item}s), one on the left and one on the right. The left bound is
376 also the X-reference point of the spanner.