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