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