]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-element.cc
release: 1.3.5
[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 /*
126   UGH. assoc vs. assq
127  */
128 void
129 Score_element::set_elt_property (String k, SCM v)
130 {
131   SCM s = ly_symbol (k);
132   element_property_alist_ = scm_assoc_set_x (element_property_alist_, s, v);
133 }
134
135 Interval
136 Score_element::do_width() const 
137 {
138   Interval r;
139
140   Molecule*m = output_p_ ?  output_p_ : do_brew_molecule_p();
141   r = m->extent().x ();
142
143   if (!output_p_)
144     delete m;
145   
146   return r;
147 }
148
149 Interval
150 Score_element::do_height() const 
151 {
152   Interval r;
153   Molecule*m = output_p_ ?  output_p_ : do_brew_molecule_p();
154   r = m->extent().y ();
155   if (!output_p_)
156     delete m;
157
158   return r;
159 }
160
161 void
162 Score_element::print() const
163 {
164 #ifndef NPRINT
165   DEBUG_OUT << classname(this) << "{\n";
166   if (flower_dstream && !flower_dstream->silent_b ("Score_element"))
167     ly_display_scm (element_property_alist_);
168   DEBUG_OUT << "dependencies: " << dependency_size();
169   if (original_l_)
170     DEBUG_OUT << "Copy ";
171   Graphical_element::do_print ();
172   do_print();
173   
174   DEBUG_OUT <<  "}\n";
175 #endif
176 }
177
178 Paper_def*
179 Score_element::paper_l ()  const
180 {
181  return pscore_l_->paper_l_;
182 }
183
184 Lookup const *
185 Score_element::lookup_l () const
186 {
187   if (!lookup_l_)
188     {
189       Score_element * urg = (Score_element*)this;
190       SCM sz = urg->remove_elt_property ("fontsize");
191       int i = (sz != SCM_UNDEFINED)
192         ? gh_scm2int  (sz)
193         : 0;
194
195       urg->lookup_l_ =  (Lookup*)pscore_l_->paper_l_->lookup_l (i);
196     }
197   return lookup_l_;
198 }
199
200 void
201 Score_element::add_processing()
202 {
203   assert (status_i_ >=0);
204   if (status_i_)
205     return;
206   status_i_ ++;
207   do_add_processing();
208 }
209
210 void
211 Score_element::calculate_dependencies (int final, int busy,
212                                     Score_element_method_pointer funcptr)
213 {
214   assert (status_i_ >=0);
215
216   if (status_i_ >= final)
217     return;
218
219   assert (status_i_!= busy);
220   status_i_= busy;
221
222   for (int i=0; i < dependency_arr_.size(); i++)
223     dependency_arr_[i]->calculate_dependencies (final, busy, funcptr);
224
225   Link_array<Score_element> extra (get_extra_dependencies());
226   for (int i=0; i < extra.size(); i++)
227     extra[i]->calculate_dependencies (final, busy, funcptr);
228   
229   invalidate_cache (X_AXIS);
230   invalidate_cache (Y_AXIS);
231   (this->*funcptr)();
232   status_i_= final;
233 }
234
235 void
236 Score_element::output_processing () 
237 {
238   if (get_elt_property ("transparent") != SCM_UNDEFINED)
239     return;
240
241   // we're being silly here. 
242   if (output_p_)
243     delete output_p_;
244   
245   output_p_ = do_brew_molecule_p ();
246   Offset o (relative_coordinate (0, X_AXIS), relative_coordinate (0, Y_AXIS));
247
248   SCM s = get_elt_property ("extra-offset");
249   if (gh_pair_p (s))
250     {
251       Real il = paper_l ()->get_var ("interline");
252       o[X_AXIS] += il * gh_scm2double (gh_car (s));
253       o[Y_AXIS] += il * gh_scm2double (gh_cdr (s));      
254     }
255   
256   pscore_l_->outputter_l_->output_molecule (output_p_,
257                                             o,
258                                             classname(this));
259
260   delete output_p_;
261   output_p_ =0;
262 }
263
264 /*
265   
266   VIRTUAL STUBS
267
268  */
269 void
270 Score_element::do_break_processing()
271 {
272   handle_broken_dependencies();
273 }
274
275 void
276 Score_element::do_post_processing()
277 {
278 }
279
280 void
281 Score_element::do_breakable_col_processing()
282 {
283   handle_prebroken_dependencies();
284 }
285
286 void
287 Score_element::do_pre_processing()
288 {
289 }
290
291 void
292 Score_element::do_space_processing ()
293 {
294 }
295
296 void
297 Score_element::do_add_processing()
298 {
299 }
300
301 void
302 Score_element::do_substitute_element_pointer (Score_element*,Score_element*)
303 {
304 }
305
306
307 Molecule*
308 Score_element::do_brew_molecule_p() const
309 {
310   Molecule a (lookup_l ()->fill (Box (Interval (0,0), Interval (0,0))));
311   return new Molecule (a);
312 }
313
314
315 Line_of_score *
316 Score_element::line_l() const
317 {
318   return 0;
319 }
320
321 void
322 Score_element::add_dependency (Score_element*e)
323 {
324   if (e)
325     {
326       dependency_arr_.push (e);
327       e->used_b_ = true;
328     }
329   else
330     programming_error ("Null dependency added");
331 }
332
333 void
334 Score_element::substitute_dependency (Score_element* old, Score_element* new_l)
335 {
336   do_substitute_element_pointer (old,new_l);
337   old->do_substitute_element_pointer (this, 0);
338 }
339
340 void
341 Score_element::handle_broken_dependencies()
342 {
343   Line_of_score *line  = line_l();
344   if (!line)
345     return;
346
347   do_substitute_arrays ();
348
349   Link_array<Score_element> new_deps;
350
351   for (int i=0; i < dependency_size(); i++) 
352     {
353       Score_element * elt = dependency (i);
354       if (elt->line_l() != line)
355         {
356           Score_element * broken = elt->find_broken_piece (line);
357           substitute_dependency (elt, broken);
358           elt  = broken ;
359         }
360       if (elt)
361         new_deps.push (elt);
362     }
363   dependency_arr_ = new_deps;
364
365 }
366
367
368 /*
369   This sux.
370
371   unlike with spanners, the number of items can increase
372
373   span: item1
374
375   becomes
376
377   span: item1 item2 item3
378
379   How to let span (a derived class) know that this happened?
380
381
382   TODO: cleanify.
383  */
384 void
385 Score_element::handle_prebroken_dependencies()
386 {
387   /*  dynamic_cast<Item*> (this) && 
388   if (!break_status_dir ())
389     return;
390   */
391   Link_array<Score_element> old_arr, new_arr;
392   
393   for (int i=0; i < dependency_size(); i++) 
394     {
395       Score_element * elt = dependency (i);
396       Item *it_l = dynamic_cast <Item *> (elt);
397       if (it_l && it_l->broken_original_b ())
398         if (Item *me = dynamic_cast<Item*> (this) )
399           {
400             Score_element *new_l = it_l->find_broken_piece (me->break_status_dir ());
401             if (new_l != elt) 
402               {
403                 new_arr.push (new_l);
404                 old_arr.push (elt);
405               }
406           }
407         else 
408           {
409             Direction d = LEFT;
410             do {
411               old_arr.push (0);
412               new_arr.push (it_l->find_broken_piece (d));
413             } while (flip(&d)!= LEFT);
414           }
415     }
416   
417   for (int i=0;  i < old_arr.size(); i++)
418     if (old_arr[i])
419       substitute_dependency (old_arr[i], new_arr[i]);
420 }
421
422 void
423 Score_element::handle_prebroken_dependents()
424 {
425 }
426
427 void
428 Score_element::handle_broken_dependents()
429 {
430 }
431
432
433
434 Link_array<Score_element>
435 Score_element::get_extra_dependencies() const
436 {
437   Link_array<Score_element> empty;
438   return empty;
439 }
440
441 bool
442 Score_element::linked_b() const
443 {
444   return used_b_;
445 }
446
447 void
448 Score_element::do_print () const
449 {
450 }
451
452 void
453 Score_element::do_substitute_arrays ()
454 {
455 }
456
457
458 Score_element*
459 Score_element::find_broken_piece (Line_of_score*) const
460 {
461   return 0;
462 }
463
464 SCM
465 Score_element::mark_smob (SCM ses)
466 {
467   void * mp = (void*) SCM_CDR(ses);
468   Score_element * s = (Score_element*) mp;
469
470   assert (s->self_scm_ == ses);
471   return s->element_property_alist_;
472 }
473
474
475 int
476 Score_element::print_smob (SCM s, SCM port, scm_print_state *)
477 {
478   Score_element *sc = (Score_element *) SCM_CDR (s);
479      
480   scm_puts ("#<Score_element ", port);
481   scm_puts ((char *)sc->name (), port);
482   scm_puts (" >", port);
483   return 1;
484 }
485
486 void
487 Score_element::do_smobify_self ()
488 {
489   scm_unprotect_object (element_property_alist_); // ugh
490 }
491 #include "ly-smobs.icc"
492 IMPLEMENT_SMOBS(Score_element);
493
494 SCM
495 Score_element::equal_p (SCM a, SCM b)
496 {
497   return SCM_CDR(a) == SCM_CDR(b) ? SCM_BOOL_T : SCM_BOOL_F;
498 }
499