]> git.donarmstrong.com Git - lilypond.git/blob - lily/line-of-score.cc
release: 1.3.70
[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<Score_element> 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           dynamic_cast<Paper_column*> (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     {
237       Score_element * e = unsmob_element (gh_car (s));
238       SCM proc = e->get_elt_property ("spacing-procedure");
239       if (gh_procedure_p (proc))
240         gh_call1 (proc, e->self_scm_);
241     }
242 }
243
244 void
245 Line_of_score::post_processing ()
246 {
247   for (SCM s = get_elt_property ("all-elements");
248        gh_pair_p (s); s = gh_cdr (s))
249     {
250       Score_element* sc = unsmob_element (gh_car (s));
251       sc->calculate_dependencies (POSTCALCED, POSTCALCING,
252                                   ly_symbol2scm ("after-line-breaking-callback"));
253     }
254
255   Interval i(extent(Y_AXIS));
256   if (i.empty_b())
257     programming_error ("Huh?  Empty Line_of_score?");
258   else
259     translate_axis (- i[MAX], Y_AXIS);
260
261   Real height = i.length ();
262   if (height > 50 CM)
263     {
264       programming_error ("Improbable system height");
265       height = 50 CM;
266     }
267
268   /*
269     generate all molecules  to trigger all font loads.
270
271     (ugh. This is not very memory efficient.)  */
272   for (SCM s = get_elt_property ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
273     unsmob_element (gh_car (s))->get_molecule ();
274   
275   /*
276     font defs;
277    */
278   SCM font_names = ly_quote_scm (all_fonts_global_p->font_descriptions ());  
279   output_scheme (gh_list (ly_symbol2scm ("define-fonts"),
280                                         font_names,
281                                         SCM_UNDEFINED));
282
283   /*
284     line preamble.
285    */
286   output_scheme (gh_list (ly_symbol2scm ("start-line"),
287                           gh_double2scm (height),
288                           SCM_UNDEFINED));
289   
290   Real il = paper_l ()->get_var ("interline");
291
292   /*
293     all elements.
294    */ 
295   for (SCM s = get_elt_property ("all-elements"); gh_pair_p (s); s = gh_cdr (s))
296     {
297       Score_element * sc =  unsmob_element (gh_car (s));
298       Molecule m = sc->get_molecule ();
299       
300       Offset o (sc->relative_coordinate (this, X_AXIS),
301                 sc->relative_coordinate (this, Y_AXIS));
302
303       SCM e = sc->get_elt_property ("extra-offset");
304       if (gh_pair_p (e))
305         {
306           o[X_AXIS] += il * gh_scm2double (gh_car (e));
307           o[Y_AXIS] += il * gh_scm2double (gh_cdr (e));      
308         }
309
310       output_molecule (m.get_expr (), o);
311     }
312   output_scheme (gh_list (ly_symbol2scm ("stop-line"), SCM_UNDEFINED));
313 }
314
315
316 Link_array<Item> 
317 Line_of_score::broken_col_range (Item const*l, Item const*r) const
318 {
319   Link_array<Item> ret;
320
321   l = l->column_l ();
322   r = r->column_l ();
323   SCM s = get_elt_property ("columns");
324
325   while (gh_pair_p (s) && gh_car (s) != r->self_scm_)
326     s = gh_cdr  (s);
327     
328   if (gh_pair_p (s))
329     s = gh_cdr (s);
330   
331   while (gh_pair_p (s) && gh_car (s) != l->self_scm_)
332     {
333       Paper_column*c = dynamic_cast<Paper_column*> ( unsmob_element (gh_car (s)));
334       if (Item::breakable_b (c) && !c->line_l_)
335         ret.push (c);
336
337       s = gh_cdr  (s);
338     }
339
340   ret.reverse ();
341   return ret;
342 }
343
344 /**
345    Return all columns, but filter out any unused columns , since they might
346    disrupt the spacing problem.
347  */
348 Link_array<Score_element>
349 Line_of_score::column_l_arr ()const
350 {
351   Link_array<Score_element> acs
352     = Pointer_group_interface__extract_elements (this, (Score_element*) 0, "columns");
353   bool bfound = false;
354   for (int i= acs.size (); i -- ; )
355     {
356       bool brb = Item::breakable_b (acs[i]);
357       bfound = bfound || brb;
358
359       /*
360         the last column should be breakable. Weed out any columns that
361         seem empty. We need to retain breakable columns, in case
362         someone forced a breakpoint.
363       */
364       if (!bfound || !Paper_column::used_b (acs[i]))
365         acs.del (i);
366     }
367   return acs;
368 }