lilypond-1.3.80
[lilypond.git] / lily / spanner.cc
blob04387ef9f702f89d4dee623f6d19d69452bc2a9b
1 /*
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>
7 */
8 #include <math.h>
9 #include <libc-extension.hh>
12 #include "debug.hh"
13 #include "spanner.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"
23 void
24 Spanner::do_break_processing ()
26 //break_into_pieces
27 Item * left = spanned_drul_[LEFT];
28 Item * right = spanned_drul_[RIGHT];
30 if (!left || !right)
31 return;
34 Check if our parent in X-direction spans equally wide
35 or wider than we do.
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'.",
44 classname (this),
45 classname (parent)));
50 if (line_l () || broken_b ())
51 return;
53 if (left == right)
56 If we have a spanner spanning one column, we must break it
57 anyway because it might provide a parent for another item. */
58 Direction d = LEFT;
61 Item* bound = left->find_prebroken_piece (d);
62 if (!bound)
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);
77 else
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];
89 Direction d = LEFT;
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. ");
100 continue;
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 broken_into_l_arr_.sort (Spanner::compare);
118 void
119 Spanner::set_my_columns()
121 Direction i = (Direction) LEFT;
124 if (!spanned_drul_[i]->line_l())
125 set_bound(i,spanned_drul_[i]->find_prebroken_piece((Direction) -i));
127 while (flip(&i) != LEFT);
130 Interval_t<int>
131 Spanner::spanned_rank_iv ()
133 Interval_t<int> iv (0, 0);
135 if (spanned_drul_[LEFT])
137 iv[LEFT] = Paper_column::rank_i (spanned_drul_[LEFT]->column_l ());
139 if (spanned_drul_[RIGHT])
141 iv[RIGHT] = Paper_column::rank_i (spanned_drul_[RIGHT]->column_l ());
143 return iv;
146 Item*
147 Spanner::get_bound (Direction d) const
149 return spanned_drul_ [d];
152 void
153 Spanner::set_bound(Direction d, Score_element*s)
155 Item * i = dynamic_cast<Item*> (s);
156 if (!i)
158 programming_error ("Must have Item for spanner bound.");
159 return;
162 spanned_drul_[d] =i;
165 We check for Line_of_score to prevent the column -> line_of_score
166 -> column -> line_of_score -> etc situation */
167 if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
169 set_parent (i, X_AXIS);
174 Spanner::Spanner (SCM s)
175 : Score_element (s)
177 spanned_drul_[LEFT]=0;
178 spanned_drul_[RIGHT]=0;
181 Spanner::Spanner (Spanner const &s)
182 : Score_element (s)
184 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
188 Real
189 Spanner::spanner_length() const
191 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
192 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
194 if (r< l)
195 programming_error ("spanner with negative length");
197 return r-l;
200 Line_of_score *
201 Spanner::line_l() const
203 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
204 return 0;
205 if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
206 return 0;
207 return spanned_drul_[LEFT]->line_l();
211 Score_element*
212 Spanner::find_broken_piece (Line_of_score*l) const
214 int idx = binsearch_link_array (broken_into_l_arr_, (Spanner*)l, Spanner::compare);
216 if (idx < 0)
217 return 0;
218 else
219 return broken_into_l_arr_ [idx];
224 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
226 return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
229 bool
230 Spanner::broken_b() const
232 return broken_into_l_arr_.size();
237 If this is a broken spanner, return the amount the left end is to be
238 shifted horizontally so that the spanner starts after the initial
239 clef and key on the staves. This is necessary for ties, slurs,
240 crescendo and decrescendo signs, for example.
242 Real
243 Spanner::get_broken_left_end_align () const
245 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
247 // Relevant only if left span point is first column in line
248 if(sc != NULL &&
249 sc->break_status_dir () == RIGHT)
253 We used to do a full search for the Break_align_item.
254 But that doesn't make a difference, since the Paper_column
255 is likely to contain only a Break_align_item.
257 return sc->extent (X_AXIS)[RIGHT];
260 return 0.0;
264 Spanner::do_derived_mark ()
267 We'd be fucked if this is called before spanned_drul_[] is inited. */
268 if (status_i_ == ORPHAN)
269 return SCM_EOL;
271 Direction d = LEFT;
273 if (spanned_drul_[d])
274 scm_gc_mark (spanned_drul_[d]->self_scm ());
275 while (flip (&d) != LEFT);
277 for (int i= broken_into_l_arr_.size () ; i--;)
278 scm_gc_mark (broken_into_l_arr_[i]->self_scm ());
280 return SCM_EOL;
283 void
284 add_bound_item (Spanner* sp, Item*it)
286 if (!sp->get_bound (LEFT))
287 sp->set_bound (LEFT, it);
288 else
289 sp->set_bound (RIGHT, it);