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