2 staff-side.cc -- implement Staff_side_element
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include <math.h> // ceil.
11 #include "side-position-interface.hh"
14 #include "dimensions.hh"
15 #include "staff-symbol-referencer.hh"
16 #include "group-interface.hh"
17 #include "directional-element-interface.hh"
20 Side_position_interface::add_support (Grob*me, Grob*e)
22 Pointer_group_interface::add_grob (me, ly_symbol2scm ("side-support-elements"), e);
28 Side_position_interface::get_direction (Grob*me)
30 SCM d = me->get_grob_property ("direction");
31 if (ly_dir_p (d) && to_dir (d))
34 Direction relative_dir = Direction (1);
35 SCM reldir = me->get_grob_property ("side-relative-direction"); // should use a lambda.
36 if (ly_dir_p (reldir))
38 relative_dir = to_dir (reldir);
41 SCM other_elt = me->get_grob_property ("direction-source");
42 Grob * e = unsmob_grob (other_elt);
45 return (Direction) (relative_dir * Directional_element_interface::get (e));
52 MAKE_SCHEME_CALLBACK (Side_position_interface,aligned_on_support_extents, 2);
54 Side_position_interface::aligned_on_support_extents (SCM element_smob, SCM axis)
56 Grob *me = unsmob_grob (element_smob);
57 Axis a = (Axis) gh_scm2int (axis);
59 return general_side_position (me, a, true);
64 Puts the element next to the support, optionally taking in
65 account the extent of the support.
68 Side_position_interface::general_side_position (Grob * me, Axis a, bool use_extents)
73 As this is only used as a callback, this is called only once. We
74 could wipe SIDE-SUPPORT-ELEMENTS after we retrieve it to conserve
75 memory; however -- we should look more into benefits of such actions?
77 The benefit is small, it seems: total GC times taken don't
78 differ. Would this also hamper Generational GC ?
81 SCM support = me->get_grob_property ("side-support-elements");
82 Grob *common = common_refpoint_of_list (support, me->get_parent (a), a);
85 for (SCM s = support; s != SCM_EOL; s = ly_cdr (s))
87 Grob * e = unsmob_grob (ly_car (s));
90 dim.unite (e->extent (common, a));
93 Real x = e->relative_coordinate (common, a);
94 dim.unite (Interval (x,x));
100 dim = Interval (0,0);
103 Direction dir = Side_position_interface::get_direction (me);
105 Real off = me->get_parent (a)->relative_coordinate (common, a);
106 SCM minimum = me->remove_grob_property ("minimum-space");
108 Real total_off = dim.linear_combination (dir) - off;
109 SCM padding = me->remove_grob_property ("padding");
110 if (gh_number_p (padding))
112 total_off += gh_scm2double (padding) * dir;
115 if (gh_number_p (minimum)
117 && total_off * dir < gh_scm2double (minimum))
119 total_off = gh_scm2double (minimum) * dir;
122 if (fabs (total_off) > 100 CM)
123 programming_error ("Huh ? Improbable staff side dim.");
125 return gh_double2scm (total_off);
131 MAKE_SCHEME_CALLBACK (Side_position_interface,aligned_on_support_refpoints,2);
133 Side_position_interface::aligned_on_support_refpoints (SCM smob, SCM axis)
135 Grob *me = unsmob_grob (smob);
136 Axis a = (Axis) gh_scm2int (axis);
138 return general_side_position (me, a, false);
145 directed_round (Real f, Direction d)
154 Callback that quantises in staff-spaces, rounding in the direction
155 of the elements "direction" elt property.
157 Only rounds when we're inside the staff, as determined by
158 Staff_symbol_referencer::staff_radius () */
159 MAKE_SCHEME_CALLBACK (Side_position_interface,quantised_position,2);
161 Side_position_interface::quantised_position (SCM element_smob, SCM)
163 Grob *me = unsmob_grob (element_smob);
166 Direction d = Side_position_interface::get_direction (me);
168 if (Staff_symbol_referencer::has_interface (me))
170 Real p = Staff_symbol_referencer::position_f (me);
171 Real rp = directed_round (p, d);
172 Real rad = Staff_symbol_referencer::staff_radius (me) *2 ;
175 if (abs (ip) <= rad && Staff_symbol_referencer::on_staffline (me,ip))
181 return gh_double2scm ((rp - p) * Staff_symbol_referencer::staff_space (me) / 2.0);
183 return gh_double2scm (0.0);
187 Position next to support, taking into account my own dimensions and padding.
189 MAKE_SCHEME_CALLBACK (Side_position_interface,aligned_side,2);
191 Side_position_interface::aligned_side (SCM element_smob, SCM axis)
193 Grob *me = unsmob_grob (element_smob);
194 Axis a = (Axis) gh_scm2int (axis);
196 Direction d = Side_position_interface::get_direction (me);
198 Real o = gh_scm2double (aligned_on_support_extents (element_smob,axis));
200 Interval iv = me->extent (me, a);
206 programming_error ("Direction unknown, but aligned-side wanted.");
211 SCM pad = me->get_grob_property ("padding");
212 if (gh_number_p (pad))
213 o += d *gh_scm2double (pad) ;
215 return gh_double2scm (o);
219 Side_position_interface::add_staff_support (Grob*me)
221 Grob* st = Staff_symbol_referencer::staff_symbol_l (me);
222 if (st && get_axis (me) == Y_AXIS)
229 Side_position_interface::set_axis (Grob*me, Axis a)
231 me->add_offset_callback (Side_position_interface::aligned_side_proc, a);
236 // ugh. doesn't cactch all variants.
238 Side_position_interface::get_axis (Grob*me)
240 if (me->has_offset_callback_b (Side_position_interface::aligned_side_proc, X_AXIS)
241 || me->has_offset_callback_b (Side_position_interface::aligned_side_proc , X_AXIS))
249 Side_position_interface::set_direction (Grob*me, Direction d)
251 me->set_grob_property ("direction", gh_int2scm (d));
255 Side_position_interface::set_minimum_space (Grob*me, Real m)
257 me->set_grob_property ("minimum-space", gh_double2scm (m));
261 Side_position_interface::set_padding (Grob*me, Real p)
263 me->set_grob_property ("padding", gh_double2scm (p));
268 Side_position_interface::supported_b (Grob*me)
270 SCM s = me->get_grob_property ("side-support-elements");
271 return gh_pair_p (s);
277 ADD_INTERFACE (Side_position_interface,"side-position-interface",
278 "Position a victim object (this one) next to other objects (the
279 support). In this case, the direction signifies where to put the
280 victim object relative to the support (left or right, up or down?)
282 "side-support-elements direction-source direction side-relative-direction minimum-space padding");