]> git.donarmstrong.com Git - lilypond.git/blob - lily/align-interface.cc
release: 1.3.53
[lilypond.git] / lily / align-interface.cc
1 /*   
2   align-interface.cc --  implement Align_interface
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "align-interface.hh"
11 #include "dimension-cache.hh"
12 #include "score-element.hh"
13 #include "group-interface.hh"
14 #include "axis-group-interface.hh"
15
16 /*
17   This callback is set in the children of the align element. It does
18   not compute anything, but a side effect of a->do_side_processing ()
19   is that the elements are placed correctly.  */
20 Real
21 Align_interface::alignment_callback (Dimension_cache const *c)
22 {
23   Axis ax = c->axis ();
24   Score_element * sc = c->element_l ()->parent_l (ax);
25
26   if (sc && sc->get_elt_property ("alignment-done") == SCM_UNDEFINED) 
27     {
28       Align_interface (sc).do_side_processing (ax);
29     }
30   return 0.0;
31 }
32
33
34 Real
35 Align_interface::center_on_element (Dimension_cache const *c)
36 {
37   Score_element *me = c->element_l ();
38   Score_element *cent = unsmob_element (me->get_elt_property ("group-center-element"));
39
40   if (cent)
41     {
42       Real r = cent->relative_coordinate (me,  c->axis ());
43       return -r;
44     }
45   return 0;
46 }
47
48 /*
49   Hairy function to put elements where they should be. Can be tweaked
50   from the outside by setting minimum-space and extra-space in its
51   children */
52 void
53 Align_interface::do_side_processing (Axis a)
54 {
55   elt_l_->set_elt_property ("alignment-done", SCM_BOOL_T);
56   
57   SCM d =   elt_l_->get_elt_property ("stacking-dir");
58   Direction stacking_dir = gh_number_p(d) ? to_dir (d) : CENTER;
59   if (!stacking_dir)
60     stacking_dir = DOWN;
61
62   
63   Array<Interval> dims;
64
65   Link_array<Score_element> elems;
66   Link_array<Score_element> all_elts
67     = Group_interface__extract_elements (  elt_l_, (Score_element*) 0, "elements");
68   for (int i=0; i < all_elts.size(); i++) 
69     {
70       Interval y = all_elts[i]->extent(a) + all_elts[i]->relative_coordinate (elt_l_, a);
71       if (!y.empty_b())
72         {
73           Score_element *e =dynamic_cast<Score_element*>(all_elts[i]);
74
75           // todo: fucks up if item both in Halign & Valign. 
76           SCM min_dims = e->remove_elt_property ("minimum-space");
77           if (gh_pair_p (min_dims) &&
78               gh_number_p (gh_car (min_dims))
79               && gh_number_p (gh_cdr (min_dims)))
80             {
81               y.unite (Interval (gh_scm2double (gh_car  (min_dims)),
82                                  gh_scm2double (gh_cdr (min_dims))));
83             }
84           
85           SCM extra_dims = e->remove_elt_property ("extra-space");
86           if (gh_pair_p (extra_dims) &&
87               gh_number_p (gh_car (extra_dims))
88               && gh_number_p (gh_cdr (extra_dims)))
89             {
90               y[LEFT] += gh_scm2double (gh_car  (extra_dims));
91               y[RIGHT] += gh_scm2double (gh_cdr (extra_dims));
92             }
93
94           elems.push (e);
95           dims.push (y);          
96         }
97     }
98
99   
100   Interval threshold = Interval (0, Interval::infinity ());
101   SCM thr = elt_l_->get_elt_property ("threshold");
102   if (gh_pair_p (thr))
103     {
104       threshold[SMALLER] = gh_scm2double (gh_car (thr));
105       threshold[BIGGER] = gh_scm2double (gh_cdr (thr));      
106     }
107
108   Real where_f=0;
109   for (int i=0 ;  i < elems.size(); i++) 
110     {
111       Real dy = - stacking_dir * dims[i][-stacking_dir];
112       if (i)
113         dy += stacking_dir * dims[i-1][stacking_dir];
114
115       if (i)
116         {
117           dy = (dy >? threshold[SMALLER] )
118             <? threshold[BIGGER];
119         }
120
121       where_f += stacking_dir * dy;
122       elems[i]->translate_axis (where_f, a);
123     }
124 }
125
126
127 Axis
128 Align_interface::axis ()const
129 {
130   return  Axis (gh_scm2int (gh_car (elt_l_->get_elt_property ("axes"))));
131 }
132
133
134 /*
135   should  use generic Scm funcs.
136  */
137 int
138 Align_interface::get_count (Score_element*s)const
139 {
140   SCM e = elt_l_->get_elt_property ("elements");
141   int c =0;
142   while (gh_pair_p (e))
143     {
144       if (gh_car (e) == s->self_scm_)
145         break;
146       c++;
147       e = gh_cdr (e);
148     }
149   return c;
150 }
151
152 void
153 Align_interface::add_element (Score_element* s)
154 {
155   s->add_offset_callback (alignment_callback, axis ());
156   Axis_group_interface (elt_l_).add_element (s);
157   
158 }
159
160 Align_interface::Align_interface (Score_element const*s)
161 {
162   elt_l_ = (Score_element*)s;
163 }
164
165 void
166 Align_interface::set_interface ()
167 {
168   Axis_group_interface (elt_l_).set_interface ();
169
170   Group_interface (elt_l_, "interfaces").add_thing (ly_symbol2scm ("Alignment"));
171 }
172
173 void
174 Align_interface::set_axis (Axis a)
175 {
176   Axis_group_interface (elt_l_).set_axes (a,a );
177 }
178
179 bool
180 Align_interface::has_interface_b ()
181 {
182   SCM ifs  = elt_l_->get_elt_property ("interfaces");
183   if (!gh_pair_p (ifs))
184     return false;
185   
186   return scm_memq (ly_symbol2scm ("Alignment"), ifs) != SCM_BOOL_F;
187 }
188