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