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]);
107 if (bounds[LEFT]->line_l ()
108 && bounds[LEFT]->line_l () != bounds[RIGHT]->line_l ())
110 programming_error ("bounds[LEFT]->line_l () != bounds[RIGHT]->line_l ()");
113 lily crashes upon displaying this ...
117 gh_display (ly_str02scm ("\nspanner:mutable_property_alist_\n"));
118 gh_display (mutable_property_alist_);
119 gh_display (ly_str02scm ("\nspanner:immutable_property_alist_\n"));
120 gh_display (immutable_property_alist_);
125 else if (!bounds[LEFT]->line_l ())
127 // bounds[LEFT]->line_l ()->typeset_element (span_p);
128 // broken_into_l_arr_.push (span_p);
129 programming_error ("bounds[LEFT]->line_l () == 0");
132 else if (!bounds[RIGHT]->line_l ())
134 // bounds[RIGHT]->line_l ()->typeset_element (span_p);
135 // broken_into_l_arr_.push (span_p);
136 programming_error ("bounds[RIGHT]->line_l () == 0");
141 bounds[LEFT]->line_l ()->typeset_element (span_p);
142 broken_into_l_arr_.push (span_p);
146 broken_into_l_arr_.sort (Spanner::compare);
150 Spanner::set_my_columns()
152 Direction i = (Direction) LEFT;
155 if (!spanned_drul_[i]->line_l())
156 set_bound(i,spanned_drul_[i]->find_prebroken_piece((Direction) -i));
158 while (flip(&i) != LEFT);
162 Spanner::spanned_rank_iv ()
164 Interval_t<int> iv (0, 0);
166 if (spanned_drul_[LEFT])
168 iv[LEFT] = Paper_column::rank_i (spanned_drul_[LEFT]->column_l ());
170 if (spanned_drul_[RIGHT])
172 iv[RIGHT] = Paper_column::rank_i (spanned_drul_[RIGHT]->column_l ());
178 Spanner::get_bound (Direction d) const
180 return spanned_drul_ [d];
184 Spanner::set_bound(Direction d, Score_element*s)
186 Item * i = dynamic_cast<Item*> (s);
189 programming_error ("Must have Item for spanner bound.");
196 We check for Line_of_score to prevent the column -> line_of_score
197 -> column -> line_of_score -> etc situation */
198 if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
200 set_parent (i, X_AXIS);
204 Signal that this column needs to be kept alive. They need to be
205 kept alive to have meaningful position and linebreaking.
207 [maybe we should try keeping all columns alive?, and perhaps
208 inherit position from their (non-)musical brother]
211 if (dynamic_cast<Paper_column*> (i))
213 Pointer_group_interface (i, "bounded-by-me").add_element (this);
218 Spanner::Spanner (SCM s)
221 spanned_drul_[LEFT]=0;
222 spanned_drul_[RIGHT]=0;
225 Spanner::Spanner (Spanner const &s)
228 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 (Line_of_score*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 (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_i_ == 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 ());
328 add_bound_item (Spanner* sp, Item*it)
330 if (!sp->get_bound (LEFT))
331 sp->set_bound (LEFT, it);
333 sp->set_bound (RIGHT, it);
337 extend_spanner_over_item (Item *it, SCM extremal_pair)
341 Item * col = it->column_l ();
342 Item * i1 = dynamic_cast<Item*> (unsmob_element (gh_car (extremal_pair)));
343 Item * i2 = dynamic_cast<Item*> (unsmob_element (gh_cdr (extremal_pair)));
344 int r = Paper_column::rank_i (col);
345 if (!i1 || r < Paper_column::rank_i (i1->column_l ()))
347 gh_set_car_x (extremal_pair, it->self_scm ());
349 if (!i2 || r > Paper_column::rank_i (i2->column_l ()))
351 gh_set_cdr_x (extremal_pair, it->self_scm ());
356 extend_spanner_over_elements (SCM value, SCM extremal_pair)
358 if (gh_pair_p (value))
360 extend_spanner_over_elements (gh_car (value), extremal_pair);
361 extend_spanner_over_elements (gh_cdr (value), extremal_pair);
363 else if (unsmob_element (value))
365 if (Spanner * sp = dynamic_cast<Spanner*> (unsmob_element(value)))
367 extend_spanner_over_item (sp->get_bound (LEFT), extremal_pair);
368 extend_spanner_over_item (sp->get_bound (RIGHT), extremal_pair);
370 else if (Item * it= dynamic_cast<Item*> (unsmob_element(value)))
371 extend_spanner_over_item (it, extremal_pair);
377 Make sure that the left and right bounds encompasses all objects it
380 TODO: maybe be more specific. Most probably fucks up if someone sets
381 a pointer to the staffsymbol in S
384 extend_spanner_over_elements (Score_element*s)
386 Spanner*sp = dynamic_cast<Spanner*> (s);
388 SCM s1 = sp->get_bound (LEFT) ? sp->get_bound (LEFT)->self_scm () : SCM_EOL;
389 SCM s2 = sp->get_bound (RIGHT) ? sp->get_bound (RIGHT)->self_scm () : SCM_EOL;
391 SCM pair = gh_cons (s1,s2);
392 extend_spanner_over_elements (sp->mutable_property_alist_, pair);
394 Score_element *p1 = unsmob_element (gh_car (pair));
395 Score_element* p2 = unsmob_element (gh_cdr (pair));
396 sp->set_bound (LEFT,p1);
397 sp->set_bound (RIGHT, p2);