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