source file of the GNU LilyPond music typesetter
- (c) 1997--2005 Jan Nieuwenhuizen <janneke@gnu.org>
+ (c) 1997--2006 Jan Nieuwenhuizen <janneke@gnu.org>
Han-Wen Nienhuys <hanwen@xs4all.nl>
*/
#include "line-interface.hh"
#include "beam.hh"
#include "warn.hh"
-#include "font-interface.hh"
#include "output-def.hh"
+#include "font-interface.hh"
#include "text-interface.hh"
#include "stem.hh"
#include "note-column.hh"
return g;
}
+
+void
+flatten_number_pair_property (Grob *me,
+ Direction xdir, SCM sym)
+{
+ Drul_array<Real> zero (0, 0);
+ Drul_array<Real> pair = robust_scm2drul (me->internal_get_property (sym), zero);
+ pair[xdir] = 0.0;
+
+ me->internal_set_property (sym, ly_interval2scm (pair));
+}
+
+
Grob *
Tuplet_bracket::parallel_beam (Grob *me_grob, Link_array<Grob> const &cols, bool *equally_long)
{
return beams[LEFT];
}
-/*
- TODO:
- in the case that there is no bracket, but there is a (single) beam,
- follow beam precisely for determining tuplet number location.
-*/
-MAKE_SCHEME_CALLBACK (Tuplet_bracket, print, 1);
+MAKE_SCHEME_CALLBACK(Tuplet_bracket,calc_connect_to_neighbors,1);
SCM
-Tuplet_bracket::print (SCM smob)
+Tuplet_bracket::calc_connect_to_neighbors (SCM smob)
{
Spanner *me = unsmob_spanner (smob);
- Stencil mol;
- extract_grob_set (me, "note-columns", columns);
- {
- SCM lp = me->get_property ("left-position");
- SCM rp = me->get_property ("right-position");
+ Direction dir = get_grob_direction (me);
+ Drul_array<Item *> bounds (get_x_bound_item (me, LEFT, dir),
+ get_x_bound_item (me, RIGHT, dir));
+
+ Drul_array<bool> connect_to_other (false, false);
+ Direction d = LEFT;
+ do
+ {
+ Direction break_dir = bounds[d]->break_status_dir ();
+
+ Spanner *orig_spanner = dynamic_cast<Spanner*> (me->original ());
- if (!scm_is_number (rp) || !scm_is_number (lp))
- {
- /*
- UGH. dependency tracking!
- */
- extract_grob_set (me, "tuplets", tuplets);
- for (int i = 0; i < tuplets.size (); i++)
- Tuplet_bracket::print (tuplets[i]->self_scm ());
+ int neighbor_idx = me->get_break_index () - break_dir;
+ if (break_dir
+ && d == RIGHT
+ && neighbor_idx < orig_spanner->broken_intos_.size ())
+ {
+ Grob *neighbor = orig_spanner->broken_intos_[neighbor_idx];
- after_line_breaking (smob);
- }
- }
+ /* trigger possible suicide*/
+ (void) neighbor->get_property ("positions");
+ }
- Real ly = robust_scm2double (me->get_property ("left-position"), 0);
- Real ry = robust_scm2double (me->get_property ("right-position"), 0);
+ connect_to_other[d]
+ = (break_dir
+ && (neighbor_idx < orig_spanner->broken_intos_.size ()
+ && neighbor_idx >= 0)
+ && orig_spanner->broken_intos_[neighbor_idx]->is_live ());
+ }
+ while (flip (&d) != LEFT);
- bool equally_long = false;
- Grob *par_beam = parallel_beam (me, columns, &equally_long);
- Spanner *sp = dynamic_cast<Spanner *> (me);
- bool bracket_visibility = !(par_beam && equally_long);
- bool number_visibility = true;
+ if (connect_to_other[LEFT] || connect_to_other[RIGHT])
+ return scm_cons (scm_from_bool (connect_to_other[LEFT]),
+ scm_from_bool (connect_to_other[RIGHT]));
+
+ return SCM_EOL;
+}
- /*
- Fixme: the type of this prop is sucky.
- */
- SCM bracket = me->get_property ("bracket-visibility");
- if (scm_is_bool (bracket))
- bracket_visibility = ly_scm2bool (bracket);
- else if (bracket == ly_symbol2scm ("if-no-beam"))
- bracket_visibility = !par_beam;
+Grob*
+Tuplet_bracket::get_common_x (Spanner *me)
+{
+ extract_grob_set (me, "note-columns", columns);
- SCM numb = me->get_property ("number-visibility");
- if (scm_is_bool (numb))
- number_visibility = ly_scm2bool (numb);
- else if (numb == ly_symbol2scm ("if-no-beam"))
- number_visibility = !par_beam;
+ Grob * commonx = common_refpoint_of_array (columns, me, X_AXIS);
+ commonx = commonx->common_refpoint (me->get_bound (LEFT), X_AXIS);
+ commonx = commonx->common_refpoint (me->get_bound (RIGHT), X_AXIS);
+
+ return commonx;
+}
+
+MAKE_SCHEME_CALLBACK(Tuplet_bracket,calc_control_points,1)
+SCM
+Tuplet_bracket::calc_control_points (SCM smob)
+{
+ Spanner *me = unsmob_spanner (smob);
- Grob *commonx = common_refpoint_of_array (columns, me, X_AXIS);
- commonx = commonx->common_refpoint (sp->get_bound (LEFT), X_AXIS);
- commonx = commonx->common_refpoint (sp->get_bound (RIGHT), X_AXIS);
+ extract_grob_set (me, "note-columns", columns);
+ Drul_array<Real> positions
+ = ly_scm2realdrul (me->get_property ("positions"));
+
+ Grob *commonx = get_common_x (me);
Direction dir = get_grob_direction (me);
Drul_array<Item *> bounds;
bounds[LEFT] = get_x_bound_item (me, LEFT, dir);
bounds[RIGHT] = get_x_bound_item (me, RIGHT, dir);
- Drul_array<bool> connect_to_other;
+ Drul_array<bool> connect_to_other =
+ robust_scm2booldrul (me->get_property ("connect-to-neighbor"),
+ Drul_array<bool> (false, false));
+
+
Interval x_span;
Direction d = LEFT;
do
{
x_span[d] = robust_relative_extent (bounds[d], commonx, X_AXIS)[d];
- Direction break_dir = bounds[d]->break_status_dir ();
- Spanner *orig_spanner = dynamic_cast<Spanner *> (me->original_);
-
- int neighbor_idx = me->get_break_index () - break_dir;
-
- /*
- UGH. dependency handling.
- */
- if (break_dir
- && d == RIGHT
- && neighbor_idx < orig_spanner->broken_intos_.size ())
- {
- Grob *neighbor = orig_spanner->broken_intos_[neighbor_idx];
-
- // ugh, should inspect callback?
- Tuplet_bracket::after_line_breaking (neighbor->self_scm ());
- }
-
- connect_to_other[d]
- = (break_dir
- && (neighbor_idx < orig_spanner->broken_intos_.size ()
- && neighbor_idx >= 0)
- && orig_spanner->broken_intos_[neighbor_idx]->is_live ());
-
if (connect_to_other[d])
{
}
while (flip (&d) != LEFT);
- Real w = x_span.length ();
- SCM number = me->get_property ("text");
+
+
+ x_span -= me->get_bound (LEFT)->relative_coordinate (commonx, X_AXIS);
+ return scm_list_2 (ly_offset2scm (Offset (x_span[LEFT], positions[LEFT])),
+ ly_offset2scm (Offset (x_span[RIGHT], positions[RIGHT])));
+}
- Output_def *pap = me->get_layout ();
- Stencil num;
- if (scm_is_string (number) && number_visibility)
- {
- SCM properties = Font_interface::text_font_alist_chain (me);
- SCM snum = Text_interface::interpret_markup (pap->self_scm (),
- properties, number);
- num = *unsmob_stencil (snum);
- num.align_to (X_AXIS, CENTER);
- num.translate_axis (w / 2, X_AXIS);
- num.align_to (Y_AXIS, CENTER);
+/*
+ TODO:
- num.translate_axis ((ry - ly) / 2, Y_AXIS);
+ in the case that there is no bracket, but there is a (single) beam,
+ follow beam precisely for determining tuplet number location.
+*/
+MAKE_SCHEME_CALLBACK (Tuplet_bracket, print, 1);
+SCM
+Tuplet_bracket::print (SCM smob)
+{
+ Spanner *me = unsmob_spanner (smob);
+ Stencil mol;
- mol.add_stencil (num);
+ extract_grob_set (me, "note-columns", columns);
+ bool equally_long = false;
+ Grob *par_beam = parallel_beam (me, columns, &equally_long);
+
+ bool bracket_visibility = !(par_beam && equally_long);
+ /*
+ Fixme: the type of this prop is sucky.
+ */
+ SCM bracket = me->get_property ("bracket-visibility");
+ if (scm_is_bool (bracket))
+ bracket_visibility = ly_scm2bool (bracket);
+ else if (bracket == ly_symbol2scm ("if-no-beam"))
+ bracket_visibility = !par_beam;
+
+
+ SCM cpoints = me->get_property ("control-points");
+ if (scm_ilength (cpoints) < 2)
+ {
+ me->suicide ();
+ return SCM_EOL;
}
+
+ Drul_array<Offset> points;
+ points[LEFT] = ly_scm2offset (scm_car (cpoints));
+ points[RIGHT] = ly_scm2offset (scm_cadr (cpoints));
+
+ Interval x_span (points[LEFT][X_AXIS], points[RIGHT][X_AXIS]);
+ Drul_array<Real> positions (points[LEFT][Y_AXIS], points[RIGHT][Y_AXIS]);
+
+
+ Output_def *pap = me->layout ();
+
+ Grob *number_grob = unsmob_grob (me->get_object ("tuplet-number"));
+
/*
No bracket when it would be smaller than the number.
-
- TODO: should use GAP in calculation too.
*/
- if (bracket_visibility && number_visibility
- && mol.extent (X_AXIS).length () > w)
- bracket_visibility = false;
+ Real gap = 0.;
+ if (bracket_visibility && number_grob)
+ {
+ Interval ext = number_grob->extent (number_grob, X_AXIS);
+ if (!ext.is_empty ())
+ {
+ gap = ext.length () + 1.0;
+
+ if (0.75 * x_span.length () < gap)
+ bracket_visibility = false;
+ }
+ }
if (bracket_visibility)
{
- Real gap = 0.;
-
- if (!num.extent (X_AXIS).is_empty ())
- gap = num.extent (X_AXIS).length () + 1.0;
-
Drul_array<Real> zero (0, 0);
Real ss = Staff_symbol_referencer::staff_space (me);
Drul_array<Real> height
= robust_scm2drul (me->get_property ("shorten-pair"), zero);
Drul_array<Stencil> edge_stencils;
+ Direction dir = get_grob_direction (me);
+
scale_drul (&height, -ss * dir);
scale_drul (&flare, ss);
scale_drul (&shorten, ss);
+
+ Drul_array<bool> connect_to_other =
+ robust_scm2booldrul (me->get_property ("connect-to-neighbor"),
+ Drul_array<bool> (false, false));
+
+ Direction d = LEFT;
do
{
if (connect_to_other[d])
SCM text = index_get_cell (edge_text, d);
if (Text_interface::is_markup (text))
{
- SCM t = Text_interface::interpret_markup (pap->self_scm (), properties, text);
+ SCM t = Text_interface::interpret_markup (pap->self_scm (),
+ properties, text);
Stencil *edge_text = unsmob_stencil (t);
edge_text->translate_axis (x_span[d] - x_span[LEFT], X_AXIS);
while (flip (&d) != LEFT);
Stencil brack = make_bracket (me, Y_AXIS,
- Offset (w, ry - ly),
+ points[RIGHT] - points[LEFT],
height,
/*
0.1 = more space at right due to italics
mol.add_stencil (brack);
}
- mol.translate_axis (ly, Y_AXIS);
- mol.translate_axis (x_span[LEFT]
- - sp->get_bound (LEFT)->relative_coordinate (commonx, X_AXIS), X_AXIS);
+ mol.translate (points[LEFT]);
return mol.smobbed_copy ();
}
if (Grob *st = Staff_symbol_referencer::get_staff_symbol (me))
commony = st->common_refpoint (commony, Y_AXIS);
- Grob *commonx = common_refpoint_of_array (columns, me, X_AXIS);
+ Grob *commonx = get_common_x (me);
commonx = common_refpoint_of_array (tuplets, commonx, Y_AXIS);
- commonx = commonx->common_refpoint (me->get_bound (LEFT), X_AXIS);
- commonx = commonx->common_refpoint (me->get_bound (RIGHT), X_AXIS);
Interval staff;
if (Grob *st = Staff_symbol_referencer::get_staff_symbol (me))
{
- staff = st->extent (commony, Y_AXIS);
- Real pad = robust_scm2double (me->get_property ("staff-padding"), 0.5);
- staff.widen (pad);
+ Real pad = robust_scm2double (me->get_property ("staff-padding"), -1.0);
+ if (pad >= 0.0)
+ {
+ staff = st->extent (commony, Y_AXIS);
+ staff.widen (pad);
+ }
}
Direction dir = get_grob_direction (me);
Interval tuplet_y (tuplets[i]->extent (commony, Y_AXIS));
Direction d = LEFT;
- Real lp = scm_to_double (tuplets[i]->get_property ("left-position"));
- Real rp = scm_to_double (tuplets[i]->get_property ("right-position"));
- Real other_dy = rp - lp;
+ Drul_array<Real> positions = ly_scm2realdrul (tuplets[i]->get_property ("positions"));
+
+
+ Real other_dy = positions[RIGHT] - positions[LEFT];
do
{
*offset *= 2 / ss;
*offset = rint (*offset);
- if (Staff_symbol_referencer::on_staffline (me, (int) rint (*offset)))
+ if (Staff_symbol_referencer::on_line (me, (int) rint (*offset)))
*offset += dir;
*offset *= 0.5 * ss;
}
}
-/*
- We depend on the beams if there are any.
-*/
-MAKE_SCHEME_CALLBACK (Tuplet_bracket, before_line_breaking, 1);
+
+MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_direction, 1);
SCM
-Tuplet_bracket::before_line_breaking (SCM smob)
+Tuplet_bracket::calc_direction (SCM smob)
{
Grob *me = unsmob_grob (smob);
- extract_grob_set (me, "note-columns", columns);
-
- for (int i = columns.size (); i--;)
- {
- Grob *s = Note_column::get_stem (columns[i]);
- Grob *b = s ? Stem::get_beam (s) : 0;
- if (b)
- me->add_dependency (b);
- }
- return SCM_UNSPECIFIED;
+ Direction dir = Tuplet_bracket::get_default_dir (me);
+ return scm_from_int (dir);
}
-MAKE_SCHEME_CALLBACK (Tuplet_bracket, after_line_breaking, 1);
+MAKE_SCHEME_CALLBACK (Tuplet_bracket, calc_positions, 1);
SCM
-Tuplet_bracket::after_line_breaking (SCM smob)
+Tuplet_bracket::calc_positions (SCM smob)
{
Grob *me = unsmob_grob (smob);
extract_grob_set (me, "note-columns", columns);
- if (columns.is_empty())
- {
- me->suicide ();
- return SCM_UNSPECIFIED;
- }
-
Direction dir = get_grob_direction (me);
- if (!dir)
- {
- dir = Tuplet_bracket::get_default_dir (me);
- set_grob_direction (me, dir);
- }
-
bool equally_long = false;
Grob *par_beam = parallel_beam (me, columns, &equally_long);
dy = rp - lp;
}
- SCM lp = me->get_property ("left-position");
- SCM rp = me->get_property ("right-position");
-
- if (scm_is_number (lp) && !scm_is_number (rp))
- rp = scm_from_double (scm_to_double (lp) + dy);
- else if (scm_is_number (rp) && !scm_is_number (lp))
- lp = scm_from_double (scm_to_double (rp) - dy);
- else if (!scm_is_number (rp) && !scm_is_number (lp))
- {
- lp = scm_from_double (offset);
- rp = scm_from_double (offset + dy);
- }
-
- me->set_property ("left-position", lp);
- me->set_property ("right-position", rp);
-
- return SCM_UNSPECIFIED;
+
+ SCM x = scm_cons (scm_from_double (offset),
+ scm_from_double (offset + dy));
+
+ return x;
}
/*
Tuplet_bracket::add_column (Grob *me, Item *n)
{
Pointer_group_interface::add_grob (me, ly_symbol2scm ("note-columns"), n);
- me->add_dependency (n);
-
add_bound_item (dynamic_cast<Spanner *> (me), n);
}
Tuplet_bracket::add_tuplet_bracket (Grob *me, Grob *bracket)
{
Pointer_group_interface::add_grob (me, ly_symbol2scm ("tuplets"), bracket);
- me->add_dependency (bracket);
}
ADD_INTERFACE (Tuplet_bracket,
"At a line break, the markups in the @code{edge-text} are printed "
"at the edges. ",
-
+
+ /* properties */
"bracket-flare "
"bracket-visibility "
"break-overshoot "
+ "connect-to-neighbor "
+ "control-points "
"direction "
"edge-height "
"edge-text "
- "left-position "
+ "gap "
+ "positions "
"note-columns "
- "number-visibility "
"padding "
- "right-position "
+ "tuplet-number "
"shorten-pair "
"staff-padding "
"thickness "
"tuplets ");
+