]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
* Documentation/topdocs/NEWS.tely (Top): add entry for percent
[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   Spanner *percent_;
53   Spanner *percent_counter_;
54   Spanner *finished_percent_;
55   Spanner *finished_percent_counter_;
56
57   int count_;
58   int total_count_; 
59 protected:
60   virtual void finalize ();
61   virtual bool try_music (Music *);
62
63   void stop_translation_timestep ();
64   void start_translation_timestep ();
65   void process_music ();
66 };
67
68 Percent_repeat_engraver::Percent_repeat_engraver ()
69 {
70   percent_ = 0;
71   percent_counter_ = 0;
72
73   finished_percent_ = 0;
74   finished_percent_counter_ = 0;
75
76   double_percent_ = 0;
77   double_percent_counter_ = 0;
78
79   repeat_ = 0;
80   count_ = 0;
81   total_count_ = 0;
82 }
83
84 bool
85 Percent_repeat_engraver::try_music (Music *m)
86 {
87   if (m->is_mus_type ("repeated-music")
88       && m->get_property ("iterator-ctor")
89       == Percent_repeat_iterator::constructor_proc
90       && !repeat_)
91     {
92       body_length_ = Repeated_music::body_get_length (m);
93       total_count_ = Repeated_music::repeat_count (m);
94       
95       Moment now = now_mom ();
96       start_mom_ = now;
97       stop_mom_ = start_mom_ + Moment (total_count_) * body_length_;
98       next_moment_ = start_mom_ + body_length_;
99
100       Moment meas_len (robust_scm2moment (get_property ("measureLength"), Moment (1)));
101       if (meas_len == body_length_)
102         repeat_sign_type_ = MEASURE;
103       else if (Moment (2) * meas_len == body_length_)
104         repeat_sign_type_ = DOUBLE_MEASURE;
105       else
106         {
107           warning (_f ("can't handle a percent repeat of length: %s",
108                        body_length_.to_string ()));
109           return false;
110         }
111
112       repeat_ = m;
113
114       Global_context *global = get_global_context ();
115       for (int i = 1; i < total_count_; i++)
116         {
117           Moment m = next_moment_ + Moment (i) * body_length_;
118           global->add_moment_to_process (m);
119
120           /* bars between % too.  */
121           if (repeat_sign_type_ == DOUBLE_MEASURE)
122             global->add_moment_to_process (m - meas_len);
123         }
124
125       if (repeat_sign_type_ == DOUBLE_MEASURE)
126         next_moment_ += meas_len;
127
128       count_ = 1;
129       return true;
130     }
131
132   return false;
133 }
134
135 void
136 Percent_repeat_engraver::process_music ()
137 {
138   if (repeat_ && now_mom () == next_moment_)
139     {
140       count_ ++; 
141       if (repeat_sign_type_ == MEASURE)
142         {
143           finished_percent_ = percent_;
144           finished_percent_counter_ = percent_counter_;
145           
146           typeset_perc ();
147           percent_ = make_spanner ("PercentRepeat", repeat_->self_scm ());
148
149           Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
150           percent_->set_bound (LEFT, col);
151
152           if (total_count_ > 2)
153             {
154               percent_counter_
155                 = make_spanner ("PercentRepeatCounter", repeat_->self_scm ());
156
157
158               SCM text = scm_number_to_string (scm_from_int (count_),
159                                                scm_from_int (10));
160               percent_counter_->set_property ("text", text);
161               percent_counter_->set_bound (LEFT, col);
162               Side_position_interface::add_support (percent_counter_,
163                                                     percent_);
164               percent_counter_->set_parent (percent_, Y_AXIS);
165             }     
166         }
167       else if (repeat_sign_type_ == DOUBLE_MEASURE)
168         {
169           double_percent_ = make_item ("DoublePercentRepeat", repeat_->self_scm ());
170
171           if (total_count_ > 2)
172             {
173               double_percent_counter_
174                 = make_item ("DoublePercentRepeatCounter",
175                              repeat_->self_scm());
176
177               SCM text = scm_number_to_string (scm_from_int (count_),
178                                                scm_from_int (10));
179               double_percent_counter_->set_property ("text", text);
180
181               Side_position_interface::add_support (double_percent_counter_,
182                                                     double_percent_);
183               double_percent_counter_->set_parent (double_percent_, Y_AXIS);
184               double_percent_counter_->set_parent (double_percent_, X_AXIS);
185             }
186           
187           /*
188             forbid breaks on a % line. Should forbid all breaks, really.
189
190             Ugh. Why can't this be regular communication between
191             contexts?
192           */
193           get_score_engraver ()->forbid_breaks ();
194         }
195       next_moment_ = next_moment_ + body_length_;
196     }
197 }
198
199 void
200 Percent_repeat_engraver::finalize ()
201 {
202   typeset_perc ();
203   if (percent_)
204     {
205       repeat_->origin ()->warning (_ ("unterminated percent repeat"));
206       percent_->suicide ();
207       percent_counter_->suicide();
208     }
209 }
210
211 void
212 Percent_repeat_engraver::typeset_perc ()
213 {
214   if (finished_percent_)
215     {
216       Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
217
218       finished_percent_->set_bound (RIGHT, col);
219       finished_percent_ = 0;
220
221       if (finished_percent_counter_)
222         finished_percent_counter_->set_bound (RIGHT, col);
223     
224       finished_percent_counter_ = 0;
225     }
226
227   double_percent_ = 0;
228   double_percent_counter_ = 0;
229 }
230
231 void
232 Percent_repeat_engraver::start_translation_timestep ()
233 {
234   if (stop_mom_ == now_mom ())
235     {
236       if (percent_)
237         {
238           finished_percent_ = percent_;
239           finished_percent_counter_ = percent_counter_;
240
241           typeset_perc ();
242         }
243       repeat_ = 0;
244       percent_ = 0;
245       
246       percent_counter_ = 0;
247       repeat_sign_type_ = UNKNOWN;
248     }
249 }
250
251 void
252 Percent_repeat_engraver::stop_translation_timestep ()
253 {
254   typeset_perc ();
255 }
256
257 ADD_TRANSLATOR (Percent_repeat_engraver,
258                 /* doc */ "Make whole bar and double bar repeats.",
259                 /* create */
260                 "PercentRepeat DoublePercentRepeat "
261                 "PercentRepeatCounter DoublePercentRepeatCounter",
262                 /* accept */ "repeated-music",
263                 /* read */ "measureLength currentCommandColumn",
264                 /* write */ "");