]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
924098c4af1c29a0216f3a6615ebddb4f5c67e22
[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--2005 Han-Wen Nienhuys <hanwen@cs.uu.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         {
111           warning (_f ("can't handle a percent repeat of length: %s",
112                        body_length_.to_string ()));
113           return false;
114         }
115
116       repeat_ = m;
117
118       Global_context *global = get_global_context ();
119       for (int i = 1; i < total_count_; i++)
120         {
121           Moment m = next_moment_ + Moment (i) * body_length_;
122           global->add_moment_to_process (m);
123
124           /* bars between % too.  */
125           if (repeat_sign_type_ == DOUBLE_MEASURE)
126             global->add_moment_to_process (m - meas_len);
127         }
128
129       if (repeat_sign_type_ == DOUBLE_MEASURE)
130         next_moment_ += meas_len;
131
132       count_ = 1;
133       return true;
134     }
135
136   return false;
137 }
138
139 void
140 Percent_repeat_engraver::process_music ()
141 {
142   if (repeat_ && now_mom () == next_moment_)
143     {
144       count_ ++; 
145       if (repeat_sign_type_ == MEASURE)
146         {
147           finished_percent_ = percent_;
148           finished_percent_counter_ = percent_counter_;
149           
150           typeset_perc ();
151           percent_ = make_spanner ("PercentRepeat", repeat_->self_scm ());
152
153           Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
154           percent_->set_bound (LEFT, col);
155
156           if (total_count_ > 2)
157             {
158               percent_counter_
159                 = make_spanner ("PercentRepeatCounter", repeat_->self_scm ());
160
161
162               SCM text = scm_number_to_string (scm_from_int (count_),
163                                                scm_from_int (10));
164               percent_counter_->set_property ("text", text);
165               percent_counter_->set_bound (LEFT, col);
166               Side_position_interface::add_support (percent_counter_,
167                                                     percent_);
168               percent_counter_->set_parent (percent_, Y_AXIS);
169             }     
170         }
171       else if (repeat_sign_type_ == DOUBLE_MEASURE)
172         {
173           double_percent_ = make_item ("DoublePercentRepeat", repeat_->self_scm ());
174
175           if (total_count_ > 2)
176             {
177               double_percent_counter_
178                 = make_item ("DoublePercentRepeatCounter",
179                              repeat_->self_scm());
180
181               SCM text = scm_number_to_string (scm_from_int (count_),
182                                                scm_from_int (10));
183               double_percent_counter_->set_property ("text", text);
184
185               Side_position_interface::add_support (double_percent_counter_,
186                                                     double_percent_);
187               double_percent_counter_->set_parent (double_percent_, Y_AXIS);
188               double_percent_counter_->set_parent (double_percent_, X_AXIS);
189             }
190           
191           /*
192             forbid breaks on a % line. Should forbid all breaks, really.
193
194             Ugh. Why can't this be regular communication between
195             contexts?
196           */
197           get_score_engraver ()->forbid_breaks ();
198         }
199       next_moment_ = next_moment_ + body_length_;
200     }
201 }
202
203 void
204 Percent_repeat_engraver::finalize ()
205 {
206   typeset_perc ();
207   if (percent_)
208     {
209       repeat_->origin ()->warning (_ ("unterminated percent repeat"));
210       percent_->suicide ();
211       percent_counter_->suicide();
212     }
213 }
214
215 void
216 Percent_repeat_engraver::typeset_perc ()
217 {
218   if (finished_percent_)
219     {
220       Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
221
222       finished_percent_->set_bound (RIGHT, col);
223       finished_percent_ = 0;
224
225       if (finished_percent_counter_)
226         finished_percent_counter_->set_bound (RIGHT, col);
227     
228       finished_percent_counter_ = 0;
229     }
230
231   double_percent_ = 0;
232   double_percent_counter_ = 0;
233 }
234
235 void
236 Percent_repeat_engraver::start_translation_timestep ()
237 {
238   if (stop_mom_ == now_mom ())
239     {
240       if (percent_)
241         {
242           finished_percent_ = percent_;
243           finished_percent_counter_ = percent_counter_;
244
245           typeset_perc ();
246         }
247       repeat_ = 0;
248       percent_ = 0;
249       
250       percent_counter_ = 0;
251       repeat_sign_type_ = UNKNOWN;
252     }
253 }
254
255 void
256 Percent_repeat_engraver::stop_translation_timestep ()
257 {
258   typeset_perc ();
259 }
260
261 ADD_TRANSLATOR (Percent_repeat_engraver,
262                 /* doc */ "Make whole bar and double bar repeats.",
263                 /* create */
264                 "PercentRepeat DoublePercentRepeat "
265                 "PercentRepeatCounter DoublePercentRepeatCounter",
266                 /* accept */ "repeated-music",
267                 /* read */ "measureLength currentCommandColumn",
268                 /* write */ "");