Use scalar instead of embedded_scm for context mod overrides.
[lilypond/mpolesky.git] / lily / tuplet-bracket.cc
blobf2136f1fe7c39e541ab0e3c02d0faa08775b4f90
1 /*
2 tuplet-bracket.cc -- implement Tuplet_bracket
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2009 Jan Nieuwenhuizen <janneke@gnu.org>
7 Han-Wen Nienhuys <hanwen@xs4all.nl>
8 */
11 TODO:
13 - tuplet bracket should probably be subject to the same rules as
14 beam sloping/quanting.
16 - There is no support for kneed brackets, or nested brackets.
18 - number placement for parallel beams should be much more advanced:
19 for sloped beams some extra horizontal offset must be introduced.
21 - number placement is usually done over the center note, not the
22 graphical center.
26 TODO: quantise, we don't want to collide with staff lines.
27 (or should we be above staff?)
29 todo: handle breaking elegantly.
33 #include "tuplet-bracket.hh"
34 #include "line-interface.hh"
35 #include "beam.hh"
36 #include "warn.hh"
37 #include "output-def.hh"
38 #include "font-interface.hh"
39 #include "text-interface.hh"
40 #include "stem.hh"
41 #include "note-column.hh"
42 #include "pointer-group-interface.hh"
43 #include "directional-element-interface.hh"
44 #include "spanner.hh"
45 #include "staff-symbol-referencer.hh"
46 #include "lookup.hh"
47 #include "paper-column.hh"
48 #include "moment.hh"
50 static Item *
51 get_x_bound_item (Grob *me_grob, Direction hdir, Direction my_dir)
53 Spanner *me = dynamic_cast<Spanner *> (me_grob);
54 Item *g = me->get_bound (hdir);
55 if (Note_column::has_interface (g)
56 && Note_column::get_stem (g)
57 && Note_column::dir (g) == my_dir)
58 g = Note_column::get_stem (g);
60 return g;
64 void
65 flatten_number_pair_property (Grob *me, Direction xdir, SCM sym)
67 Drul_array<Real> zero (0, 0);
68 Drul_array<Real> pair
69 = robust_scm2drul (me->internal_get_property (sym), zero);
70 pair[xdir] = 0.0;
72 me->set_property (sym, ly_interval2scm (pair));
77 Return beam that encompasses the span of the tuplet bracket.
79 Grob *
80 Tuplet_bracket::parallel_beam (Grob *me_grob, vector<Grob*> const &cols,
81 bool *equally_long)
83 Spanner *me = dynamic_cast<Spanner *> (me_grob);
85 if (me->get_bound (LEFT)->break_status_dir ()
86 || me->get_bound (RIGHT)->break_status_dir ())
87 return 0;
89 Drul_array<Grob *> stems (Note_column::get_stem (cols[0]),
90 Note_column::get_stem (cols.back ()));
92 if (!stems[RIGHT]
93 || !stems[LEFT]
94 || (dynamic_cast<Item*> (stems[RIGHT])->get_column ()
95 != me->get_bound (RIGHT)->get_column ()))
96 return 0;
98 Drul_array<Grob *> beams;
99 Direction d = LEFT;
100 do {
101 beams[d] = stems[d] ? Stem::get_beam (stems[d]) : 0;
102 } while (flip (&d) != LEFT);
104 *equally_long = false;
105 if (!(beams[LEFT] && (beams[LEFT] == beams[RIGHT]) && !me->is_broken ()))
106 return 0;
108 extract_grob_set (beams[LEFT], "stems", beam_stems);
109 if (beam_stems.size () == 0)
111 programming_error ("beam under tuplet bracket has no stems");
112 *equally_long = 0;
113 return 0;
116 *equally_long =
117 (beam_stems[0] == stems[LEFT]
118 && beam_stems.back () == stems[RIGHT]);
119 return beams[LEFT];
123 MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_connect_to_neighbors, 1);
125 Tuplet_bracket::calc_connect_to_neighbors (SCM smob)
127 Spanner *me = unsmob_spanner (smob);
129 Direction dir = get_grob_direction (me);
130 Drul_array<Item *> bounds (get_x_bound_item (me, LEFT, dir),
131 get_x_bound_item (me, RIGHT, dir));
133 Drul_array<bool> connect_to_other (false, false);
134 Direction d = LEFT;
137 Direction break_dir = bounds[d]->break_status_dir ();
138 Spanner *orig_spanner = dynamic_cast<Spanner *> (me->original ());
139 vsize neighbor_idx = me->get_break_index () - break_dir;
140 if (break_dir
141 && d == RIGHT
142 && neighbor_idx < orig_spanner->broken_intos_.size ())
144 Grob *neighbor = orig_spanner->broken_intos_[neighbor_idx];
146 /* trigger possible suicide*/
147 (void) neighbor->get_property ("positions");
150 connect_to_other[d]
151 = (break_dir
152 && neighbor_idx < orig_spanner->broken_intos_.size ()
153 && orig_spanner->broken_intos_[neighbor_idx]->is_live ());
155 while (flip (&d) != LEFT);
158 if (connect_to_other[LEFT] || connect_to_other[RIGHT])
159 return scm_cons (scm_from_bool (connect_to_other[LEFT]),
160 scm_from_bool (connect_to_other[RIGHT]));
162 return SCM_EOL;
165 Grob *
166 Tuplet_bracket::get_common_x (Spanner *me)
168 extract_grob_set (me, "note-columns", columns);
170 Grob *commonx = common_refpoint_of_array (columns, me, X_AXIS);
171 commonx = commonx->common_refpoint (me->get_bound (LEFT), X_AXIS);
172 commonx = commonx->common_refpoint (me->get_bound (RIGHT), X_AXIS);
174 return commonx;
177 MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_control_points, 1)
179 Tuplet_bracket::calc_control_points (SCM smob)
181 Spanner *me = unsmob_spanner (smob);
183 extract_grob_set (me, "note-columns", columns);
185 SCM scm_positions = me->get_property ("positions");
186 if (!me->is_live ())
187 return SCM_EOL;
189 if (!scm_is_pair (scm_positions))
190 programming_error ("Positions should be number pair");
192 Drul_array<Real> positions
193 = robust_scm2drul (scm_positions, Drul_array<Real> (0, 0));
195 Grob *commonx = get_common_x (me);
196 Direction dir = get_grob_direction (me);
198 Drul_array<Item *> bounds;
199 bounds[LEFT] = get_x_bound_item (me, LEFT, dir);
200 bounds[RIGHT] = get_x_bound_item (me, RIGHT, dir);
202 Drul_array<bool> connect_to_other =
203 robust_scm2booldrul (me->get_property ("connect-to-neighbor"),
204 Drul_array<bool> (false, false));
206 Interval x_span;
207 Direction d = LEFT;
210 x_span[d] = robust_relative_extent (bounds[d], commonx, X_AXIS)[d];
212 if (connect_to_other[d])
214 Interval overshoot (robust_scm2drul (me->get_property ("break-overshoot"),
215 Interval (-0.5, 0.0)));
217 if (d == RIGHT)
218 x_span[d] += d * overshoot[d];
219 else
220 x_span[d] = robust_relative_extent (bounds[d],
221 commonx, X_AXIS)[RIGHT]
222 - overshoot[LEFT];
225 else if (d == RIGHT
226 && (columns.empty ()
227 || (bounds[d]->get_column ()
228 != dynamic_cast<Item *> (columns.back ())->get_column ())))
231 We're connecting to a column, for the last bit of a broken
232 fullLength bracket.
234 Real padding =
235 robust_scm2double(me->get_property("full-length-padding"), 1.0);
237 if (bounds[d]->break_status_dir ())
238 padding = 0.0;
240 Real coord = bounds[d]->relative_coordinate(commonx, X_AXIS);
241 if (to_boolean (me->get_property ("full-length-to-extent")))
242 coord = robust_relative_extent(bounds[d], commonx, X_AXIS)[LEFT];
244 coord = max (coord, x_span[LEFT]);
246 x_span[d] = coord - padding;
249 while (flip (&d) != LEFT);
252 x_span -= me->get_bound (LEFT)->relative_coordinate (commonx, X_AXIS);
253 return scm_list_2 (ly_offset2scm (Offset (x_span[LEFT], positions[LEFT])),
254 ly_offset2scm (Offset (x_span[RIGHT], positions[RIGHT])));
258 TODO:
260 in the case that there is no bracket, but there is a (single) beam,
261 follow beam precisely for determining tuplet number location.
263 MAKE_SCHEME_CALLBACK (Tuplet_bracket, print, 1);
265 Tuplet_bracket::print (SCM smob)
267 Spanner *me = unsmob_spanner (smob);
268 Stencil mol;
270 extract_grob_set (me, "note-columns", columns);
271 bool equally_long = false;
272 Grob *par_beam = parallel_beam (me, columns, &equally_long);
274 bool bracket_visibility = !(par_beam && equally_long);
276 Fixme: the type of this prop is sucky.
278 SCM bracket = me->get_property ("bracket-visibility");
279 if (scm_is_bool (bracket))
280 bracket_visibility = ly_scm2bool (bracket);
281 else if (bracket == ly_symbol2scm ("if-no-beam"))
282 bracket_visibility = !par_beam;
285 Don't print a tuplet bracket and number if
286 no control-points were calculated
288 SCM cpoints = me->get_property ("control-points");
289 if (scm_ilength (cpoints) < 2)
291 me->suicide ();
292 return SCM_EOL;
294 /* if the tuplet does not span any time, i.e. a single-note tuplet, hide
295 the bracket, but still let the number be displayed */
296 if (robust_scm2moment (me->get_bound (LEFT)->get_column ()->get_property ("when"), Moment (0))
297 == robust_scm2moment (me->get_bound (RIGHT)->get_column ()->get_property ("when"), Moment (0)))
299 bracket_visibility = false;
302 Drul_array<Offset> points;
303 points[LEFT] = ly_scm2offset (scm_car (cpoints));
304 points[RIGHT] = ly_scm2offset (scm_cadr (cpoints));
306 Interval x_span (points[LEFT][X_AXIS], points[RIGHT][X_AXIS]);
307 Drul_array<Real> positions (points[LEFT][Y_AXIS], points[RIGHT][Y_AXIS]);
309 Output_def *pap = me->layout ();
311 Grob *number_grob = unsmob_grob (me->get_object ("tuplet-number"));
314 No bracket when it would be smaller than the number.
316 Real gap = 0.;
317 if (bracket_visibility && number_grob)
319 Interval ext = number_grob->extent (number_grob, X_AXIS);
320 if (!ext.is_empty ())
322 gap = ext.length () + 1.0;
324 if (0.75 * x_span.length () < gap)
325 bracket_visibility = false;
329 if (bracket_visibility)
331 Drul_array<Real> zero (0, 0);
332 Real ss = Staff_symbol_referencer::staff_space (me);
333 Drul_array<Real> height
334 = robust_scm2drul (me->get_property ("edge-height"), zero);
335 Drul_array<Real> flare
336 = robust_scm2drul (me->get_property ("bracket-flare"), zero);
337 Drul_array<Real> shorten
338 = robust_scm2drul (me->get_property ("shorten-pair"), zero);
339 Drul_array<Stencil> edge_stencils;
341 Direction dir = get_grob_direction (me);
343 scale_drul (&height, -ss * dir);
344 scale_drul (&flare, ss);
345 scale_drul (&shorten, ss);
347 Drul_array<bool> connect_to_other =
348 robust_scm2booldrul (me->get_property ("connect-to-neighbor"),
349 Drul_array<bool> (false, false));
351 Direction d = LEFT;
354 if (connect_to_other[d])
356 height[d] = 0.0;
357 flare[d] = 0.0;
358 shorten[d] = 0.0;
360 SCM edge_text = me->get_property ("edge-text");
362 if (scm_is_pair (edge_text))
364 SCM properties = Font_interface::text_font_alist_chain (me);
365 SCM text = index_get_cell (edge_text, d);
366 if (Text_interface::is_markup (text))
368 SCM t
369 = Text_interface::interpret_markup (pap->self_scm (),
370 properties, text);
372 Stencil *edge_text = unsmob_stencil (t);
373 edge_text->translate_axis (x_span[d] - x_span[LEFT],
374 X_AXIS);
375 edge_stencils[d] = *edge_text;
380 while (flip (&d) != LEFT);
382 Stencil brack = make_bracket (me, Y_AXIS,
383 points[RIGHT] - points[LEFT],
384 height,
386 0.1 = more space at right due to italics
387 TODO: use italic correction of font.
389 Interval (-0.5, 0.5) * gap + 0.1,
390 flare, shorten);
394 if (!edge_stencils[d].is_empty ())
395 brack.add_stencil (edge_stencils[d]);
397 while (flip (&d) != LEFT);
399 mol.add_stencil (brack);
402 mol.translate (points[LEFT]);
403 return mol.smobbed_copy ();
407 should move to lookup?
409 TODO: this will fail for very short (shorter than the flare)
410 brackets.
412 Stencil
413 Tuplet_bracket::make_bracket (Grob *me, // for line properties.
414 Axis protrusion_axis,
415 Offset dz,
416 Drul_array<Real> height,
417 Interval gap,
418 Drul_array<Real> flare,
419 Drul_array<Real> shorten)
421 Drul_array<Offset> corners (Offset (0, 0), dz);
423 Real length = dz.length ();
424 Drul_array<Offset> gap_corners;
426 Axis bracket_axis = other_axis (protrusion_axis);
428 Drul_array<Offset> straight_corners = corners;
430 Direction d = LEFT;
432 straight_corners[d] += -d * shorten[d] / length * dz;
433 while (flip (&d) != LEFT);
435 if (!gap.is_empty ())
438 gap_corners[d] = (dz * 0.5) + gap[d] / length * dz;
439 while (flip (&d) != LEFT);
442 Drul_array<Offset> flare_corners = straight_corners;
445 flare_corners[d][bracket_axis] = straight_corners[d][bracket_axis];
446 flare_corners[d][protrusion_axis] += height[d];
447 straight_corners[d][bracket_axis] += -d * flare[d];
449 while (flip (&d) != LEFT);
451 Stencil m;
454 if (!gap.is_empty ())
455 m.add_stencil (Line_interface::line (me, straight_corners[d],
456 gap_corners[d]));
458 m.add_stencil (Line_interface::line (me, straight_corners[d],
459 flare_corners[d]));
462 while (flip (&d) != LEFT);
464 if (gap.is_empty ())
465 m.add_stencil (Line_interface::line (me, straight_corners[LEFT],
466 straight_corners[RIGHT]));
468 return m;
471 void
472 Tuplet_bracket::get_bounds (Grob *me, Grob **left, Grob **right)
474 extract_grob_set (me, "note-columns", columns);
475 vsize l = 0;
476 while (l < columns.size () && Note_column::has_rests (columns[l]))
477 l++;
479 vsize r = columns.size ();
480 while (r > l && Note_column::has_rests (columns[r-1]))
481 r--;
483 *left = *right = 0;
485 if (l < r)
487 *left = columns[l];
488 *right = columns[r-1];
493 use first -> last note for slope, and then correct for disturbing
494 notes in between. */
495 void
496 Tuplet_bracket::calc_position_and_height (Grob *me_grob, Real *offset, Real *dy)
498 Spanner *me = dynamic_cast<Spanner *> (me_grob);
500 extract_grob_set (me, "note-columns", columns);
501 extract_grob_set (me, "tuplets", tuplets);
503 Grob *commony = common_refpoint_of_array (columns, me, Y_AXIS);
504 commony = common_refpoint_of_array (tuplets, commony, Y_AXIS);
505 if (Grob *st = Staff_symbol_referencer::get_staff_symbol (me))
506 commony = st->common_refpoint (commony, Y_AXIS);
507 Real my_offset = me->relative_coordinate (commony, Y_AXIS);
509 Grob *commonx = get_common_x (me);
510 commonx = common_refpoint_of_array (tuplets, commonx, Y_AXIS);
512 Interval staff;
513 Grob *st = Staff_symbol_referencer::get_staff_symbol (me);
515 /* staff-padding doesn't work correctly on cross-staff tuplets
516 because it only considers one staff symbol. Until this works,
517 disable it. */
518 if (st && !to_boolean (me->get_property ("cross-staff")))
520 Real pad = robust_scm2double (me->get_property ("staff-padding"), -1.0);
521 if (pad >= 0.0)
523 staff = st->extent (commony, Y_AXIS) - my_offset;
524 staff.widen (pad);
528 Direction dir = get_grob_direction (me);
530 bool equally_long = false;
531 Grob *par_beam = parallel_beam (me, columns, &equally_long);
533 Item *lgr = get_x_bound_item (me, LEFT, dir);
534 Item *rgr = get_x_bound_item (me, RIGHT, dir);
535 Real x0 = robust_relative_extent (lgr, commonx, X_AXIS)[LEFT];
536 Real x1 = robust_relative_extent (rgr, commonx, X_AXIS)[RIGHT];
537 bool follow_beam = par_beam
538 && get_grob_direction (par_beam) == dir
539 && ! to_boolean (par_beam->get_property ("knee"));
541 vector<Offset> points;
542 if (columns.size ()
543 && follow_beam
544 && Note_column::get_stem (columns[0])
545 && Note_column::get_stem (columns.back ()))
548 trigger set_stem_ends
550 (void) par_beam->get_property ("quantized-positions");
552 Drul_array<Grob *> stems (Note_column::get_stem (columns[0]),
553 Note_column::get_stem (columns.back ()));
555 Real ss = 0.5 * Staff_symbol_referencer::staff_space (me);
556 Real lp = ss * robust_scm2double (stems[LEFT]->get_property ("stem-end-position"), 0.0)
557 + stems[LEFT]->get_parent (Y_AXIS)->relative_coordinate (commony, Y_AXIS);
558 Real rp = ss * robust_scm2double (stems[RIGHT]->get_property ("stem-end-position"), 0.0)
559 + stems[RIGHT]->get_parent (Y_AXIS)->relative_coordinate (commony, Y_AXIS);
561 *dy = rp - lp;
562 points.push_back (Offset (stems[LEFT]->relative_coordinate (commonx, X_AXIS) - x0, lp));
563 points.push_back (Offset (stems[RIGHT]->relative_coordinate (commonx, X_AXIS) - x0, rp));
565 else
568 Use outer non-rest columns to determine slope
570 Grob *left_col = 0;
571 Grob *right_col = 0;
572 get_bounds (me, &left_col, &right_col);
573 if (left_col && right_col)
575 Interval rv = Note_column::cross_staff_extent (right_col, commony);
576 Interval lv = Note_column::cross_staff_extent (left_col, commony);
577 rv.unite (staff);
578 lv.unite (staff);
580 Real graphical_dy = rv[dir] - lv[dir];
582 Slice ls = Note_column::head_positions_interval (left_col);
583 Slice rs = Note_column::head_positions_interval (right_col);
585 Interval musical_dy;
586 musical_dy[UP] = rs[UP] - ls[UP];
587 musical_dy[DOWN] = rs[DOWN] - ls[DOWN];
588 if (sign (musical_dy[UP]) != sign (musical_dy[DOWN]))
589 *dy = 0.0;
590 else if (sign (graphical_dy) != sign (musical_dy[DOWN]))
591 *dy = 0.0;
592 else
593 *dy = graphical_dy;
595 else
596 *dy = 0;
598 for (vsize i = 0; i < columns.size (); i++)
600 Interval note_ext = Note_column::cross_staff_extent (columns[i],
601 commony);
602 Real x = columns[i]->relative_coordinate (commonx, X_AXIS) - x0;
604 points.push_back (Offset (x, note_ext[dir]));
608 if (!follow_beam)
610 points.push_back (Offset (x0 - x0, staff[dir]));
611 points.push_back (Offset (x1 - x0, staff[dir]));
615 This is a slight hack. We compute two encompass points from the
616 bbox of the smaller tuplets.
618 We assume that the smaller bracket is 1.0 space high.
620 Real ss = Staff_symbol_referencer::staff_space (me);
621 for (vsize i = 0; i < tuplets.size (); i++)
623 Interval tuplet_x (tuplets[i]->extent (commonx, X_AXIS));
624 Interval tuplet_y (tuplets[i]->extent (commony, Y_AXIS));
626 if (!tuplets[i]->is_live ())
627 continue;
629 Direction d = LEFT;
630 Drul_array<Real> positions
631 = robust_scm2interval (tuplets[i]->get_property ("positions"),
632 Interval (0,0));
634 Real other_dy = positions[RIGHT] - positions[LEFT];
638 Real y
639 = tuplet_y.linear_combination (d * sign (other_dy));
642 We don't take padding into account for nested tuplets.
643 the edges can come very close to the stems, likewise for
644 nested tuplets?
647 points.push_back (Offset (tuplet_x[d] - x0, y));
649 while (flip (&d) != LEFT);
652 *offset = -dir * infinity_f;
653 Real factor = (columns.size () > 1) ? 1 / (x1 - x0) : 1.0;
654 for (vsize i = 0; i < points.size (); i++)
656 Real x = points[i][X_AXIS];
657 Real tuplety = (*dy) * x * factor + my_offset;
659 if (points[i][Y_AXIS] * dir > (*offset + tuplety) * dir)
660 *offset = points[i][Y_AXIS] - tuplety;
663 *offset += scm_to_double (me->get_property ("padding")) * dir;
666 horizontal brackets should not collide with staff lines.
668 Kind of pointless since we put them outside the staff anyway, but
669 let's leave code for the future when possibly allow them to move
670 into the staff once again.
672 This doesn't seem to support cross-staff tuplets atm.
674 if (*dy == 0
675 && fabs (*offset) < ss * Staff_symbol_referencer::staff_radius (me))
677 // quantize, then do collision check.
678 *offset *= 2 / ss;
680 *offset = rint (*offset);
681 if (Staff_symbol_referencer::on_line (me, (int) rint (*offset)))
682 *offset += dir;
684 *offset *= 0.5 * ss;
688 MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_direction, 1);
690 Tuplet_bracket::calc_direction (SCM smob)
692 Grob *me = unsmob_grob (smob);
693 Direction dir = Tuplet_bracket::get_default_dir (me);
694 return scm_from_int (dir);
697 MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_positions, 1);
699 Tuplet_bracket::calc_positions (SCM smob)
701 Spanner *me = unsmob_spanner (smob);
703 Real dy = 0.0;
704 Real offset = 0.0;
705 calc_position_and_height (me, &offset, &dy);
707 SCM x = scm_cons (scm_from_double (offset),
708 scm_from_double (offset + dy));
710 return x;
714 similar to beam ?
716 Direction
717 Tuplet_bracket::get_default_dir (Grob *me)
719 Drul_array<int> dirs (0, 0);
720 extract_grob_set (me, "note-columns", columns);
721 for (vsize i = 0; i < columns.size (); i++)
723 Grob *nc = columns[i];
724 Direction d = Note_column::dir (nc);
725 if (d)
726 dirs[d]++;
729 return dirs[UP] >= dirs[DOWN] ? UP : DOWN;
732 void
733 Tuplet_bracket::add_column (Grob *me, Item *n)
735 Pointer_group_interface::add_grob (me, ly_symbol2scm ("note-columns"), n);
736 add_bound_item (dynamic_cast<Spanner *> (me), n);
739 void
740 Tuplet_bracket::add_tuplet_bracket (Grob *me, Grob *bracket)
742 Pointer_group_interface::add_grob (me, ly_symbol2scm ("tuplets"), bracket);
745 MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_cross_staff, 1);
747 Tuplet_bracket::calc_cross_staff (SCM smob)
749 Grob *me = unsmob_grob (smob);
750 extract_grob_set (me, "note-columns", cols);
751 extract_grob_set (me, "tuplets", tuplets);
753 Grob *commony = common_refpoint_of_array (cols, me, Y_AXIS);
754 commony = common_refpoint_of_array (tuplets, commony, Y_AXIS);
755 if (Grob *st = Staff_symbol_referencer::get_staff_symbol (me))
756 commony = st->common_refpoint (commony, Y_AXIS);
757 if (me->check_cross_staff (commony))
758 return SCM_BOOL_T;
760 bool equally_long = false;
761 Grob *par_beam = parallel_beam (me, cols, &equally_long);
763 if (par_beam && to_boolean (par_beam->get_property ("cross-staff")))
764 return SCM_BOOL_T;
766 for (vsize i = 0; i < cols.size (); i++)
768 Grob *stem = unsmob_grob (cols[i]->get_object ("stem"));
769 if (stem && to_boolean (stem->get_property ("cross-staff")))
770 return SCM_BOOL_T;
773 return SCM_BOOL_F;
776 ADD_INTERFACE (Tuplet_bracket,
777 "A bracket with a number in the middle, used for tuplets."
778 " When the bracket spans a line break, the value of"
779 " @code{break-overshoot} determines how far it extends"
780 " beyond the staff. At a line break, the markups in the"
781 " @code{edge-text} are printed at the edges.",
783 /* properties */
784 "bracket-flare "
785 "bracket-visibility "
786 "break-overshoot "
787 "connect-to-neighbor "
788 "control-points "
789 "direction "
790 "edge-height "
791 "edge-text "
792 "full-length-padding "
793 "full-length-to-extent "
794 "gap "
795 "positions "
796 "note-columns "
797 "padding "
798 "tuplet-number "
799 "shorten-pair "
800 "staff-padding "
801 "thickness "
802 "tuplets "