]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-elem.cc
release: 0.0.73pre
[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
71 Score_elem::Score_elem(Score_elem const&s)
72 {
73     transparent_b_ = s.transparent_b_;
74     empty_b_ = s.empty_b_;
75     /* called from derived ctor, so most info points to the same deps
76       as (Directed_graph_node&)s. Nobody points to us, so don't copy
77       dependents.      
78      */
79     copy_edges_out(s);
80     x_group_element_i_ = 0;
81     y_group_element_i_ = 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     assert(!x_group_element_i_ && !y_group_element_i_);
97 }
98
99 void
100 Score_elem::translate_x(Real x)
101 {
102     offset_.x += x;
103 }
104
105
106
107 void
108 Score_elem::translate_y(Real y)
109 {
110     offset_.y += y;
111 }
112
113
114 void
115 Score_elem::translate(Offset O)
116 {
117     translate_y(O.y);
118     translate_x(O.x);
119 }
120
121 Interval
122 Score_elem::do_width() const 
123 {
124     Interval r;
125
126     if (!output){
127         Molecule*m = brew_molecule_p();
128         r = m->extent().x;
129         delete m;
130     } else
131         r = output->extent().x;
132     return r;
133 }
134
135 Interval
136 Score_elem::width() const
137 {
138     Interval r=(empty_b_)?Interval(0,0):do_width();
139
140     if (!r.empty_b()) // float exception on DEC Alpha
141         r+=offset_.x;
142
143     return r;
144 }
145
146 Interval
147 Score_elem::do_height() const 
148 {
149     Interval r;
150     if (!output){
151         Molecule*m = brew_molecule_p();
152         r = m->extent().y;
153         delete m;
154     } else
155         r = output->extent().y;
156     return r;
157 }
158
159 Interval
160 Score_elem::height() const
161 {
162     Interval r=(empty_b_)?Interval(0,0): do_height();
163
164     if (!r.empty_b())
165         r+=offset_.y;
166
167   
168     return r;
169 }
170
171 void
172 Score_elem::print()const
173 {
174 #ifndef NPRINT
175     mtor << name() << "{\n";
176     mtor << "dets: " << dependent_size() << "dependencies: " << 
177         dependency_size();
178     if (offset_.x || offset_.y)
179         mtor << "offset (" << offset_.x << ", " << offset_.y <<")";
180     mtor << "\n";
181
182     do_print();
183     if (output)
184         output->print();
185     
186     mtor <<  "}\n";
187 #endif
188 }
189
190
191
192 Score_elem::Score_elem()
193 {
194     transparent_b_ = empty_b_ = false;
195     x_group_element_i_ = 0;
196     y_group_element_i_ =0;
197     pscore_l_=0;
198     offset_ = Offset(0,0);
199     output = 0;
200     status = ORPHAN;
201 }
202
203
204 Paper_def*
205 Score_elem::paper()  const
206 {
207     assert(pscore_l_);
208     return pscore_l_->paper_l_;
209 }
210
211 void
212 Score_elem::add_processing()
213 {
214     if (status >= VIRGIN)
215         return;
216     status = VIRGIN;
217     do_add_processing();
218 }
219
220 void
221 Score_elem::pre_processing()
222 {
223     if (status >= PRECALCED )
224         return;
225
226     assert(status != PRECALCING); // cyclic dependency
227     status = PRECALCING;
228
229     for (int i=0; i < dependency_size(); i++)
230         dependency(i)->pre_processing();
231
232     
233     do_pre_processing();
234     status = PRECALCED;
235 }
236
237 void
238 Score_elem::breakable_col_processing()
239 {
240     if (status >= PREBROKEN )
241         return;
242
243     assert(status != PREBREAKING); // cyclic dependency
244     status = PREBREAKING;
245
246     for (int i=0; i < dependency_size(); i++)
247         dependency(i)->breakable_col_processing();
248
249     
250     do_breakable_col_processing();
251     status = PREBROKEN;
252 }
253
254 void
255 Score_elem::break_processing()
256 {
257     if (status >= BROKEN )
258         return;
259
260     assert(status != BREAKING); // cyclic dependency
261     status = BREAKING;
262
263     for (int i=0; i < dependency_size(); i++)
264         dependency(i)->break_processing();
265
266     
267     do_break_processing();
268     status = BROKEN;
269 }
270
271 void
272 Score_elem::do_break_processing()
273 {
274     handle_broken_dependencies();
275 }
276
277
278 void
279 Score_elem::post_processing()
280 {
281     if (status >= POSTCALCED)
282         return;
283     assert(status != POSTCALCING);// cyclic dependency
284     status=POSTCALCING; 
285
286   
287     for (int i=0; i < dependency_size(); i++)
288         dependency(i)->post_processing();
289     do_post_processing();
290     status=POSTCALCED;
291 }
292
293 void 
294 Score_elem::molecule_processing()
295 {
296     if (status >= OUTPUT)
297         return;
298     status = OUTPUT;            // do it only once.
299   
300     for (int i=0; i < dependency_size(); i++)
301         dependency(i)->molecule_processing();
302
303     if (transparent_b_)
304         return ;
305     output= brew_molecule_p();
306 }
307
308 void
309 Score_elem::do_post_processing()
310 {
311 }
312
313 void
314 Score_elem::do_breakable_col_processing()
315 {
316     handle_prebroken_dependencies();
317 }
318
319 void
320 Score_elem::do_pre_processing()
321 {
322 }
323
324 void
325 Score_elem::do_add_processing()
326 {
327
328 }
329
330 void
331 Score_elem::do_substitute_dependency(Score_elem*,Score_elem*)
332 {
333 }
334 void
335 Score_elem::do_substitute_dependent(Score_elem*,Score_elem*)
336 {}
337
338
339 IMPLEMENT_STATIC_NAME(Score_elem);
340 IMPLEMENT_IS_TYPE_B(Score_elem);
341
342 Molecule*
343 Score_elem::brew_molecule_p()const
344 {
345     Atom a(paper()->lookup_l()->fill(Box(Interval(0,0), Interval(0,0))));
346     return new Molecule (a);
347 }
348 Offset
349 Score_elem::offset() const
350 {
351     return offset_; 
352 }
353
354 Line_of_score *
355 Score_elem::line_l()const
356 {
357     return 0;
358 }
359
360 /*
361   DEPENDENCIES
362  */
363
364 void
365 Score_elem::remove_dependency(Score_elem*e)
366 {
367     remove_edge_out(e);
368     e->do_substitute_dependent(this, 0);
369     do_substitute_dependency(e, 0);
370 }
371
372 void
373 Score_elem::add_dependency(Score_elem*e)
374 {
375     Directed_graph_node::add(e);
376 }
377
378
379 void
380 Score_elem::handle_broken_dependencies()
381 {
382     Line_of_score *line  = line_l();
383     if (!line)
384         return;
385
386     Link_array<Score_elem> remove_us_arr;
387     for (int i=0; i < dependency_size(); i++) {
388         Score_elem * elt = dependency(i);
389         if (elt->line_l() != line){ 
390             if (elt->spanner()) {
391                 Spanner * sp = elt->spanner();
392                 Spanner * broken = sp->find_broken_piece(line);
393                 do_substitute_dependency(sp, broken);
394
395                 add_dependency(broken);
396             } else if (elt->item() && elt->item()->pcol_l_->breakpoint_b()
397                        && elt->item()->break_status_i() == 0) {
398                 Item * my_item = elt->item()->find_prebroken_piece(line);
399                 do_substitute_dependency( elt, my_item);
400                 if (my_item)
401                     add_dependency( my_item);
402             }
403             remove_us_arr.push(elt);
404         } 
405         
406     }
407
408     remove_us_arr.default_sort();
409     remove_us_arr.uniq();
410     for (int i=0;  i <remove_us_arr.size(); i++)
411         remove_dependency(remove_us_arr[i]);
412
413     /* Reset this. If we are a (broken) copy of a spanner, then
414       break_processing() was not called on us (and we are not breaking).  */
415     if (status < BROKEN)
416         status = BROKEN;
417 }
418
419 /*
420   This sux.
421
422   unlike with spanners, the number of items can increase
423
424   span: item1
425
426   becomes
427
428   span: item1 item2 item3
429
430   How to let span (a derived class) know that this happened?
431  */
432 void
433 Score_elem::handle_prebroken_dependencies()
434 {
435     Link_array<Score_elem> remove_us_arr;
436     for (int i=0; i < dependency_size(); i++) {
437         Score_elem * elt = dependency(i);
438         Item *it_l = elt->item();
439         if (it_l && it_l->pcol_l_->breakable_b())
440             if (item()) {
441                 Score_elem *new_l = it_l->find_prebroken_piece(item()->pcol_l_);
442                 if (new_l != elt ) {
443                     do_substitute_dependency( elt, new_l);
444                     remove_us_arr.push(elt);
445                     
446                     add_dependency(new_l);
447                 } 
448             }else {
449                 add_dependency(it_l->broken_to_a_[0]);
450                 add_dependency(it_l->broken_to_a_[1]);          
451             }
452
453     }
454     
455     remove_us_arr.default_sort();
456     remove_us_arr.uniq();
457     for (int i=0;  i <remove_us_arr.size(); i++)
458         remove_dependency(remove_us_arr[i]);
459
460     /*
461       see comment at handle_broken_dependencies()
462      */
463     if (status < PREBROKEN)
464         status = PREBROKEN;
465 }
466
467
468
469 void
470 Score_elem::unlink_all()
471 {
472     for (int i=0; i < dependency_size(); i++) 
473         dependency(i)->unlink_all();
474     junk_links();
475     y_group_element_i_ = 0;
476     x_group_element_i_ = 0;
477 }
478
479 void
480 Score_elem::unlink()
481 {
482     while ( dependency_size()) {
483         do_substitute_dependency(dependency(0),0);
484         remove_edge_out_idx(0);
485     }
486     while  ( dependent_size() ) {
487         dependent(0)->remove_dependency(this);
488     }
489 }
490
491
492
493 void
494 Score_elem::OK()const
495 {
496 #ifndef NDEBUG
497     for (int i=0; i < dependency_size(); i++) {
498         dependency(i)->OK();
499     }
500 #endif
501 }