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