]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
Doc: CSS: Add a maximum width for the sidebar in the manuals
[lilypond.git] / lily / spanner.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2015 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   For example, when a slur crosses a line break, it's broken into two
188   pieces.  The second piece shouldn't be positioned relative to the
189   original NoteColumn, but rather to the PaperColumn after the break.
190 */
191 void
192 Spanner::set_bound (Direction d, Grob *s)
193 {
194   Item *i = dynamic_cast<Item *> (s);
195   if (!i)
196     {
197       programming_error ("must have Item for spanner bound of " + name ());
198       return;
199     }
200
201   spanned_drul_[d] = i;
202
203   /**
204      We check for System to prevent the column -> line_of_score
205      -> column -> line_of_score -> etc situation */
206   if (d == LEFT && !dynamic_cast<System *> (this))
207     /*
208       If the X-parent is a spanner, it will be split across linebreaks, too,
209       so we shouldn't have to overwrite it with the bound. Also, we need
210       original parent for alignment.
211       This happens e.g. for MultiMeasureRestNumbers and PercentRepeatCounters.
212     */
213     if (!dynamic_cast <Spanner *> (get_parent (X_AXIS)))
214       set_parent (i, X_AXIS);
215
216   /*
217     Signal that this column needs to be kept alive. They need to be
218     kept alive to have meaningful position and linebreaking.
219
220     [maybe we should try keeping all columns alive?, and perhaps
221     inherit position from their (non-)musical brother]
222   */
223   if (dynamic_cast<Paper_column *> (i))
224     Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
225 }
226
227 Preinit_Spanner::Preinit_Spanner ()
228 {
229   spanned_drul_.set (0, 0);
230   pure_property_cache_ = SCM_UNDEFINED;
231 }
232
233 Spanner::Spanner (SCM s)
234   : Grob (s)
235 {
236   break_index_ = 0;
237 }
238
239 Spanner::Spanner (Spanner const &s)
240   : Grob (s)
241 {
242   break_index_ = 0;
243 }
244
245 /*
246   Certain spanners have pre-computed X values that lie either in
247   X-positions or the X key of the alists returned for left-bound-info
248   and right-bound-info.  These are calculated to give the real length
249   of a spanner (which, because of various padding or overhang properties,
250   can extend pass or arrive short of a given bound).  If possible, we
251   use these to calculate the spanner's length, and otherwise, we use
252   the bound.
253
254   For those writing a new spanner, DO NOT use both X-positions and
255   left-bound-info/right-bound-info.
256 */
257 Real
258 Spanner::spanner_length () const
259 {
260   Interval lr = robust_scm2interval (get_property ("X-positions"),
261                                      Interval (1, -1));
262
263   if (lr.is_empty ())
264     {
265       Drul_array<SCM> bounds (get_property ("left-bound-info"),
266                               get_property ("right-bound-info"));
267
268       for (LEFT_and_RIGHT (d))
269         lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
270                                                  bounds[d], SCM_BOOL_F), -d);
271     }
272
273   if (lr.is_empty ())
274     {
275       for (LEFT_and_RIGHT (d))
276         lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
277     }
278
279   if (lr.is_empty ())
280     programming_error ("spanner with negative length");
281
282   return lr.length ();
283 }
284
285 System *
286 Spanner::get_system () const
287 {
288   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
289     return 0;
290   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
291     return 0;
292   return spanned_drul_[LEFT]->get_system ();
293 }
294
295 Grob *
296 Spanner::find_broken_piece (System *l) const
297 {
298   vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
299   if (idx != VPOS)
300     return broken_intos_ [idx];
301   return 0;
302 }
303
304 Spanner *
305 Spanner::broken_neighbor (Direction d) const
306 {
307   if (!original_)
308     return 0;
309
310   vsize k = get_break_index ();
311   Spanner *orig = dynamic_cast<Spanner *> (original_);
312   int j = int (k) + d;
313   if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
314     return 0;
315
316   return orig->broken_intos_[j];
317 }
318
319 int
320 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
321 {
322   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
323 }
324
325 bool
326 Spanner::less (Spanner *const &a, Spanner *const &b)
327 {
328   return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
329 }
330
331 bool
332 Spanner::is_broken () const
333 {
334   return broken_intos_.size ();
335 }
336
337 void
338 Spanner::derived_mark () const
339 {
340   scm_gc_mark (pure_property_cache_);
341
342   for (LEFT_and_RIGHT (d))
343     if (spanned_drul_[d])
344       scm_gc_mark (spanned_drul_[d]->self_scm ());
345   ;
346
347   // If break_index_ is -1, broken_intos_ might not yet have run its
348   // constructor and any access might break things.
349   if (break_index_ != (vsize)-1)
350     for (vsize i = broken_intos_.size (); i--;)
351       scm_gc_mark (broken_intos_[i]->self_scm ());
352 }
353
354 /*
355   Set left or right bound to IT.
356
357   Warning: caller should ensure that subsequent calls put in ITems
358   that are left-to-right ordered.
359 */
360 void
361 add_bound_item (Spanner *sp, Grob *it)
362 {
363   if (!sp->get_bound (LEFT))
364     sp->set_bound (LEFT, it);
365   else
366     sp->set_bound (RIGHT, it);
367 }
368
369 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
370 SCM
371 Spanner::set_spacing_rods (SCM smob)
372 {
373   Grob *me = unsmob<Grob> (smob);
374   SCM num_length = me->get_property ("minimum-length");
375   SCM broken_length = me->get_property ("minimum-length-after-break");
376   if (scm_is_number (num_length)
377      || scm_is_number (broken_length))
378     {
379       Spanner *sp = dynamic_cast<Spanner *> (me);
380       System *root = get_root_system (me);
381       Drul_array<Item *> bounds (sp->get_bound (LEFT),
382                                  sp->get_bound (RIGHT));
383       if (!bounds[LEFT] || !bounds[RIGHT])
384         return SCM_UNSPECIFIED;
385
386       vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
387                                                    bounds[RIGHT]->get_column ()));
388
389       if (cols.size ())
390         {
391           Rod r;
392           r.item_drul_[LEFT] = sp->get_bound (LEFT);
393           r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
394           r.distance_ = robust_scm2double (num_length, 0);
395           r.add_to_cols ();
396
397           r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
398           r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
399           if (scm_is_number (broken_length))
400             /*
401               r.distance_ may have been modified by add_to_cols ()
402               above.  For treatment of minimum-distance-after-break
403               consistent with minimum-distance (which will use the
404               changed value), we cannot directly reset r.distance_ to
405               broken_length.
406             */
407             r.distance_ += robust_scm2double (broken_length, 0) -
408               robust_scm2double (num_length, 0);
409           r.add_to_cols ();
410         }
411
412       Rod r;
413       /*
414         As r is a fresh rod, we can set distance_ with no complication.
415       */
416       r.distance_ = robust_scm2double (num_length, 0);
417       r.item_drul_[LEFT] = sp->get_bound (LEFT);
418       r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
419       r.add_to_cols ();
420
421       /*
422         We do not know yet if the spanner is going to have a bound that is
423         broken. To account for this uncertainty, we add the rod twice:
424         once for the central column (see above) and once for the left column
425         (see below). As end_rods_ are never used when rods_ are used and vice
426         versa, this rod will only be accessed once for each spacing
427         configuraiton before line breaking. Then, as a grob never exists in
428         both unbroken and broken forms after line breaking, only one of these
429         two rods will be in the column vector used for spacing in
430         simple-spacer.cc get_line_confugration.
431       */
432       if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
433         {
434           r.item_drul_[RIGHT] = left_pbp;
435           r.add_to_cols ();
436         }
437     }
438
439   return SCM_UNSPECIFIED;
440 }
441
442 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
443 SCM
444 Spanner::calc_normalized_endpoints (SCM smob)
445 {
446   Spanner *me = unsmob<Spanner> (smob);
447   SCM result = SCM_EOL;
448
449   Spanner *orig = dynamic_cast<Spanner *> (me->original ());
450
451   orig = orig ? orig : me;
452
453   if (orig->is_broken ())
454     {
455       Real total_width = 0.0;
456       vector<Real> span_data;
457
458       for (vsize i = 0; i < orig->broken_intos_.size (); i++)
459         span_data.push_back (orig->broken_intos_[i]->spanner_length ());
460
461       vector<Interval> unnormalized_endpoints;
462
463       for (vsize i = 0; i < span_data.size (); i++)
464         {
465           unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
466           total_width += span_data[i];
467         }
468
469       for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
470         {
471           SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
472           orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
473           if (me->get_break_index () == i)
474             result = t;
475         }
476     }
477   else
478     {
479       result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
480       orig->set_property ("normalized-endpoints", result);
481     }
482
483   return result;
484 }
485
486 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
487 SCM
488 Spanner::bounds_width (SCM grob)
489 {
490   Spanner *me = unsmob<Spanner> (grob);
491
492   Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
493
494   Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
495               me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
496
497   w -= me->relative_coordinate (common, X_AXIS);
498
499   return ly_interval2scm (w);
500 }
501
502 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
503 SCM
504 Spanner::kill_zero_spanned_time (SCM grob)
505 {
506   Spanner *me = unsmob<Spanner> (grob);
507   /*
508     Remove the line or hairpin at the start of the line.  For
509     piano voice indicators, it makes no sense to have them at
510     the start of the line.
511
512     I'm not sure what the official rules for glissandi are, but
513     usually the 2nd note of the glissando is "exact", so when playing
514     from the start of the line, there is no need to glide.
515
516     From a typographical p.o.v. this makes sense, since the amount of
517     space left of a note at the start of a line is very small.
518
519     --hwn.
520
521   */
522   if (me->get_bound (LEFT)->break_status_dir ())
523     {
524       Interval_t<Moment> moments = me->spanned_time ();
525       moments [LEFT].grace_part_ = 0;
526       if (moments.length () == Moment (0, 0))
527         me->suicide ();
528     }
529
530   return SCM_UNSPECIFIED;
531 }
532
533 SCM
534 Spanner::get_cached_pure_property (SCM sym, int start, int end)
535 {
536   // The pure property cache is indexed by (name start . end), where name is
537   // a symbol, and start and end are numbers referring to the starting and
538   // ending column ranks of the current line.
539   if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
540     return SCM_UNDEFINED;
541
542   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
543   return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
544 }
545
546 void
547 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
548 {
549   if (scm_is_false (scm_hash_table_p (pure_property_cache_)))
550     pure_property_cache_ = scm_c_make_hash_table (17);
551
552   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
553   scm_hash_set_x (pure_property_cache_, key, val);
554 }
555
556 ADD_INTERFACE (Spanner,
557                "Some objects are horizontally spanned between objects.  For"
558                " example, slurs, beams, ties, etc.  These grobs form a subtype"
559                " called @code{Spanner}.  All spanners have two span points"
560                " (these must be @code{Item} objects), one on the left and one"
561                " on the right.  The left bound is also the X@tie{}reference"
562                " point of the spanner.",
563
564                /* properties */
565                "normalized-endpoints "
566                "minimum-length "
567                "minimum-length-after-break "
568                "spanner-broken "
569                "spanner-id "
570                "to-barline "
571               );