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];
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'.",
50 if (line_l () || broken_b ())
56 FIXME: this is broken.
59 If we have a spanner spanning one column, we must break it
60 anyway because it might provide a parent for another item. */
64 Item* bound = left->find_prebroken_piece (d);
67 Spanner * span_p = dynamic_cast<Spanner*>( clone ());
68 span_p->set_bound (LEFT, bound);
69 span_p->set_bound (RIGHT, bound);
71 assert (span_p->line_l ());
72 span_p->line_l ()->typeset_element (span_p);
73 broken_into_l_arr_.push (span_p);
76 while ((flip(&d))!= LEFT);
80 Link_array<Item> break_points = pscore_l_->line_l_->broken_col_range (left,right);
82 break_points.insert (left,0);
83 break_points.push (right);
85 for (int i=1; i < break_points.size(); i++)
87 Drul_array<Item*> bounds;
88 bounds[LEFT] = break_points[i-1];
89 bounds[RIGHT] = break_points[i];
93 if (!bounds[d]->line_l())
94 bounds[d] = bounds[d]->find_prebroken_piece(- d);
96 while ((flip(&d))!= LEFT);
98 if (!bounds[LEFT] || ! bounds[RIGHT])
100 programming_error ("bounds of this piece aren't breakable. ");
104 Spanner *span_p = dynamic_cast<Spanner*>(clone ());
105 span_p->set_bound(LEFT,bounds[LEFT]);
106 span_p->set_bound(RIGHT,bounds[RIGHT]);
109 assert (bounds[LEFT]->line_l () ==
110 bounds[RIGHT]->line_l ());
112 bounds[LEFT]->line_l ()->typeset_element (span_p);
113 broken_into_l_arr_.push (span_p);
116 broken_into_l_arr_.sort (Spanner::compare);
120 Spanner::set_my_columns()
122 Direction i = (Direction) LEFT;
125 if (!spanned_drul_[i]->line_l())
126 set_bound(i,spanned_drul_[i]->find_prebroken_piece((Direction) -i));
128 while (flip(&i) != LEFT);
132 Spanner::spanned_rank_iv ()
134 Interval_t<int> iv (0, 0);
136 if (spanned_drul_[LEFT])
138 iv[LEFT] = spanned_drul_[LEFT]->column_l ()->rank_i ();
140 if (spanned_drul_[RIGHT])
142 iv[RIGHT] = spanned_drul_[RIGHT]->column_l ()->rank_i ();
148 Spanner::get_bound (Direction d) const
150 return spanned_drul_ [d];
154 Spanner::set_bound(Direction d, Score_element*s)
156 Item * i = dynamic_cast<Item*> (s);
159 programming_error ("Must have Item for spanner bound.");
166 We check for Line_of_score to prevent the column -> line_of_score
167 -> column -> line_of_score -> etc situation */
168 if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
170 set_parent (i, X_AXIS);
175 Spanner::Spanner (SCM s)
178 spanned_drul_[LEFT]=0;
179 spanned_drul_[RIGHT]=0;
182 Spanner::Spanner (Spanner const &s)
185 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
190 Spanner::spanner_length() const
192 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
193 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
196 programming_error ("spanner with negative length");
202 Spanner::line_l() const
204 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
206 if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
208 return spanned_drul_[LEFT]->line_l();
213 Spanner::find_broken_piece (Line_of_score*l) const
215 int idx = binsearch_link_array (broken_into_l_arr_, (Spanner*)l, Spanner::compare);
220 return broken_into_l_arr_ [idx];
225 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
227 return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
231 Spanner::broken_b() const
233 return broken_into_l_arr_.size();
237 Spanner::get_rods () const
244 Spanner::get_springs () const
251 Spanner::do_space_processing ()
253 Array<Rod> rs (get_rods ());
254 for (int i=0; i < rs.size (); i++)
256 rs[i].add_to_cols ();
259 Array<Spring> ss (get_springs ());
260 for (int i=0; i < ss.size (); i++)
262 if (isinf (ss[i].distance_f_))
263 programming_error ("weird spring");
265 ss[i].add_to_cols ();
270 If this is a broken spanner, return the amount the left end is to be
271 shifted horizontally so that the spanner starts after the initial
272 clef and key on the staves. This is necessary for ties, slurs,
273 crescendo and decrescendo signs, for example.
276 Spanner::get_broken_left_end_align () const
278 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
280 // Relevant only if left span point is first column in line
282 sc->break_status_dir () == RIGHT)
286 We used to do a full search for the Break_align_item.
287 But that doesn't make a difference, since the Paper_column
288 is likely to contain only a Break_align_item.
290 return sc->extent (X_AXIS)[RIGHT];
297 Spanner::do_derived_mark ()
301 if (spanned_drul_[d])
302 scm_gc_mark (spanned_drul_[d]->self_scm_);
303 while (flip (&d) != LEFT);
307 add_bound_item (Spanner* sp, Item*it)
309 if (!sp->get_bound (LEFT))
310 sp->set_bound (LEFT, it);
312 sp->set_bound (RIGHT, it);