]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
Add some translation markers; normalize whitespace.
[lilypond.git] / lily / spanner.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "libc-extension.hh"
21 #include "moment.hh"
22 #include "paper-column.hh"
23 #include "paper-score.hh"
24 #include "pointer-group-interface.hh"
25 #include "stencil.hh"
26 #include "system.hh"
27 #include "warn.hh"
28
29 Grob *
30 Spanner::clone () const
31 {
32   return new Spanner (*this);
33 }
34
35 void
36 Spanner::do_break_processing ()
37 {
38   //break_into_pieces
39   Item *left = spanned_drul_[LEFT];
40   Item *right = spanned_drul_[RIGHT];
41
42   if (!left || !right)
43     return;
44
45   if (get_system () || is_broken ())
46     return;
47
48   if (left == right)
49     {
50       /*
51         If we have a spanner spanning one column, we must break it
52         anyway because it might provide a parent for another item.  */
53       for (LEFT_and_RIGHT (d))
54         {
55           Item *bound = left->find_prebroken_piece (d);
56           if (!bound)
57             programming_error ("no broken bound");
58           else if (bound->get_system ())
59             {
60               Spanner *span = dynamic_cast<Spanner *> (clone ());
61               span->set_bound (LEFT, bound);
62               span->set_bound (RIGHT, bound);
63
64               assert (span->get_system ());
65               span->get_system ()->typeset_grob (span);
66               broken_intos_.push_back (span);
67             }
68         }
69     }
70   else
71     {
72       System *root = get_root_system (this);
73       vector<Item *> break_points = root->broken_col_range (left, right);
74
75       break_points.insert (break_points.begin () + 0, left);
76       break_points.push_back (right);
77
78       Slice parent_rank_slice;
79       parent_rank_slice.set_full ();
80
81       /*
82         Check if our parent in X-direction spans equally wide
83         or wider than we do.
84       */
85       for (int a = X_AXIS; a < NO_AXES; a++)
86         {
87           if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
88             parent_rank_slice.intersect (parent->spanned_rank_interval ());
89         }
90
91       for (vsize i = 1; i < break_points.size (); i++)
92         {
93           Drul_array<Item *> bounds;
94           bounds[LEFT] = break_points[i - 1];
95           bounds[RIGHT] = break_points[i];
96           for (LEFT_and_RIGHT (d))
97             {
98               if (!bounds[d]->get_system ())
99                 bounds[d] = bounds[d]->find_prebroken_piece (- d);
100             }
101
102           if (!bounds[LEFT] || ! bounds[RIGHT])
103             {
104               programming_error ("bounds of this piece aren't breakable.");
105               continue;
106             }
107
108           bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
109           ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
110
111           if (!ok)
112             {
113               programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner."
114                                             "  Ignoring orphaned part",
115                                             name ().c_str ()));
116               continue;
117             }
118
119           Spanner *span = dynamic_cast<Spanner *> (clone ());
120           span->set_bound (LEFT, bounds[LEFT]);
121           span->set_bound (RIGHT, bounds[RIGHT]);
122
123           if (!bounds[LEFT]->get_system ()
124               || !bounds[RIGHT]->get_system ()
125               || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
126             {
127               programming_error ("bounds of spanner are invalid");
128               span->suicide ();
129             }
130           else
131             {
132               bounds[LEFT]->get_system ()->typeset_grob (span);
133               broken_intos_.push_back (span);
134             }
135         }
136     }
137   vector_sort (broken_intos_, Spanner::less);
138   for (vsize i = broken_intos_.size (); i--;)
139     broken_intos_[i]->break_index_ = i;
140 }
141
142 vsize
143 Spanner::get_break_index () const
144 {
145   return break_index_;
146 }
147
148 void
149 Spanner::set_my_columns ()
150 {
151   for (LEFT_and_RIGHT (d))
152     {
153       if (!spanned_drul_[d]->get_system ())
154         set_bound (d, spanned_drul_[d]->find_prebroken_piece ((Direction) - d));
155     }
156 }
157
158 Interval_t<int>
159 Spanner::spanned_rank_interval () const
160 {
161   Interval_t<int> iv (0, 0);
162
163   if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
164     iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
165   if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
166     iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
167   return iv;
168 }
169
170 Interval_t<Moment>
171 Spanner::spanned_time () const
172 {
173   return spanned_time_interval (spanned_drul_[LEFT],
174                                 spanned_drul_[RIGHT]);
175 }
176
177 Item *
178 Spanner::get_bound (Direction d) const
179 {
180   return spanned_drul_[d];
181 }
182
183 /*
184   Set the items that this spanner spans. If D == LEFT, we also set the
185   X-axis parent of THIS to S.
186 */
187 void
188 Spanner::set_bound (Direction d, Grob *s)
189 {
190   Item *i = dynamic_cast<Item *> (s);
191   if (!i)
192     {
193       programming_error ("must have Item for spanner bound of " + name ());
194       return;
195     }
196
197   spanned_drul_[d] = i;
198
199   /**
200      We check for System to prevent the column -> line_of_score
201      -> column -> line_of_score -> etc situation */
202   if (d == LEFT && !dynamic_cast<System *> (this))
203     set_parent (i, X_AXIS);
204
205   /*
206     Signal that this column needs to be kept alive. They need to be
207     kept alive to have meaningful position and linebreaking.
208
209     [maybe we should try keeping all columns alive?, and perhaps
210     inherit position from their (non-)musical brother]
211   */
212   if (dynamic_cast<Paper_column *> (i))
213     Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
214 }
215
216 Spanner::Spanner (SCM s)
217   : Grob (s)
218 {
219   break_index_ = 0;
220   spanned_drul_.set (0, 0);
221   pure_property_cache_ = SCM_UNDEFINED;
222 }
223
224 Spanner::Spanner (Spanner const &s)
225   : Grob (s)
226 {
227   spanned_drul_.set (0, 0);
228   pure_property_cache_ = SCM_UNDEFINED;
229 }
230
231 /*
232   Certain spanners have pre-computed X values that lie either in
233   X-positions or the X key of the alists returned for left-bound-info
234   and right-bound-info.  These are calculated to give the real length
235   of a spanner (which, because of various padding or overhang properties,
236   can extend pass or arrive short of a given bound).  If possible, we
237   use these to calculate the spanner's length, and otherwise, we use
238   the bound.
239
240   For those writing a new spanner, DO NOT use both X-positions and
241   left-bound-info/right-bound-info.
242 */
243 Real
244 Spanner::spanner_length () const
245 {
246   Interval lr = robust_scm2interval (get_property ("X-positions"),
247                                      Interval (1, -1));
248
249   if (lr.is_empty ())
250     {
251       Drul_array<SCM> bounds (get_property ("left-bound-info"),
252                               get_property ("right-bound-info"));
253
254       for (LEFT_and_RIGHT (d))
255         lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
256                                                  bounds[d], SCM_BOOL_F), -d);
257     }
258
259   if (lr.is_empty ())
260     {
261       for (LEFT_and_RIGHT (d))
262         lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
263     }
264
265   if (lr.is_empty ())
266     programming_error ("spanner with negative length");
267
268   return lr.length ();
269 }
270
271 System *
272 Spanner::get_system () const
273 {
274   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
275     return 0;
276   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
277     return 0;
278   return spanned_drul_[LEFT]->get_system ();
279 }
280
281 Grob *
282 Spanner::find_broken_piece (System *l) const
283 {
284   vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
285   if (idx != VPOS)
286     return broken_intos_ [idx];
287   return 0;
288 }
289
290 Spanner *
291 Spanner::broken_neighbor (Direction d) const
292 {
293   if (!original_)
294     return 0;
295
296   vsize k = get_break_index ();
297   Spanner *orig = dynamic_cast<Spanner *> (original_);
298   int j = int (k) + d;
299   if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
300     return 0;
301
302   return orig->broken_intos_[j];
303 }
304
305 int
306 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
307 {
308   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
309 }
310
311 bool
312 Spanner::less (Spanner *const &a, Spanner *const &b)
313 {
314   return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
315 }
316
317 bool
318 Spanner::is_broken () const
319 {
320   return broken_intos_.size ();
321 }
322
323 void
324 Spanner::derived_mark () const
325 {
326   scm_gc_mark (pure_property_cache_);
327
328   for (LEFT_and_RIGHT (d))
329     if (spanned_drul_[d])
330       scm_gc_mark (spanned_drul_[d]->self_scm ());
331     ;
332
333   for (vsize i = broken_intos_.size (); i--;)
334     scm_gc_mark (broken_intos_[i]->self_scm ());
335 }
336
337 /*
338   Set left or right bound to IT.
339
340   Warning: caller should ensure that subsequent calls put in ITems
341   that are left-to-right ordered.
342 */
343 void
344 add_bound_item (Spanner *sp, Grob *it)
345 {
346   if (!sp->get_bound (LEFT))
347     sp->set_bound (LEFT, it);
348   else
349     sp->set_bound (RIGHT, it);
350 }
351
352 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
353 SCM
354 Spanner::set_spacing_rods (SCM smob)
355 {
356   Grob *me = unsmob_grob (smob);
357   SCM num_length = me->get_property ("minimum-length");
358   if (scm_is_number (num_length))
359     {
360       Rod r;
361       Spanner *sp = dynamic_cast<Spanner *> (me);
362       System *root = get_root_system (me);
363       Drul_array<Item *> bounds (sp->get_bound (LEFT),
364                                  sp->get_bound (RIGHT));
365       if (!bounds[LEFT] || !bounds[RIGHT])
366         return SCM_UNSPECIFIED;
367
368       vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
369                                                    bounds[RIGHT]->get_column ()));
370
371       if (cols.size ())
372         {
373           Rod r;
374           r.item_drul_[LEFT] = sp->get_bound (LEFT);
375           r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
376           r.distance_ = robust_scm2double (num_length, 0);
377           r.add_to_cols ();
378
379           r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
380           r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
381           r.add_to_cols ();
382         }
383
384       r.distance_ = robust_scm2double (num_length, 0);
385       r.item_drul_[LEFT] = sp->get_bound (LEFT);
386       r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
387       r.add_to_cols ();
388     }
389
390   return SCM_UNSPECIFIED;
391 }
392
393 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
394 SCM
395 Spanner::calc_normalized_endpoints (SCM smob)
396 {
397   Spanner *me = unsmob_spanner (smob);
398   SCM result = SCM_EOL;
399
400   Spanner *orig = dynamic_cast<Spanner *> (me->original ());
401
402   orig = orig ? orig : me;
403
404   if (orig->is_broken ())
405     {
406       Real total_width = 0.0;
407       vector<Real> span_data;
408
409       if (!orig->is_broken ())
410         span_data.push_back (orig->spanner_length ());
411       else
412         for (vsize i = 0; i < orig->broken_intos_.size (); i++)
413           span_data.push_back (orig->broken_intos_[i]->spanner_length ());
414
415       vector<Interval> unnormalized_endpoints;
416
417       for (vsize i = 0; i < span_data.size (); i++)
418         {
419           unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
420           total_width += span_data[i];
421         }
422
423       for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
424         {
425           SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
426           orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
427           if (me->get_break_index () == i)
428             result = t;
429         }
430     }
431   else
432     {
433       result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
434       orig->set_property ("normalized-endpoints", result);
435     }
436
437   return result;
438 }
439
440 Spanner *
441 unsmob_spanner (SCM s)
442 {
443   return dynamic_cast<Spanner *> (unsmob_grob (s));
444 }
445
446 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
447 SCM
448 Spanner::bounds_width (SCM grob)
449 {
450   Spanner *me = unsmob_spanner (grob);
451
452   Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
453
454   Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
455               me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
456
457   w -= me->relative_coordinate (common, X_AXIS);
458
459   return ly_interval2scm (w);
460 }
461
462 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
463 SCM
464 Spanner::kill_zero_spanned_time (SCM grob)
465 {
466   Spanner *me = unsmob_spanner (grob);
467   /*
468     Remove the line or hairpin at the start of the line.  For
469     piano voice indicators, it makes no sense to have them at
470     the start of the line.
471
472     I'm not sure what the official rules for glissandi are, but
473     usually the 2nd note of the glissando is "exact", so when playing
474     from the start of the line, there is no need to glide.
475
476     From a typographical p.o.v. this makes sense, since the amount of
477     space left of a note at the start of a line is very small.
478
479     --hwn.
480
481   */
482   if (me->get_bound (LEFT)->break_status_dir ())
483     {
484       Interval_t<Moment> moments = me->spanned_time ();
485       moments [LEFT].grace_part_ = 0;
486       if (moments.length () == Moment (0, 0))
487         me->suicide ();
488     }
489
490   return SCM_UNSPECIFIED;
491 }
492
493 SCM
494 Spanner::get_cached_pure_property (SCM sym, int start, int end)
495 {
496   // The pure property cache is indexed by (name start . end), where name is
497   // a symbol, and start and end are numbers referring to the starting and
498   // ending column ranks of the current line.
499   if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
500     return SCM_UNDEFINED;
501
502   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
503   return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
504 }
505
506 void
507 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
508 {
509   if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
510     pure_property_cache_ = scm_c_make_hash_table (17);
511
512   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
513   scm_hash_set_x (pure_property_cache_, key, val);
514 }
515
516 ADD_INTERFACE (Spanner,
517                "Some objects are horizontally spanned between objects.  For"
518                " example, slurs, beams, ties, etc.  These grobs form a subtype"
519                " called @code{Spanner}.  All spanners have two span points"
520                " (these must be @code{Item} objects), one on the left and one"
521                " on the right.  The left bound is also the X@tie{}reference"
522                " point of the spanner.",
523
524                /* properties */
525                "normalized-endpoints "
526                "minimum-length "
527                "spanner-broken "
528                "spanner-id "
529                "to-barline "
530               );