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