]> git.donarmstrong.com Git - lilypond.git/blob - lily/line-of-score.cc
patch::: 1.3.59.uu2.jcn1
[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
183 void
184 fixup_refpoints (SCM s)
185 {
186   for (; gh_pair_p (s); s = gh_cdr (s))
187     {
188       Score_element * se = unsmob_element (gh_car (s));
189       if (se)
190         {
191           se->fixup_refpoint ();
192           if (!dynamic_cast<Line_of_score*> (se) && !se->parent_l (Y_AXIS))
193             {
194               programming_error ("No parent!");
195             }
196         }
197     }
198 }
199
200
201 void
202 Line_of_score::pre_processing ()
203 {
204   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
205     unsmob_element (gh_car (s))->discretionary_processing ();
206
207   progress_indication ( _f("Element count %d ",  element_count ()));
208
209   
210   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
211     unsmob_element (gh_car (s))->handle_prebroken_dependencies ();
212   
213   fixup_refpoints (get_elt_pointer ("all-elements"));
214   
215   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
216     {
217       Score_element* sc = unsmob_element (gh_car (s));
218       sc->calculate_dependencies (PRECALCED, PRECALCING, &Score_element::before_line_breaking);
219     }
220   
221   progress_indication ("\n" + _ ("Calculating column positions...") + " " );
222   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
223     unsmob_element (gh_car (s))->do_space_processing ();
224 }
225
226 void
227 Line_of_score::post_processing ()
228 {
229   for (SCM s = get_elt_pointer ("all-elements");
230        gh_pair_p (s); s = gh_cdr (s))
231     {
232       Score_element* sc = unsmob_element (gh_car (s));
233       sc->calculate_dependencies (POSTCALCED, POSTCALCING, &Score_element::after_line_breaking);
234     }
235
236   Interval i(extent(Y_AXIS));
237   if (i.empty_b())
238     programming_error ("Huh?  Empty Line_of_score?");
239   else
240     translate_axis (- i[MAX], Y_AXIS);
241
242   Real height = i.length ();
243   if (height > 50 CM)
244     {
245       programming_error ("Improbable system height");
246       height = 50 CM;
247     }
248
249   /*
250     generate all molecules  to trigger all font loads.
251
252     (ugh. This is not very memory efficient.)  */
253   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
254     unsmob_element (gh_car (s))->get_molecule ();
255   
256   /*
257     font defs;
258    */
259   SCM font_names = ly_quote_scm (all_fonts_global_p->font_descriptions ());  
260   output_scheme (gh_list (ly_symbol2scm ("define-fonts"),
261                                         font_names,
262                                         SCM_UNDEFINED));
263
264   /*
265     line preamble.
266    */
267   output_scheme (gh_list (ly_symbol2scm ("start-line"),
268                           gh_double2scm (height),
269                           SCM_UNDEFINED));
270   
271   Real il = paper_l ()->get_var ("interline");
272
273   /*
274     all elements.
275    */ 
276   for (SCM s = get_elt_pointer ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
277     {
278       Score_element * sc =  unsmob_element (gh_car (s));
279       Molecule m = sc->get_molecule ();
280       
281       Offset o (sc->relative_coordinate (this, X_AXIS),
282                 sc->relative_coordinate (this, Y_AXIS));
283
284       SCM e = sc->get_elt_property ("extra-offset");
285       if (gh_pair_p (e))
286         {
287           o[X_AXIS] += il * gh_scm2double (gh_car (e));
288           o[Y_AXIS] += il * gh_scm2double (gh_cdr (e));      
289         }
290
291       output_molecule (m.get_expr (), o);
292     }
293   output_scheme (gh_list (ly_symbol2scm ("stop-line"), SCM_UNDEFINED));
294 }
295
296
297 Link_array<Item> 
298 Line_of_score::broken_col_range (Item const*l, Item const*r) const
299 {
300   Link_array<Item> ret;
301
302   l = l->column_l ();
303   r = r->column_l ();
304   SCM s = get_elt_pointer ("columns");
305
306   while (gh_pair_p (s) && gh_car (s) != r->self_scm_)
307     s = gh_cdr  (s);
308     
309   if (gh_pair_p (s))
310     s = gh_cdr (s);
311   
312   while (gh_pair_p (s) && gh_car (s) != l->self_scm_)
313     {
314       Paper_column *c
315         = dynamic_cast<Paper_column*> (unsmob_element (gh_car (s)));
316       if (c->breakable_b () && !c->line_l_)
317         ret.push (c);
318
319       s = gh_cdr  (s);
320     }
321
322   ret.reverse ();
323   return ret;
324 }
325
326 /**
327    Return all columns, but filter out any unused columns , since they might
328    disrupt the spacing problem.
329  */
330 Link_array<Paper_column>
331 Line_of_score::column_l_arr ()const
332 {
333   Link_array<Paper_column> acs
334     = Pointer_group_interface__extract_elements (this, (Paper_column*) 0, "columns");
335   bool bfound = false;
336   for (int i= acs.size (); i -- ; )
337     {
338       bool brb = acs[i]->breakable_b();
339       bfound = bfound || brb;
340
341       /*
342         the last column should be breakable. Weed out any columns that
343         seem empty. We need to retain breakable columns, in case
344         someone forced a breakpoint.
345       */
346       if (!bfound || !acs[i]->used_b ())
347         acs.del (i);
348     }
349   return acs;
350 }