]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-element.cc
release: 1.1.36
[lilypond.git] / lily / score-element.cc
1 /*
2   score-elem.cc -- implement Score_element
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9
10 #include <string.h>
11
12 #include "p-score.hh"
13 #include "paper-def.hh"
14 #include "lookup.hh"
15 #include "molecule.hh"
16 #include "score-element.hh"
17 #include "debug.hh"
18 #include "spanner.hh"
19 #include "line-of-score.hh"
20 #include "item.hh"
21 #include "p-col.hh"
22 #include "molecule.hh"
23 #include "misc.hh"
24 #include "paper-outputter.hh"
25
26 Interval
27 Score_element::dim_cache_callback (Dimension_cache*c)
28 {
29   Score_element *  e =dynamic_cast<Score_element*>( c->element_l());
30   if(&e->dim_cache_[X_AXIS] == c)
31     return e->do_width ();
32   else
33     return e->do_height ();
34 }
35
36 Score_element::Score_element()
37 {
38   output_p_ =0;
39   dim_cache_[X_AXIS].set_callback (dim_cache_callback);
40   dim_cache_[Y_AXIS].set_callback (dim_cache_callback); 
41   used_b_ = false;
42   pscore_l_=0;
43   lookup_l_ =0;
44   status_i_ = 0;
45   original_l_ = 0;
46   element_property_alist_ = SCM_EOL;
47 }
48
49 Score_element::Score_element (Score_element const&s)
50   : Graphical_element (s)
51 {
52   used_b_ = true;
53   original_l_ =(Score_element*) &s;
54   element_property_alist_ = scm_list_copy (s.element_property_alist_);
55   dependency_arr_ = s.dependency_arr_;
56   output_p_ =0;
57   status_i_ = s.status_i_;
58   lookup_l_ = s.lookup_l_;
59   pscore_l_ = s.pscore_l_;
60 }
61
62 Score_element::~Score_element()
63 {
64   delete output_p_; 
65   assert (status_i_ >=0);
66   status_i_  = -1;
67 }
68
69 Score_element*
70 Score_element::dependency (int i) const
71 {
72   return dependency_arr_ [i];
73 }
74
75 int
76 Score_element::dependency_size () const
77 {
78   return dependency_arr_.size ();
79 }
80
81
82
83 SCM
84 Score_element::get_elt_property (SCM sym) const
85 {
86   SCM s =  scm_assq(sym, element_property_alist_);
87
88   // is this a good idea?
89   if (s == SCM_BOOL_F && pscore_l_ && pscore_l_->paper_l_)
90     s = pscore_l_->paper_l_->get_scm_var (sym);
91
92   return s;
93 }
94
95 SCM
96 Score_element::remove_elt_property (SCM key)
97 {
98   SCM s = get_elt_property (key); 
99   element_property_alist_ =  scm_assq_remove_x (element_property_alist_, key);
100   return s;
101 }
102
103 void
104 Score_element::set_elt_property (SCM s, SCM v)
105 {
106   element_property_alist_ =
107     scm_assoc_set_x (element_property_alist_, s, v);
108 }
109
110 Interval
111 Score_element::do_width() const 
112 {
113   Interval r;
114
115   Molecule*m = output_p_ ?  output_p_ : do_brew_molecule_p();
116   r = m->extent().x ();
117
118   if (!output_p_)
119     delete m;
120   
121   return r;
122 }
123
124 Interval
125 Score_element::do_height() const 
126 {
127   Interval r;
128   Molecule*m = output_p_ ?  output_p_ : do_brew_molecule_p();
129   r = m->extent().y ();
130   if (!output_p_)
131     delete m;
132
133   return r;
134 }
135
136
137 /*
138   STANDARD METHS
139  */
140 void
141 Score_element::print() const
142 {
143 #ifndef NPRINT
144   DOUT << classname(this) << "{\n";
145   DOUT << "dependencies: " << dependency_size();
146  
147   Graphical_element::do_print ();
148   do_print();
149   
150   DOUT <<  "}\n";
151 #endif
152 }
153
154
155 Paper_def*
156 Score_element::paper_l ()  const
157 {
158  return pscore_l_->paper_l_;
159 }
160
161
162 Lookup const *
163 Score_element::lookup_l () const
164 {
165   if (!lookup_l_)
166     {
167       Score_element * me = (Score_element*)this;
168       SCM sz = me->remove_elt_property (fontsize_scm_sym);
169       int i = (sz != SCM_BOOL_F)
170         ? gh_scm2int (SCM_CDR (sz))
171         : 0;
172
173
174       me->lookup_l_ =  pscore_l_->paper_l_->lookup_l (i);
175     }
176   return lookup_l_;
177 }
178
179 void
180 Score_element::add_processing()
181 {
182   assert (status_i_ >=0);
183   if (status_i_)
184     return;
185   status_i_ ++;
186   do_add_processing();
187 }
188
189
190 void
191 Score_element::calculate_dependencies (int final, int busy,
192                                     Score_element_method_pointer funcptr)
193 {
194   assert (status_i_ >=0);
195
196   if (status_i_ >= final)
197     return;
198
199   assert (status_i_!= busy);
200   status_i_= busy;
201
202   for (int i=0; i < dependency_arr_.size(); i++)
203     dependency_arr_[i]->calculate_dependencies (final, busy, funcptr);
204
205   Link_array<Score_element> extra (get_extra_dependencies());
206   for (int i=0; i < extra.size(); i++)
207     extra[i]->calculate_dependencies (final, busy, funcptr);
208   
209   invalidate_cache (X_AXIS);
210   invalidate_cache (Y_AXIS);
211   (this->*funcptr)();
212   status_i_= final;
213 }
214
215 void
216 Score_element::output_processing () 
217 {
218   if (get_elt_property (transparent_scm_sym) != SCM_BOOL_F)
219     return;
220
221   // we're being silly here. 
222   if (output_p_)
223     delete output_p_;
224   
225   output_p_ = do_brew_molecule_p ();
226   pscore_l_->outputter_l_->output_molecule (output_p_,
227                                             absolute_offset (),
228                                             classname(this));
229
230   pscore_l_->schedule_for_delete (this);
231 }
232
233
234
235 /*
236   
237   VIRTUAL STUBS
238
239  */
240
241 void
242 Score_element::do_break_processing()
243 {
244   handle_broken_dependencies();
245 }
246
247 void
248 Score_element::do_post_processing()
249 {
250 }
251
252 void
253 Score_element::do_breakable_col_processing()
254 {
255   handle_prebroken_dependencies();
256 }
257
258 void
259 Score_element::do_pre_processing()
260 {
261 }
262
263 void
264 Score_element::do_space_processing ()
265 {
266 }
267
268 void
269 Score_element::do_add_processing()
270 {
271 }
272
273 void
274 Score_element::do_substitute_element_pointer (Score_element*,Score_element*)
275 {
276 }
277
278
279 Molecule*
280 Score_element::do_brew_molecule_p() const
281 {
282   Molecule a (lookup_l ()->fill (Box (Interval (0,0), Interval (0,0))));
283   return new Molecule (a);
284 }
285
286
287 Line_of_score *
288 Score_element::line_l() const
289 {
290   return 0;
291 }
292
293 /*
294   
295   DEPENDENCIES
296
297   */
298
299 void
300 Score_element::remove_dependency (Score_element*e)
301 {
302   int i;
303   while ((i = dependency_arr_.find_i (e)) >=0 )
304     dependency_arr_.unordered_del (i);
305
306   substitute_dependency (e, 0);
307 }
308
309 void
310 Score_element::add_dependency (Score_element*e)
311 {
312   if (e)
313     {
314       dependency_arr_.push (e);
315       e->used_b_ = true;
316     }
317   else
318     warning("Null dependency added");
319       
320 }
321 void
322 Score_element::substitute_dependency (Score_element* old, Score_element* new_l)
323 {
324   do_substitute_element_pointer (old,new_l);
325   old->do_substitute_element_pointer (this, 0);
326 }
327
328 void
329 Score_element::handle_broken_dependencies()
330 {
331   Line_of_score *line  = line_l();
332   if (!line)
333     return;
334
335   Link_array<Score_element> remove_us_arr;
336   for (int i=0; i < dependency_size(); i++) 
337     {
338       Score_element * elt = dependency (i);
339       if (elt->line_l() != line)
340         {
341           if (Spanner *sp = dynamic_cast<Spanner *> (elt)) 
342             {
343               Spanner * broken = sp->find_broken_piece (line);
344               substitute_dependency (sp, broken);
345
346               if (broken)
347                 add_dependency (broken);
348             }
349           else if (Item *original = dynamic_cast <Item *> (elt))
350             {
351               Item * my_item = original->find_prebroken_piece (line);
352                 
353               substitute_dependency (elt, my_item);
354               if (my_item)
355                 add_dependency (my_item);
356             }
357           remove_us_arr.push (elt);
358         }
359     }
360
361   remove_us_arr.default_sort();
362   remove_us_arr.uniq();
363   for (int i=0;  i <remove_us_arr.size(); i++)
364     remove_dependency (remove_us_arr[i]);
365 }
366
367 /*
368   This sux.
369
370   unlike with spanners, the number of items can increase
371
372   span: item1
373
374   becomes
375
376   span: item1 item2 item3
377
378   How to let span (a derived class) know that this happened?
379  */
380 void
381 Score_element::handle_prebroken_dependencies()
382 {
383   /*  dynamic_cast<Item*> (this) && 
384   if (!break_status_dir ())
385     return;
386   */
387   Link_array<Score_element> old_arr, new_arr;
388   
389   for (int i=0; i < dependency_size(); i++) 
390     {
391       Score_element * elt = dependency (i);
392       Item *it_l = dynamic_cast <Item *> (elt);
393       if (it_l && it_l->broken_original_b ())
394         if (Item *me = dynamic_cast<Item*> (this) )
395           {
396             Score_element *new_l = it_l->find_prebroken_piece (me->break_status_dir ());
397             if (new_l != elt) 
398               {
399                 new_arr.push (new_l);
400                 old_arr.push (elt);
401               }
402           }
403         else 
404           {
405             Direction d = LEFT;
406             do {
407               old_arr.push (0);
408               new_arr.push (it_l->find_prebroken_piece (d));
409             } while (flip(&d)!= LEFT);
410           }
411     }
412   
413   for (int i=0;  i < old_arr.size(); i++)
414     if (old_arr[i])
415       substitute_dependency (old_arr[i], new_arr[i]);
416 }
417
418 void
419 Score_element::handle_prebroken_dependents()
420 {
421 }
422
423
424
425 Link_array<Score_element>
426 Score_element::get_extra_dependencies() const
427 {
428   Link_array<Score_element> empty;
429   return empty;
430 }
431
432 bool
433 Score_element::linked_b() const
434 {
435   return used_b_;
436 }
437
438 void
439 Score_element::do_print () const
440 {
441 }