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"
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);
200 Spanner::Spanner (SCM s)
203 spanned_drul_[LEFT]=0;
204 spanned_drul_[RIGHT]=0;
207 Spanner::Spanner (Spanner const &s)
210 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
215 Spanner::spanner_length() const
217 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
218 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
221 programming_error ("spanner with negative length");
227 Spanner::line_l() const
229 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
231 if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
233 return spanned_drul_[LEFT]->line_l();
238 Spanner::find_broken_piece (Line_of_score*l) const
240 int idx = binsearch_link_array (broken_into_l_arr_, (Spanner*)l, Spanner::compare);
245 return broken_into_l_arr_ [idx];
250 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
252 return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
256 Spanner::broken_b() const
258 return broken_into_l_arr_.size();
263 If this is a broken spanner, return the amount the left end is to be
264 shifted horizontally so that the spanner starts after the initial
265 clef and key on the staves. This is necessary for ties, slurs,
266 crescendo and decrescendo signs, for example.
269 Spanner::get_broken_left_end_align () const
271 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
273 // Relevant only if left span point is first column in line
275 sc->break_status_dir () == RIGHT)
279 We used to do a full search for the Break_align_item.
280 But that doesn't make a difference, since the Paper_column
281 is likely to contain only a Break_align_item.
283 return sc->extent (X_AXIS)[RIGHT];
290 Spanner::do_derived_mark ()
293 We'd be fucked if this is called before spanned_drul_[] is inited. */
294 if (status_i_ == ORPHAN)
299 if (spanned_drul_[d])
300 scm_gc_mark (spanned_drul_[d]->self_scm ());
301 while (flip (&d) != LEFT);
303 for (int i= broken_into_l_arr_.size () ; i--;)
304 scm_gc_mark (broken_into_l_arr_[i]->self_scm ());
310 add_bound_item (Spanner* sp, Item*it)
312 if (!sp->get_bound (LEFT))
313 sp->set_bound (LEFT, it);
315 sp->set_bound (RIGHT, it);