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