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