]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-elem.cc
release: 0.0.70pre
[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
335
336 IMPLEMENT_STATIC_NAME(Score_elem);
337 IMPLEMENT_IS_TYPE_B(Score_elem);
338
339 Molecule*
340 Score_elem::brew_molecule_p()const
341 {
342     Atom a(paper()->lookup_l()->fill(Box(Interval(0,0), Interval(0,0))));
343     return new Molecule (a);
344 }
345 Offset
346 Score_elem::offset() const
347 {
348     return offset_; 
349 }
350
351 Line_of_score *
352 Score_elem::line_l()const
353 {
354     return 0;
355 }
356
357 /*
358   DEPENDENCIES
359  */
360
361 void
362 Score_elem::remove_dependency(Score_elem*e)
363 {
364     remove_edge_out(e);
365     do_substitute_dependency(e, 0);
366 }
367
368 void
369 Score_elem::add_dependency(Score_elem*e)
370 {
371     Directed_graph_node::add(e);
372 }
373
374
375 void
376 Score_elem::handle_broken_dependencies()
377 {
378     Line_of_score *line  = line_l();
379     if (!line)
380         return;
381
382     Link_array<Score_elem> remove_us_arr;
383     for (int i=0; i < dependency_size(); i++) {
384         Score_elem * elt = dependency(i);
385         if (elt->line_l() != line){ 
386             if (elt->spanner()) {
387                 Spanner * sp = elt->spanner();
388                 Spanner * broken = sp->find_broken_piece(line);
389                 do_substitute_dependency(sp, broken);
390                 add_dependency(broken);
391             } else if (elt->item() && elt->item()->pcol_l_->breakpoint_b()
392                        && elt->item()->break_status_i() == 0) {
393                 Item * my_item = elt->item()->find_prebroken_piece(line);
394                 do_substitute_dependency( elt, my_item);
395                 if (my_item)
396                     add_dependency( my_item);
397             }
398             remove_us_arr.push(elt);
399         } 
400         
401     }
402
403     remove_us_arr.default_sort();
404     remove_us_arr.uniq();
405     for (int i=0;  i <remove_us_arr.size(); i++)
406         remove_dependency(remove_us_arr[i]);
407
408     /* Reset this. If we are a (broken) copy of a spanner, then
409       break_processing() was not called on us (and we are not breaking).  */
410     if (status < BROKEN)
411         status = BROKEN;
412 }
413
414 /*
415   This sux.
416
417   unlike with spanners, the number of items can increase
418
419   span: item1
420
421   becomes
422
423   span: item1 item2 item3
424
425   How to let span (a derived class) know that this happened?
426  */
427 void
428 Score_elem::handle_prebroken_dependencies()
429 {
430     Link_array<Score_elem> remove_us_arr;
431     for (int i=0; i < dependency_size(); i++) {
432         Score_elem * elt = dependency(i);
433         Item *it_l = elt->item();
434         if (it_l && it_l->pcol_l_->breakable_b())
435             if (item()) {
436                 Score_elem *new_l = it_l->find_prebroken_piece(item()->pcol_l_);
437                 if (new_l != elt ) {
438                     do_substitute_dependency( elt, new_l);
439                     remove_us_arr.push(elt);
440                     
441                     add_dependency(new_l);
442                 } 
443             }else {
444                 add_dependency(it_l->broken_to_a_[0]);
445                 add_dependency(it_l->broken_to_a_[1]);          
446             }
447
448     }
449     
450     remove_us_arr.default_sort();
451     remove_us_arr.uniq();
452     for (int i=0;  i <remove_us_arr.size(); i++)
453         remove_dependency(remove_us_arr[i]);
454
455     /*
456       see comment at handle_broken_dependencies()
457      */
458     if (status < PREBROKEN)
459         status = PREBROKEN;
460 }
461
462
463
464 void
465 Score_elem::unlink_all()
466 {
467     for (int i=0; i < dependency_size(); i++) 
468         dependency(i)->unlink_all();
469     junk_links();
470     y_group_element_i_ = 0;
471     x_group_element_i_ = 0;
472 }
473
474 void
475 Score_elem::unlink()
476 {
477     while ( dependency_size()) {
478         do_substitute_dependency(dependency(0),0);
479         remove_edge_out_idx(0);
480     }
481     while  ( dependent_size() ) {
482         dependent(0)->remove_dependency(this);
483     }
484 }
485
486
487
488 void
489 Score_elem::OK()const
490 {
491 #ifndef NDEBUG
492     for (int i=0; i < dependency_size(); i++) {
493         dependency(i)->OK();
494     }
495 #endif
496 }