]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-elem.cc
release: 0.1.9
[lilypond.git] / lily / score-elem.cc
1 /*
2   score-elem.cc -- implement Score_elem
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
7 */
8 /*
9   too big. Should split.
10  */
11 #include "p-score.hh"
12 #include "paper-def.hh"
13 #include "lookup.hh"
14 #include "molecule.hh"
15 #include "score-elem.hh"
16 #include "debug.hh"
17 #include "tex.hh"
18 #include "dimen.hh"
19 #include "spanner.hh"
20 #include "scoreline.hh"
21 #include "item.hh"
22 #include "p-col.hh"
23
24 Score_elem*
25 Score_elem::dependency (int i)const
26 {
27   return (Score_elem*) get_out_edge_arr()[i];
28 }
29
30 int
31 Score_elem::dependency_size() const
32 {
33   return get_out_edge_arr().size ();
34 }
35
36 Score_elem*
37 Score_elem::dependent (int i) const
38 {
39   return (Score_elem*) get_in_edge_arr()[i];
40 }
41
42 int
43 Score_elem::dependent_size() const
44 {
45   return get_in_edge_arr().size ();
46 }
47
48
49
50 String
51 Score_elem::TeX_string_without_offset (Offset o)const
52 {
53   if (transparent_b_)
54         return "";
55   String s ("\\placebox{%}{%}{%}");
56   Array<String> a;
57   a.push (print_dimen (o.y()));
58   a.push (print_dimen (o.x()));
59   String t = output->TeX_string();
60   if (t == "")
61         return t;
62
63   a.push (t);
64   String r;
65   if (check_debug)
66         r = String ("\n%start: ") + name() + "\n";
67   r += substitute_args (s, a);;
68   return r;
69 }
70
71 String
72 Score_elem::TeX_string() const
73 {
74   assert (status_ > POSTCALCED);
75   return TeX_string_without_offset (offset_);
76 }
77
78 void
79 Score_elem::copy_dependencies (Score_elem const &s)
80 {
81   /* called from derived ctor, so most info points to the same deps
82     as (Directed_graph_node&)s. Nobody points to us, so don't copy
83     dependents.      
84    */
85   copy_edges_out (s);
86 }
87
88 Score_elem::Score_elem (Score_elem const&s)
89 {
90   transparent_b_ = s.transparent_b_;
91   empty_b_ = s.empty_b_;
92   axis_group_l_a_[0] = axis_group_l_a_[1] =0;
93   status_ = s.status_;
94   assert (!s.output);
95   output = 0;
96   pscore_l_ = s.pscore_l_;
97   offset_ = Offset (0,0);
98 }
99
100 Score_elem::~Score_elem()
101 {
102   // some paranoia to prevent weird segv's
103   assert (status_ < DELETED);
104   delete output;
105   status_ = DELETED;
106   output = 0;
107
108 }
109
110 /*
111   GEOMETRY
112  */
113 Real
114 Score_elem::absolute_coordinate (Axis a)const
115 {
116   Real r = offset_[a];
117   for ( Axis_group_element * axis_group_l = axis_group_l_a_[a];
118           axis_group_l; axis_group_l = axis_group_l->axis_group_l_a_[a])
119         
120         r += axis_group_l->offset_[a];
121   return r;
122 }
123  
124
125 Offset
126 Score_elem::absolute_offset() const
127 {
128   return Offset (absolute_coordinate (X_AXIS), absolute_coordinate (Y_AXIS));
129 }
130
131  void
132 Score_elem::translate (Real y, Axis a)
133 {
134   offset_[a] += y;
135 }
136
137 Real
138 Score_elem::relative_coordinate (Axis_group_element*e, Axis a)const
139 {
140   Real r =0.0;
141   for ( Axis_group_element * axis_group_l = axis_group_l_a_[a];
142           axis_group_l != e;
143           axis_group_l = axis_group_l->axis_group_l_a_[a])
144         r +=  axis_group_l->offset_[a];
145
146   return r;
147 }
148
149 Axis_group_element* 
150 Score_elem::common_group (Score_elem const* s, Axis a)const
151 {
152   Link_array<Axis_group_element> my_groups;
153   for ( Axis_group_element * axis_group_l = axis_group_l_a_[a];
154           axis_group_l;
155           axis_group_l = axis_group_l->axis_group_l_a_[a])
156         my_groups.push (axis_group_l);
157
158   Axis_group_element* common_l=0;
159   for ( Axis_group_element * axis_group_l = s->axis_group_l_a_[a];
160           !common_l && axis_group_l;
161           axis_group_l = axis_group_l->axis_group_l_a_[a])
162         common_l = my_groups.find_l (axis_group_l);
163
164   return common_l;
165 }
166
167
168
169 void
170 Score_elem::translate (Offset O)
171 {
172   offset_ += O;
173 }
174
175 Interval
176 Score_elem::do_width() const 
177 {
178   Interval r;
179
180   if (!output)
181     {
182         Molecule*m = brew_molecule_p();
183         r = m->extent().x ();
184         delete m;
185     }
186   else
187         r = output->extent().x ();
188   return r;
189 }
190
191 Interval
192 Score_elem::width() const
193 {
194   return extent (X_AXIS);
195 }
196
197 Interval
198 Score_elem::extent (Axis a)const
199 {
200   Interval r;
201   if ( !empty_b_) 
202     {
203         
204         r = (a == X_AXIS)? do_width(): do_height ();
205     }
206   
207   if (!r.empty_b()) // float exception on DEC Alpha
208         r+=offset_[a];
209
210   return r;
211 }
212
213 Interval
214 Score_elem::do_height() const 
215 {
216   Interval r;
217   if (!output)
218     {
219         Molecule*m = brew_molecule_p();
220         r = m->extent().y ();
221         delete m;
222     }
223   else
224         r = output->extent().y ();
225   return r;
226 }
227
228 Interval
229 Score_elem::height() const
230 {
231   return extent (Y_AXIS);
232 }
233
234 /*
235   STANDARD METHS
236  */
237 void
238 Score_elem::print()const
239 {
240 #ifndef NPRINT
241   DOUT << name() << "{\n";
242   DOUT << "dets: " << dependent_size() << "dependencies: " << 
243         dependency_size();
244   if (offset_.x() || offset_.y ())
245         DOUT << "offset (" << offset_.x() << ", " << offset_.y () <<")";
246   DOUT << "\n";
247
248   do_print();
249   if (output)
250         output->print();
251   
252   DOUT <<  "}\n";
253 #endif
254 }
255
256 Score_elem::Score_elem()
257 {
258   transparent_b_ = empty_b_ = false;
259   axis_group_l_a_[0] = axis_group_l_a_[1] =0;
260   pscore_l_=0;
261   offset_ = Offset (0,0);
262   output = 0;
263   status_ = ORPHAN;
264 }
265
266
267 Paper_def*
268 Score_elem::paper()  const
269 {
270   assert (pscore_l_);
271   return pscore_l_->paper_l_;
272 }
273
274 void
275 Score_elem::add_processing()
276 {
277   if (status_ >= VIRGIN)
278         return;
279   status_ = VIRGIN;
280   do_add_processing();
281 }
282
283 void
284 Score_elem::pre_processing()
285 {
286   if (status_ >= PRECALCED)
287         return;
288
289   assert (status_ != PRECALCING); // cyclic dependency
290   status_ = PRECALCING;
291
292   for (int i=0; i < dependency_size(); i++)
293         dependency (i)->pre_processing();
294
295   Link_array<Score_elem> extra (get_extra_dependencies());
296   for (int i=0; i < extra.size(); i++)
297         extra[i]->pre_processing();
298   
299   do_pre_processing();
300   status_ = PRECALCED;
301 }
302
303 void
304 Score_elem::breakable_col_processing()
305 {
306   if (status_ >= PREBROKEN)
307         return;
308
309   if (status_== PREBREAKING) 
310     {
311         status_ = PREBROKEN;
312         return ;
313     }
314   status_ = PREBREAKING;
315
316   for (int i=0; i < dependency_size(); i++)
317         dependency (i)->breakable_col_processing();
318
319     Link_array<Score_elem> extra (get_extra_dependencies());
320   for (int i=0; i < extra.size(); i++)
321         extra[i]->breakable_col_processing();
322   
323   
324   do_breakable_col_processing();
325   status_ = PREBROKEN;
326 }
327
328 void
329 Score_elem::break_processing()
330 {
331   if (status_ >= BROKEN)
332         return;
333
334   if (status_ == BREAKING) 
335     {
336         status_ = BROKEN;
337         return;
338     }
339   status_ = BREAKING;
340
341   for (int i=0; i < dependency_size(); i++)
342         dependency (i)->break_processing();
343
344   Link_array<Score_elem> extra (get_extra_dependencies());
345   for (int i=0; i < extra.size(); i++)
346         extra[i]->break_processing();
347   
348
349   
350   do_break_processing();
351   status_ = BROKEN;
352
353 }
354
355 void
356 Score_elem::do_break_processing()
357 {
358   handle_broken_dependencies();
359 }
360
361
362 void
363 Score_elem::post_processing()
364 {
365   if (status_ >= POSTCALCED)
366         return;
367   assert (status_ != POSTCALCING);// cyclic dependency
368   status_=POSTCALCING;  
369
370   
371   for (int i=0; i < dependency_size(); i++)
372         dependency (i)->post_processing();
373
374   Link_array<Score_elem> extra (get_extra_dependencies());
375   for (int i=0; i < extra.size(); i++)
376         extra[i]->post_processing();
377   
378
379   do_post_processing();
380   status_=POSTCALCED;
381 }
382
383 Score_elem::Status
384 Score_elem::status()const
385 {
386   return status_;
387 }
388
389 void 
390 Score_elem::molecule_processing()
391 {
392   if (status_ >= OUTPUT)
393         return;
394   status_ = OUTPUT;             // do it only once.
395   
396   for (int i=0; i < dependency_size(); i++)
397         dependency (i)->molecule_processing();
398
399   Link_array<Score_elem> extra (get_extra_dependencies());
400   for (int i=0; i < extra.size(); i++)
401         extra[i]->molecule_processing();
402   
403
404   if (transparent_b_)
405         return ;
406   output= brew_molecule_p();
407 }
408
409 /*
410   
411   VIRTUAL STUBS
412
413  */
414 void
415 Score_elem::do_post_processing()
416 {
417 }
418
419 void
420 Score_elem::do_breakable_col_processing()
421 {
422   handle_prebroken_dependencies();
423 }
424
425 void
426 Score_elem::do_pre_processing()
427 {
428 }
429
430 void
431 Score_elem::do_add_processing()
432 {
433 }
434
435 void
436 Score_elem::do_substitute_dependency (Score_elem*,Score_elem*)
437 {
438 }
439 void
440 Score_elem::do_substitute_dependent (Score_elem*,Score_elem*)
441 {
442 }
443
444 void
445 Score_elem::do_unlink()
446 {}
447
448 IMPLEMENT_IS_TYPE_B(Score_elem);
449
450 Molecule*
451 Score_elem::brew_molecule_p()const
452 {
453   Atom a (paper()->lookup_l ()->fill (Box (Interval (0,0), Interval (0,0))));
454   return new Molecule (a);
455 }
456
457
458 Line_of_score *
459 Score_elem::line_l()const
460 {
461   return 0;
462 }
463
464 /*
465   
466   DEPENDENCIES
467
468   */
469
470 void
471 Score_elem::remove_dependency (Score_elem*e)
472 {
473   remove_edge_out (e);
474   substitute_dependency (e, 0);
475 }
476
477 void
478 Score_elem::add_dependency (Score_elem*e)
479 {
480   Directed_graph_node::add (e);
481 }
482 void
483 Score_elem::substitute_dependency (Score_elem* old, Score_elem* new_l)
484 {
485   do_substitute_dependency (old,new_l);
486   old->do_substitute_dependent (this, 0);
487 }
488
489 void
490 Score_elem::junk_dependencies()
491 {
492   while ( dependency_size()) 
493     {
494         remove_edge_out (dependency (0));
495     }
496 }
497
498 void
499 Score_elem::handle_broken_dependencies()
500 {
501   Line_of_score *line  = line_l();
502   if (!line)
503         return;
504
505   Link_array<Score_elem> remove_us_arr;
506   for (int i=0; i < dependency_size(); i++) 
507     {
508         Score_elem * elt = dependency (i);
509         if (elt->line_l() != line)
510           {
511             if (elt->spanner()) 
512               {
513                 Spanner * sp = elt->spanner();
514                 Spanner * broken = sp->find_broken_piece (line);
515                 substitute_dependency (sp, broken);
516
517                 add_dependency (broken);
518               }
519             else if (elt->item() && elt->item ()->pcol_l_->breakpoint_b ()
520                        && elt->item()->break_status_i () == 0) 
521                          {
522                 Item * my_item = elt->item()->find_prebroken_piece (line);
523                 substitute_dependency (elt, my_item);
524                 if (my_item)
525                     add_dependency (my_item);
526               }
527             remove_us_arr.push (elt);
528           }
529     }
530
531   remove_us_arr.default_sort();
532   remove_us_arr.uniq();
533   for (int i=0;  i <remove_us_arr.size(); i++)
534         remove_dependency (remove_us_arr[i]);
535
536   status_ = BROKEN;
537 }
538
539 /*
540   This sux.
541
542   unlike with spanners, the number of items can increase
543
544   span: item1
545
546   becomes
547
548   span: item1 item2 item3
549
550   How to let span (a derived class) know that this happened?
551  */
552 void
553 Score_elem::handle_prebroken_dependencies()
554 {
555   Link_array<Score_elem> old_arr, new_arr;
556   
557   for (int i=0; i < dependency_size(); i++) 
558     {
559         Score_elem * elt = dependency (i);
560         Item *it_l = elt->item();
561         if (it_l && it_l->breakable_b_)
562             if (item()) 
563               {
564                 Score_elem *new_l = it_l->find_prebroken_piece (item()->pcol_l_);
565                 if (new_l != elt) 
566                   {
567                     new_arr.push (new_l);
568                     old_arr.push (elt);
569                   }
570             }else 
571               {
572                 new_arr.push (it_l->broken_to_a_[0]);
573                 old_arr.push (0);
574                 old_arr.push (0);               
575                 new_arr.push (it_l->broken_to_a_[1]);           
576               }
577     }
578   
579   for (int i=0;  i < old_arr.size(); i++)
580         if (old_arr[i])
581             substitute_dependency (old_arr[i], new_arr[i]);
582         
583         
584   status_ = PREBROKEN;
585 }
586
587
588
589 void
590 Score_elem::unlink_all()
591 {
592   for (int i=0; i < dependency_size(); i++) 
593         dependency (i)->unlink_all();
594   Link_array<Score_elem> extra (get_extra_dependencies());
595   for (int i=0; i < extra.size(); i++)
596         extra[i]->unlink_all();
597   
598   junk_links();
599   axis_group_l_a_[0] = axis_group_l_a_[1] =0;
600 }
601
602 void
603 Score_elem::unlink()
604 {
605   do_unlink();
606   while ( dependency_size()) 
607     {
608         do_substitute_dependency (dependency (0),0);
609         remove_edge_out_idx (0);
610     }
611   while  ( dependent_size()) 
612     {
613         dependent (0)->remove_dependency (this);
614     }
615   for (int j=0; j < 2; j++)
616         if ( axis_group_l_a_[j])
617             axis_group_l_a_[j]->remove_element (this);
618
619 }
620
621 void
622 Score_elem::OK()const
623 {
624 #ifndef NDEBUG
625   for (int i=0; i < dependency_size(); i++) 
626     {
627         dependency (i)->OK();
628     }
629 #endif
630 }
631
632 Link_array<Score_elem>
633 Score_elem::get_extra_dependencies()const
634 {
635   Link_array<Score_elem> empty;
636   return empty;
637 }