]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
* The grand 2005-2006 replace.
[lilypond.git] / lily / percent-repeat-engraver.cc
1 /*
2   new-chord-tremolo-engraver.cc -- implement Chord_tremolo_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2000--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9
10 #include "score-engraver.hh"
11
12 #include "repeated-music.hh"
13 #include "global-context.hh"
14 #include "warn.hh"
15 #include "misc.hh"
16 #include "spanner.hh"
17 #include "item.hh"
18 #include "percent-repeat-iterator.hh"
19 #include "bar-line.hh"
20 #include "side-position-interface.hh"
21
22 #include "translator.icc"
23
24 class Percent_repeat_engraver : public Engraver
25 {
26   void typeset_perc ();
27 public:
28   TRANSLATOR_DECLARATIONS (Percent_repeat_engraver);
29   
30 protected:
31   Music *repeat_;
32
33   /// moment (global time) where beam started.
34   Moment start_mom_;
35   Moment stop_mom_;
36
37   /// location within measure where beam started.
38   Moment beam_start_location_;
39   Moment next_moment_;
40   Moment body_length_;
41
42   enum Repeat_sign_type
43     {
44       UNKNOWN,
45       MEASURE,
46       DOUBLE_MEASURE,
47     };
48   Repeat_sign_type repeat_sign_type_;
49
50   Item *double_percent_;
51   Item *double_percent_counter_;
52   
53   Spanner *percent_;
54   Spanner *percent_counter_;
55   Spanner *finished_percent_;
56   Spanner *finished_percent_counter_;
57
58   int count_;
59   int total_count_; 
60 protected:
61   virtual void finalize ();
62   virtual bool try_music (Music *);
63
64   void stop_translation_timestep ();
65   void start_translation_timestep ();
66   void process_music ();
67 };
68
69 Percent_repeat_engraver::Percent_repeat_engraver ()
70 {
71   percent_ = 0;
72   percent_counter_ = 0;
73
74   finished_percent_ = 0;
75   finished_percent_counter_ = 0;
76
77   double_percent_ = 0;
78   double_percent_counter_ = 0;
79
80   repeat_ = 0;
81   count_ = 0;
82   total_count_ = 0;
83 }
84
85 bool
86 Percent_repeat_engraver::try_music (Music *m)
87 {
88   if (m->is_mus_type ("repeated-music")
89       && m->get_property ("iterator-ctor")
90       == Percent_repeat_iterator::constructor_proc
91       && !repeat_)
92     {
93       body_length_ = Repeated_music::body_get_length (m);
94       total_count_ = Repeated_music::repeat_count (m);
95       
96       Moment now = now_mom ();
97       start_mom_ = now;
98       stop_mom_ = start_mom_ + Moment (total_count_) * body_length_;
99       next_moment_ = start_mom_;
100       next_moment_ += body_length_;
101
102       Moment meas_len (robust_scm2moment (get_property ("measureLength"),
103                                           Moment (1)));
104       
105       if (meas_len == body_length_)
106         repeat_sign_type_ = MEASURE;
107       else if (Moment (2) * meas_len == body_length_)
108         repeat_sign_type_ = DOUBLE_MEASURE;
109       else
110         return false;
111     
112
113       repeat_ = m;
114
115       Global_context *global = get_global_context ();
116       for (int i = 1; i < total_count_; i++)
117         {
118           Moment m = next_moment_ + Moment (i) * body_length_;
119           global->add_moment_to_process (m);
120
121           /* bars between % too.  */
122           if (repeat_sign_type_ == DOUBLE_MEASURE)
123             global->add_moment_to_process (m - meas_len);
124         }
125
126       if (repeat_sign_type_ == DOUBLE_MEASURE)
127         next_moment_ += meas_len;
128
129       count_ = 1;
130       return true;
131     }
132
133   return false;
134 }
135
136 void
137 Percent_repeat_engraver::process_music ()
138 {
139   if (repeat_ && now_mom () == next_moment_)
140     {
141       count_ ++; 
142       if (repeat_sign_type_ == MEASURE)
143         {
144           finished_percent_ = percent_;
145           finished_percent_counter_ = percent_counter_;
146           
147           typeset_perc ();
148           percent_ = make_spanner ("PercentRepeat", repeat_->self_scm ());
149
150           Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
151           percent_->set_bound (LEFT, col);
152
153           if (total_count_ > 2
154               && to_boolean (get_property ("countPercentRepeats")))
155             {
156               percent_counter_
157                 = make_spanner ("PercentRepeatCounter", repeat_->self_scm ());
158
159
160               SCM text = scm_number_to_string (scm_from_int (count_),
161                                                scm_from_int (10));
162               percent_counter_->set_property ("text", text);
163               percent_counter_->set_bound (LEFT, col);
164               Side_position_interface::add_support (percent_counter_,
165                                                     percent_);
166               percent_counter_->set_parent (percent_, Y_AXIS);
167             }     
168         }
169       else if (repeat_sign_type_ == DOUBLE_MEASURE)
170         {
171           double_percent_ = make_item ("DoublePercentRepeat", repeat_->self_scm ());
172
173           if (total_count_ > 2
174               && to_boolean (get_property ("countPercentRepeats")))
175             {
176               double_percent_counter_
177                 = make_item ("DoublePercentRepeatCounter",
178                              repeat_->self_scm());
179
180               SCM text = scm_number_to_string (scm_from_int (count_),
181                                                scm_from_int (10));
182               double_percent_counter_->set_property ("text", text);
183
184               Side_position_interface::add_support (double_percent_counter_,
185                                                     double_percent_);
186               double_percent_counter_->set_parent (double_percent_, Y_AXIS);
187               double_percent_counter_->set_parent (double_percent_, X_AXIS);
188             }
189           
190           /*
191             forbid breaks on a % line. Should forbid all breaks, really.
192
193             Ugh. Why can't this be regular communication between
194             contexts?
195           */
196           get_score_engraver ()->forbid_breaks ();
197         }
198       next_moment_ = next_moment_ + body_length_;
199     }
200 }
201
202 void
203 Percent_repeat_engraver::finalize ()
204 {
205   typeset_perc ();
206   if (percent_)
207     {
208       repeat_->origin ()->warning (_ ("unterminated percent repeat"));
209       percent_->suicide ();
210       percent_counter_->suicide();
211     }
212 }
213
214 void
215 Percent_repeat_engraver::typeset_perc ()
216 {
217   if (finished_percent_)
218     {
219       Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
220
221       finished_percent_->set_bound (RIGHT, col);
222       finished_percent_ = 0;
223
224       if (finished_percent_counter_)
225         finished_percent_counter_->set_bound (RIGHT, col);
226     
227       finished_percent_counter_ = 0;
228     }
229
230   double_percent_ = 0;
231   double_percent_counter_ = 0;
232 }
233
234 void
235 Percent_repeat_engraver::start_translation_timestep ()
236 {
237   if (stop_mom_ == now_mom ())
238     {
239       if (percent_)
240         {
241           finished_percent_ = percent_;
242           finished_percent_counter_ = percent_counter_;
243
244           typeset_perc ();
245         }
246       repeat_ = 0;
247       percent_ = 0;
248       
249       percent_counter_ = 0;
250       repeat_sign_type_ = UNKNOWN;
251     }
252 }
253
254 void
255 Percent_repeat_engraver::stop_translation_timestep ()
256 {
257   typeset_perc ();
258 }
259
260 ADD_TRANSLATOR (Percent_repeat_engraver,
261                 /* doc */
262                 "Make whole bar and double bar repeats.",
263                 
264                 /* create */
265                 "PercentRepeat "
266                 "DoublePercentRepeat "
267                 "PercentRepeatCounter "
268                 "DoublePercentRepeatCounter",
269                 
270                 /* accept */
271                 "repeated-music",
272
273                 /* read */
274                 "measureLength "
275                 "currentCommandColumn "
276                 "countPercentRepeats",
277
278                 /* write */ "");