]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-elem.cc
release: 0.1.7
[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         Molecule*m = brew_molecule_p();
182         r = m->extent().x();
183         delete m;
184     } else
185         r = output->extent().x();
186     return r;
187 }
188
189 Interval
190 Score_elem::width() const
191 {
192     return extent( X_AXIS);
193 }
194
195 Interval
196 Score_elem::extent(Axis a)const
197 {
198     Interval r;
199     if ( !empty_b_ ) {
200         
201         r = (a == X_AXIS)? do_width(): do_height();
202     }
203     
204     if (!r.empty_b()) // float exception on DEC Alpha
205         r+=offset_[a];
206
207     return r;
208 }
209
210 Interval
211 Score_elem::do_height() const 
212 {
213     Interval r;
214     if (!output){
215         Molecule*m = brew_molecule_p();
216         r = m->extent().y();
217         delete m;
218     } else
219         r = output->extent().y();
220     return r;
221 }
222
223 Interval
224 Score_elem::height() const
225 {
226     return extent(Y_AXIS);
227 }
228
229 /*
230   STANDARD METHS
231  */
232 void
233 Score_elem::print()const
234 {
235 #ifndef NPRINT
236     mtor << name() << "{\n";
237     mtor << "dets: " << dependent_size() << "dependencies: " << 
238         dependency_size();
239     if (offset_.x() || offset_.y())
240         mtor << "offset (" << offset_.x() << ", " << offset_.y() <<")";
241     mtor << "\n";
242
243     do_print();
244     if (output)
245         output->print();
246     
247     mtor <<  "}\n";
248 #endif
249 }
250
251 Score_elem::Score_elem()
252 {
253     transparent_b_ = empty_b_ = false;
254     axis_group_l_a_[0] = axis_group_l_a_[1] =0;
255     pscore_l_=0;
256     offset_ = Offset(0,0);
257     output = 0;
258     status_ = ORPHAN;
259 }
260
261
262 Paper_def*
263 Score_elem::paper()  const
264 {
265     assert(pscore_l_);
266     return pscore_l_->paper_l_;
267 }
268
269 void
270 Score_elem::add_processing()
271 {
272     if (status_ >= VIRGIN)
273         return;
274     status_ = VIRGIN;
275     do_add_processing();
276 }
277
278 void
279 Score_elem::pre_processing()
280 {
281     if (status_ >= PRECALCED )
282         return;
283
284     assert(status_ != PRECALCING); // cyclic dependency
285     status_ = PRECALCING;
286
287     for (int i=0; i < dependency_size(); i++)
288         dependency(i)->pre_processing();
289
290     Link_array<Score_elem> extra(get_extra_dependencies());
291     for (int i=0; i < extra.size(); i++)
292         extra[i]->pre_processing();
293     
294     do_pre_processing();
295     status_ = PRECALCED;
296 }
297
298 void
299 Score_elem::breakable_col_processing()
300 {
301     if (status_ >= PREBROKEN )
302         return;
303
304     if(status_== PREBREAKING) {
305         status_ = PREBROKEN;
306         return ;
307     }
308     status_ = PREBREAKING;
309
310     for (int i=0; i < dependency_size(); i++)
311         dependency(i)->breakable_col_processing();
312
313       Link_array<Score_elem> extra(get_extra_dependencies());
314     for (int i=0; i < extra.size(); i++)
315         extra[i]->breakable_col_processing();
316     
317   
318     do_breakable_col_processing();
319     status_ = PREBROKEN;
320 }
321
322 void
323 Score_elem::break_processing()
324 {
325     if (status_ >= BROKEN )
326         return;
327
328     if (status_ == BREAKING) {
329         status_ = BROKEN;
330         return;
331     }
332     status_ = BREAKING;
333
334     for (int i=0; i < dependency_size(); i++)
335         dependency(i)->break_processing();
336
337     Link_array<Score_elem> extra(get_extra_dependencies());
338     for (int i=0; i < extra.size(); i++)
339         extra[i]->break_processing();
340     
341
342     
343     do_break_processing();
344     status_ = BROKEN;
345
346 }
347
348 void
349 Score_elem::do_break_processing()
350 {
351     handle_broken_dependencies();
352 }
353
354
355 void
356 Score_elem::post_processing()
357 {
358     if (status_ >= POSTCALCED)
359         return;
360     assert(status_ != POSTCALCING);// cyclic dependency
361     status_=POSTCALCING;        
362
363   
364     for (int i=0; i < dependency_size(); i++)
365         dependency(i)->post_processing();
366
367     Link_array<Score_elem> extra(get_extra_dependencies());
368     for (int i=0; i < extra.size(); i++)
369         extra[i]->post_processing();
370     
371
372     do_post_processing();
373     status_=POSTCALCED;
374 }
375
376 Score_elem::Status
377 Score_elem::status()const
378 {
379     return status_;
380 }
381
382 void 
383 Score_elem::molecule_processing()
384 {
385     if (status_ >= OUTPUT)
386         return;
387     status_ = OUTPUT;           // do it only once.
388   
389     for (int i=0; i < dependency_size(); i++)
390         dependency(i)->molecule_processing();
391
392     Link_array<Score_elem> extra(get_extra_dependencies());
393     for (int i=0; i < extra.size(); i++)
394         extra[i]->molecule_processing();
395     
396
397     if (transparent_b_)
398         return ;
399     output= brew_molecule_p();
400 }
401
402 /*
403   
404   VIRTUAL STUBS
405
406  */
407 void
408 Score_elem::do_post_processing()
409 {
410 }
411
412 void
413 Score_elem::do_breakable_col_processing()
414 {
415     handle_prebroken_dependencies();
416 }
417
418 void
419 Score_elem::do_pre_processing()
420 {
421 }
422
423 void
424 Score_elem::do_add_processing()
425 {
426 }
427
428 void
429 Score_elem::do_substitute_dependency(Score_elem*,Score_elem*)
430 {
431 }
432 void
433 Score_elem::do_substitute_dependent(Score_elem*,Score_elem*)
434 {
435 }
436
437 void
438 Score_elem::do_unlink()
439 {}
440
441 IMPLEMENT_IS_TYPE_B(Score_elem);
442
443 Molecule*
444 Score_elem::brew_molecule_p()const
445 {
446     Atom a(paper()->lookup_l()->fill(Box(Interval(0,0), Interval(0,0))));
447     return new Molecule (a);
448 }
449
450
451 Line_of_score *
452 Score_elem::line_l()const
453 {
454     return 0;
455 }
456
457 /*
458   
459   DEPENDENCIES
460
461   */
462
463 void
464 Score_elem::remove_dependency(Score_elem*e)
465 {
466     remove_edge_out(e);
467     substitute_dependency(e, 0);
468 }
469
470 void
471 Score_elem::add_dependency(Score_elem*e)
472 {
473     Directed_graph_node::add(e);
474 }
475 void
476 Score_elem::substitute_dependency(Score_elem* old, Score_elem* new_l)
477 {
478     do_substitute_dependency(old,new_l);
479     old->do_substitute_dependent(this, 0);
480 }
481
482 void
483 Score_elem::junk_dependencies()
484 {
485     while ( dependency_size() ) {
486         remove_edge_out( dependency( 0 ));
487     }
488 }
489
490 void
491 Score_elem::handle_broken_dependencies()
492 {
493     Line_of_score *line  = line_l();
494     if (!line)
495         return;
496
497     Link_array<Score_elem> remove_us_arr;
498     for (int i=0; i < dependency_size(); i++) {
499         Score_elem * elt = dependency(i);
500         if (elt->line_l() != line){ 
501             if (elt->spanner()) {
502                 Spanner * sp = elt->spanner();
503                 Spanner * broken = sp->find_broken_piece(line);
504                 substitute_dependency(sp, broken);
505
506                 add_dependency(broken);
507             } else if (elt->item() && elt->item()->pcol_l_->breakpoint_b()
508                        && elt->item()->break_status_i() == 0) {
509                 Item * my_item = elt->item()->find_prebroken_piece(line);
510                 substitute_dependency( elt, my_item);
511                 if (my_item)
512                     add_dependency( my_item);
513             }
514             remove_us_arr.push(elt);
515         } 
516     }
517
518     remove_us_arr.default_sort();
519     remove_us_arr.uniq();
520     for (int i=0;  i <remove_us_arr.size(); i++)
521         remove_dependency(remove_us_arr[i]);
522
523     status_ = BROKEN;
524 }
525
526 /*
527   This sux.
528
529   unlike with spanners, the number of items can increase
530
531   span: item1
532
533   becomes
534
535   span: item1 item2 item3
536
537   How to let span (a derived class) know that this happened?
538  */
539 void
540 Score_elem::handle_prebroken_dependencies()
541 {
542     Link_array<Score_elem> old_arr, new_arr;
543     
544     for (int i=0; i < dependency_size(); i++) {
545         Score_elem * elt = dependency(i);
546         Item *it_l = elt->item();
547         if (it_l && it_l->breakable_b_)
548             if (item()) {
549                 Score_elem *new_l = it_l->find_prebroken_piece(item()->pcol_l_);
550                 if (new_l != elt ) {
551                     new_arr.push (new_l);
552                     old_arr.push(elt);
553                 } 
554             }else {
555                 new_arr.push(it_l->broken_to_a_[0]);
556                 old_arr.push(0);
557                 old_arr.push(0);                
558                 new_arr.push(it_l->broken_to_a_[1]);            
559             }
560     }
561     
562     for (int i=0;  i < old_arr.size(); i++)
563         if (old_arr[i])
564             substitute_dependency( old_arr[i], new_arr[i] );
565         
566         
567     status_ = PREBROKEN;
568 }
569
570
571
572 void
573 Score_elem::unlink_all()
574 {
575     for (int i=0; i < dependency_size(); i++) 
576         dependency(i)->unlink_all();
577     Link_array<Score_elem> extra(get_extra_dependencies());
578     for (int i=0; i < extra.size(); i++)
579         extra[i]->unlink_all();
580     
581     junk_links();
582     axis_group_l_a_[0] = axis_group_l_a_[1] =0;
583 }
584
585 void
586 Score_elem::unlink()
587 {
588     do_unlink();
589     while ( dependency_size()) {
590         do_substitute_dependency(dependency(0),0);
591         remove_edge_out_idx(0);
592     }
593     while  ( dependent_size() ) {
594         dependent(0)->remove_dependency(this);
595     }
596     for (int j=0; j < 2; j++)
597         if ( axis_group_l_a_[j])
598             axis_group_l_a_[j]->remove_element(this);
599
600 }
601
602 void
603 Score_elem::OK()const
604 {
605 #ifndef NDEBUG
606     for (int i=0; i < dependency_size(); i++) {
607         dependency(i)->OK();
608     }
609 #endif
610 }
611
612 Link_array<Score_elem>
613 Score_elem::get_extra_dependencies()const
614 {
615     Link_array<Score_elem> empty;
616     return empty;
617 }