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"
22 /* spanner in name? */
23 LY_DEFINE (get_broken_into,
24 "get-broken-into", 1, 0, 0, (SCM spanner),
26 Return broken-into list for @var{spanner}.
30 /// Spanner *me = unsmob_spanner (spanner);
31 Spanner *me = dynamic_cast<Spanner*> (unsmob_grob (spanner));
32 SCM_ASSERT_TYPE (me, spanner, SCM_ARG1, __FUNCTION__, "spanner");
35 for (int i = me->broken_intos_.size (); i; i--)
36 s = gh_cons (me->broken_intos_[i-1]->self_scm (), s);
41 Spanner::do_break_processing ()
44 Item * left = spanned_drul_[LEFT];
45 Item * right = spanned_drul_[RIGHT];
51 Check if our parent in X-direction spans equally wide
54 for (int a = X_AXIS; a < NO_AXES; a ++)
56 if (Spanner* parent = dynamic_cast<Spanner*> (get_parent ((Axis)a)))
58 if (!parent->spanned_rank_iv ().contains_b (this->spanned_rank_iv ()))
60 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner `%s'.",
62 parent->name ().to_str0 ()));
67 if (get_system () || broken_b ())
73 If we have a spanner spanning one column, we must break it
74 anyway because it might provide a parent for another item. */
78 Item* bound = left->find_prebroken_piece (d);
80 programming_error ("no broken bound");
81 else if (bound->get_system ())
83 Spanner * span = dynamic_cast<Spanner*> (clone ());
84 span->set_bound (LEFT, bound);
85 span->set_bound (RIGHT, bound);
87 assert (span->get_system ());
88 span->get_system ()->typeset_grob (span);
89 broken_intos_.push (span);
92 while ((flip (&d))!= LEFT);
96 Link_array<Item> break_points = pscore_->system_->broken_col_range (left,right);
98 break_points.insert (left,0);
99 break_points.push (right);
101 for (int i=1; i < break_points.size (); i++)
103 Drul_array<Item*> bounds;
104 bounds[LEFT] = break_points[i-1];
105 bounds[RIGHT] = break_points[i];
109 if (!bounds[d]->get_system ())
110 bounds[d] = bounds[d]->find_prebroken_piece (- d);
112 while ((flip (&d))!= LEFT);
114 if (!bounds[LEFT] || ! bounds[RIGHT])
116 programming_error ("bounds of this piece aren't breakable. ");
120 Spanner *span = dynamic_cast<Spanner*> (clone ());
121 span->set_bound (LEFT,bounds[LEFT]);
122 span->set_bound (RIGHT,bounds[RIGHT]);
124 if (!bounds[LEFT]->get_system ()
126 || !bounds[RIGHT]->get_system ()
127 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
129 programming_error ("bounds of spanner are invalid");
134 bounds[LEFT]->get_system ()->typeset_grob (span);
135 broken_intos_.push (span);
139 broken_intos_.sort (Spanner::compare);
143 Spanner::set_my_columns ()
145 Direction i = (Direction) LEFT;
148 if (!spanned_drul_[i]->get_system ())
149 set_bound (i,spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
151 while (flip (&i) != LEFT);
155 Spanner::spanned_rank_iv ()
157 Interval_t<int> iv (0, 0);
159 if (spanned_drul_[LEFT])
161 iv[LEFT] = Paper_column::get_rank (spanned_drul_[LEFT]->get_column ());
163 if (spanned_drul_[RIGHT])
165 iv[RIGHT] = Paper_column::get_rank (spanned_drul_[RIGHT]->get_column ());
171 Spanner::get_bound (Direction d) const
173 return spanned_drul_ [d];
177 Set the items that this spanner spans. If D == LEFT, we also set the
178 X-axis parent of THIS to S.
181 Spanner::set_bound (Direction d, Grob*s)
183 Item * i = dynamic_cast<Item*> (s);
186 programming_error ("Must have Item for spanner bound.");
193 We check for System to prevent the column -> line_of_score
194 -> column -> line_of_score -> etc situation */
195 if (d== LEFT && !dynamic_cast<System*> (this))
197 set_parent (i, X_AXIS);
201 Signal that this column needs to be kept alive. They need to be
202 kept alive to have meaningful position and linebreaking.
204 [maybe we should try keeping all columns alive?, and perhaps
205 inherit position from their (non-)musical brother]
208 if (dynamic_cast<Paper_column*> (i))
210 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
214 Spanner::Spanner (SCM s)
217 spanned_drul_[LEFT]=0;
218 spanned_drul_[RIGHT]=0;
219 Group_interface::add_thing (this, ly_symbol2scm ("interfaces"), ly_symbol2scm ("spanner-interface"));
224 Spanner::Spanner (Spanner const &s)
227 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
231 Spanner::spanner_length () const
233 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
234 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
237 programming_error ("spanner with negative length");
243 Spanner::get_system () const
245 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
247 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
249 return spanned_drul_[LEFT]->get_system ();
254 Spanner::find_broken_piece (System*l) const
256 int idx = binsearch_links (broken_intos_, (Spanner*)l, Spanner::compare);
261 return broken_intos_ [idx];
266 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
268 return p1->get_system ()->rank_ - p2->get_system ()->rank_;
272 Spanner::broken_b () const
274 return broken_intos_.size ();
279 If this is a broken spanner, return the amount the left end is to be
280 shifted horizontally so that the spanner starts after the initial
281 clef and key on the staves. This is necessary for ties, slurs,
282 crescendo and decrescendo signs, for example.
285 Spanner::get_broken_left_end_align () const
287 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->get_column ());
289 // Relevant only if left span point is first column in line
291 sc->break_status_dir () == RIGHT)
295 We used to do a full search for the Break_align_item.
296 But that doesn't make a difference, since the Paper_column
297 is likely to contain only a Break_align_item.
299 return sc->extent (sc, X_AXIS)[RIGHT];
306 Spanner::do_derived_mark ()
309 We'd be fucked if this is called before spanned_drul_[] is inited. */
310 if (status_ == ORPHAN)
315 if (spanned_drul_[d])
316 scm_gc_mark (spanned_drul_[d]->self_scm ());
317 while (flip (&d) != LEFT);
319 for (int i= broken_intos_.size () ; i--;)
320 scm_gc_mark (broken_intos_[i]->self_scm ());
327 Set left or right bound to IT.
329 Warning: caller should ensure that subsequent calls put in ITems
330 that are left-to-right ordered.
333 add_bound_item (Spanner* sp, Grob*it)
335 if (!sp->get_bound (LEFT))
336 sp->set_bound (LEFT, it);
338 sp->set_bound (RIGHT, it);
342 MAKE_SCHEME_CALLBACK (Spanner,set_spacing_rods,1);
344 Spanner::set_spacing_rods (SCM smob)
346 Grob*me = unsmob_grob (smob);
349 Spanner*sp = dynamic_cast<Spanner*> (me);
350 r.item_l_drul_[LEFT] = sp->get_bound (LEFT);
351 r.item_l_drul_[RIGHT] = sp->get_bound (RIGHT);
353 gh_scm2double (me->get_grob_property ("minimum-length"))
357 return SCM_UNSPECIFIED;
362 unsmob_spanner (SCM s )
364 return dynamic_cast<Spanner*> (unsmob_grob (s));
367 ADD_INTERFACE(Spanner,
370 Other grobs have a shape that depends on the horizontal spacing. For
371 example, slur, beam, tie, etc. These grobs form a subtype called
372 @code{Spanner}. All spanners have two span-points (these must be
373 @code{Item}s), one on the left and one on the right. The left bound is
374 also the X-reference point of the spanner.