2 spanner.cc -- implement Spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2000 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"
19 #include "line-of-score.hh"
20 #include "break-align-item.hh"
21 #include "group-interface.hh"
24 Spanner::do_break_processing ()
27 Item * left = spanned_drul_[LEFT];
28 Item * right = spanned_drul_[RIGHT];
34 Check if our parent in X-direction spans equally wide
37 for (int a = X_AXIS; a < NO_AXES; a ++)
39 if (Spanner* parent = dynamic_cast<Spanner*> (parent_l ((Axis)a)))
41 if (!parent->spanned_rank_iv ().contains_b (this->spanned_rank_iv ()))
43 programming_error (to_str ("Spanner `%s' is not fully contained in parent spanner `%s'.",
45 parent->name ().ch_C ()));
50 if (line_l () || broken_b ())
56 If we have a spanner spanning one column, we must break it
57 anyway because it might provide a parent for another item. */
61 Item* bound = left->find_prebroken_piece (d);
63 programming_error ("no broken bound");
64 else if (bound->line_l ())
66 Spanner * span_p = dynamic_cast<Spanner*>( clone ());
67 span_p->set_bound (LEFT, bound);
68 span_p->set_bound (RIGHT, bound);
70 assert (span_p->line_l ());
71 span_p->line_l ()->typeset_element (span_p);
72 broken_into_l_arr_.push (span_p);
75 while ((flip(&d))!= LEFT);
79 Link_array<Item> break_points = pscore_l_->line_l_->broken_col_range (left,right);
81 break_points.insert (left,0);
82 break_points.push (right);
84 for (int i=1; i < break_points.size(); i++)
86 Drul_array<Item*> bounds;
87 bounds[LEFT] = break_points[i-1];
88 bounds[RIGHT] = break_points[i];
92 if (!bounds[d]->line_l())
93 bounds[d] = bounds[d]->find_prebroken_piece(- d);
95 while ((flip(&d))!= LEFT);
97 if (!bounds[LEFT] || ! bounds[RIGHT])
99 programming_error ("bounds of this piece aren't breakable. ");
103 Spanner *span_p = dynamic_cast<Spanner*>(clone ());
104 span_p->set_bound(LEFT,bounds[LEFT]);
105 span_p->set_bound(RIGHT,bounds[RIGHT]);
108 assert (bounds[LEFT]->line_l () ==
109 bounds[RIGHT]->line_l ());
111 bounds[LEFT]->line_l ()->typeset_element (span_p);
112 broken_into_l_arr_.push (span_p);
115 if (bounds[LEFT]->line_l () != bounds[RIGHT]->line_l ())
117 programming_error ("bounds[LEFT]->line_l () != bounds[RIGHT]->line_l ()");
120 lily crashes upon displaying this ...
124 gh_display (ly_str02scm ("\nspanner:mutable_property_alist_\n"));
125 gh_display (mutable_property_alist_);
126 gh_display (ly_str02scm ("\nspanner:immutable_property_alist_\n"));
127 gh_display (immutable_property_alist_);
134 bounds[LEFT]->line_l ()->typeset_element (span_p);
135 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 Spanner::set_bound(Direction d, Score_element*s)
181 Item * i = dynamic_cast<Item*> (s);
184 programming_error ("Must have Item for spanner bound.");
191 We check for Line_of_score to prevent the column -> line_of_score
192 -> column -> line_of_score -> etc situation */
193 if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
195 set_parent (i, X_AXIS);
199 Signal that this column needs to be kept alive. They need to be
200 kept alive to have meaningful position and linebreaking.
202 [maybe we should try keeping all columns alive?, and perhaps
203 inherit position from their (non-)musical brother]
206 if (dynamic_cast<Paper_column*> (i))
208 Pointer_group_interface (i, "bounded-by-me").add_element (this);
213 Spanner::Spanner (SCM s)
216 spanned_drul_[LEFT]=0;
217 spanned_drul_[RIGHT]=0;
220 Spanner::Spanner (Spanner const &s)
223 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
228 Spanner::spanner_length() const
230 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
231 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
234 programming_error ("spanner with negative length");
240 Spanner::line_l() const
242 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
244 if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
246 return spanned_drul_[LEFT]->line_l();
251 Spanner::find_broken_piece (Line_of_score*l) const
253 int idx = binsearch_link_array (broken_into_l_arr_, (Spanner*)l, Spanner::compare);
258 return broken_into_l_arr_ [idx];
263 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
265 return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
269 Spanner::broken_b() const
271 return broken_into_l_arr_.size();
276 If this is a broken spanner, return the amount the left end is to be
277 shifted horizontally so that the spanner starts after the initial
278 clef and key on the staves. This is necessary for ties, slurs,
279 crescendo and decrescendo signs, for example.
282 Spanner::get_broken_left_end_align () const
284 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
286 // Relevant only if left span point is first column in line
288 sc->break_status_dir () == RIGHT)
292 We used to do a full search for the Break_align_item.
293 But that doesn't make a difference, since the Paper_column
294 is likely to contain only a Break_align_item.
296 return sc->extent (X_AXIS)[RIGHT];
303 Spanner::do_derived_mark ()
306 We'd be fucked if this is called before spanned_drul_[] is inited. */
307 if (status_i_ == ORPHAN)
312 if (spanned_drul_[d])
313 scm_gc_mark (spanned_drul_[d]->self_scm ());
314 while (flip (&d) != LEFT);
316 for (int i= broken_into_l_arr_.size () ; i--;)
317 scm_gc_mark (broken_into_l_arr_[i]->self_scm ());
323 add_bound_item (Spanner* sp, Item*it)
325 if (!sp->get_bound (LEFT))
326 sp->set_bound (LEFT, it);
328 sp->set_bound (RIGHT, it);
332 extend_spanner_over_item (Item *it, SCM extremal_pair)
336 Item * col = it->column_l ();
337 Item * i1 = dynamic_cast<Item*> (unsmob_element (gh_car (extremal_pair)));
338 Item * i2 = dynamic_cast<Item*> (unsmob_element (gh_cdr (extremal_pair)));
339 int r = Paper_column::rank_i (col);
340 if (!i1 || r < Paper_column::rank_i (i1->column_l ()))
342 gh_set_car_x (extremal_pair, it->self_scm ());
344 if (!i2 || r > Paper_column::rank_i (i2->column_l ()))
346 gh_set_cdr_x (extremal_pair, it->self_scm ());
351 extend_spanner_over_elements (SCM value, SCM extremal_pair)
353 if (gh_pair_p (value))
355 extend_spanner_over_elements (gh_car (value), extremal_pair);
356 extend_spanner_over_elements (gh_cdr (value), extremal_pair);
358 else if (unsmob_element (value))
360 if (Spanner * sp = dynamic_cast<Spanner*> (unsmob_element(value)))
362 extend_spanner_over_item (sp->get_bound (LEFT), extremal_pair);
363 extend_spanner_over_item (sp->get_bound (RIGHT), extremal_pair);
365 else if (Item * it= dynamic_cast<Item*> (unsmob_element(value)))
366 extend_spanner_over_item (it, extremal_pair);
372 Make sure that the left and right bounds encompasses all objects it
375 TODO: maybe be more specific. Most probably fucks up if someone sets
376 a pointer to the staffsymbol in S
379 extend_spanner_over_elements (Score_element*s)
381 Spanner*sp = dynamic_cast<Spanner*> (s);
383 SCM s1 = sp->get_bound (LEFT) ? sp->get_bound (LEFT)->self_scm () : SCM_EOL;
384 SCM s2 = sp->get_bound (RIGHT) ? sp->get_bound (RIGHT)->self_scm () : SCM_EOL;
386 SCM pair = gh_cons (s1,s2);
387 extend_spanner_over_elements (sp->mutable_property_alist_, pair);
389 Score_element *p1 = unsmob_element (gh_car (pair));
390 Score_element* p2 = unsmob_element (gh_cdr (pair));
391 sp->set_bound (LEFT,p1);
392 sp->set_bound (RIGHT, p2);