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->get_grob_property ("minimum-space");
108 Real total_off = dim.linear_combination (dir) - off;
109 SCM padding = me->get_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::get_position (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 return gh_double2scm (o);
215 Side_position_interface::add_staff_support (Grob*me)
217 Grob* st = Staff_symbol_referencer::get_staff_symbol (me);
218 if (st && get_axis (me) == Y_AXIS)
225 Side_position_interface::set_axis (Grob*me, Axis a)
227 me->add_offset_callback (Side_position_interface::aligned_side_proc, a);
232 // ugh. doesn't cactch all variants.
234 Side_position_interface::get_axis (Grob*me)
236 if (me->has_offset_callback_b (Side_position_interface::aligned_side_proc, X_AXIS)
237 || me->has_offset_callback_b (Side_position_interface::aligned_side_proc , X_AXIS))
245 Side_position_interface::set_direction (Grob*me, Direction d)
247 me->set_grob_property ("direction", gh_int2scm (d));
251 Side_position_interface::set_minimum_space (Grob*me, Real m)
253 me->set_grob_property ("minimum-space", gh_double2scm (m));
257 Side_position_interface::set_padding (Grob*me, Real p)
259 me->set_grob_property ("padding", gh_double2scm (p));
264 Side_position_interface::supported_b (Grob*me)
266 SCM s = me->get_grob_property ("side-support-elements");
267 return gh_pair_p (s);
273 ADD_INTERFACE (Side_position_interface,"side-position-interface",
274 "Position a victim object (this one) next to other objects (the
275 support). In this case, the direction signifies where to put the
276 victim object relative to the support (left or right, up or down?)
278 "side-support-elements direction-source direction side-relative-direction minimum-space padding");