]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
* lily/tie-column.cc (set_manual_tie_configuration): new function.
[lilypond.git] / lily / spanner.cc
1 /*
2   spanner.cc -- implement Spanner
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1996--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "spanner.hh"
10
11 #include <cmath>
12 using namespace std;
13
14 #include "pointer-group-interface.hh"
15 #include "libc-extension.hh"
16 #include "paper-column.hh"
17 #include "paper-column.hh"
18 #include "paper-score.hh"
19 #include "stencil.hh"
20 #include "system.hh"
21 #include "warn.hh"
22
23 Grob *
24 Spanner::clone (int count) const
25 {
26   return new Spanner (*this, count);
27 }
28
29 void
30 Spanner::do_break_processing ()
31 {
32   //break_into_pieces
33   Item *left = spanned_drul_[LEFT];
34   Item *right = spanned_drul_[RIGHT];
35
36   if (!left || !right)
37     return;
38
39   /*
40     Check if our parent in X-direction spans equally wide
41     or wider than we do.
42   */
43   for (int a = X_AXIS; a < NO_AXES; a++)
44     {
45       if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
46         {
47           if (!parent->spanned_rank_iv ().superset (this->spanned_rank_iv ()))
48             {
49               programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner `%s'.",
50                                             name ().to_str0 (),
51                                             parent->name ().to_str0 ()));
52             }
53         }
54     }
55
56   if (get_system () || is_broken ())
57     return;
58
59   if (left == right)
60     {
61       /*
62         If we have a spanner spanning one column, we must break it
63         anyway because it might provide a parent for another item.  */
64       Direction d = LEFT;
65       do
66         {
67           Item *bound = left->find_prebroken_piece (d);
68           if (!bound)
69             programming_error ("no broken bound");
70           else if (bound->get_system ())
71             {
72               Spanner *span = dynamic_cast<Spanner *> (clone (broken_intos_.size ()));
73               span->set_bound (LEFT, bound);
74               span->set_bound (RIGHT, bound);
75
76               assert (span->get_system ());
77               span->get_system ()->typeset_grob (span);
78               broken_intos_.push (span);
79             }
80         }
81       while ((flip (&d)) != LEFT);
82     }
83   else
84     {
85       Link_array<Item> break_points = pscore_->root_system ()->broken_col_range (left, right);
86
87       break_points.insert (left, 0);
88       break_points.push (right);
89
90       for (int i = 1; i < break_points.size (); i++)
91         {
92           Drul_array<Item *> bounds;
93           bounds[LEFT] = break_points[i - 1];
94           bounds[RIGHT] = break_points[i];
95           Direction d = LEFT;
96           do
97             {
98               if (!bounds[d]->get_system ())
99                 bounds[d] = bounds[d]->find_prebroken_piece (- d);
100             }
101           while ((flip (&d)) != LEFT);
102
103           if (!bounds[LEFT] || ! bounds[RIGHT])
104             {
105               programming_error ("bounds of this piece aren't breakable. ");
106               continue;
107             }
108
109           Spanner *span = dynamic_cast<Spanner *> (clone (broken_intos_.size ()));
110           span->set_bound (LEFT, bounds[LEFT]);
111           span->set_bound (RIGHT, bounds[RIGHT]);
112
113           if (!bounds[LEFT]->get_system ()
114
115               || !bounds[RIGHT]->get_system ()
116               || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
117             {
118               programming_error ("bounds of spanner are invalid");
119               span->suicide ();
120             }
121           else
122             {
123               bounds[LEFT]->get_system ()->typeset_grob (span);
124               broken_intos_.push (span);
125             }
126         }
127     }
128   broken_intos_.sort (Spanner::compare);
129   for (int i = broken_intos_.size ();i--;)
130     broken_intos_[i]->break_index_ = i;
131 }
132
133 int
134 Spanner::get_break_index () const
135 {
136   return break_index_;
137 }
138
139 void
140 Spanner::set_my_columns ()
141 {
142   Direction i = (Direction) LEFT;
143   do
144     {
145       if (!spanned_drul_[i]->get_system ())
146         set_bound (i, spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
147     }
148   while (flip (&i) != LEFT);
149 }
150
151 Interval_t<int>
152 Spanner::spanned_rank_iv ()
153 {
154   Interval_t<int> iv (0, 0);
155
156   if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
157     iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
158   if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
159     iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
160   return iv;
161 }
162
163 Item *
164 Spanner::get_bound (Direction d) const
165 {
166   return spanned_drul_ [d];
167 }
168
169 /*
170   Set the items that this spanner spans. If D == LEFT, we also set the
171   X-axis parent of THIS to S.
172 */
173 void
174 Spanner::set_bound (Direction d, Grob *s)
175 {
176   Item *i = dynamic_cast<Item *> (s);
177   if (!i)
178     {
179       programming_error ("must have Item for spanner bound");
180       return;
181     }
182
183   spanned_drul_[d] = i;
184
185   /**
186      We check for System to prevent the column -> line_of_score
187      -> column -> line_of_score -> etc situation */
188   if (d == LEFT && !dynamic_cast<System *> (this))
189     set_parent (i, X_AXIS);
190
191   /*
192     Signal that this column needs to be kept alive. They need to be
193     kept alive to have meaningful position and linebreaking.
194
195     [maybe we should try keeping all columns alive?, and perhaps
196     inherit position from their (non-)musical brother]
197
198   */
199   if (dynamic_cast<Paper_column *> (i))
200     Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
201 }
202
203 Spanner::Spanner (SCM s, Object_key const *key)
204   : Grob (s, key)
205 {
206   break_index_ = 0;
207   spanned_drul_[LEFT] = 0;
208   spanned_drul_[RIGHT] = 0;
209 }
210
211 Spanner::Spanner (Spanner const &s, int count)
212   : Grob (s, count)
213 {
214   spanned_drul_[LEFT] = spanned_drul_[RIGHT] = 0;
215 }
216
217 Real
218 Spanner::spanner_length () const
219 {
220   Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
221   Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
222
223   if (r < l)
224     programming_error ("spanner with negative length");
225
226   return r - l;
227 }
228
229 System *
230 Spanner::get_system () const
231 {
232   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
233     return 0;
234   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
235     return 0;
236   return spanned_drul_[LEFT]->get_system ();
237 }
238
239 Grob *
240 Spanner::find_broken_piece (System *l) const
241 {
242   int idx = binsearch_links (broken_intos_, (Spanner *)l, Spanner::compare);
243
244   if (idx < 0)
245     return 0;
246   else
247     return broken_intos_ [idx];
248 }
249
250 int
251 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
252 {
253   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
254 }
255
256 bool
257 Spanner::is_broken () const
258 {
259   return broken_intos_.size ();
260 }
261
262 /*
263   If this is a broken spanner, return the amount the left end is to be
264   shifted horizontally so that the spanner starts after the initial
265   clef and key on the staves. This is necessary for ties, slurs,
266   crescendo and decrescendo signs, for example.
267 */
268 Real
269 Spanner::get_broken_left_end_align () const
270 {
271   Paper_column *sc = dynamic_cast<Paper_column *> (spanned_drul_[LEFT]->get_column ());
272
273   // Relevant only if left span point is first column in line
274   if (sc != NULL
275       && sc->break_status_dir () == RIGHT)
276     {
277       /*
278         We used to do a full search for the Break_align_item.
279         But that doesn't make a difference, since the Paper_column
280         is likely to contain only a Break_align_item.
281       */
282       return sc->extent (sc, X_AXIS)[RIGHT];
283     }
284
285   return 0.0;
286 }
287
288 void
289 Spanner::derived_mark () const
290 {
291   Direction d = LEFT;
292   do
293     if (spanned_drul_[d])
294       scm_gc_mark (spanned_drul_[d]->self_scm ());
295   while (flip (&d) != LEFT)
296     ;
297
298   for (int i = broken_intos_.size (); i--;)
299     scm_gc_mark (broken_intos_[i]->self_scm ());
300 }
301
302 /*
303   Set left or right bound to IT.
304
305   Warning: caller should ensure that subsequent calls put in ITems
306   that are left-to-right ordered.
307 */
308 void
309 add_bound_item (Spanner *sp, Grob *it)
310 {
311   if (!sp->get_bound (LEFT))
312     sp->set_bound (LEFT, it);
313   else
314     sp->set_bound (RIGHT, it);
315 }
316
317 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
318 SCM
319 Spanner::set_spacing_rods (SCM smob)
320 {
321   Grob *me = unsmob_grob (smob);
322
323   Rod r;
324   Spanner *sp = dynamic_cast<Spanner *> (me);
325   r.item_drul_[LEFT] = sp->get_bound (LEFT);
326   r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
327   r.distance_
328     = robust_scm2double (me->get_property ("minimum-length"), 0);
329
330   r.add_to_cols ();
331   return SCM_UNSPECIFIED;
332 }
333
334 /*
335   Return I such that SP == SP->ORIGINAL_->BROKEN_INTOS_[I].
336 */
337 int
338 broken_spanner_index (Spanner *sp)
339 {
340   Spanner *parent = dynamic_cast<Spanner *> (sp->original_);
341   return parent->broken_intos_.find_index (sp);
342 }
343
344 Spanner *
345 unsmob_spanner (SCM s)
346 {
347   return dynamic_cast<Spanner *> (unsmob_grob (s));
348 }
349
350 ADD_INTERFACE (Spanner,
351                "spanner-interface",
352                "Some objects are horizontally spanned between objects. For\n"
353                "example, slur, beam, tie, etc. These grobs form a subtype called\n"
354                "@code{Spanner}. All spanners have two span-points (these must be\n"
355                "@code{Item} objects), one on the left and one on the right. The left bound is\n"
356                "also the X-reference point of the spanner.\n",
357                "minimum-length");