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>
11 #include "dimension-cache.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];
35 warning (_f ("Spanner `%s' has equal left and right spanpoints",
40 Check if our parent in X-direction spans equally wide
43 for (int a = X_AXIS; a < NO_AXES; a ++)
45 if (Spanner* parent = dynamic_cast<Spanner*> (parent_l ((Axis)a)))
47 if (!parent->spanned_rank_iv ().contains_b (this->spanned_rank_iv ()))
49 programming_error (to_str ("Spanner `%s' is not fully contained in parent spanner `%s'.",
56 if (line_l () || broken_b ())
62 FIXME: this is broken.
65 If we have a spanner spanning one column, we must break it
66 anyway because it might provide a parent for another item. */
70 Item* bound = left->find_prebroken_piece (d);
73 Spanner * span_p = dynamic_cast<Spanner*>( clone ());
74 span_p->set_bound (LEFT, bound);
75 span_p->set_bound (RIGHT, bound);
77 assert (span_p->line_l ());
78 span_p->line_l ()->typeset_element (span_p);
79 broken_into_l_arr_.push (span_p);
82 while ((flip(&d))!= LEFT);
86 Link_array<Item> break_points = pscore_l_->line_l_->broken_col_range (left,right);
88 break_points.insert (left,0);
89 break_points.push (right);
91 for (int i=1; i < break_points.size(); i++)
93 Drul_array<Item*> bounds;
94 bounds[LEFT] = break_points[i-1];
95 bounds[RIGHT] = break_points[i];
99 if (!bounds[d]->line_l())
100 bounds[d] = bounds[d]->find_prebroken_piece(- d);
102 while ((flip(&d))!= LEFT);
104 if (!bounds[LEFT] || ! bounds[RIGHT])
106 programming_error ("bounds of this piece aren't breakable. ");
110 Spanner *span_p = dynamic_cast<Spanner*>(clone ());
111 span_p->set_bound(LEFT,bounds[LEFT]);
112 span_p->set_bound(RIGHT,bounds[RIGHT]);
115 assert (bounds[LEFT]->line_l () ==
116 bounds[RIGHT]->line_l ());
118 bounds[LEFT]->line_l ()->typeset_element (span_p);
119 broken_into_l_arr_.push (span_p);
122 broken_into_l_arr_.sort (Spanner::compare);
126 Spanner::set_my_columns()
128 Direction i = (Direction) LEFT;
131 if (!spanned_drul_[i]->line_l())
132 set_bound(i,spanned_drul_[i]->find_prebroken_piece((Direction) -i));
134 while (flip(&i) != LEFT);
138 Spanner::spanned_rank_iv ()
140 Interval_t<int> iv (0, 0);
142 if (spanned_drul_[LEFT])
144 iv[LEFT] = spanned_drul_[LEFT]->column_l ()->rank_i ();
146 if (spanned_drul_[RIGHT])
148 iv[RIGHT] = spanned_drul_[RIGHT]->column_l ()->rank_i ();
154 Spanner::get_bound (Direction d) const
156 return spanned_drul_ [d];
160 Spanner::set_bound(Direction d, Score_element*s)
162 Item * i = dynamic_cast<Item*> (s);
165 programming_error ("Must have Item for spanner bound.");
172 We check for Line_of_score to prevent the column -> line_of_score
173 -> column -> line_of_score -> etc situation */
174 if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
176 set_parent (i, X_AXIS);
179 if (spanned_drul_[Direction(-d)] == spanned_drul_[d]
181 warning (_f ("Spanner `%s' has equal left and right spanpoints",
186 Spanner::Spanner (SCM s)
189 spanned_drul_[LEFT]=0;
190 spanned_drul_[RIGHT]=0;
193 Spanner::Spanner (Spanner const &s)
196 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
201 Spanner::spanner_length() const
203 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
204 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
207 programming_error ("spanner with negative length");
213 Spanner::line_l() const
215 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
217 if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
219 return spanned_drul_[LEFT]->line_l();
224 Spanner::find_broken_piece (Line_of_score*l) const
226 int idx = binsearch_link_array (broken_into_l_arr_, (Spanner*)l, Spanner::compare);
231 return broken_into_l_arr_ [idx];
236 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
238 return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
242 Spanner::broken_b() const
244 return broken_into_l_arr_.size();
248 Spanner::get_rods () const
255 Spanner::get_springs () const
262 Spanner::do_space_processing ()
264 Array<Rod> rs (get_rods ());
265 for (int i=0; i < rs.size (); i++)
267 rs[i].add_to_cols ();
270 Array<Spring> ss (get_springs ());
271 for (int i=0; i < ss.size (); i++)
273 if (isinf (ss[i].distance_f_))
274 programming_error ("weird spring");
276 ss[i].add_to_cols ();
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 ()
312 if (spanned_drul_[d])
313 scm_gc_mark (spanned_drul_[d]->self_scm_);
314 while (flip (&d) != LEFT);