]> git.donarmstrong.com Git - lilypond.git/blob - lily/align-element.cc
patch::: 1.3.1.hwn1
[lilypond.git] / lily / align-element.cc
1 /*
2   align-elem.cc -- implement Align_elem
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "align-element.hh"
10 #include "interval.hh"
11 #include "direction.hh"
12 #include "debug.hh"
13 #include "hash-table-iter.hh"
14 #include "dimension-cache.hh"
15
16 struct Align_element_content {
17   Graphical_element * elem_l_;
18   int priority_i_;
19   
20   static int compare (Align_element_content const &h1, 
21                       Align_element_content const &h2) 
22     {
23       return h1.priority_i_ - h2.priority_i_;
24     }
25   Align_element_content (Graphical_element *elem_l, int p) 
26     {
27       priority_i_ = p;
28       elem_l_ = elem_l;
29     }
30   Align_element_content () {
31     elem_l_ = 0;
32     priority_i_ = 0;
33   }
34 };
35
36
37
38 void
39 Align_element::add_element (Score_element*el_l)
40 {
41   int p = elem_l_arr_.size ();
42   add_element_priority (el_l, p);
43 }
44
45 void
46 Align_element::add_element_priority (Score_element *el, int p)
47 {
48   assert (! contains_b (el));
49   Axis_group_element::add_element (el);
50   priority_i_hash_[el] = p;
51   add_dependency (el);
52 }
53
54 void
55 Align_element::do_substitute_element_pointer (Score_element*o,
56                                               Score_element*n)
57 {
58   Axis_group_element :: do_substitute_element_pointer (o,n);
59   if (o == center_l_)
60     {
61       center_l_ = n;
62     }
63   if (priority_i_hash_.elem_b (o))
64     {
65       priority_i_hash_[n] = priority_i_hash_[o];
66       /*
67         Huh? It seems the old pointers are still used.  Why?
68        */
69       // priority_i_hash_.remove (o);
70     }
71 }
72
73 void
74 Align_element::do_post_processing()
75 {
76   if (axis () == Y_AXIS)
77     do_side_processing ();
78 }
79
80 void
81 Align_element::do_pre_processing ()
82 {
83   if (axis () == X_AXIS)
84     do_side_processing ();
85 }
86
87 void
88 Align_element::do_side_processing ()
89 {
90   Array<Interval> dims;
91
92   Link_array<Score_element> elems;
93   for (int i=0; i < elem_l_arr_.size(); i++) 
94     {
95       Interval y = elem_l_arr_[i]->extent(axis ()) + elem_l_arr_[i]->relative_coordinate (this, axis ());
96       if (!y.empty_b())
97         {
98           Score_element *e =dynamic_cast<Score_element*>(elem_l_arr_[i]);
99
100           // todo: fucks up if item both in Halign & Valign. 
101           SCM min_dims = e->remove_elt_property ("minimum-space");
102           if (min_dims != SCM_UNDEFINED)
103             {
104               y.unite (Interval (gh_scm2double (SCM_CAR (min_dims)),
105                                  gh_scm2double (SCM_CDR (min_dims))));
106             }
107           
108           SCM extra_dims = e->remove_elt_property ("extra-space");
109           if (extra_dims != SCM_UNDEFINED)
110             {
111               y[LEFT] += gh_scm2double (SCM_CAR (extra_dims));
112               y[RIGHT] += gh_scm2double (SCM_CDR (extra_dims));
113             }
114
115           elems.push (e);
116           dims.push (y);          
117         }
118     }
119
120   Real where_f=0;
121   Real center_f = 0.0;
122   for (int i=0 ;  i < elems.size(); i++) 
123     {
124       Real dy = - stacking_dir_ * dims[i][-stacking_dir_];
125       if (i)
126         dy += stacking_dir_ * dims[i-1][stacking_dir_];
127
128       if (i)
129         {
130           dy = (dy >? threshold_interval_[SMALLER] )
131             <? threshold_interval_[BIGGER];
132         }
133
134       if (!i && align_dir_ == LEFT)
135         center_f = where_f;
136       else if (align_dir_ == CENTER && elems[i] == center_l_)
137         center_f = where_f;
138
139       where_f += stacking_dir_ * dy;
140       elems[i]->translate_axis (where_f, axis ());
141     }
142
143   if (dims.size ())
144     where_f += dims.top ()[stacking_dir_];
145   if (align_dir_ == RIGHT)
146     center_f = where_f;
147   else if (align_dir_ == CENTER && !center_l_)
148     center_f = where_f / 2;
149     
150   if (center_f)
151     translate_axis ( - center_f, axis ());
152
153   dim_cache_[axis ()]->invalidate ();
154 }
155
156 Align_element::Align_element()
157 {
158   ordered_b_ = true;
159   threshold_interval_ = Interval (0, Interval::infinity ());
160   stacking_dir_ = DOWN;
161   align_dir_ = CENTER;
162   center_l_ =0;
163   priority_i_hash_.hash_func_ = pointer_hash;
164 }
165
166 Axis
167 Align_element::axis () const
168 {
169   return axes_[0];
170 }
171
172 void
173 Align_element::set_axis (Axis a)
174 {
175   set_axes (a,a);
176 }
177
178
179 bool
180 Align_element::contains_b (Score_element const *e) const
181 {
182   return elem_l_arr_.find_l (e);
183 }
184
185 void
186 Align_element::sort_elements ()
187 {
188   Array<Align_element_content> content;
189   for  (int i =0; i < elem_l_arr_.size(); i++)
190     {
191       Score_element * e = dynamic_cast<Score_element*> (elem_l_arr_[i]);
192       assert (priority_i_hash_.elem_b (e));
193       int p = priority_i_hash_[e];
194       content.push (Align_element_content (e, p));
195     }
196   content.sort (Align_element_content::compare);
197   
198   elem_l_arr_.clear();
199   priority_i_hash_.clear();
200
201   for  (int i =0; i < content.size(); i++) 
202     {
203       elem_l_arr_.push (content[i].elem_l_);
204     }
205 }
206
207 void
208 Align_element::do_print () const
209 {
210 #ifndef NPRINT
211   DEBUG_OUT << "contains: ";
212   for (int i=0 ;  i < elem_l_arr_.size(); i++) 
213     DEBUG_OUT << classname (elem_l_arr_[i]) << ", ";
214 #endif
215 }
216
217 Score_element*
218 Align_element::get_elt_by_priority (int p) const
219 {
220   for (Hash_table_iter<Score_element*, int>  i(priority_i_hash_); i.ok (); i++)
221     {
222       if (i.val () == p)
223         return i.key();
224     }
225   return 0;
226 }
227
228 int
229 Align_element::get_priority (Score_element const * e) const
230 {
231   Score_element * nonconst = (Score_element*) e;
232   if ( priority_i_hash_.elem_b (nonconst))
233     return priority_i_hash_[nonconst];
234   else
235     return elem_l_arr_.find_i (nonconst);
236 }
237