]> git.donarmstrong.com Git - lilypond.git/blob - lily/line-of-score.cc
release: 1.3.55
[lilypond.git] / lily / line-of-score.cc
1 /*
2   scoreline.cc -- implement Line_of_score
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1996--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "axis-group-interface.hh"
10 #include "debug.hh"
11 #include "line-of-score.hh"
12 #include "main.hh"
13 #include "paper-column.hh"
14 #include "paper-def.hh"
15 #include "paper-outputter.hh"
16 #include "paper-score.hh"
17 #include "string.hh"
18 #include "warn.hh"
19 #include "dimensions.hh"
20 #include "molecule.hh"
21 #include "all-font-metrics.hh"
22
23 Line_of_score::Line_of_score()
24   : Spanner (SCM_EOL)
25 {
26   set_elt_pointer ("columns", SCM_EOL);
27   set_elt_pointer ("all-elements", SCM_EOL);
28
29   Axis_group_interface (this).set_interface ();
30   Axis_group_interface (this).set_axes (Y_AXIS,X_AXIS);
31 }
32
33 int
34 Line_of_score::element_count () const
35 {
36   return scm_ilength ( get_elt_pointer ("all-elements"));
37 }
38
39
40 /*
41   Ugh.  this is grossly hairy.
42  */
43 void
44 Line_of_score::typeset_element (Score_element * elem_p)
45 {
46   elem_p->pscore_l_ = pscore_l_;
47   Pointer_group_interface (this, "all-elements").add_element (elem_p);
48   scm_unprotect_object (elem_p->self_scm_);
49 }
50
51 void
52 Line_of_score::output_lines ()
53 {
54   for (SCM s = get_elt_pointer ("all-elements");
55        gh_pair_p (s); s = gh_cdr (s))
56     {
57       unsmob_element (gh_car (s))->do_break_processing ();
58     }
59   /*
60     fixups must be done in broken line_of_scores, because new elements
61     are put over there.  */
62   int count = 0;
63   for (int i=0; i < broken_into_l_arr_.size (); i++)
64     {
65       Score_element *se = broken_into_l_arr_[i];
66       SCM all = se->get_elt_pointer ("all-elements");
67       for (SCM s = all; gh_pair_p (s); s = gh_cdr (s))
68         {
69           unsmob_element (gh_car (s))->fixup_refpoint ();
70         }
71       count += scm_ilength (all);
72     }
73
74   
75   /*
76     needed for doing items.
77    */
78   for (SCM s = get_elt_pointer ("all-elements");
79        gh_pair_p (s); s = gh_cdr (s))
80     {
81       unsmob_element (gh_car (s))->fixup_refpoint ();
82     }
83   
84   for (SCM s = get_elt_pointer ("all-elements");
85        gh_pair_p (s); s = gh_cdr (s))
86     {
87       unsmob_element (gh_car (s))->handle_broken_dependencies ();
88     }
89   handle_broken_dependencies ();
90   progress_indication ( _f("Element count %d.",  count + element_count()));
91
92   
93   for (int i=0; i < broken_into_l_arr_.size (); i++)
94     {
95       Line_of_score *line_l = dynamic_cast<Line_of_score*> (broken_into_l_arr_[i]);
96
97       progress_indication ("[");
98       line_l->post_processing ();
99       progress_indication (to_str (i));
100       progress_indication ("]");
101     }
102 }
103
104 // const?
105 void
106 Line_of_score::break_into_pieces (Array<Column_x_positions> const &breaking)
107 {
108   for (int i=0; i < breaking.size (); i++)
109     {
110       Line_of_score *line_l = dynamic_cast <Line_of_score*> (clone());
111       line_l->rank_i_ = i;
112       Link_array<Paper_column> c (breaking[i].cols_);
113       pscore_l_->typeset_line (line_l);
114       
115       line_l->set_bound(LEFT,c[0]);
116       line_l->set_bound(RIGHT,c.top ());
117       for (int j=0; j < c.size(); j++)
118         {
119           c[j]->translate_axis (breaking[i].config_[j],X_AXIS);
120           c[j]->line_l_ = line_l;
121         }
122       
123       broken_into_l_arr_.push (line_l);
124     }
125 }
126
127
128 void
129 Line_of_score::output_molecule (SCM expr, Offset o)
130 {
131   SCM offset_sym = ly_symbol2scm ("translate-molecule");
132   SCM combine_sym = ly_symbol2scm ("combine-molecule");
133 enter:
134
135   if (!gh_pair_p (expr))
136     return;
137   
138   SCM head =gh_car (expr);
139   if (head == offset_sym)
140     {
141       o += ly_scm2offset (gh_cadr (expr));
142       expr = gh_caddr (expr);
143       goto enter;
144     }
145   else if (head == combine_sym)
146     {
147       output_molecule (gh_cadr (expr), o);
148       expr = gh_caddr (expr);
149       goto enter;               // tail recursion
150     }
151   else
152     {
153       pscore_l_->outputter_l_->
154         output_scheme (gh_list (ly_symbol2scm ("placebox"),
155                                 gh_double2scm (o[X_AXIS]),
156                                 gh_double2scm (o[Y_AXIS]),
157                                 expr,
158                                 SCM_UNDEFINED));
159     }
160 }
161
162 void
163 Line_of_score::output_scheme (SCM s)
164 {
165   pscore_l_->outputter_l_->output_scheme (s);
166 }
167
168 void
169 Line_of_score::add_column (Paper_column*p)
170 {
171   SCM cs = get_elt_pointer ("columns");
172   Score_element * prev =  gh_pair_p (cs) ? unsmob_element (gh_car (cs)) : 0;
173   int rank = prev ? dynamic_cast<Paper_column*> (prev)->rank_i () + 1 : 0; 
174
175   p->set_rank (rank);
176   set_elt_pointer ("columns",  gh_cons (p->self_scm_, cs));
177
178   Axis_group_interface (this).add_element (p);
179   typeset_element (p);
180 }
181
182 Link_array<Paper_column>
183 Line_of_score::column_l_arr ()const
184 {
185   Link_array<Paper_column> acs
186     = Pointer_group_interface__extract_elements (this, (Paper_column*) 0, "columns");
187   bool bfound = false;
188   for (int i= acs.size (); i -- ; )
189     {
190       bool brb = acs[i]->breakable_b();
191       bfound = bfound || brb;
192
193       /*
194         the last column should be breakable. Weed out any columns that
195         seem empty. We need to retain breakable columns, in case
196         someone forced a breakpoint.
197       */
198       if (!bfound || !acs[i]->used_b ())
199         acs.del (i);
200     }
201   return acs;
202 }
203
204 void
205 fixup_refpoints (SCM s)
206 {
207   for (; gh_pair_p (s); s = gh_cdr (s))
208     {
209       Score_element * se = unsmob_element (gh_car (s));
210       if (se)
211         {
212           se->fixup_refpoint ();
213           if (!dynamic_cast<Line_of_score*> (se) && !se->parent_l (Y_AXIS))
214             {
215               programming_error ("No parent!");
216             }
217         }
218     }
219 }
220
221
222 void
223 Line_of_score::pre_processing ()
224 {
225   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
226     unsmob_element (gh_car (s))->discretionary_processing ();
227
228   progress_indication ( _f("Element count %d ",  element_count ()));
229
230   
231   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
232     unsmob_element (gh_car (s))->handle_prebroken_dependencies ();
233   
234   fixup_refpoints (get_elt_pointer ("all-elements"));
235   
236   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
237     {
238       Score_element* sc = unsmob_element (gh_car (s));
239       sc->calculate_dependencies (PRECALCED, PRECALCING, &Score_element::before_line_breaking);
240     }
241   
242   progress_indication ("\n" + _ ("Calculating column positions...") + " " );
243   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
244     unsmob_element (gh_car (s))->do_space_processing ();
245 }
246
247 void
248 Line_of_score::post_processing ()
249 {
250   for (SCM s = get_elt_pointer ("all-elements");
251        gh_pair_p (s); s = gh_cdr (s))
252     {
253       Score_element* sc = unsmob_element (gh_car (s));
254       sc->calculate_dependencies (POSTCALCED, POSTCALCING, &Score_element::after_line_breaking);
255     }
256
257   Interval i(extent(Y_AXIS));
258   if (i.empty_b())
259     programming_error ("Huh?  Empty Line_of_score?");
260   else
261     translate_axis (- i[MAX], Y_AXIS);
262
263   Real height = i.length ();
264   if (height > 50 CM)
265     {
266       programming_error ("Improbable system height");
267       height = 50 CM;
268     }
269
270   /*
271     generate all molecules  to trigger all font loads.
272
273     (ugh. This is not very memory efficient.)  */
274   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
275     unsmob_element (gh_car (s))->get_molecule ();
276   
277   /*
278     font defs;
279    */
280   SCM font_names = ly_quote_scm (all_fonts_global_p->font_descriptions ());  
281   output_scheme (gh_list (ly_symbol2scm ("define-fonts"),
282                                         font_names,
283                                         SCM_UNDEFINED));
284
285   /*
286     line preamble.
287    */
288   output_scheme (gh_list (ly_symbol2scm ("start-line"),
289                           gh_double2scm (height),
290                           SCM_UNDEFINED));
291   
292   Real il = paper_l ()->get_var ("interline");
293
294   /*
295     all elements.
296    */ 
297   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
298     {
299       Score_element * sc =  unsmob_element (gh_car (s));
300       Molecule m = sc->get_molecule ();
301       
302       Offset o (sc->relative_coordinate (this, X_AXIS),
303                 sc->relative_coordinate (this, Y_AXIS));
304
305       SCM e = sc->get_elt_property ("extra-offset");
306       if (gh_pair_p (e))
307         {
308           o[X_AXIS] += il * gh_scm2double (gh_car (e));
309           o[Y_AXIS] += il * gh_scm2double (gh_cdr (e));      
310         }
311
312       output_molecule (m.get_expr (), o);
313     }
314   output_scheme (gh_list (ly_symbol2scm ("stop-line"), SCM_UNDEFINED));
315 }
316
317
318 Link_array<Item> 
319 Line_of_score::broken_col_range (Item const*l, Item const*r) const
320 {
321   Link_array<Item> ret;
322
323   l = l->column_l ();
324   r = r->column_l ();
325   SCM s = get_elt_pointer ("columns");
326
327   while (gh_car (s) != r->self_scm_)
328     s = gh_cdr  (s);
329     
330
331   s = gh_cdr (s);
332   
333   while (gh_car (s) != l->self_scm_)
334     {
335       Paper_column *c
336         = dynamic_cast<Paper_column*> (unsmob_element (gh_car (s)));
337       if (c->breakable_b () && !c->line_l_)
338         ret.push (c);
339
340       s = gh_cdr  (s);
341     }
342
343   ret.reverse ();
344   return ret;
345 }
346
347
348