2 spanner.cc -- implement Spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2002 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"
20 #include "group-interface.hh"
23 Spanner::do_break_processing ()
26 Item * left = spanned_drul_[LEFT];
27 Item * right = spanned_drul_[RIGHT];
33 Check if our parent in X-direction spans equally wide
36 for (int a = X_AXIS; a < NO_AXES; a ++)
38 if (Spanner* parent = dynamic_cast<Spanner*> (get_parent ((Axis)a)))
40 if (!parent->spanned_rank_iv ().contains_b (this->spanned_rank_iv ()))
42 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner `%s'.",
44 parent->name ().to_str0 ()));
49 if (get_system () || broken_b ())
55 If we have a spanner spanning one column, we must break it
56 anyway because it might provide a parent for another item. */
60 Item* bound = left->find_prebroken_piece (d);
62 programming_error ("no broken bound");
63 else if (bound->get_system ())
65 Spanner * span = dynamic_cast<Spanner*> (clone ());
66 span->set_bound (LEFT, bound);
67 span->set_bound (RIGHT, bound);
69 assert (span->get_system ());
70 span->get_system ()->typeset_grob (span);
71 broken_intos_.push (span);
74 while ((flip (&d))!= LEFT);
78 Link_array<Item> break_points = pscore_->system_->broken_col_range (left,right);
80 break_points.insert (left,0);
81 break_points.push (right);
83 for (int i=1; i < break_points.size (); i++)
85 Drul_array<Item*> bounds;
86 bounds[LEFT] = break_points[i-1];
87 bounds[RIGHT] = break_points[i];
91 if (!bounds[d]->get_system ())
92 bounds[d] = bounds[d]->find_prebroken_piece (- d);
94 while ((flip (&d))!= LEFT);
96 if (!bounds[LEFT] || ! bounds[RIGHT])
98 programming_error ("bounds of this piece aren't breakable. ");
102 Spanner *span = dynamic_cast<Spanner*> (clone ());
103 span->set_bound (LEFT,bounds[LEFT]);
104 span->set_bound (RIGHT,bounds[RIGHT]);
106 if (!bounds[LEFT]->get_system ()
108 || !bounds[RIGHT]->get_system ()
109 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
111 programming_error ("bounds of spanner are invalid");
116 bounds[LEFT]->get_system ()->typeset_grob (span);
117 broken_intos_.push (span);
121 broken_intos_.sort (Spanner::compare);
125 Spanner::set_my_columns ()
127 Direction i = (Direction) LEFT;
130 if (!spanned_drul_[i]->get_system ())
131 set_bound (i,spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
133 while (flip (&i) != LEFT);
137 Spanner::spanned_rank_iv ()
139 Interval_t<int> iv (0, 0);
141 if (spanned_drul_[LEFT])
143 iv[LEFT] = Paper_column::get_rank (spanned_drul_[LEFT]->get_column ());
145 if (spanned_drul_[RIGHT])
147 iv[RIGHT] = Paper_column::get_rank (spanned_drul_[RIGHT]->get_column ());
153 Spanner::get_bound (Direction d) const
155 return spanned_drul_ [d];
159 Set the items that this spanner spans. If D == LEFT, we also set the
160 X-axis parent of THIS to S.
163 Spanner::set_bound (Direction d, Grob*s)
165 Item * i = dynamic_cast<Item*> (s);
168 programming_error ("Must have Item for spanner bound.");
175 We check for System to prevent the column -> line_of_score
176 -> column -> line_of_score -> etc situation */
177 if (d== LEFT && !dynamic_cast<System*> (this))
179 set_parent (i, X_AXIS);
183 Signal that this column needs to be kept alive. They need to be
184 kept alive to have meaningful position and linebreaking.
186 [maybe we should try keeping all columns alive?, and perhaps
187 inherit position from their (non-)musical brother]
190 if (dynamic_cast<Paper_column*> (i))
192 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
196 Spanner::Spanner (SCM s)
199 spanned_drul_[LEFT]=0;
200 spanned_drul_[RIGHT]=0;
201 Group_interface::add_thing (this, ly_symbol2scm ("interfaces"), ly_symbol2scm ("spanner-interface"));
206 Spanner::Spanner (Spanner const &s)
209 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
213 Spanner::spanner_length () const
215 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
216 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
219 programming_error ("spanner with negative length");
225 Spanner::get_system () const
227 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
229 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
231 return spanned_drul_[LEFT]->get_system ();
236 Spanner::find_broken_piece (System*l) const
238 int idx = binsearch_links (broken_intos_, (Spanner*)l, Spanner::compare);
243 return broken_intos_ [idx];
248 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
250 return p1->get_system ()->rank_ - p2->get_system ()->rank_;
254 Spanner::broken_b () const
256 return broken_intos_.size ();
261 If this is a broken spanner, return the amount the left end is to be
262 shifted horizontally so that the spanner starts after the initial
263 clef and key on the staves. This is necessary for ties, slurs,
264 crescendo and decrescendo signs, for example.
267 Spanner::get_broken_left_end_align () const
269 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->get_column ());
271 // Relevant only if left span point is first column in line
273 sc->break_status_dir () == RIGHT)
277 We used to do a full search for the Break_align_item.
278 But that doesn't make a difference, since the Paper_column
279 is likely to contain only a Break_align_item.
281 return sc->extent (sc, X_AXIS)[RIGHT];
288 Spanner::do_derived_mark ()
291 We'd be fucked if this is called before spanned_drul_[] is inited. */
292 if (status_ == ORPHAN)
297 if (spanned_drul_[d])
298 scm_gc_mark (spanned_drul_[d]->self_scm ());
299 while (flip (&d) != LEFT);
301 for (int i= broken_intos_.size () ; i--;)
302 scm_gc_mark (broken_intos_[i]->self_scm ());
309 Set left or right bound to IT.
311 Warning: caller should ensure that subsequent calls put in ITems
312 that are left-to-right ordered.
315 add_bound_item (Spanner* sp, Grob*it)
317 if (!sp->get_bound (LEFT))
318 sp->set_bound (LEFT, it);
320 sp->set_bound (RIGHT, it);
324 MAKE_SCHEME_CALLBACK (Spanner,set_spacing_rods,1);
326 Spanner::set_spacing_rods (SCM smob)
328 Grob*me = unsmob_grob (smob);
331 Spanner*sp = dynamic_cast<Spanner*> (me);
332 r.item_l_drul_[LEFT] = sp->get_bound (LEFT);
333 r.item_l_drul_[RIGHT] = sp->get_bound (RIGHT);
335 gh_scm2double (me->get_grob_property ("minimum-length"))
339 return SCM_UNSPECIFIED;
344 unsmob_spanner (SCM s )
346 return dynamic_cast<Spanner*> (unsmob_grob (s));
349 ADD_INTERFACE(Spanner,
352 Other grobs have a shape that depends on the horizontal spacing. For
353 example, slur, beam, tie, etc. These grobs form a subtype called
354 @code{Spanner}. All spanners have two span-points (these must be
355 @code{Item}s), one on the left and one on the right. The left bound is
356 also the X-reference point of the spanner.