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