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