]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
* Documentation/user/changing-defaults.itely (Module): add menu entry.
[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 "bar-line.hh"
13 #include "global-context.hh"
14 #include "international.hh"
15 #include "item.hh"
16 #include "misc.hh"
17 #include "percent-repeat-iterator.hh"
18 #include "repeated-music.hh"
19 #include "side-position-interface.hh"
20 #include "spanner.hh"
21 #include "warn.hh"
22
23 #include "translator.icc"
24
25 class Percent_repeat_engraver : public Engraver
26 {
27   void typeset_perc ();
28 public:
29   TRANSLATOR_DECLARATIONS (Percent_repeat_engraver);
30   
31 protected:
32   Music *repeat_;
33
34   /// moment (global time) where beam started.
35   Moment start_mom_;
36   Moment stop_mom_;
37
38   /// location within measure where beam started.
39   Moment beam_start_location_;
40   Moment next_moment_;
41   Moment body_length_;
42
43   enum Repeat_sign_type
44     {
45       UNKNOWN,
46       MEASURE,
47       DOUBLE_MEASURE,
48     };
49   Repeat_sign_type repeat_sign_type_;
50
51   Item *double_percent_;
52   Item *double_percent_counter_;
53   
54   Spanner *percent_;
55   Spanner *percent_counter_;
56   Spanner *finished_percent_;
57   Spanner *finished_percent_counter_;
58
59   int count_;
60   int total_count_; 
61 protected:
62   virtual void finalize ();
63   virtual bool try_music (Music *);
64
65   void stop_translation_timestep ();
66   void start_translation_timestep ();
67   void process_music ();
68 };
69
70 Percent_repeat_engraver::Percent_repeat_engraver ()
71 {
72   percent_ = 0;
73   percent_counter_ = 0;
74
75   finished_percent_ = 0;
76   finished_percent_counter_ = 0;
77
78   double_percent_ = 0;
79   double_percent_counter_ = 0;
80
81   repeat_ = 0;
82   count_ = 0;
83   total_count_ = 0;
84 }
85
86 bool
87 Percent_repeat_engraver::try_music (Music *m)
88 {
89   if (m->is_mus_type ("repeated-music")
90       && m->get_property ("iterator-ctor")
91       == Percent_repeat_iterator::constructor_proc
92       && !repeat_)
93     {
94       body_length_ = Repeated_music::body_get_length (m);
95       total_count_ = Repeated_music::repeat_count (m);
96       
97       Moment now = now_mom ();
98       start_mom_ = now;
99       stop_mom_ = start_mom_ + Moment (total_count_) * body_length_;
100       next_moment_ = start_mom_;
101       next_moment_ += body_length_;
102
103       Moment meas_len (robust_scm2moment (get_property ("measureLength"),
104                                           Moment (1)));
105       
106       if (meas_len == body_length_)
107         repeat_sign_type_ = MEASURE;
108       else if (Moment (2) * meas_len == body_length_)
109         repeat_sign_type_ = DOUBLE_MEASURE;
110       else
111         return false;
112     
113
114       repeat_ = m;
115
116       Global_context *global = get_global_context ();
117       for (int i = 1; i < total_count_; i++)
118         {
119           Moment m = next_moment_ + Moment (i) * body_length_;
120           global->add_moment_to_process (m);
121
122           /* bars between % too.  */
123           if (repeat_sign_type_ == DOUBLE_MEASURE)
124             global->add_moment_to_process (m - meas_len);
125         }
126
127       if (repeat_sign_type_ == DOUBLE_MEASURE)
128         next_moment_ += meas_len;
129
130       count_ = 1;
131       return true;
132     }
133
134   return false;
135 }
136
137 void
138 Percent_repeat_engraver::process_music ()
139 {
140   if (repeat_ && now_mom ().main_part_ == next_moment_.main_part_)
141     {
142       count_ ++; 
143       if (repeat_sign_type_ == MEASURE)
144         {
145           finished_percent_ = percent_;
146           finished_percent_counter_ = percent_counter_;
147           
148           typeset_perc ();
149           percent_ = make_spanner ("PercentRepeat", repeat_->self_scm ());
150
151           Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
152           percent_->set_bound (LEFT, col);
153
154           if (total_count_ > 2
155               && to_boolean (get_property ("countPercentRepeats")))
156             {
157               percent_counter_
158                 = make_spanner ("PercentRepeatCounter", repeat_->self_scm ());
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       next_moment_.grace_part_ = Rational (0);
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_.main_part_ == now_mom ().main_part_)
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 */
263                 "Make whole bar and double bar repeats.",
264                 
265                 /* create */
266                 "PercentRepeat "
267                 "DoublePercentRepeat "
268                 "PercentRepeatCounter "
269                 "DoublePercentRepeatCounter",
270                 
271                 /* accept */
272                 "repeated-music",
273
274                 /* read */
275                 "measureLength "
276                 "currentCommandColumn "
277                 "countPercentRepeats",
278
279                 /* write */ "");