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 Spanner::do_break_processing ()
26 Item * left = spanned_drul_[LEFT];
27 Item * right = spanned_drul_[RIGHT];
33 Check if our parent in X-direction spans equally wide
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 ().contains_b (this->spanned_rank_iv ()))
42 programming_error (to_str ("Spanner `%s' is not fully contained in parent spanner `%s'.",
44 parent->name ().ch_C ()));
49 if (line_l () || broken_b ())
55 If we have a spanner spanning one column, we must break it
56 anyway because it might provide a parent for another item. */
60 Item* bound = left->find_prebroken_piece (d);
62 programming_error ("no broken bound");
63 else if (bound->line_l ())
65 Spanner * span_p = dynamic_cast<Spanner*> (clone ());
66 span_p->set_bound (LEFT, bound);
67 span_p->set_bound (RIGHT, bound);
69 assert (span_p->line_l ());
70 span_p->line_l ()->typeset_grob (span_p);
71 broken_into_l_arr_.push (span_p);
74 while ((flip (&d))!= LEFT);
78 Link_array<Item> break_points = pscore_l_->line_l_->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];
91 if (!bounds[d]->line_l ())
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. ");
102 Spanner *span_p = dynamic_cast<Spanner*> (clone ());
103 span_p->set_bound (LEFT,bounds[LEFT]);
104 span_p->set_bound (RIGHT,bounds[RIGHT]);
106 if (!bounds[LEFT]->line_l ()
108 || !bounds[RIGHT]->line_l ()
109 || bounds[LEFT]->line_l () != bounds[RIGHT]->line_l ())
111 programming_error ("bounds of spanner are invalid");
116 bounds[LEFT]->line_l ()->typeset_grob (span_p);
117 broken_into_l_arr_.push (span_p);
121 broken_into_l_arr_.sort (Spanner::compare);
125 Spanner::set_my_columns ()
127 Direction i = (Direction) LEFT;
130 if (!spanned_drul_[i]->line_l ())
131 set_bound (i,spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
133 while (flip (&i) != LEFT);
137 Spanner::spanned_rank_iv ()
139 Interval_t<int> iv (0, 0);
141 if (spanned_drul_[LEFT])
143 iv[LEFT] = Paper_column::rank_i (spanned_drul_[LEFT]->column_l ());
145 if (spanned_drul_[RIGHT])
147 iv[RIGHT] = Paper_column::rank_i (spanned_drul_[RIGHT]->column_l ());
153 Spanner::get_bound (Direction d) const
155 return spanned_drul_ [d];
159 Set the items that this spanner spans. If D == LEFT, we also set the
160 X-axis parent of THIS to S.
163 Spanner::set_bound (Direction d, Grob*s)
165 Item * i = dynamic_cast<Item*> (s);
168 programming_error ("Must have Item for spanner bound.");
175 We check for System to prevent the column -> line_of_score
176 -> column -> line_of_score -> etc situation */
177 if (d== LEFT && !dynamic_cast<System*> (this))
179 set_parent (i, X_AXIS);
183 Signal that this column needs to be kept alive. They need to be
184 kept alive to have meaningful position and linebreaking.
186 [maybe we should try keeping all columns alive?, and perhaps
187 inherit position from their (non-)musical brother]
190 if (dynamic_cast<Paper_column*> (i))
192 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
196 Spanner::Spanner (SCM s)
199 spanned_drul_[LEFT]=0;
200 spanned_drul_[RIGHT]=0;
201 Group_interface::add_thing (this, ly_symbol2scm ("interfaces"), ly_symbol2scm ("spanner-interface"));
206 Spanner::Spanner (Spanner const &s)
209 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
213 Spanner::spanner_length () const
215 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
216 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
219 programming_error ("spanner with negative length");
225 Spanner::line_l () const
227 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
229 if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
231 return spanned_drul_[LEFT]->line_l ();
236 Spanner::find_broken_piece (System*l) const
238 int idx = binsearch_link_array (broken_into_l_arr_, (Spanner*)l, Spanner::compare);
243 return broken_into_l_arr_ [idx];
248 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
250 return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
254 Spanner::broken_b () const
256 return broken_into_l_arr_.size ();
261 If this is a broken spanner, return the amount the left end is to be
262 shifted horizontally so that the spanner starts after the initial
263 clef and key on the staves. This is necessary for ties, slurs,
264 crescendo and decrescendo signs, for example.
267 Spanner::get_broken_left_end_align () const
269 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l ());
271 // Relevant only if left span point is first column in line
273 sc->break_status_dir () == RIGHT)
277 We used to do a full search for the Break_align_item.
278 But that doesn't make a difference, since the Paper_column
279 is likely to contain only a Break_align_item.
281 return sc->extent (sc, X_AXIS)[RIGHT];
288 Spanner::do_derived_mark ()
291 We'd be fucked if this is called before spanned_drul_[] is inited. */
292 if (status_c_ == ORPHAN)
297 if (spanned_drul_[d])
298 scm_gc_mark (spanned_drul_[d]->self_scm ());
299 while (flip (&d) != LEFT);
301 for (int i= broken_into_l_arr_.size () ; i--;)
302 scm_gc_mark (broken_into_l_arr_[i]->self_scm ());
309 Set left or right bound to IT.
311 Warning: caller should ensure that subsequent calls put in ITems
312 that are left-to-right ordered.
315 add_bound_item (Spanner* sp, Grob*it)
317 if (!sp->get_bound (LEFT))
318 sp->set_bound (LEFT, it);
320 sp->set_bound (RIGHT, it);
324 Extends EXTREMAL_PAIR to include IT
327 extend_spanner_over_item (Item *it, SCM extremal_pair)
331 Item * col = it->column_l ();
332 Item * i1 = dynamic_cast<Item*> (unsmob_grob (ly_car (extremal_pair)));
333 Item * i2 = dynamic_cast<Item*> (unsmob_grob (ly_cdr (extremal_pair)));
334 int r = Paper_column::rank_i (col);
335 if (!i1 || r < Paper_column::rank_i (i1->column_l ()))
337 gh_set_car_x (extremal_pair, it->self_scm ());
339 if (!i2 || r > Paper_column::rank_i (i2->column_l ()))
341 gh_set_cdr_x (extremal_pair, it->self_scm ());
346 Extends EXTREMAL_PAIR to include every grob in VALUE
349 extend_spanner_over_elements (SCM value, SCM extremal_pair)
351 if (gh_pair_p (value))
353 extend_spanner_over_elements (ly_car (value), extremal_pair);
354 extend_spanner_over_elements (ly_cdr (value), extremal_pair);
356 else if (unsmob_grob (value))
358 if (Spanner * sp = dynamic_cast<Spanner*> (unsmob_grob (value)))
360 extend_spanner_over_item (sp->get_bound (LEFT), extremal_pair);
361 extend_spanner_over_item (sp->get_bound (RIGHT), extremal_pair);
363 else if (Item * it= dynamic_cast<Item*> (unsmob_grob (value)))
364 extend_spanner_over_item (it, extremal_pair);
370 Make sure that the left and right bounds encompasses all objects it
373 TODO: maybe be more specific. Most probably fucks up if someone sets
374 a pointer to the staff symbol in S
377 extend_spanner_over_elements (Grob*s)
379 Spanner*sp = dynamic_cast<Spanner*> (s);
381 SCM s1 = sp->get_bound (LEFT) ? sp->get_bound (LEFT)->self_scm () : SCM_EOL;
382 SCM s2 = sp->get_bound (RIGHT) ? sp->get_bound (RIGHT)->self_scm () : SCM_EOL;
384 SCM pair = gh_cons (s1,s2);
385 extend_spanner_over_elements (sp->mutable_property_alist_, pair);
387 Grob *p1 = unsmob_grob (ly_car (pair));
388 Grob* p2 = unsmob_grob (ly_cdr (pair));
389 sp->set_bound (LEFT,p1);
390 sp->set_bound (RIGHT, p2);
394 MAKE_SCHEME_CALLBACK (Spanner,set_spacing_rods,1);
396 Spanner::set_spacing_rods (SCM smob)
398 Grob*me = unsmob_grob (smob);
401 Spanner*sp = dynamic_cast<Spanner*> (me);
402 r.item_l_drul_[LEFT] = sp->get_bound (LEFT);
403 r.item_l_drul_[RIGHT] = sp->get_bound (RIGHT);
405 gh_scm2double (me->get_grob_property ("minimum-length"))
409 return SCM_UNSPECIFIED;
414 unsmob_spanner (SCM s )
416 return dynamic_cast<Spanner*> (unsmob_grob (s));
419 ADD_INTERFACE(Spanner,