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