]> git.donarmstrong.com Git - lilypond.git/blob - lily/p-score.cc
release: 0.1.1
[lilypond.git] / lily / p-score.cc
1 /*
2   p-score.cc -- implement PScore
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1996, 1997 Han-Wen Nienhuys <hanwen@stack.nl>
7 */
8
9 #include "super-elem.hh"
10 #include "debug.hh"
11 #include "lookup.hh"
12 #include "spanner.hh"
13 #include "paper-def.hh"
14 #include "scoreline.hh"
15 #include "p-score.hh"
16 #include "tex-stream.hh"
17 #include "p-col.hh"
18
19 #include "word-wrap.hh"
20 #include "gourlay-breaking.hh"
21
22 PScore::PScore(Paper_def*p)
23 {
24     paper_l_ = p;
25     super_elem_l_   = new Super_elem;
26     typeset_element(super_elem_l_);
27 }
28
29 PScore::~PScore()
30 {
31     super_elem_l_->unlink_all();
32 }
33
34 void
35 PScore::typeset_element(Score_elem * elem_p)
36 {
37     elem_p_list_.bottom().add(elem_p);
38     elem_p->pscore_l_ = this;
39
40     elem_p->add_processing();
41 }
42
43 void
44 PScore::typeset_item(Item *i, PCol *c, int breakstat)
45 {
46     assert(c && i);
47
48     if (breakstat == -1) {
49         typeset_item(i, c->prebreak_p_);
50         return;
51     }
52
53     if (breakstat == 1) {
54         typeset_item(i, c->postbreak_p_);
55         return;
56     }
57
58     c->add(i);
59     typeset_element(i);
60 }
61
62 void
63 PScore::typeset_broken_spanner(Spanner*span_p)
64 {
65     span_p->left_col_l_->starters.bottom().add (span_p);
66     span_p->right_col_l_->stoppers.bottom().add(span_p);
67     assert(span_p->left_col_l_->line_l_ == span_p->right_col_l_->line_l_);
68
69     typeset_element(span_p);
70 }
71
72
73 void
74 PScore::typeset_unbroken_spanner(Spanner*span_p)
75 {
76     span_p_list_.bottom().add(span_p);
77     span_p->pscore_l_=this;
78
79     if (span_p->left_col_l_) 
80         span_p->left_col_l_->used_b_ = true;
81     if ( span_p->right_col_l_)
82         span_p->right_col_l_->used_b_ = true;
83     
84     // do not init start/stop fields. These are for broken spans only.
85     span_p->add_processing();
86 }
87
88
89 void
90 PScore::clean_cols()
91 {
92     int rank_i = 0;
93     for (iter_top(col_p_list_,c); c.ok(); )
94         if (!c->used_b()) {
95             delete c.remove_p();
96         } else {
97             c->set_rank(rank_i++);
98             c++;
99         }
100 }
101
102 void
103 PScore::add(PCol *p)
104 {
105     p->pscore_l_ = this;
106     if (p->breakable_b()){
107         p->prebreak_p_->pscore_l_ = this;
108         p->postbreak_p_->pscore_l_ = this;
109     }
110     col_p_list_.bottom().add(p);
111 }
112
113 void
114 PScore::output(Tex_stream &ts)
115 {
116     ts << "\n "<<  paper_l_->lookup_l()->texsetting << "%(Tex id)\n";
117     ts<< super_elem_l_->TeX_string();
118     ts << "\n\\EndLilyPondOutput";
119 }
120
121
122 void
123 PScore::OK()const
124 {
125 #ifndef NDEBUG
126     for (iter_top(col_p_list_,cc); cc.ok(); cc++)
127         cc->OK();
128 #endif
129 }
130
131 void
132 PScore::print() const
133 {    
134 #ifndef NPRINT
135     if ( !check_debug)
136         return ;
137     mtor << "PScore { ";
138     paper_l_->print();
139     mtor << "\n elements: ";
140     for (iter_top(elem_p_list_,cc); cc.ok(); cc++)      
141         cc->print();
142     mtor << "\n unbroken spanners: ";
143     for (iter(span_p_list_.top(), i); i.ok(); i++)
144         i->print();
145     mtor << "\ncolumns: ";
146      for (iter_top(col_p_list_,cc); cc.ok(); cc++)
147         cc->print();
148     
149     mtor << "}\n";
150 #endif 
151 }
152
153 void
154 PScore::preprocess()
155 {
156     super_elem_l_->breakable_col_processing();
157     super_elem_l_->pre_processing();
158 }
159
160 void
161 PScore::postprocess()
162 {
163     super_elem_l_->post_processing();
164     super_elem_l_->molecule_processing();
165 }
166
167 PCursor<PCol *>
168 PScore::find_col(PCol const *c)const
169 {
170     PCol const *what = c;
171     if (what->daddy_l_ )
172         what = what->daddy_l_;
173     
174     return col_p_list_.find((PCol*)what);
175 }
176
177
178 void
179 PScore::set_breaking(Array<Col_hpositions> const &breaking)
180 {
181     super_elem_l_->line_of_score_l_->set_breaking( breaking);
182     super_elem_l_->break_processing();
183
184
185     for (iter(span_p_list_.top(),i); i.ok(); ) {
186         Spanner *span_p = i.remove_p();
187         if (span_p->broken_b()) {
188             span_p->unlink();
189             delete span_p;
190         }else{
191             typeset_broken_spanner(span_p);
192         }
193     }
194     for (iter(elem_p_list_.top(),i ); i.ok() ;) {
195         Item *i_l =i->item();
196         if ( i_l && !i_l->pcol_l_->line_l_) {
197             i_l->unlink();
198             delete i.remove_p();
199         } else
200             i++;
201     }
202
203     for (iter_top(col_p_list_, i); i.ok(); i++)
204         i->clean_breakable_items();
205 }
206
207 void
208 PScore::calc_breaking()
209 {
210     Break_algorithm *algorithm_p;
211     Array<Col_hpositions> sol;
212     bool try_wrap = ! paper_l_->get_var( "castingalgorithm");
213
214     if (!try_wrap) {
215         algorithm_p = new Gourlay_breaking ;
216         algorithm_p->set_pscore(this);
217         sol = algorithm_p->solve();
218         delete algorithm_p;
219         if ( ! sol.size()) { 
220             error ( "Can not solve this casting problem exactly; revert to Word_wrap");
221             try_wrap = true;
222         } 
223     }
224     if  (try_wrap) {
225         algorithm_p = new Word_wrap;    
226         algorithm_p->set_pscore(this);
227         sol = algorithm_p->solve();
228         delete algorithm_p;
229     }
230     set_breaking(sol);
231 }
232
233 void
234 PScore::process()
235 {
236     clean_cols();
237     print();
238     *mlog << "Preprocessing elements... " <<flush;
239     preprocess();
240     *mlog << "\nCalculating column positions ... " <<flush;
241     calc_breaking();
242     *mlog << "\nPostprocessing elements..." << endl;
243     postprocess();
244 }
245
246 /** Get all breakable columns between l and r, (not counting l and r).  */
247 Link_array<PCol>
248 PScore::breakable_col_range(PCol*l,PCol*r)const
249 {
250     Link_array<PCol> ret;
251
252     PCursor<PCol*> start(l ? find_col(l)+1 : col_p_list_.top() );
253     PCursor<PCol*> stop(r ? find_col(r) : col_p_list_.bottom());
254
255     /*
256       ugh! windows-suck-suck-suck.
257      */
258     while ( PCursor<PCol*>::compare(start,stop) < 0 ) {
259         if (start->breakable_b())
260             ret.push(start);
261         start++;
262     }
263
264     return ret;
265 }
266 Link_array<PCol>
267 PScore::col_range(PCol*l,PCol*r)const
268 {
269     Link_array<PCol> ret;
270     
271     PCursor<PCol*> start(l ? find_col(l)+1 : col_p_list_.top() );
272     PCursor<PCol*> stop(r ? find_col(r) : col_p_list_.bottom());
273     ret.push(l);
274     
275     /*
276       ugh! windows-suck-suck-suck.
277      */
278     while ( PCursor<PCol*>::compare(start,stop) < 0 )
279         ret.push(start++);
280     ret.push(r);
281     return ret;
282 }
283
284 Link_array<PCol>
285 PScore::broken_col_range(PCol*l,PCol*r)const
286 {
287     Link_array<PCol> ret;
288
289     PCursor<PCol*> start(l ? find_col(l)+1 : col_p_list_.top() );
290     PCursor<PCol*> stop(r ? find_col(r) : col_p_list_.bottom());
291   
292     /*
293       ugh! windows-suck-suck-suck.
294       */
295     while ( PCursor<PCol*>::compare(start,stop) < 0 ) {
296         if (start->breakable_b() && !start->line_l_ )
297             ret.push(start);
298         start++;
299     }
300
301     return ret;
302 }