]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
patch::: 1.3.141.jcn3
[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 acknowledge_grob (Grob_info);
69   virtual void stop_translation_timestep ();
70   virtual void start_translation_timestep ();
71   virtual void process_music ();
72 };
73
74 Percent_repeat_engraver::Percent_repeat_engraver ()
75 {
76   perc_p_  = finished_perc_p_ = 0;
77   repeat_ =0;
78   stem_tremolo_ = 0;
79
80   beat_slash_ = 0;
81   double_percent_ = 0;
82 }
83
84 bool
85 Percent_repeat_engraver::try_music (Music * m)
86 {
87   Repeated_music * rp = dynamic_cast<Repeated_music*> (m);
88   if (rp
89       && rp->get_mus_property ("iterator-ctor")
90          == Percent_repeat_iterator::constructor_cxx_function
91       && !repeat_)
92     {
93       body_length_ = rp->body_length_mom ();
94       int count =   rp->repeat_count ();
95       
96       Moment now = now_mom ();
97       start_mom_ = now;
98       stop_mom_ = start_mom_ + Moment (count) * body_length_;
99       next_moment_ = start_mom_ + body_length_;
100
101       SCM m = get_property ("measureLength");
102       Moment meas_len;
103       if (unsmob_moment (m))
104         meas_len = *unsmob_moment (m);
105
106       if (body_length_ < meas_len &&
107           meas_len.mod_rat (body_length_) == Moment (0,0))
108         repeat_sign_type_ = BEAT;
109       else if (meas_len == body_length_)
110         repeat_sign_type_ = MEASURE;
111       else if (Moment (2)* meas_len == body_length_)
112         {
113           repeat_sign_type_ = DOUBLE_MEASURE;
114           next_moment_ += meas_len ;
115         }
116       else
117         {
118           warning (_ ("Don't know how to handle a percent repeat of this length."));
119           return false;
120         }
121
122       repeat_ = rp;
123
124       
125       Global_translator *global_l =0;
126       Translator *t = this;
127       do
128         {
129           t = t->daddy_trans_l_ ;
130           global_l = dynamic_cast<Global_translator*> (t);
131         }
132       while (!global_l);
133
134       for (int i = 0; i < count; i++)  
135         global_l->add_moment_to_process (now + Moment (1+i) * body_length_);
136   
137       return true;
138     }
139
140   return false;
141 }
142
143 void
144 Percent_repeat_engraver::process_music ()
145 {
146   if (repeat_ && now_mom () == next_moment_)
147     {
148       if (repeat_sign_type_ == BEAT)
149         {
150           beat_slash_ = new Item (get_property ("RepeatSlash"));
151           announce_grob (beat_slash_, repeat_);
152         }
153       else if (repeat_sign_type_ == MEASURE)
154         {
155           finished_perc_p_ = perc_p_;
156           typeset_perc ();
157           perc_p_ = new Spanner (get_property ("PercentRepeat"));
158           SCM col =get_property ("currentCommandColumn");
159           perc_p_->set_bound (LEFT, unsmob_grob (col));
160           announce_grob (perc_p_, repeat_);
161         }
162       else if (repeat_sign_type_ == DOUBLE_MEASURE)
163         
164         {
165           double_percent_ = new Item (get_property ("DoublePercentRepeat"));
166           announce_grob (double_percent_, repeat_);
167
168       /*
169         forbid breaks on a % line. Should forbid all breaks, really.
170        */
171           Score_engraver * e = 0;
172           Translator * t  =  daddy_grav_l ();
173           for (; !e && t;  t = t->daddy_trans_l_)
174             {
175               e = dynamic_cast<Score_engraver*> (t);
176             }
177
178           if (!e)
179             programming_error ("No score engraver!");
180           else
181             e->forbid_breaks ();        // guh. Use properties!      
182         }
183       next_moment_ = next_moment_ + body_length_;
184     }
185 }
186
187 void
188 Percent_repeat_engraver::finalize ()
189 {
190   typeset_perc ();
191   if (perc_p_)
192     {
193       repeat_->origin ()->warning (_ ("unterminated chord tremolo"));
194       perc_p_->suicide ();
195     }
196 }
197
198 void
199 Percent_repeat_engraver::typeset_perc ()
200 {
201   if (finished_perc_p_)
202     {
203       SCM col =get_property ("currentCommandColumn");
204       finished_perc_p_->set_bound (RIGHT, unsmob_grob (col));
205       typeset_grob (finished_perc_p_);
206       finished_perc_p_ = 0;
207     }
208
209   if (beat_slash_)
210     {
211       typeset_grob (beat_slash_);
212       beat_slash_ = 0;
213     }
214
215   if (double_percent_)
216     {
217       typeset_grob (double_percent_);
218       double_percent_ = 0;
219     }
220 }
221
222
223 void
224 Percent_repeat_engraver::acknowledge_grob (Grob_info info)
225 {
226
227 }
228
229
230 void
231 Percent_repeat_engraver::start_translation_timestep ()
232 {
233   if (stop_mom_ == now_mom ())
234     {
235       if (perc_p_)
236         {
237           finished_perc_p_ = perc_p_;
238           typeset_perc ();
239         }
240       repeat_ = 0;
241       perc_p_ = 0;
242       repeat_sign_type_ = UNKNOWN;
243     }
244 }
245
246
247 void
248 Percent_repeat_engraver::stop_translation_timestep ()
249 {
250   typeset_perc ();
251 }
252
253 ADD_THIS_TRANSLATOR (Percent_repeat_engraver);
254
255