]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-element.cc
release: 1.3.2
[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   SCM s = get_elt_property ("extra-offset");
246   if (gh_pair_p (s))
247     {
248       Real il = paper_l ()->get_var ("interline");
249       o[X_AXIS] += il * gh_scm2double (gh_car (s));
250       o[Y_AXIS] += il * gh_scm2double (gh_cdr (s));      
251     }
252   
253   pscore_l_->outputter_l_->output_molecule (output_p_,
254                                             o,
255                                             classname(this));
256
257   delete output_p_;
258   output_p_ =0;
259 }
260
261 /*
262   
263   VIRTUAL STUBS
264
265  */
266 void
267 Score_element::do_break_processing()
268 {
269   handle_broken_dependencies();
270 }
271
272 void
273 Score_element::do_post_processing()
274 {
275 }
276
277 void
278 Score_element::do_breakable_col_processing()
279 {
280   handle_prebroken_dependencies();
281 }
282
283 void
284 Score_element::do_pre_processing()
285 {
286 }
287
288 void
289 Score_element::do_space_processing ()
290 {
291 }
292
293 void
294 Score_element::do_add_processing()
295 {
296 }
297
298 void
299 Score_element::do_substitute_element_pointer (Score_element*,Score_element*)
300 {
301 }
302
303
304 Molecule*
305 Score_element::do_brew_molecule_p() const
306 {
307   Molecule a (lookup_l ()->fill (Box (Interval (0,0), Interval (0,0))));
308   return new Molecule (a);
309 }
310
311
312 Line_of_score *
313 Score_element::line_l() const
314 {
315   return 0;
316 }
317
318 void
319 Score_element::add_dependency (Score_element*e)
320 {
321   if (e)
322     {
323       dependency_arr_.push (e);
324       e->used_b_ = true;
325     }
326   else
327     programming_error ("Null dependency added");
328 }
329
330 void
331 Score_element::substitute_dependency (Score_element* old, Score_element* new_l)
332 {
333   do_substitute_element_pointer (old,new_l);
334   old->do_substitute_element_pointer (this, 0);
335 }
336
337 void
338 Score_element::handle_broken_dependencies()
339 {
340   Line_of_score *line  = line_l();
341   if (!line)
342     return;
343
344   do_substitute_arrays ();
345
346   Link_array<Score_element> new_deps;
347
348   for (int i=0; i < dependency_size(); i++) 
349     {
350       Score_element * elt = dependency (i);
351       if (elt->line_l() != line)
352         {
353           Score_element * broken = elt->find_broken_piece (line);
354           substitute_dependency (elt, broken);
355           elt  = broken ;
356         }
357       if (elt)
358         new_deps.push (elt);
359     }
360   dependency_arr_ = new_deps;
361
362 }
363
364
365 /*
366   This sux.
367
368   unlike with spanners, the number of items can increase
369
370   span: item1
371
372   becomes
373
374   span: item1 item2 item3
375
376   How to let span (a derived class) know that this happened?
377
378
379   TODO: cleanify.
380  */
381 void
382 Score_element::handle_prebroken_dependencies()
383 {
384   /*  dynamic_cast<Item*> (this) && 
385   if (!break_status_dir ())
386     return;
387   */
388   Link_array<Score_element> old_arr, new_arr;
389   
390   for (int i=0; i < dependency_size(); i++) 
391     {
392       Score_element * elt = dependency (i);
393       Item *it_l = dynamic_cast <Item *> (elt);
394       if (it_l && it_l->broken_original_b ())
395         if (Item *me = dynamic_cast<Item*> (this) )
396           {
397             Score_element *new_l = it_l->find_broken_piece (me->break_status_dir ());
398             if (new_l != elt) 
399               {
400                 new_arr.push (new_l);
401                 old_arr.push (elt);
402               }
403           }
404         else 
405           {
406             Direction d = LEFT;
407             do {
408               old_arr.push (0);
409               new_arr.push (it_l->find_broken_piece (d));
410             } while (flip(&d)!= LEFT);
411           }
412     }
413   
414   for (int i=0;  i < old_arr.size(); i++)
415     if (old_arr[i])
416       substitute_dependency (old_arr[i], new_arr[i]);
417 }
418
419 void
420 Score_element::handle_prebroken_dependents()
421 {
422 }
423
424 void
425 Score_element::handle_broken_dependents()
426 {
427 }
428
429
430
431 Link_array<Score_element>
432 Score_element::get_extra_dependencies() const
433 {
434   Link_array<Score_element> empty;
435   return empty;
436 }
437
438 bool
439 Score_element::linked_b() const
440 {
441   return used_b_;
442 }
443
444 void
445 Score_element::do_print () const
446 {
447 }
448
449 void
450 Score_element::do_substitute_arrays ()
451 {
452 }
453
454
455 Score_element*
456 Score_element::find_broken_piece (Line_of_score*) const
457 {
458   return 0;
459 }
460
461 SCM
462 Score_element::mark_smob (SCM ses)
463 {
464   void * mp = (void*) SCM_CDR(ses);
465   Score_element * s = (Score_element*) mp;
466
467   assert (s->self_scm_ == ses);
468   return s->element_property_alist_;
469 }
470
471
472 int
473 Score_element::print_smob (SCM s, SCM port, scm_print_state *)
474 {
475   Score_element *sc = (Score_element *) SCM_CDR (s);
476      
477   scm_puts ("#<Score_element ", port);
478   scm_puts ((char *)sc->name (), port);
479   scm_puts (" >", port);
480   return 1;
481 }
482
483 void
484 Score_element::do_smobify_self ()
485 {
486   scm_unprotect_object (element_property_alist_); // ugh
487 }
488 #include "ly-smobs.icc"
489 IMPLEMENT_SMOBS(Score_element);
490
491 SCM
492 Score_element::equal_p (SCM a, SCM b)
493 {
494   return SCM_CDR(a) == SCM_CDR(b) ? SCM_BOOL_T : SCM_BOOL_F;
495 }
496