]> git.donarmstrong.com Git - lilypond.git/blob - lily/side-position-interface.cc
patch::: 1.3.17.jcn2
[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--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "side-position-interface.hh"
11 #include "staff-symbol.hh"
12 #include "debug.hh"
13 #include "warn.hh"
14 #include "dimensions.hh"
15 #include "dimension-cache.hh"
16 #include "staff-symbol-referencer.hh"
17
18 Side_position_interface::Side_position_interface (Score_element const *e)
19 {
20   elt_l_ = (Score_element*)e;
21 }
22
23
24 void
25 Side_position_interface::add_support (Score_element*e)
26 {
27   SCM sup = elt_l_->get_elt_property ("side-support");
28   elt_l_->set_elt_property ("side-support",
29                             gh_cons (e->self_scm_,sup));
30 }
31
32
33
34 Direction
35 Side_position_interface::get_direction () const
36 {
37   SCM d = elt_l_->get_elt_property ("direction");
38   if (isdir_b (d))
39     return to_dir (d) ? to_dir (d) : DOWN;
40
41   Direction relative_dir = UP;
42   SCM reldir = elt_l_->get_elt_property ("side-relative-direction");    // should use a lambda.
43   if (isdir_b (reldir))
44     {
45       relative_dir = to_dir (reldir);
46     }
47   
48   SCM other_elt = elt_l_->get_elt_property ("direction-source");
49   Score_element * e = unsmob_element(other_elt);
50   if (e)
51     {
52       return (Direction)(relative_dir * Side_position_interface (e).get_direction ());
53     }
54   
55   return DOWN;
56 }
57   
58 /**
59    Callback that does the aligning.
60  */
61 Real
62 Side_position_interface::side_position (Dimension_cache const * c)
63 {
64   Score_element * me = dynamic_cast<Score_element*> (c->element_l ());
65
66   Interval dim;
67   Axis  axis = c->axis ();
68   Score_element *common = me->parent_l (axis);
69   SCM support = me->get_elt_property ("side-support");
70   for (SCM s = support; s != SCM_EOL; s = gh_cdr (s))
71     {
72       Score_element * e  = unsmob_element ( gh_car (s));
73       if (e)
74         common = common->common_refpoint (e, axis);
75     }
76   
77   for (SCM s = support; s != SCM_EOL; s = gh_cdr (s))
78     {
79
80       Score_element * e  = unsmob_element ( gh_car (s));
81       if (e)
82         {
83           Real coord = e->relative_coordinate (common, axis);
84
85           dim.unite (coord + e->extent (axis));
86         }
87     }
88
89   if (dim.empty_b ())
90     {
91       dim = Interval(0,0);
92     }
93
94   Real off =  me->parent_l (axis)->relative_coordinate (common, axis);
95
96
97   Direction dir = Side_position_interface (me).get_direction ();
98     
99   SCM pad = me->remove_elt_property ("padding");
100   if (gh_number_p (pad))
101     {
102       off += gh_scm2double (pad) * dir;
103     }
104   Real total_off = dim[dir] + off;
105
106   if (fabs (total_off) > 100 CM)
107     programming_error ("Huh ? Improbable staff side dim.");
108
109   return total_off;
110 }
111
112 Real
113 Side_position_interface::self_alignment (Dimension_cache const *c)
114 {
115   String s ("self-alignment-");
116   Axis ax = c->axis ();
117   s +=  (ax == X_AXIS) ? "X" : "Y";
118   Score_element *elm = dynamic_cast<Score_element*> (c->element_l ());
119   SCM align (elm->get_elt_property (s));
120   if (isdir_b (align))
121     {
122       Direction d = to_dir (align);
123       Interval ext(elm->extent (ax));
124       if (d)
125         {
126           return - ext[d];
127         }
128       return - ext.center ();
129     }
130   else
131     return 0.0;
132 }
133
134
135 Real
136 directed_round (Real f, Direction d)
137 {
138   if (d < 0)
139     return floor (f);
140   else
141     return ceil (f);
142 }
143
144 Real
145 Side_position_interface::quantised_position (Dimension_cache const *c)
146 {
147   Score_element * me = dynamic_cast<Score_element*> (c->element_l ());
148   Side_position_interface s(me);
149   Direction d = s.get_direction ();
150   Staff_symbol_referencer_interface si (me);
151
152   if (si.has_interface_b ())
153     {
154       Real p = si.position_f ();
155       Real rp = directed_round (p, d);
156
157       int ip = int  (rp);
158       if ((ip % 2) == 0)
159         {
160           ip += d;
161           rp += d;
162         }
163
164       return (rp - p) * si.staff_space () / 2.0;
165     }
166   return 0.0;
167 }
168
169 Real
170 Side_position_interface::aligned_side (Dimension_cache const *c)
171 {
172   Score_element * me = dynamic_cast<Score_element*> (c->element_l ());
173   Side_position_interface s(me);
174   Direction d = s.get_direction ();
175   Axis ax = c->axis ();
176   Real o = side_position (c);
177
178   Interval iv =  me->extent (ax);
179
180   if (!iv.empty_b ())
181     {
182       o += - iv[-d];
183
184       SCM pad = me->get_elt_property ("padding");
185       if (gh_number_p (pad))
186         o += d *gh_scm2double (pad) ; 
187     }
188   return o;
189 }
190
191
192
193
194 void
195 Side_position_interface::set_axis (Axis a)
196 {
197   // prop transparent ? 
198   if (elt_l_->get_elt_property ("side-support") == SCM_UNDEFINED)
199     elt_l_->set_elt_property ("side-support" ,SCM_EOL);
200
201   elt_l_->dim_cache_[a]->off_callbacks_.push (aligned_side);
202 }
203
204
205 void
206 Side_position_interface::set_quantised (Axis a)
207 {
208   Dimension_cache * c = elt_l_->dim_cache_[a];
209   
210   c->off_callbacks_.push (quantised_position);
211 }
212
213 Axis
214 Side_position_interface::get_axis () const
215 {
216   Dimension_cache * c =  elt_l_->dim_cache_[X_AXIS];
217   for (int i=0 ; i < c->off_callbacks_.size();i ++)
218     if (c->off_callbacks_[i] == side_position
219         ||c->off_callbacks_[i] == aligned_side)
220       return X_AXIS;
221
222   
223   return Y_AXIS;
224 }
225
226 void
227 Side_position_interface::set_direction (Direction d) 
228 {
229   elt_l_->set_elt_property ("direction", gh_int2scm (d));
230 }
231
232 bool
233 Side_position_interface::has_interface_b () const
234 {
235   return elt_l_->get_elt_property ("side-support") != SCM_UNDEFINED;
236 }
237
238 bool
239 Side_position_interface::supported_b () const
240 {
241   SCM s =elt_l_->get_elt_property  ("side-support"); 
242   return s != SCM_UNDEFINED && s != SCM_EOL;
243 }