]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
release: 1.5.0
[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--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "engraver.hh"
11 #include "repeated-music.hh"
12 #include "engraver-group-engraver.hh"
13 #include "global-translator.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.hh"
20
21 #include "score-engraver.hh"
22 #include "translator-group.hh"
23
24 /**
25   This acknowledges repeated music with "percent" style.  It typesets
26   a % sign.  
27
28   TODO:
29
30   - BEAT case: Create items for single beat repeats, i.e. c4 / / /
31
32   - DOUBLE_MEASURE case: attach a % to an appropriate barline.
33   
34 */
35 class Percent_repeat_engraver : public Engraver
36 {
37   void typeset_perc ();
38 public:
39   VIRTUAL_COPY_CONS (Translator);
40   Percent_repeat_engraver ();
41 protected:
42   Repeated_music * repeat_;
43
44   /// moment (global time) where beam started.
45   Moment start_mom_;
46   Moment stop_mom_;
47
48   /// location  within measure where beam started.
49   Moment beam_start_location_;
50   Moment next_moment_;
51   Moment body_length_;
52
53   enum {
54     UNKNOWN,
55     BEAT,
56     MEASURE,
57     DOUBLE_MEASURE,
58   } repeat_sign_type_ ;
59
60   Item * beat_slash_;
61   Item * double_percent_;
62   Spanner * perc_p_;
63   Spanner * finished_perc_p_;
64   Item * stem_tremolo_;
65 protected:
66   virtual void finalize ();
67   virtual bool try_music (Music*);
68   virtual void stop_translation_timestep ();
69   virtual void start_translation_timestep ();
70   virtual void process_music ();
71 };
72
73 Percent_repeat_engraver::Percent_repeat_engraver ()
74 {
75   perc_p_  = finished_perc_p_ = 0;
76   repeat_ =0;
77   stem_tremolo_ = 0;
78
79   beat_slash_ = 0;
80   double_percent_ = 0;
81 }
82
83 bool
84 Percent_repeat_engraver::try_music (Music * m)
85 {
86   Repeated_music * rp = dynamic_cast<Repeated_music*> (m);
87   if (rp
88       && rp->get_mus_property ("iterator-ctor")
89          == Percent_repeat_iterator::constructor_cxx_function
90       && !repeat_)
91     {
92       body_length_ = rp->body_length_mom ();
93       int count =   rp->repeat_count ();
94       
95       Moment now = now_mom ();
96       start_mom_ = now;
97       stop_mom_ = start_mom_ + Moment (count) * body_length_;
98       next_moment_ = start_mom_ + body_length_;
99
100       SCM m = get_property ("measureLength");
101       Moment meas_len;
102       if (unsmob_moment (m))
103         meas_len = *unsmob_moment (m);
104
105       if (body_length_ < meas_len &&
106           meas_len.main_part_.mod_rat (body_length_.main_part_) == Moment (0,0))
107         repeat_sign_type_ = BEAT;
108       else if (meas_len == body_length_)
109         repeat_sign_type_ = MEASURE;
110       else if (Moment (2)* meas_len == body_length_)
111         {
112           repeat_sign_type_ = DOUBLE_MEASURE;
113           next_moment_ += meas_len ;
114         }
115       else
116         {
117           warning (_ ("Don't know how to handle a percent repeat of this length."));
118           return false;
119         }
120
121       repeat_ = rp;
122
123       
124       Global_translator *global_l =0;
125       Translator *t = this;
126       do
127         {
128           t = t->daddy_trans_l_ ;
129           global_l = dynamic_cast<Global_translator*> (t);
130         }
131       while (!global_l);
132
133       for (int i = 0; i < count; i++)  
134         global_l->add_moment_to_process (now + Moment (1+i) * body_length_);
135   
136       return true;
137     }
138
139   return false;
140 }
141
142 void
143 Percent_repeat_engraver::process_music ()
144 {
145   if (repeat_ && now_mom () == next_moment_)
146     {
147       if (repeat_sign_type_ == BEAT)
148         {
149           beat_slash_ = new Item (get_property ("RepeatSlash"));
150           announce_grob (beat_slash_, repeat_);
151         }
152       else if (repeat_sign_type_ == MEASURE)
153         {
154           finished_perc_p_ = perc_p_;
155           typeset_perc ();
156           perc_p_ = new Spanner (get_property ("PercentRepeat"));
157           SCM col =get_property ("currentCommandColumn");
158           perc_p_->set_bound (LEFT, unsmob_grob (col));
159           announce_grob (perc_p_, repeat_);
160         }
161       else if (repeat_sign_type_ == DOUBLE_MEASURE)
162         
163         {
164           double_percent_ = new Item (get_property ("DoublePercentRepeat"));
165           announce_grob (double_percent_, repeat_);
166
167       /*
168         forbid breaks on a % line. Should forbid all breaks, really.
169        */
170           Score_engraver * e = 0;
171           Translator * t  =  daddy_grav_l ();
172           for (; !e && t;  t = t->daddy_trans_l_)
173             {
174               e = dynamic_cast<Score_engraver*> (t);
175             }
176
177           if (!e)
178             programming_error ("No score engraver!");
179           else
180             e->forbid_breaks ();        // guh. Use properties!      
181         }
182       next_moment_ = next_moment_ + body_length_;
183     }
184 }
185
186 void
187 Percent_repeat_engraver::finalize ()
188 {
189   typeset_perc ();
190   if (perc_p_)
191     {
192       repeat_->origin ()->warning (_ ("unterminated chord tremolo"));
193       perc_p_->suicide ();
194     }
195 }
196
197 void
198 Percent_repeat_engraver::typeset_perc ()
199 {
200   if (finished_perc_p_)
201     {
202       SCM col =get_property ("currentCommandColumn");
203       finished_perc_p_->set_bound (RIGHT, unsmob_grob (col));
204       typeset_grob (finished_perc_p_);
205       finished_perc_p_ = 0;
206     }
207
208   if (beat_slash_)
209     {
210       typeset_grob (beat_slash_);
211       beat_slash_ = 0;
212     }
213
214   if (double_percent_)
215     {
216       typeset_grob (double_percent_);
217       double_percent_ = 0;
218     }
219 }
220
221
222
223
224 void
225 Percent_repeat_engraver::start_translation_timestep ()
226 {
227   if (stop_mom_ == now_mom ())
228     {
229       if (perc_p_)
230         {
231           finished_perc_p_ = perc_p_;
232           typeset_perc ();
233         }
234       repeat_ = 0;
235       perc_p_ = 0;
236       repeat_sign_type_ = UNKNOWN;
237     }
238 }
239
240
241 void
242 Percent_repeat_engraver::stop_translation_timestep ()
243 {
244   typeset_perc ();
245 }
246
247 ADD_THIS_TRANSLATOR (Percent_repeat_engraver);
248
249