]> git.donarmstrong.com Git - lilypond.git/blob - lily/align-element.cc
release: 1.3.36
[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--2000 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 "dimension-cache.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_element::alignment_callback (Dimension_cache const *c)
22 {
23   Axis ax = c->axis ();
24   Score_element * sc = c->element_l ()->parent_l (ax);
25   Align_element * a = dynamic_cast<Align_element*> (sc);
26   if (a && a->get_elt_property ("alignment-done") == SCM_UNDEFINED) 
27     {
28       a->do_side_processing (ax);
29     }
30   return 0.0;
31 }
32
33 void
34 Align_element::add_element (Score_element* s)
35 {
36   s->add_offset_callback (alignment_callback, axis ());
37   axis_group (this).add_element (s);
38 }
39
40 /*
41   Hairy function to put elements where they should be. Can be tweaked
42   from the outside by setting minimum-space and extra-space in its
43   children */
44 void
45 Align_element::do_side_processing (Axis a)
46 {
47   set_elt_property ("alignment-done", SCM_BOOL_T);
48   
49   SCM d = get_elt_property ("stacking-dir");
50   Direction stacking_dir = gh_number_p(d) ? to_dir (d) : CENTER;
51   if (!stacking_dir)
52     stacking_dir = DOWN;
53
54   
55   Array<Interval> dims;
56
57   Link_array<Score_element> elems;
58   Link_array<Score_element> all_elts
59     = Group_interface__extract_elements (this, (Score_element*) 0, "elements");
60   for (int i=0; i < all_elts.size(); i++) 
61     {
62       Interval y = all_elts[i]->extent(a) + all_elts[i]->relative_coordinate (this, a);
63       if (!y.empty_b())
64         {
65           Score_element *e =dynamic_cast<Score_element*>(all_elts[i]);
66
67           // todo: fucks up if item both in Halign & Valign. 
68           SCM min_dims = e->remove_elt_property ("minimum-space");
69           if (gh_pair_p (min_dims) &&
70               gh_number_p (gh_car (min_dims))
71               && gh_number_p (gh_cdr (min_dims)))
72             {
73               y.unite (Interval (gh_scm2double (gh_car  (min_dims)),
74                                  gh_scm2double (gh_cdr (min_dims))));
75             }
76           
77           SCM extra_dims = e->remove_elt_property ("extra-space");
78           if (gh_pair_p (extra_dims) &&
79               gh_number_p (gh_car (extra_dims))
80               && gh_number_p (gh_cdr (extra_dims)))
81             {
82               y[LEFT] += gh_scm2double (gh_car  (extra_dims));
83               y[RIGHT] += gh_scm2double (gh_cdr (extra_dims));
84             }
85
86           elems.push (e);
87           dims.push (y);          
88         }
89     }
90
91   
92   Interval threshold = Interval (0, Interval::infinity ());
93   SCM thr = get_elt_property ("threshold");
94   if (gh_pair_p (thr))
95     {
96       threshold[SMALLER] = gh_scm2double (gh_car (thr));
97       threshold[BIGGER] = gh_scm2double (gh_cdr (thr));      
98     }
99
100   Real where_f=0;
101   for (int i=0 ;  i < elems.size(); i++) 
102     {
103       Real dy = - stacking_dir * dims[i][-stacking_dir];
104       if (i)
105         dy += stacking_dir * dims[i-1][stacking_dir];
106
107       if (i)
108         {
109           dy = (dy >? threshold[SMALLER] )
110             <? threshold[BIGGER];
111         }
112
113       where_f += stacking_dir * dy;
114       elems[i]->translate_axis (where_f, a);
115     }
116 }
117
118
119 int
120 Align_element::get_count (Score_element*s)const
121 {
122   SCM e = get_elt_property ("elements");
123   int c =0;
124   while (gh_pair_p (e))
125     {
126       if (gh_car (e) == s->self_scm_)
127         break;
128       c++;
129       e = gh_cdr (e);
130     }
131   return c;
132 }
133
134 Axis
135 Align_element::axis () const
136 {
137   return Axis (gh_scm2int (gh_car (get_elt_property ("axes"))));
138 }
139
140 void
141 Align_element::set_axis (Axis a)
142 {
143   axis_group (this).set_axes (a, a);
144 }
145
146 Align_element::Align_element ()
147 {
148   axis_group (this).set_interface ();
149 }