]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-element.cc
patch::: 1.3.8.uu1
[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 "misc.hh"
13 #include "paper-score.hh"
14 #include "paper-def.hh"
15 #include "lookup.hh"
16 #include "molecule.hh"
17 #include "score-element.hh"
18 #include "debug.hh"
19 #include "spanner.hh"
20 #include "line-of-score.hh"
21 #include "item.hh"
22 #include "paper-column.hh"
23 #include "molecule.hh"
24 #include "misc.hh"
25 #include "paper-outputter.hh"
26 #include "dimension-cache.hh"
27 #include "staff-side.hh"
28
29 Interval
30 Score_element::dim_cache_callback (Dimension_cache const*c)
31 {
32   Score_element *  e =dynamic_cast<Score_element*> (c->element_l());
33   if(e->dim_cache_[X_AXIS] == c)
34     return e->do_width ();
35   else
36     return e->do_height ();
37 }
38
39
40 Score_element::Score_element()
41 {
42   output_p_ =0;
43   dim_cache_[X_AXIS]->set_callback (dim_cache_callback);
44   dim_cache_[Y_AXIS]->set_callback (dim_cache_callback); 
45   used_b_ = false;
46   pscore_l_=0;
47   lookup_l_ =0;
48   status_i_ = 0;
49   self_scm_ = SCM_EOL;
50   original_l_ = 0;
51   element_property_alist_ = SCM_EOL;
52
53   smobify_self ();
54 }
55
56 Score_element::Score_element (Score_element const&s)
57   : Graphical_element (s)
58 {
59   
60   self_scm_ = SCM_EOL;
61   used_b_ = true;
62   original_l_ =(Score_element*) &s;
63   element_property_alist_ = scm_protect_object (scm_list_copy (s.element_property_alist_));
64   dependency_arr_ = s.dependency_arr_;
65   output_p_ =0;
66   status_i_ = s.status_i_;
67   lookup_l_ = s.lookup_l_;
68   pscore_l_ = s.pscore_l_;
69
70   smobify_self ();
71 }
72
73 Score_element::~Score_element()
74 {
75   assert (!output_p_);
76   assert (status_i_ >=0);
77   status_i_  = -1;
78 }
79
80 Score_element*
81 Score_element::dependency (int i) const
82 {
83   return dependency_arr_ [i];
84 }
85
86 int
87 Score_element::dependency_size () const
88 {
89   return dependency_arr_.size ();
90 }
91
92 // should also have one that takes SCM arg. 
93 SCM
94 Score_element::get_elt_property (String nm) const
95 {
96   SCM sym =  ly_symbol2scm (nm.ch_C());
97   SCM s = scm_assq(sym, element_property_alist_);
98
99   if (s != SCM_BOOL_F)
100     return SCM_CDR (s); 
101   
102   if (pscore_l_)
103     {
104       SCM sym2 = ly_symbol2scm ((name () + ("::" + nm)).ch_C());
105       SCM val;
106       
107       // should probably check for Type::sym as well.
108       Paper_def * p= pscore_l_->paper_l_;
109       if (p->default_properties_.try_retrieve (sym2, &val))
110         return val;
111       else if (p->default_properties_.try_retrieve (sym, &val))
112         return val;
113     }
114   
115   return SCM_UNDEFINED;
116 }
117
118 SCM
119 Score_element::remove_elt_property (String key)
120 {
121   SCM s = get_elt_property (key); 
122   SCM sym = ly_symbol2scm (key.ch_C());
123   element_property_alist_ =  scm_assq_remove_x (element_property_alist_, sym);
124   return s;
125 }
126
127 /*
128   UGH. assoc vs. assq
129  */
130 void
131 Score_element::set_elt_property (String k, SCM v)
132 {
133   SCM s = ly_symbol2scm (k.ch_C( ));
134   element_property_alist_ = scm_assoc_set_x (element_property_alist_, s, v);
135 }
136
137 Interval
138 Score_element::do_width() const 
139 {
140   Interval r;
141
142   Molecule*m = output_p_ ?  output_p_ : do_brew_molecule_p();
143   r = m->extent().x ();
144
145   if (!output_p_)
146     delete m;
147   
148   return r;
149 }
150
151 Interval
152 Score_element::do_height() const 
153 {
154   Interval r;
155   Molecule*m = output_p_ ?  output_p_ : do_brew_molecule_p();
156   r = m->extent().y ();
157   if (!output_p_)
158     delete m;
159
160   return r;
161 }
162
163 void
164 Score_element::print() const
165 {
166 #ifndef NPRINT
167   DEBUG_OUT << classname(this) << "{\n";
168   if (flower_dstream && !flower_dstream->silent_b ("Score_element"))
169     ly_display_scm (element_property_alist_);
170   DEBUG_OUT << "dependencies: " << dependency_size();
171   if (original_l_)
172     DEBUG_OUT << "Copy ";
173   Graphical_element::do_print ();
174   do_print();
175   
176   DEBUG_OUT <<  "}\n";
177 #endif
178 }
179
180 Paper_def*
181 Score_element::paper_l ()  const
182 {
183  return pscore_l_->paper_l_;
184 }
185
186 Lookup const *
187 Score_element::lookup_l () const
188 {
189   if (!lookup_l_)
190     {
191       Score_element * urg = (Score_element*)this;
192       SCM sz = urg->remove_elt_property ("fontsize");
193       int i = (sz != SCM_UNDEFINED)
194         ? gh_scm2int  (sz)
195         : 0;
196
197       urg->lookup_l_ =  (Lookup*)pscore_l_->paper_l_->lookup_l (i);
198     }
199   return lookup_l_;
200 }
201
202 void
203 Score_element::add_processing()
204 {
205   assert (status_i_ >=0);
206   if (status_i_)
207     return;
208   status_i_ ++;
209
210   /*
211     UGH. UGH. UGH.
212    */
213   if (get_elt_property ("self-alignment-X") != SCM_UNDEFINED
214       && !dim_cache_[X_AXIS]->off_callback_l_)
215     {
216       dim_cache_[X_AXIS]->set_offset_callback (Side_position_interface::self_alignment);
217     }
218   
219   if (get_elt_property ("self-alignment-Y") != SCM_UNDEFINED
220       && !dim_cache_[X_AXIS]->off_callback_l_)
221       
222     {
223       dim_cache_[Y_AXIS]->set_offset_callback (Side_position_interface::self_alignment);
224     }
225   
226   do_add_processing();
227 }
228
229 void
230 Score_element::calculate_dependencies (int final, int busy,
231                                        Score_element_method_pointer funcptr)
232 {
233   assert (status_i_ >=0);
234
235   if (status_i_ >= final)
236     return;
237
238   assert (status_i_!= busy);
239   status_i_= busy;
240
241   for (int i=0; i < dependency_arr_.size(); i++)
242     dependency_arr_[i]->calculate_dependencies (final, busy, funcptr);
243
244   Link_array<Score_element> extra (get_extra_dependencies());
245   for (int i=0; i < extra.size(); i++)
246     extra[i]->calculate_dependencies (final, busy, funcptr);
247   
248   invalidate_cache (X_AXIS);
249   invalidate_cache (Y_AXIS);
250   (this->*funcptr)();
251   status_i_= final;
252 }
253
254 void
255 Score_element::output_processing () 
256 {
257   if (get_elt_property ("transparent") != SCM_UNDEFINED)
258     return;
259
260   // we're being silly here. 
261   if (output_p_)
262     delete output_p_;
263   
264   output_p_ = do_brew_molecule_p ();
265   Offset o (relative_coordinate (0, X_AXIS), relative_coordinate (0, Y_AXIS));
266
267   SCM s = get_elt_property ("extra-offset");
268   if (gh_pair_p (s))
269     {
270       Real il = paper_l ()->get_var ("interline");
271       o[X_AXIS] += il * gh_scm2double (gh_car (s));
272       o[Y_AXIS] += il * gh_scm2double (gh_cdr (s));      
273     }
274   
275   pscore_l_->outputter_l_->output_molecule (output_p_,
276                                             o,
277                                             classname(this));
278
279   delete output_p_;
280   output_p_ =0;
281 }
282
283 /*
284   
285   VIRTUAL STUBS
286
287  */
288 void
289 Score_element::do_break_processing()
290 {
291   handle_broken_dependencies();
292 }
293
294 void
295 Score_element::do_post_processing()
296 {
297 }
298
299 void
300 Score_element::do_breakable_col_processing()
301 {
302   handle_prebroken_dependencies();
303 }
304
305 void
306 Score_element::do_pre_processing()
307 {
308 }
309
310 void
311 Score_element::do_space_processing ()
312 {
313 }
314
315 void
316 Score_element::do_add_processing()
317 {
318 }
319
320 void
321 Score_element::do_substitute_element_pointer (Score_element*,Score_element*)
322 {
323 }
324
325
326 Molecule*
327 Score_element::do_brew_molecule_p() const
328 {
329   Molecule a (lookup_l ()->fill (Box (Interval (0,0), Interval (0,0))));
330   return new Molecule (a);
331 }
332
333
334 Line_of_score *
335 Score_element::line_l() const
336 {
337   return 0;
338 }
339
340 void
341 Score_element::add_dependency (Score_element*e)
342 {
343   if (e)
344     {
345       dependency_arr_.push (e);
346       e->used_b_ = true;
347     }
348   else
349     programming_error ("Null dependency added");
350 }
351
352 void
353 Score_element::substitute_dependency (Score_element* old, Score_element* new_l)
354 {
355   do_substitute_element_pointer (old,new_l);
356   old->do_substitute_element_pointer (this, 0);
357 }
358
359
360 /**
361    Do break substitution, and return new value.
362  */
363 SCM 
364 Score_element::handle_broken_smobs (SCM s, Line_of_score * line)
365 {
366   if (SMOB_IS_TYPE_B (Score_element, s))
367     {
368       Score_element *sc = SMOB_TO_TYPE (Score_element, s);
369       if (sc->line_l () != line)
370         {
371           sc= sc->find_broken_piece (line);
372         }
373
374       return  sc ? sc->self_scm_ : SCM_UNDEFINED;
375     }
376   else if (gh_pair_p (s))
377     {
378       /*
379         UGH! breaks on circular lists.
380        */
381       gh_set_car_x (s, handle_broken_smobs (gh_car (s), line));
382       gh_set_cdr_x (s, handle_broken_smobs (gh_cdr (s), line));
383     }
384   return s;
385 }
386
387 void
388 Score_element::handle_broken_dependencies()
389 {
390   Line_of_score *line  = line_l();
391   if (!line)
392     return;
393
394   element_property_alist_ = handle_broken_smobs (element_property_alist_, line);
395
396   Link_array<Score_element> new_deps;
397
398   for (int i=0; i < dependency_size(); i++) 
399     {
400       Score_element * elt = dependency (i);
401       if (elt->line_l() != line)
402         {
403           Score_element * broken = elt->find_broken_piece (line);
404           substitute_dependency (elt, broken);
405           elt  = broken ;
406         }
407       if (elt)
408         new_deps.push (elt);
409     }
410   dependency_arr_ = new_deps;
411
412 }
413
414
415 /*
416   TODO: cleanify.
417  */
418 void
419 Score_element::handle_prebroken_dependencies()
420 {
421   element_property_alist_
422     = handle_broken_smobs (element_property_alist_, line_l ());
423
424   Link_array<Score_element> old_arr, new_arr;
425   
426   for (int i=0; i < dependency_size(); i++) 
427     {
428       Score_element * elt = dependency (i);
429       Item *it_l = dynamic_cast <Item *> (elt);
430       if (it_l && it_l->broken_original_b ())
431         if (Item *me = dynamic_cast<Item*> (this) )
432           {
433             Score_element *new_l = it_l->find_broken_piece (me->break_status_dir ());
434             if (new_l != elt) 
435               {
436                 new_arr.push (new_l);
437                 old_arr.push (elt);
438               }
439           }
440         else 
441           {
442             Direction d = LEFT;
443             do {
444               old_arr.push (0);
445               new_arr.push (it_l->find_broken_piece (d));
446             } while (flip(&d)!= LEFT);
447           }
448     }
449   
450   for (int i=0;  i < old_arr.size(); i++)
451     if (old_arr[i])
452       substitute_dependency (old_arr[i], new_arr[i]);
453 }
454
455 void
456 Score_element::handle_prebroken_dependents()
457 {
458 }
459
460 void
461 Score_element::handle_broken_dependents()
462 {
463 }
464
465
466
467 Link_array<Score_element>
468 Score_element::get_extra_dependencies() const
469 {
470   Link_array<Score_element> empty;
471   return empty;
472 }
473
474 bool
475 Score_element::linked_b() const
476 {
477   return used_b_;
478 }
479
480 void
481 Score_element::do_print () const
482 {
483 }
484
485
486
487 Score_element*
488 Score_element::find_broken_piece (Line_of_score*) const
489 {
490   return 0;
491 }
492
493 SCM
494 Score_element::mark_smob (SCM ses)
495 {
496   void * mp = (void*) SCM_CDR(ses);
497   Score_element * s = (Score_element*) mp;
498
499   assert (s->self_scm_ == ses);
500   return s->element_property_alist_;
501 }
502
503
504 int
505 Score_element::print_smob (SCM s, SCM port, scm_print_state *)
506 {
507   Score_element *sc = (Score_element *) SCM_CDR (s);
508      
509   scm_puts ("#<Score_element ", port);
510   scm_puts ((char *)sc->name (), port);
511   scm_puts ("properties = ", port);
512   scm_display (sc->element_property_alist_, port);
513   scm_puts (" >", port);
514   return 1;
515 }
516
517 void
518 Score_element::do_smobify_self ()
519 {
520   scm_unprotect_object (element_property_alist_); // ugh
521 }
522 #include "ly-smobs.icc"
523 IMPLEMENT_SMOBS(Score_element);
524
525 SCM
526 Score_element::equal_p (SCM a, SCM b)
527 {
528   return SCM_CDR(a) == SCM_CDR(b) ? SCM_BOOL_T : SCM_BOOL_F;
529 }
530