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