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