Remove debug code.
[lilypond.git] / lily / side-position-interface.cc
blobceede5d9f1c6d65a5130aa587d0a9de348a5788d
1 /*
2 side-position-interface.cc -- implement Side_position_interface
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
9 #include "side-position-interface.hh"
11 #include <cmath> // ceil.
12 #include <algorithm>
14 using namespace std;
16 #include "directional-element-interface.hh"
17 #include "grob.hh"
18 #include "main.hh"
19 #include "misc.hh"
20 #include "note-head.hh"
21 #include "pointer-group-interface.hh"
22 #include "staff-symbol-referencer.hh"
23 #include "staff-symbol.hh"
24 #include "stem.hh"
25 #include "string-convert.hh"
26 #include "warn.hh"
28 void
29 Side_position_interface::add_support (Grob *me, Grob *e)
31 Pointer_group_interface::add_unordered_grob (me, ly_symbol2scm ("side-support-elements"), e);
34 Direction
35 Side_position_interface::get_direction (Grob *me)
37 Direction relative_dir = Direction (1);
38 SCM reldir = me->get_property ("side-relative-direction");
39 if (is_direction (reldir))
40 relative_dir = to_dir (reldir);
42 SCM other_elt = me->get_object ("direction-source");
43 Grob *e = unsmob_grob (other_elt);
44 if (e)
45 return (Direction) (relative_dir * get_grob_direction (e));
47 return CENTER;
50 /* Put the element next to the support, optionally taking in
51 account the extent of the support.
53 Does not take into account the extent of ME.
55 SCM
56 Side_position_interface::general_side_position (Grob *me, Axis a, bool use_extents,
57 bool include_my_extent,
58 bool pure, int start, int end,
59 Real *current_offset)
61 Real ss = Staff_symbol_referencer::staff_space (me);
63 extract_grob_set (me, "side-support-elements", support);
65 Grob *common = common_refpoint_of_array (support, me->get_parent (a), a);
66 Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me);
67 bool include_staff =
68 staff_symbol
69 && a == Y_AXIS
70 && scm_is_number (me->get_property ("staff-padding"))
71 && !to_boolean (me->get_property ("quantize-position"));
73 Interval dim;
74 Interval staff_extents;
75 if (include_staff)
77 common = staff_symbol->common_refpoint (common, Y_AXIS);
78 staff_extents = staff_symbol->maybe_pure_extent (common, Y_AXIS, pure, start, end);
80 if (include_staff)
81 dim.unite (staff_extents);
84 Direction dir = get_grob_direction (me);
86 for (vsize i = 0; i < support.size (); i++)
88 Grob *e = support[i];
90 // In the case of a stem, we will find a note head as well
91 // ignoring the stem solves cyclic dependencies if the stem is
92 // attached to a cross-staff beam.
93 if (a == Y_AXIS
94 && Stem::has_interface (e)
95 && dir == - get_grob_direction (e))
96 continue;
98 if (e)
100 if (use_extents)
101 dim.unite (e->maybe_pure_extent (common, a, pure, start, end));
102 else
104 Real x = e->maybe_pure_coordinate (common, a, pure, start, end);
105 dim.unite (Interval (x, x));
110 if (dim.is_empty ())
111 dim = Interval (0, 0);
113 Real off = me->get_parent (a)->maybe_pure_coordinate (common, a, pure, start, end);
114 Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1);
116 Real total_off = dim.linear_combination (dir) - off;
117 total_off += dir * ss * robust_scm2double (me->get_property ("padding"), 0);
119 if (minimum_space >= 0
120 && dir
121 && total_off * dir < minimum_space)
122 total_off = minimum_space * dir;
124 if (include_my_extent)
126 Interval iv = me->maybe_pure_extent (me, a, pure, start, end);
127 if (!iv.is_empty ())
129 if (!dir)
131 programming_error ("direction unknown, but aligned-side wanted");
132 dir = DOWN;
134 total_off += -iv[-dir];
138 if (current_offset)
139 total_off = dir * max (dir * total_off,
140 dir * (*current_offset));
143 /* FIXME: 1000 should relate to paper size. */
144 if (fabs (total_off) > 1000)
146 string msg
147 = String_convert::form_string ("Improbable offset for grob %s: %f",
148 me->name ().c_str (), total_off);
150 programming_error (msg);
151 if (strict_infinity_checking)
152 scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL);
154 return scm_from_double (total_off);
158 MAKE_SCHEME_CALLBACK (Side_position_interface, y_aligned_on_support_refpoints, 1);
160 Side_position_interface::y_aligned_on_support_refpoints (SCM smob)
162 return general_side_position (unsmob_grob (smob), Y_AXIS, false, false, false, 0, 0, 0);
165 MAKE_SCHEME_CALLBACK (Side_position_interface, pure_y_aligned_on_support_refpoints, 3);
167 Side_position_interface::pure_y_aligned_on_support_refpoints (SCM smob, SCM start, SCM end)
169 return general_side_position (unsmob_grob (smob), Y_AXIS, false, false,
170 true, scm_to_int (start), scm_to_int (end), 0);
175 Position next to support, taking into account my own dimensions and padding.
178 axis_aligned_side_helper (SCM smob, Axis a, bool pure, int start, int end, SCM current_off_scm)
180 Real r;
181 Real *current_off_ptr = 0;
182 if (scm_is_number (current_off_scm))
184 r = scm_to_double (current_off_scm);
185 current_off_ptr = &r;
188 return Side_position_interface::aligned_side (unsmob_grob (smob), a, pure, start, end, current_off_ptr);
192 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, x_aligned_side, 2, 1, "");
194 Side_position_interface::x_aligned_side (SCM smob, SCM current_off)
196 return axis_aligned_side_helper (smob, X_AXIS, false, 0, 0, current_off);
199 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, y_aligned_side, 2, 1, "");
201 Side_position_interface::y_aligned_side (SCM smob, SCM current_off)
203 return axis_aligned_side_helper (smob, Y_AXIS, false, 0, 0, current_off);
206 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, pure_y_aligned_side, 4, 1, "");
208 Side_position_interface::pure_y_aligned_side (SCM smob, SCM start, SCM end, SCM cur_off)
210 return axis_aligned_side_helper (smob, Y_AXIS, true,
211 scm_to_int (start),
212 scm_to_int (end),
213 cur_off);
216 MAKE_SCHEME_CALLBACK (Side_position_interface, calc_cross_staff, 1)
218 Side_position_interface::calc_cross_staff (SCM smob)
220 Grob *me = unsmob_grob (smob);
221 extract_grob_set (me, "side-support-elements", elts);
223 for (vsize i = 0; i < elts.size (); i++)
224 if (to_boolean (elts[i]->get_property ("cross-staff")))
225 return SCM_BOOL_T;
227 Grob *common = common_refpoint_of_array (elts, me->get_parent (Y_AXIS), Y_AXIS);
228 return scm_from_bool (common != me->get_parent (Y_AXIS));
232 Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, int end,
233 Real *current_off)
235 Direction dir = get_grob_direction (me);
237 Real o = scm_to_double (general_side_position (me, a, true, true, pure, start, end, current_off));
240 Maintain a minimum distance to the staff. This is similar to side
241 position with padding, but it will put adjoining objects on a row if
242 stuff sticks out of the staff a little.
244 Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
245 if (staff && a == Y_AXIS)
247 if (to_boolean (me->get_property ("quantize-position")))
249 Grob *common = me->common_refpoint (staff, Y_AXIS);
250 Real my_off = me->get_parent (Y_AXIS)->maybe_pure_coordinate (common, Y_AXIS, pure, start, end);
251 Real staff_off = staff->maybe_pure_coordinate (common, Y_AXIS, pure, start, end);
252 Real ss = Staff_symbol::staff_space (staff);
253 Real position = 2 * (my_off + o - staff_off) / ss;
254 Real rounded = directed_round (position, dir);
255 Grob *head = me->get_parent (X_AXIS);
257 if (fabs (position) <= 2 * Staff_symbol_referencer::staff_radius (me) + 1
258 /* In case of a ledger lines, quantize even if we're outside the staff. */
259 || (Note_head::has_interface (head)
261 && abs (Staff_symbol_referencer::get_position (head)) > abs (position)))
263 o += (rounded - position) * 0.5 * ss;
264 if (Staff_symbol_referencer::on_line (me, int (rounded)))
265 o += dir * 0.5 * ss;
268 else if (scm_is_number (me->get_property ("staff-padding")) && dir)
270 Interval iv = me->maybe_pure_extent (me, a, pure, start, end);
272 Real padding
273 = Staff_symbol_referencer::staff_space (me)
274 * scm_to_double (me->get_property ("staff-padding"));
276 Grob *common = me->common_refpoint (staff, Y_AXIS);
278 Interval staff_size = staff->maybe_pure_extent (common, Y_AXIS, pure, start, end);
279 Real diff = dir*staff_size[dir] + padding - dir * (o + iv[-dir]);
280 o += dir * max (diff, 0.0);
283 return scm_from_double (o);
286 void
287 Side_position_interface::set_axis (Grob *me, Axis a)
289 if (!scm_is_number (me->get_property ("side-axis")))
291 me->set_property ("side-axis", scm_from_int (a));
292 chain_offset_callback (me,
293 (a==X_AXIS)
294 ? x_aligned_side_proc
295 : y_aligned_side_proc,
300 Axis
301 Side_position_interface::get_axis (Grob *me)
303 if (scm_is_number (me->get_property ("side-axis")))
304 return Axis (scm_to_int (me->get_property ("side-axis")));
306 string msg = String_convert::form_string ("side-axis not set for grob %s.",
307 me->name ().c_str ());
308 me->programming_error (msg);
309 return NO_AXES;
312 ADD_INTERFACE (Side_position_interface,
313 "Position a victim object (this one) next to other objects"
314 " (the support). The property @code{direction} signifies where"
315 " to put the victim object relative to the support (left or"
316 " right, up or down?)\n"
317 "\n"
318 "The routine also takes the size of the staff into account if"
319 " @code{staff-padding} is set. If undefined, the staff symbol"
320 " is ignored.",
322 /* properties */
323 "direction "
324 "direction-source "
325 "minimum-space "
326 "padding "
327 "quantize-position "
328 "side-axis "
329 "side-relative-direction "
330 "side-support-elements "
331 "slur-padding "
332 "staff-padding "