]> git.donarmstrong.com Git - lilypond.git/blob - lily/side-position-interface.cc
*** empty log message ***
[lilypond.git] / lily / side-position-interface.cc
1 /*   
2   staff-side.cc --  implement Staff_side_element
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1998--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9 #include <math.h>               // ceil.
10
11 #include "side-position-interface.hh"
12 #include "warn.hh"
13 #include "warn.hh"
14 #include "dimensions.hh"
15 #include "staff-symbol-referencer.hh"
16 #include "group-interface.hh"
17 #include "directional-element-interface.hh"
18 #include "staff-symbol-referencer.hh"
19
20 void
21 Side_position_interface::add_support (Grob*me, Grob*e)
22 {
23   Pointer_group_interface::add_grob (me, ly_symbol2scm ("side-support-elements"), e);
24 }
25
26 Direction
27 Side_position_interface::get_direction (Grob*me)
28 {
29   SCM d = me->get_grob_property ("direction");
30   if (is_direction (d) && to_dir (d))
31     return to_dir (d);
32
33   Direction relative_dir = Direction (1);
34   SCM reldir = me->get_grob_property ("side-relative-direction");       // should use a lambda.
35   if (is_direction (reldir))
36     {
37       relative_dir = to_dir (reldir);
38     }
39   
40   SCM other_elt = me->get_grob_property ("direction-source");
41   Grob * e = unsmob_grob (other_elt);
42   if (e)
43     {
44       return (Direction) (relative_dir * get_grob_direction (e));
45     }
46   
47   return CENTER;
48 }
49   
50
51 MAKE_SCHEME_CALLBACK (Side_position_interface,aligned_on_support_extents, 2);
52 SCM
53 Side_position_interface::aligned_on_support_extents (SCM element_smob, SCM axis)
54 {
55   Grob *me = unsmob_grob (element_smob);
56   Axis a = (Axis) gh_scm2int (axis);
57
58   return general_side_position (me, a, true);
59 }
60
61
62 /*
63  Puts the element next to the support, optionally taking in
64  account the extent of the support.
65 */
66 SCM
67 Side_position_interface::general_side_position (Grob * me, Axis a, bool use_extents)
68 {
69   Real ss = Staff_symbol_referencer::staff_space (me);
70   SCM support = me->get_grob_property ("side-support-elements");
71   Grob *common = common_refpoint_of_list (support, me->get_parent (a), a);
72   Grob * st = Staff_symbol_referencer::get_staff_symbol (me);
73   bool include_staff = (st
74                         && a == Y_AXIS
75                         && gh_number_p (me->get_grob_property ("staff-padding")));
76
77   Interval dim;
78   if (include_staff)
79     {
80       common = st->common_refpoint (common, Y_AXIS);
81       dim = st->extent (common, Y_AXIS);
82     }
83     
84   for (SCM s = support; s != SCM_EOL; s = ly_cdr (s))
85     {
86       Grob * e  = unsmob_grob (ly_car (s));
87       if (e)
88         if (use_extents)
89           dim.unite (e->extent (common, a));
90         else
91           {
92             Real x = e->relative_coordinate (common, a);
93             dim.unite (Interval (x,x));
94           }
95     }
96
97   if (dim.is_empty ())
98     {
99       dim = Interval (0,0);
100     }
101
102   Direction dir = Side_position_interface::get_direction (me);
103     
104   Real off =  me->get_parent (a)->relative_coordinate (common, a);
105   Real  minimum_space = ss * robust_scm2double (me->get_grob_property ("minimum-space"),  -1);
106
107   Real total_off = dim.linear_combination (dir) - off;
108   total_off += dir * ss * robust_scm2double (me->get_grob_property ("padding"), 0);
109
110   if (minimum_space >= 0
111       && dir
112       && total_off * dir < minimum_space)
113     {
114       total_off = minimum_space * dir;
115     }
116
117   if (fabs (total_off) > 100 CM)
118     programming_error ("Huh ? Improbable staff side dim.");
119
120
121   
122   
123   return gh_double2scm (total_off);
124 }
125
126 /*
127   Cut & paste (ugh.)
128  */
129 MAKE_SCHEME_CALLBACK (Side_position_interface,aligned_on_support_refpoints,2);
130 SCM
131 Side_position_interface::aligned_on_support_refpoints (SCM smob, SCM axis)
132 {
133   Grob *me = unsmob_grob (smob);
134   Axis a = (Axis) gh_scm2int (axis);
135
136   return general_side_position (me, a, false); 
137 }
138
139
140
141
142 Real
143 directed_round (Real f, Direction d)
144 {
145   if (d < 0)
146     return floor (f);
147   else
148     return ceil (f);
149 }
150
151 /*
152   Callback that quantises in staff-spaces, rounding in the direction
153   of the elements "direction" elt property.
154
155   Only rounds when we're inside the staff, as determined by
156   Staff_symbol_referencer::staff_radius () */
157 MAKE_SCHEME_CALLBACK (Side_position_interface,quantised_position,2);
158 SCM
159 Side_position_interface::quantised_position (SCM element_smob, SCM)
160 {
161   Grob *me = unsmob_grob (element_smob);
162   
163   Direction d = Side_position_interface::get_direction (me);
164
165   Grob * stsym = Staff_symbol_referencer::get_staff_symbol (me);
166   if (stsym)
167     {
168       Real p = Staff_symbol_referencer::get_position (me);
169       Real rp = directed_round (p, d);
170       Real rad = Staff_symbol_referencer::staff_radius (me) *2 ;
171       int ip = int (rp);
172
173       if (abs (ip) <= rad && Staff_symbol_referencer::on_staffline (me,ip))
174         {
175           ip += d;
176           rp += d;
177         }
178
179       return gh_double2scm ((rp - p) * Staff_symbol_referencer::staff_space (me) / 2.0);
180     }
181   return gh_double2scm (0.0);
182 }
183
184 /*
185   Position next to support, taking into account my own dimensions and padding.
186  */
187 MAKE_SCHEME_CALLBACK (Side_position_interface,aligned_side,2);
188 SCM
189 Side_position_interface::aligned_side (SCM element_smob, SCM axis)
190 {
191   Grob *me = unsmob_grob (element_smob);
192   Axis a = (Axis) gh_scm2int (axis);
193   
194   Direction d = Side_position_interface::get_direction (me);
195   
196   Real o = gh_scm2double (aligned_on_support_extents (element_smob,axis));
197
198   Interval iv =  me->extent (me, a);
199
200   if (!iv.is_empty ())
201     {
202       if (!d)
203         {
204           programming_error ("Direction unknown, but aligned-side wanted.");
205           d = DOWN;
206         }
207       o += - iv[-d];
208     }
209
210   /*
211   Maintain a minimum distance to the staff. This is similar to side
212   position with padding, but it will put adjoining objects on a row if
213   stuff sticks out of the staff a little.
214  */
215   Grob * st = Staff_symbol_referencer::get_staff_symbol (me);
216   if (st && a == Y_AXIS
217       && gh_number_p (me->get_grob_property ("staff-padding")))
218     {
219       Real padding=
220       Staff_symbol_referencer::staff_space (me)
221       * gh_scm2double (me->get_grob_property ("staff-padding"));
222   
223       Grob *common = me->common_refpoint (st, Y_AXIS);
224       
225       Interval staff_size = st->extent (common, Y_AXIS);
226       Interval me_ext = me->extent (common, a);
227       Real diff =  d*staff_size[d] + padding - d*(o + iv[-d]);
228       o += (d*  (diff >? 0));
229     }
230       
231   return gh_double2scm (o);
232 }
233
234
235 void
236 Side_position_interface::set_axis (Grob*me, Axis a)
237 {
238   me->add_offset_callback (Side_position_interface::aligned_side_proc, a);
239 }
240
241
242
243 // ugh. doesn't catch all variants. 
244 Axis
245 Side_position_interface::get_axis (Grob*me)
246 {
247   if (me->has_offset_callback_b (Side_position_interface::aligned_side_proc, X_AXIS)
248       || me->has_offset_callback_b (Side_position_interface::aligned_side_proc , X_AXIS))
249     return X_AXIS;
250
251   
252   return Y_AXIS;
253 }
254
255
256
257
258 ADD_INTERFACE (Side_position_interface,"side-position-interface",
259                "Position a victim object (this one) next to other objects (the "
260                "support).  In this case, the property @code{direction} signifies where to put the  "
261                "victim object relative to the support (left or right, up or down?)\n\n "
262                "The routine also takes the size the staff into account if "
263                "@code{staff-padding} is set. If undefined, the staff symbol is ignored." 
264                ,
265                "staff-padding side-support-elements direction-source "
266                "direction side-relative-direction minimum-space padding");