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 ()
109 || !bounds[RIGHT]->line_l ()
110 || bounds[LEFT]->line_l () != bounds[RIGHT]->line_l ())
112 programming_error ("bounds of spanner are invalid");
115 lily crashes upon displaying this ...
119 gh_display (ly_str02scm ("\nspanner:mutable_property_alist_\n"));
120 gh_display (mutable_property_alist_);
121 gh_display (ly_str02scm ("\nspanner:immutable_property_alist_\n"));
122 gh_display (immutable_property_alist_);
129 bounds[LEFT]->line_l ()->typeset_element (span_p);
130 broken_into_l_arr_.push (span_p);
134 broken_into_l_arr_.sort (Spanner::compare);
138 Spanner::set_my_columns()
140 Direction i = (Direction) LEFT;
143 if (!spanned_drul_[i]->line_l())
144 set_bound(i,spanned_drul_[i]->find_prebroken_piece((Direction) -i));
146 while (flip(&i) != LEFT);
150 Spanner::spanned_rank_iv ()
152 Interval_t<int> iv (0, 0);
154 if (spanned_drul_[LEFT])
156 iv[LEFT] = Paper_column::rank_i (spanned_drul_[LEFT]->column_l ());
158 if (spanned_drul_[RIGHT])
160 iv[RIGHT] = Paper_column::rank_i (spanned_drul_[RIGHT]->column_l ());
166 Spanner::get_bound (Direction d) const
168 return spanned_drul_ [d];
172 Spanner::set_bound(Direction d, Score_element*s)
174 Item * i = dynamic_cast<Item*> (s);
177 programming_error ("Must have Item for spanner bound.");
184 We check for Line_of_score to prevent the column -> line_of_score
185 -> column -> line_of_score -> etc situation */
186 if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
188 set_parent (i, X_AXIS);
192 Signal that this column needs to be kept alive. They need to be
193 kept alive to have meaningful position and linebreaking.
195 [maybe we should try keeping all columns alive?, and perhaps
196 inherit position from their (non-)musical brother]
199 if (dynamic_cast<Paper_column*> (i))
201 Pointer_group_interface::add_element (i, "bounded-by-me",this);
206 Spanner::Spanner (SCM s)
209 spanned_drul_[LEFT]=0;
210 spanned_drul_[RIGHT]=0;
213 Spanner::Spanner (Spanner const &s)
216 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
221 Spanner::spanner_length() const
223 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
224 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
227 programming_error ("spanner with negative length");
233 Spanner::line_l() const
235 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
237 if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
239 return spanned_drul_[LEFT]->line_l();
244 Spanner::find_broken_piece (Line_of_score*l) const
246 int idx = binsearch_link_array (broken_into_l_arr_, (Spanner*)l, Spanner::compare);
251 return broken_into_l_arr_ [idx];
256 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
258 return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
262 Spanner::broken_b() const
264 return broken_into_l_arr_.size();
269 If this is a broken spanner, return the amount the left end is to be
270 shifted horizontally so that the spanner starts after the initial
271 clef and key on the staves. This is necessary for ties, slurs,
272 crescendo and decrescendo signs, for example.
275 Spanner::get_broken_left_end_align () const
277 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
279 // Relevant only if left span point is first column in line
281 sc->break_status_dir () == RIGHT)
285 We used to do a full search for the Break_align_item.
286 But that doesn't make a difference, since the Paper_column
287 is likely to contain only a Break_align_item.
289 return sc->extent (sc, X_AXIS)[RIGHT];
296 Spanner::do_derived_mark ()
299 We'd be fucked if this is called before spanned_drul_[] is inited. */
300 if (status_i_ == ORPHAN)
305 if (spanned_drul_[d])
306 scm_gc_mark (spanned_drul_[d]->self_scm ());
307 while (flip (&d) != LEFT);
309 for (int i= broken_into_l_arr_.size () ; i--;)
310 scm_gc_mark (broken_into_l_arr_[i]->self_scm ());
316 add_bound_item (Spanner* sp, Item*it)
318 if (!sp->get_bound (LEFT))
319 sp->set_bound (LEFT, it);
321 sp->set_bound (RIGHT, it);
325 extend_spanner_over_item (Item *it, SCM extremal_pair)
329 Item * col = it->column_l ();
330 Item * i1 = dynamic_cast<Item*> (unsmob_element (gh_car (extremal_pair)));
331 Item * i2 = dynamic_cast<Item*> (unsmob_element (gh_cdr (extremal_pair)));
332 int r = Paper_column::rank_i (col);
333 if (!i1 || r < Paper_column::rank_i (i1->column_l ()))
335 gh_set_car_x (extremal_pair, it->self_scm ());
337 if (!i2 || r > Paper_column::rank_i (i2->column_l ()))
339 gh_set_cdr_x (extremal_pair, it->self_scm ());
344 extend_spanner_over_elements (SCM value, SCM extremal_pair)
346 if (gh_pair_p (value))
348 extend_spanner_over_elements (gh_car (value), extremal_pair);
349 extend_spanner_over_elements (gh_cdr (value), extremal_pair);
351 else if (unsmob_element (value))
353 if (Spanner * sp = dynamic_cast<Spanner*> (unsmob_element(value)))
355 extend_spanner_over_item (sp->get_bound (LEFT), extremal_pair);
356 extend_spanner_over_item (sp->get_bound (RIGHT), extremal_pair);
358 else if (Item * it= dynamic_cast<Item*> (unsmob_element(value)))
359 extend_spanner_over_item (it, extremal_pair);
365 Make sure that the left and right bounds encompasses all objects it
368 TODO: maybe be more specific. Most probably fucks up if someone sets
369 a pointer to the staffsymbol in S
372 extend_spanner_over_elements (Score_element*s)
374 Spanner*sp = dynamic_cast<Spanner*> (s);
376 SCM s1 = sp->get_bound (LEFT) ? sp->get_bound (LEFT)->self_scm () : SCM_EOL;
377 SCM s2 = sp->get_bound (RIGHT) ? sp->get_bound (RIGHT)->self_scm () : SCM_EOL;
379 SCM pair = gh_cons (s1,s2);
380 extend_spanner_over_elements (sp->mutable_property_alist_, pair);
382 Score_element *p1 = unsmob_element (gh_car (pair));
383 Score_element* p2 = unsmob_element (gh_cdr (pair));
384 sp->set_bound (LEFT,p1);
385 sp->set_bound (RIGHT, p2);