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