]> git.donarmstrong.com Git - lilypond.git/blob - lily/score-engraver.cc
release: 1.3.74
[lilypond.git] / lily / score-engraver.cc
1 /*
2   score-engraver.cc -- implement Score_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "debug.hh"
10
11 #include "line-of-score.hh"
12 #include "item.hh"
13 #include "score-engraver.hh"
14 #include "paper-score.hh"
15 #include "musical-request.hh"
16 #include "paper-column.hh"
17 #include "command-request.hh"
18 #include "paper-def.hh"
19 #include "axis-group-interface.hh"
20
21 Score_engraver::Score_engraver()
22 {
23   scoreline_l_ =0;
24   command_column_l_ =0;
25   musical_column_l_ =0;
26   breaks_i_ =0;
27   pscore_p_ = 0;
28 }
29  
30 void
31 Score_engraver::prepare (Moment w)
32 {
33   Global_translator::prepare (w);
34
35   SCM props = get_property (ly_symbol2scm ("basicPaperColumnProperties"));
36   set_columns (new Paper_column (props),  new Paper_column (props));
37   
38   command_column_l_->set_elt_property ("when", w.make_scm());
39   musical_column_l_->set_elt_property ("when", w.make_scm());
40   command_column_l_->set_elt_property ("breakable", SCM_BOOL_T);
41   
42   Score_element_info i1(command_column_l_, 0), i2 (musical_column_l_,0);
43
44   i1.origin_trans_l_ = this;
45   i2.origin_trans_l_ = this;
46   announce_element (i1);
47   announce_element (i2);
48   
49   post_move_processing();
50 }
51
52 void
53 Score_engraver::finish()
54 {
55   if ((breaks_i_%8))
56     progress_indication ("[" + to_str ( breaks_i_) + "]");
57    
58   check_removal();
59   removal_processing();
60 }
61
62 /*
63   use start/finish?
64  */
65 void
66 Score_engraver::do_creation_processing ()
67 {
68   scoreline_l_ = pscore_p_->line_l_;
69
70   scoreline_l_->set_bound(LEFT, command_column_l_);
71   
72   command_column_l_->set_elt_property ("breakable", SCM_BOOL_T);
73
74   Engraver_group_engraver::do_creation_processing();
75 }
76
77
78 void
79 Score_engraver::do_removal_processing()
80 {
81   Engraver_group_engraver::do_removal_processing();
82   scoreline_l_->set_bound(RIGHT,command_column_l_);
83   command_column_l_->set_elt_property ("breakable", SCM_BOOL_T);
84
85   
86   typeset_all ();
87
88
89   set_columns (0,0);
90 }
91
92 void
93 Score_engraver::process()
94 {
95   process_music();
96   do_announces();
97   pre_move_processing();
98   check_removal();
99 }
100
101 void
102 Score_engraver::announce_element (Score_element_info info)
103 {
104   announce_info_arr_.push (info);
105   pscore_p_->line_l_->typeset_element (info.elem_l_);
106 }
107
108 /* All elements are propagated to the top upon announcement. If
109    something was created during one run of
110    Engraver_group_engraver::do_announces, then
111    announce_info_arr_.size() will be nonzero again
112 */
113 /* junkme? Done by Engraver_group_engraver::do_announces ()?
114  */
115    
116 void
117 Score_engraver::do_announces()
118 {
119   while (announce_info_arr_.size()) 
120     Engraver_group_engraver::do_announces();
121 }
122
123
124 void
125 Score_engraver::typeset_element (Score_element *elem_p)
126 {
127   elem_p_arr_.push (elem_p);
128 }
129
130
131 void
132 Score_engraver::typeset_all()
133 {
134   for  (int i =0; i < elem_p_arr_.size(); i++) 
135     {
136       Score_element * elem_p = elem_p_arr_[i];
137       elem_p->add_processing ();
138
139       
140       if (Spanner *s = dynamic_cast <Spanner *> (elem_p))
141         {
142             /*
143             do something sensible if spanner not 
144             spanned on 2 items.
145            */
146           Direction d = LEFT;
147           do {
148             if (!s->get_bound (d))
149               {
150                 s->set_bound(d, command_column_l_);
151                 ::warning (_f ("unbound spanner `%s'", classname(s)));
152               }
153           } while (flip(&d) != LEFT);
154         }
155       else 
156         {
157           if (!elem_p->parent_l (X_AXIS))
158             {
159               bool br = to_boolean (elem_p->get_elt_property ("breakable"));
160               Axis_group_interface::add_element (br ? command_column_l_ : musical_column_l_, elem_p);
161
162             }
163         }
164       if (!elem_p->parent_l(Y_AXIS))
165         Axis_group_interface::add_element (scoreline_l_, elem_p);
166     }
167   elem_p_arr_.clear();
168 }
169
170 void
171 Score_engraver::do_pre_move_processing()
172 {
173   if (to_boolean (command_column_l_->get_elt_property ("breakable")))
174     {
175       breaks_i_ ++;
176       if (! (breaks_i_%8))
177         progress_indication ("[" + to_str ( breaks_i_) + "]");
178     }
179   // this generates all items.
180   Engraver_group_engraver::do_pre_move_processing();
181   
182   typeset_all();
183 }
184
185 void
186 Score_engraver::set_columns (Paper_column *new_command_l, 
187                              Paper_column *new_musical_l)
188 {
189   Paper_column * news[] = {new_command_l, new_musical_l};
190   Paper_column **current[] = {&command_column_l_, &musical_column_l_};
191
192   for (int i=00; i< 2; i++) 
193     {
194       if (*current[i])
195         {
196           scoreline_l_->add_column ((*current[i]));
197           if (!Paper_column::used_b (*current[i]))
198             {
199               (*current[i])->suicide ();
200               *current[i]  =0;
201             }
202         }
203       if (news[i])
204         *current[i] = news[i];
205     }
206
207   if (new_musical_l)
208     set_property ("currentMusicalColumn", new_musical_l->self_scm ());
209   if (new_command_l)
210     set_property ("currentCommandColumn", new_command_l->self_scm ());  
211 }
212
213 Music_output*
214 Score_engraver::get_output_p ()
215 {
216   Music_output * o = pscore_p_;
217   pscore_p_=0;
218   return o;
219 }
220
221 bool
222 Score_engraver::do_try_music (Music*r)
223 {
224   bool gotcha = Engraver_group_engraver::do_try_music (r);  
225
226   if (!gotcha)
227     {
228       if (Break_req* b = dynamic_cast<Break_req *> (r))
229         {
230           gotcha = true;
231
232
233           SCM pen = command_column_l_->get_elt_property  ("penalty");
234           Real total_penalty = gh_number_p (pen)
235             ? gh_scm2double(pen)
236             : 0.0;
237
238           total_penalty += b->penalty_f_;
239           if (b->penalty_f_ > 10000.0) //  ugh. arbitrary.
240             forbid_breaks ();
241
242           command_column_l_->set_elt_property ("penalty",
243                                                gh_double2scm (total_penalty));
244         }
245     }
246    return gotcha;
247 }
248
249 void
250 Score_engraver::forbid_breaks ()
251 {
252   /*
253     result is junked.
254    */
255   command_column_l_->remove_elt_property ("breakable");
256 }
257
258 ADD_THIS_TRANSLATOR(Score_engraver);
259
260 void
261 Score_engraver::do_add_processing ()
262 {
263   Translator_group::do_add_processing ();
264   assert (dynamic_cast<Paper_def *> (output_def_l_));
265   assert (!daddy_trans_l_);
266   pscore_p_ = new Paper_score;
267   pscore_p_->paper_l_ = dynamic_cast<Paper_def*>(output_def_l_);
268
269   SCM props = get_property(ly_symbol2scm ("basicLineOfScoreProperties"));
270
271   pscore_p_->typeset_line (new Line_of_score (props));
272 }
273