]> git.donarmstrong.com Git - lilypond.git/blob - lily/break-align-item.cc
91ea3fea3eb6eeba8048081075f92e5f1df5acf7
[lilypond.git] / lily / break-align-item.cc
1 /*
2   break-align-item.cc -- implement Break_align_item
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
10 #include <math.h>
11 #include <libc-extension.hh>
12
13 #include "side-position-interface.hh"
14 #include "axis-group-interface.hh"
15 #include "warn.hh"
16 #include "lily-guile.hh"
17 #include "break-align-item.hh"
18 #include "dimensions.hh"
19 #include "paper-def.hh"
20 #include "paper-column.hh"
21 #include "group-interface.hh"
22 #include "align-interface.hh"
23
24 MAKE_SCHEME_CALLBACK(Break_align_item,before_line_breaking);
25
26 SCM
27 Break_align_item::before_line_breaking (SCM smob)
28 {
29   Score_element* me = unsmob_element (smob);
30   do_alignment (me);
31   return SCM_UNSPECIFIED;
32 }
33
34 Real
35 Break_align_item::alignment_callback (Score_element*c, Axis a)
36 {
37   assert (a == X_AXIS);
38   Score_element *par = c->parent_l (a);
39   if (par && !to_boolean (par->get_elt_property ("break-alignment-done")))\
40     {
41       par->set_elt_property ("break-alignment-done", SCM_BOOL_T);
42       Break_align_item::do_alignment (par);
43     }
44     
45   return 0.0;
46 }
47
48 void
49 Break_align_item::add_element (Score_element*me, Score_element *toadd)
50 {
51   toadd->add_offset_callback (alignment_callback, X_AXIS);
52   Axis_group_interface::add_element (me, toadd);
53 }
54
55 void
56 Break_align_item::do_alignment (Score_element *me)
57 {
58   Item * item = dynamic_cast<Item*> (me);
59   Item *column = item->column_l ();
60   if (item->break_status_dir() == LEFT)
61     {
62       me->set_elt_property ("self-alignment-X", gh_int2scm (RIGHT));
63     }
64   else
65     {
66       me->add_offset_callback (Align_interface::center_on_element, X_AXIS);
67     }
68
69   Real interline= me->paper_l ()->get_var ("staffspace");       
70   Link_array<Score_element> elems;
71   Link_array<Score_element> all_elems
72     = Pointer_group_interface__extract_elements (me, (Score_element*)0,
73                                                  "elements");
74   
75   for (int i=0; i < all_elems.size(); i++) 
76     {
77       Interval y = all_elems[i]->extent(X_AXIS);
78       if (!y.empty_b())
79         elems.push (dynamic_cast<Score_element*> (all_elems[i]));
80     }
81   
82   if (!elems.size ())
83     return;
84
85   SCM symbol_list = SCM_EOL;
86   Array<Real> dists;
87   SCM current_origin = ly_symbol2scm ("none");
88   for (int i=0; i <= elems.size (); i++)
89     {
90       Score_element *next_elt  = i < elems.size ()
91         ? elems[i]
92         : 0 ;
93       
94       SCM next_origin;
95
96       if (next_elt)
97         {
98           next_origin = next_elt->get_elt_property ("break-align-symbol");
99           next_origin =
100             gh_symbol_p (next_origin)? 
101             next_origin : ly_symbol2scm ("none")
102 ;
103         }
104       else
105         next_origin = ly_symbol2scm ("begin-of-note");
106       
107       SCM e = scm_assoc (scm_listify (current_origin,
108                                       next_origin,
109                                       SCM_UNDEFINED),
110                          scm_eval2 (ly_symbol2scm ("space-alist"), SCM_EOL));
111       
112       SCM extra_space;
113       if (e != SCM_BOOL_F)
114         {
115           extra_space = gh_cdr (e);
116         }
117       else
118         {
119           warning (_f ("unknown spacing pair `%s', `%s'",
120                        ly_symbol2string (current_origin),
121                        ly_symbol2string (next_origin)));
122           extra_space = scm_listify (ly_symbol2scm ("minimum-space"), gh_double2scm (0.0), SCM_UNDEFINED);
123         }
124
125       SCM symbol = gh_car  (extra_space);
126       Real spc = gh_scm2double (gh_cadr(extra_space));
127       spc *= interline;
128
129       dists.push(spc);
130       symbol_list = gh_cons (symbol, symbol_list);
131       current_origin = next_origin;
132     }
133
134
135   // skip the first sym.
136   symbol_list  = gh_cdr (scm_reverse (symbol_list));
137   for (int i=0; i <elems.size()-1; i++)
138     {
139       elems[i]->set_elt_property (gh_car  (symbol_list),
140                                   scm_cons (gh_double2scm (0),
141                                             gh_double2scm (dists[i+1])));
142
143       symbol_list = gh_cdr (symbol_list);
144     }
145
146
147   // urg
148   SCM first_pair = elems[0]->get_elt_property ("minimum-space");
149   if (gh_pair_p (first_pair))
150     first_pair = first_pair;
151   else
152     first_pair = gh_cons (gh_double2scm (0.0), gh_double2scm (0.0));
153   
154   scm_set_car_x (first_pair, gh_double2scm (-dists[0]));
155   elems[0]->set_elt_property ("minimum-space", first_pair);
156
157
158   /*
159     Force callbacks for alignment to be called   
160   */
161   Align_interface::do_side_processing (me, X_AXIS);
162
163   Real pre_space = elems[0]->relative_coordinate (column, X_AXIS);
164
165   Real xl = elems[0]->extent (X_AXIS)[LEFT];
166   if (!isinf (xl))
167     pre_space += xl;
168   else
169     programming_error ("Infinity reached. ");
170
171   Real xr = elems.top ()->extent (X_AXIS)[RIGHT];
172   Real spring_len = elems.top ()->relative_coordinate (column, X_AXIS);
173   if (!isinf (xr))
174     spring_len += xr;
175   else
176     programming_error ("Infinity reached.");
177   
178   Real stretch_distance =0.;
179   
180   if (gh_car  (symbol_list) == ly_symbol2scm ("extra-space"))
181     {
182       spring_len += dists.top ();
183       stretch_distance = dists.top ();
184     }
185   else if (gh_car  (symbol_list) == ly_symbol2scm ("minimum-space"))
186     {
187       spring_len = spring_len >? dists.top ();
188       stretch_distance = spring_len;
189     }
190
191   /*
192     Hint the spacing engine how much space to put in.
193
194     The pairs are in the format of an interval (ie. CAR <  CDR).
195   */
196   column->set_elt_property ("extra-space",
197                             scm_cons (gh_double2scm (pre_space),
198                                       gh_double2scm (spring_len)));
199
200   column->set_elt_property ("stretch-distance",
201                             gh_cons (gh_double2scm (-dists[0]),
202                                      gh_double2scm (stretch_distance)));
203
204
205 }
206
207
208 void
209 Break_align_item::set_interface (Score_element*me)
210 {
211   Align_interface::set_interface (me); 
212   Align_interface::set_axis (me,X_AXIS);
213
214   me->add_offset_callback (Side_position::aligned_on_self, X_AXIS);
215 }