]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
74c87e873bd6a5c9e125b56e29631b76ac585f2d
[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--2002 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-line.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   TRANSLATOR_DECLARATIONS(Percent_repeat_engraver);
40 protected:
41   Repeated_music * repeat_;
42
43   /// moment (global time) where beam started.
44   Moment start_mom_;
45   Moment stop_mom_;
46
47   /// location  within measure where beam started.
48   Moment beam_start_location_;
49   Moment next_moment_;
50   Moment body_length_;
51
52   enum {
53     UNKNOWN,
54     BEAT,
55     MEASURE,
56     DOUBLE_MEASURE,
57   } repeat_sign_type_ ;
58
59   Item * beat_slash_;
60   Item * double_percent_;
61   Spanner * perc_;
62   Spanner * finished_perc_;
63   Item * stem_tremolo_;
64 protected:
65   virtual void finalize ();
66   virtual bool try_music (Music*);
67   virtual void stop_translation_timestep ();
68   virtual void start_translation_timestep ();
69   virtual void process_music ();
70 };
71
72 Percent_repeat_engraver::Percent_repeat_engraver ()
73 {
74   perc_  = finished_perc_ = 0;
75   repeat_ =0;
76   stem_tremolo_ = 0;
77
78   beat_slash_ = 0;
79   double_percent_ = 0;
80 }
81
82 bool
83 Percent_repeat_engraver::try_music (Music * m)
84 {
85   Repeated_music * rp = dynamic_cast<Repeated_music*> (m);
86   if (rp
87       && rp->get_mus_property ("iterator-ctor")
88          == Percent_repeat_iterator::constructor_cxx_function
89       && !repeat_)
90     {
91       body_length_ = rp->body_length_mom ();
92       int count =   rp->repeat_count ();
93       
94       Moment now = now_mom ();
95       start_mom_ = now;
96       stop_mom_ = start_mom_ + Moment (count) * body_length_;
97       next_moment_ = start_mom_ + body_length_;
98
99       SCM m = get_property ("measureLength");
100       Moment meas_len;
101       if (unsmob_moment (m))
102         meas_len = *unsmob_moment (m);
103
104       if (body_length_ < meas_len &&
105           meas_len.main_part_.mod_rat (body_length_.main_part_) == Moment (Rational (0,0)))
106         repeat_sign_type_ = BEAT;
107       else if (meas_len == body_length_)
108         repeat_sign_type_ = MEASURE;
109       else if (Moment (2)* meas_len == body_length_)
110         {
111           repeat_sign_type_ = DOUBLE_MEASURE;
112           next_moment_ += meas_len ;
113         }
114       else
115         {
116           warning (_ ("Don't know how to handle a percent repeat of this length."));
117           return false;
118         }
119
120       repeat_ = rp;
121
122       
123       Global_translator *global =0;
124       Translator *t = this;
125       do
126         {
127           t = t->daddy_trans_ ;
128           global = dynamic_cast<Global_translator*> (t);
129         }
130       while (!global);
131
132       for (int i = 0; i < count; i++)  
133         global->add_moment_to_process (now + Moment (1+i) * body_length_);
134   
135       return true;
136     }
137
138   return false;
139 }
140
141 void
142 Percent_repeat_engraver::process_music ()
143 {
144   if (repeat_ && now_mom () == next_moment_)
145     {
146       if (repeat_sign_type_ == BEAT)
147         {
148           beat_slash_ = new Item (get_property ("RepeatSlash"));
149           announce_grob(beat_slash_, repeat_->self_scm());
150         }
151       else if (repeat_sign_type_ == MEASURE)
152         {
153           finished_perc_ = perc_;
154           typeset_perc ();
155           perc_ = new Spanner (get_property ("PercentRepeat"));
156           SCM col =get_property ("currentCommandColumn");
157           perc_->set_bound (LEFT, unsmob_grob (col));
158           announce_grob(perc_, repeat_->self_scm());
159         }
160       else if (repeat_sign_type_ == DOUBLE_MEASURE)
161         
162         {
163           double_percent_ = new Item (get_property ("DoublePercentRepeat"));
164           announce_grob(double_percent_, repeat_->self_scm());
165
166       /*
167         forbid breaks on a % line. Should forbid all breaks, really.
168        */
169
170             top_engraver()->forbid_breaks ();   // guh. Use properties!      
171         }
172       next_moment_ = next_moment_ + body_length_;
173     }
174 }
175
176 void
177 Percent_repeat_engraver::finalize ()
178 {
179   typeset_perc ();
180   if (perc_)
181     {
182       repeat_->origin ()->warning (_ ("unterminated chord tremolo"));
183       perc_->suicide ();
184     }
185 }
186
187 void
188 Percent_repeat_engraver::typeset_perc ()
189 {
190   if (finished_perc_)
191     {
192       SCM col =get_property ("currentCommandColumn");
193       finished_perc_->set_bound (RIGHT, unsmob_grob (col));
194       typeset_grob (finished_perc_);
195       finished_perc_ = 0;
196     }
197
198   if (beat_slash_)
199     {
200       typeset_grob (beat_slash_);
201       beat_slash_ = 0;
202     }
203
204   if (double_percent_)
205     {
206       typeset_grob (double_percent_);
207       double_percent_ = 0;
208     }
209 }
210
211
212
213
214 void
215 Percent_repeat_engraver::start_translation_timestep ()
216 {
217   if (stop_mom_ == now_mom ())
218     {
219       if (perc_)
220         {
221           finished_perc_ = perc_;
222           typeset_perc ();
223         }
224       repeat_ = 0;
225       perc_ = 0;
226       repeat_sign_type_ = UNKNOWN;
227     }
228 }
229
230
231 void
232 Percent_repeat_engraver::stop_translation_timestep ()
233 {
234   typeset_perc ();
235 }
236
237
238
239
240 ENTER_DESCRIPTION(Percent_repeat_engraver,
241 /* descr */       "Make beat, whole bar and double bar repeats.",
242 /* creats*/       "PercentRepeat RepeatSlash DoublePercentRepeat",
243 /* acks  */       "",
244 /* reads */       "measureLength currentCommandColumn",
245 /* write */       "");