]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-element.cc
patch::: 1.3.1.hwn1
[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 #include "dimension-cache.hh"
26
27
28 Interval
29 Score_element::dim_cache_callback (Dimension_cache*c)
30 {
31   Score_element *  e =dynamic_cast<Score_element*>( c->element_l());
32   if(e->dim_cache_[X_AXIS] == c)
33     return e->do_width ();
34   else
35     return e->do_height ();
36 }
37
38 Score_element::Score_element()
39 {
40   output_p_ =0;
41   dim_cache_[X_AXIS]->set_callback (dim_cache_callback);
42   dim_cache_[Y_AXIS]->set_callback (dim_cache_callback); 
43   used_b_ = false;
44   pscore_l_=0;
45   lookup_l_ =0;
46   status_i_ = 0;
47   self_scm_ = SCM_EOL;
48   original_l_ = 0;
49   element_property_alist_ = SCM_EOL;
50
51   smobify_self ();
52 }
53
54 Score_element::Score_element (Score_element const&s)
55   : Graphical_element (s)
56 {
57   
58   self_scm_ = SCM_EOL;
59   used_b_ = true;
60   original_l_ =(Score_element*) &s;
61   element_property_alist_ = scm_protect_object (scm_list_copy (s.element_property_alist_));
62   dependency_arr_ = s.dependency_arr_;
63   output_p_ =0;
64   status_i_ = s.status_i_;
65   lookup_l_ = s.lookup_l_;
66   pscore_l_ = s.pscore_l_;
67
68   smobify_self ();
69 }
70
71 Score_element::~Score_element()
72 {
73   assert (!output_p_);
74   assert (status_i_ >=0);
75   status_i_  = -1;
76 }
77
78 Score_element*
79 Score_element::dependency (int i) const
80 {
81   return dependency_arr_ [i];
82 }
83
84 int
85 Score_element::dependency_size () const
86 {
87   return dependency_arr_.size ();
88 }
89
90 // should also have one that takes SCM arg. 
91 SCM
92 Score_element::get_elt_property (String nm) const
93 {
94   SCM sym =  ly_symbol (nm);
95   SCM s = scm_assq(sym, element_property_alist_);
96
97   if (s != SCM_BOOL_F)
98     return SCM_CDR (s); 
99   
100   if (pscore_l_)
101     {
102       SCM sym2 = ly_symbol (name () + ("::" + nm));
103       SCM val;
104       
105       // should probably check for Type::sym as well.
106       Paper_def * p= pscore_l_->paper_l_;
107       if (p->default_properties_.try_retrieve (sym2, &val))
108         return val;
109       else if (p->default_properties_.try_retrieve (sym, &val))
110         return val;
111     }
112   
113   return SCM_UNDEFINED;
114 }
115
116 SCM
117 Score_element::remove_elt_property (String key)
118 {
119   SCM s = get_elt_property (key); 
120   SCM sym = ly_symbol (key);    
121   element_property_alist_ =  scm_assq_remove_x (element_property_alist_, sym);
122   return s;
123 }
124
125 void
126 Score_element::set_elt_property (String k, SCM v)
127 {
128   SCM s = ly_symbol (k);
129   element_property_alist_ = scm_assoc_set_x (element_property_alist_, s, v);
130 }
131
132 Interval
133 Score_element::do_width() const 
134 {
135   Interval r;
136
137   Molecule*m = output_p_ ?  output_p_ : do_brew_molecule_p();
138   r = m->extent().x ();
139
140   if (!output_p_)
141     delete m;
142   
143   return r;
144 }
145
146 Interval
147 Score_element::do_height() const 
148 {
149   Interval r;
150   Molecule*m = output_p_ ?  output_p_ : do_brew_molecule_p();
151   r = m->extent().y ();
152   if (!output_p_)
153     delete m;
154
155   return r;
156 }
157
158 void
159 Score_element::print() const
160 {
161 #ifndef NPRINT
162   DEBUG_OUT << classname(this) << "{\n";
163   if (flower_dstream && !flower_dstream->silent_b ("Score_element"))
164     ly_display_scm (element_property_alist_);
165   DEBUG_OUT << "dependencies: " << dependency_size();
166   if (original_l_)
167     DEBUG_OUT << "Copy ";
168   Graphical_element::do_print ();
169   do_print();
170   
171   DEBUG_OUT <<  "}\n";
172 #endif
173 }
174
175 Paper_def*
176 Score_element::paper_l ()  const
177 {
178  return pscore_l_->paper_l_;
179 }
180
181 Lookup const *
182 Score_element::lookup_l () const
183 {
184   if (!lookup_l_)
185     {
186       Score_element * urg = (Score_element*)this;
187       SCM sz = urg->remove_elt_property ("fontsize");
188       int i = (sz != SCM_UNDEFINED)
189         ? gh_scm2int  (sz)
190         : 0;
191
192       urg->lookup_l_ =  (Lookup*)pscore_l_->paper_l_->lookup_l (i);
193     }
194   return lookup_l_;
195 }
196
197 void
198 Score_element::add_processing()
199 {
200   assert (status_i_ >=0);
201   if (status_i_)
202     return;
203   status_i_ ++;
204   do_add_processing();
205 }
206
207 void
208 Score_element::calculate_dependencies (int final, int busy,
209                                     Score_element_method_pointer funcptr)
210 {
211   assert (status_i_ >=0);
212
213   if (status_i_ >= final)
214     return;
215
216   assert (status_i_!= busy);
217   status_i_= busy;
218
219   for (int i=0; i < dependency_arr_.size(); i++)
220     dependency_arr_[i]->calculate_dependencies (final, busy, funcptr);
221
222   Link_array<Score_element> extra (get_extra_dependencies());
223   for (int i=0; i < extra.size(); i++)
224     extra[i]->calculate_dependencies (final, busy, funcptr);
225   
226   invalidate_cache (X_AXIS);
227   invalidate_cache (Y_AXIS);
228   (this->*funcptr)();
229   status_i_= final;
230 }
231
232 void
233 Score_element::output_processing () 
234 {
235   if (get_elt_property ("transparent") != SCM_UNDEFINED)
236     return;
237
238   // we're being silly here. 
239   if (output_p_)
240     delete output_p_;
241   
242   output_p_ = do_brew_molecule_p ();
243   Offset o (relative_coordinate (0, X_AXIS), relative_coordinate (0, Y_AXIS));
244   
245   pscore_l_->outputter_l_->output_molecule (output_p_,
246                                             o,
247                                             classname(this));
248
249   delete output_p_;
250   output_p_ =0;
251 }
252
253 /*
254   
255   VIRTUAL STUBS
256
257  */
258 void
259 Score_element::do_break_processing()
260 {
261   handle_broken_dependencies();
262 }
263
264 void
265 Score_element::do_post_processing()
266 {
267 }
268
269 void
270 Score_element::do_breakable_col_processing()
271 {
272   handle_prebroken_dependencies();
273 }
274
275 void
276 Score_element::do_pre_processing()
277 {
278 }
279
280 void
281 Score_element::do_space_processing ()
282 {
283 }
284
285 void
286 Score_element::do_add_processing()
287 {
288 }
289
290 void
291 Score_element::do_substitute_element_pointer (Score_element*,Score_element*)
292 {
293 }
294
295
296 Molecule*
297 Score_element::do_brew_molecule_p() const
298 {
299   Molecule a (lookup_l ()->fill (Box (Interval (0,0), Interval (0,0))));
300   return new Molecule (a);
301 }
302
303
304 Line_of_score *
305 Score_element::line_l() const
306 {
307   return 0;
308 }
309
310 void
311 Score_element::add_dependency (Score_element*e)
312 {
313   if (e)
314     {
315       dependency_arr_.push (e);
316       e->used_b_ = true;
317     }
318   else
319     programming_error ("Null dependency added");
320 }
321
322 void
323 Score_element::substitute_dependency (Score_element* old, Score_element* new_l)
324 {
325   do_substitute_element_pointer (old,new_l);
326   old->do_substitute_element_pointer (this, 0);
327 }
328
329 void
330 Score_element::handle_broken_dependencies()
331 {
332   Line_of_score *line  = line_l();
333   if (!line)
334     return;
335
336   do_substitute_arrays ();
337
338   Link_array<Score_element> new_deps;
339
340   for (int i=0; i < dependency_size(); i++) 
341     {
342       Score_element * elt = dependency (i);
343       if (elt->line_l() != line)
344         {
345           Score_element * broken = elt->find_broken_piece (line);
346           substitute_dependency (elt, broken);
347           elt  = broken ;
348         }
349       if (elt)
350         new_deps.push (elt);
351     }
352   dependency_arr_ = new_deps;
353
354 }
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
371   TODO: cleanify.
372  */
373 void
374 Score_element::handle_prebroken_dependencies()
375 {
376   /*  dynamic_cast<Item*> (this) && 
377   if (!break_status_dir ())
378     return;
379   */
380   Link_array<Score_element> old_arr, new_arr;
381   
382   for (int i=0; i < dependency_size(); i++) 
383     {
384       Score_element * elt = dependency (i);
385       Item *it_l = dynamic_cast <Item *> (elt);
386       if (it_l && it_l->broken_original_b ())
387         if (Item *me = dynamic_cast<Item*> (this) )
388           {
389             Score_element *new_l = it_l->find_broken_piece (me->break_status_dir ());
390             if (new_l != elt) 
391               {
392                 new_arr.push (new_l);
393                 old_arr.push (elt);
394               }
395           }
396         else 
397           {
398             Direction d = LEFT;
399             do {
400               old_arr.push (0);
401               new_arr.push (it_l->find_broken_piece (d));
402             } while (flip(&d)!= LEFT);
403           }
404     }
405   
406   for (int i=0;  i < old_arr.size(); i++)
407     if (old_arr[i])
408       substitute_dependency (old_arr[i], new_arr[i]);
409 }
410
411 void
412 Score_element::handle_prebroken_dependents()
413 {
414 }
415
416 void
417 Score_element::handle_broken_dependents()
418 {
419 }
420
421
422
423 Link_array<Score_element>
424 Score_element::get_extra_dependencies() const
425 {
426   Link_array<Score_element> empty;
427   return empty;
428 }
429
430 bool
431 Score_element::linked_b() const
432 {
433   return used_b_;
434 }
435
436 void
437 Score_element::do_print () const
438 {
439 }
440
441 void
442 Score_element::do_substitute_arrays ()
443 {
444 }
445
446
447 Score_element*
448 Score_element::find_broken_piece (Line_of_score*) const
449 {
450   return 0;
451 }
452
453 SCM
454 Score_element::mark_smob (SCM ses)
455 {
456   void * mp = (void*) SCM_CDR(ses);
457   Score_element * s = (Score_element*) mp;
458
459   assert (s->self_scm_ == ses);
460   return s->element_property_alist_;
461 }
462
463
464 int
465 Score_element::print_smob (SCM s, SCM port, scm_print_state *)
466 {
467   Score_element *sc = (Score_element *) SCM_CDR (s);
468      
469   scm_puts ("#<Score_element ", port);
470   scm_puts ((char *)sc->name (), port);
471   scm_puts (" >", port);
472   return 1;
473 }
474
475 void
476 Score_element::do_smobify_self ()
477 {
478   scm_unprotect_object (element_property_alist_); // ugh
479 }
480 #include "ly-smobs.icc"
481 IMPLEMENT_SMOBS(Score_element);
482
483 SCM
484 Score_element::equal_p (SCM a, SCM b)
485 {
486   return SCM_CDR(a) == SCM_CDR(b) ? SCM_BOOL_T : SCM_BOOL_F;
487 }
488