]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
dc6ba4213fc8e983b21ce2c9f6069046bbe8450c
[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>, Erik Sandberg <mandolaerik@gmail.com>
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 "repeated-music.hh"
18 #include "side-position-interface.hh"
19 #include "spanner.hh"
20 #include "stream-event.hh"
21 #include "warn.hh"
22
23 #include "translator.icc"
24
25 /*
26 * TODO: Create separate Double_percent_repeat_engraver? 
27 * Or, at least move double percent handling to Slash_repeat_engraver
28 */
29
30 class Percent_repeat_engraver : public Engraver
31 {
32   void typeset_perc ();
33 public:
34   TRANSLATOR_DECLARATIONS (Percent_repeat_engraver);
35   
36 protected:
37   Stream_event *percent_event_;
38
39   /// moment (global time) where percent started.
40   Moment stop_mom_;
41   Moment start_mom_;
42
43   enum Repeat_sign_type
44     {
45       UNKNOWN,
46       MEASURE,
47       DOUBLE_MEASURE,
48     };
49   Repeat_sign_type repeat_sign_type_;
50
51   Spanner *percent_;
52   Spanner *percent_counter_;
53
54   
55   Grob *first_command_column_;
56   Moment command_moment_;
57   
58 protected:
59   virtual void finalize ();
60   DECLARE_TRANSLATOR_LISTENER (percent);
61
62   void stop_translation_timestep ();
63   void start_translation_timestep ();
64   void process_music ();
65 };
66
67 Percent_repeat_engraver::Percent_repeat_engraver ()
68 {
69   percent_ = 0;
70   percent_counter_ = 0;
71   percent_event_ = 0;
72
73   first_command_column_ = 0;
74   command_moment_ = Moment (-1);
75 }
76
77 void
78 Percent_repeat_engraver::start_translation_timestep ()
79 {
80   if (now_mom ().main_part_ != command_moment_.main_part_)
81     {
82       first_command_column_ = unsmob_grob (get_property ("currentCommandColumn"));
83       command_moment_ = now_mom ();
84     }
85
86   if (stop_mom_.main_part_ == now_mom ().main_part_)
87     {
88       if (percent_)
89         typeset_perc ();
90       percent_event_ = 0;
91       repeat_sign_type_ = UNKNOWN;
92     }
93 }
94
95 IMPLEMENT_TRANSLATOR_LISTENER (Percent_repeat_engraver, percent);
96 void
97 Percent_repeat_engraver::listen_percent (Stream_event *ev)
98 {
99   if (!percent_event_)
100     {
101       Moment body_length = get_event_length (ev);
102       Moment meas_len (robust_scm2moment (get_property ("measureLength"),
103                                           Moment (1)));
104       if (meas_len == body_length)
105         {
106           repeat_sign_type_ = MEASURE;
107           start_mom_ = now_mom ();
108           stop_mom_ = now_mom () + body_length;
109           get_global_context ()->add_moment_to_process (stop_mom_);
110         }
111       else if (Moment (2) * meas_len == body_length)
112         {
113           repeat_sign_type_ = DOUBLE_MEASURE;
114           start_mom_ = now_mom () + meas_len;
115           stop_mom_ = now_mom () + body_length; /* never used */
116           get_global_context ()->add_moment_to_process (start_mom_);
117         }
118       else
119         {
120           ev->origin ()->warning (_ ("Junking percent repeat event: Duration must be exactly one or two measures"));
121           return;
122         }
123       percent_event_ = ev;
124     }
125   else
126     /* print a warning: no assignment happens because
127        percent_event_ != 0 */
128     ASSIGN_EVENT_ONCE (percent_event_, ev);
129 }
130
131 void
132 Percent_repeat_engraver::process_music ()
133 {
134   if (percent_event_ && now_mom ().main_part_ == start_mom_.main_part_)
135     {
136       if (repeat_sign_type_ == MEASURE)
137         {
138           if (percent_)
139             typeset_perc ();
140           
141           percent_ = make_spanner ("PercentRepeat", percent_event_->self_scm ());
142
143           Grob *col = first_command_column_;
144           percent_->set_bound (LEFT, col);
145
146           SCM count = percent_event_->get_property ("repeat-count");
147           if (count != SCM_EOL && to_boolean (get_property ("countPercentRepeats")))
148             {
149               percent_counter_
150                 = make_spanner ("PercentRepeatCounter", percent_event_->self_scm ());
151
152               SCM text = scm_number_to_string (count, scm_from_int (10));
153               percent_counter_->set_property ("text", text);
154               percent_counter_->set_bound (LEFT, col);
155               Side_position_interface::add_support (percent_counter_,
156                                                     percent_);
157               percent_counter_->set_parent (percent_, Y_AXIS);
158             }
159           else
160             percent_counter_ = 0;
161         }
162       else if (repeat_sign_type_ == DOUBLE_MEASURE)
163         {
164           Item *double_percent = make_item ("DoublePercentRepeat", percent_event_->self_scm ());
165
166           SCM count = percent_event_->get_property ("repeat-count");
167           if (count != SCM_EOL
168               && to_boolean (get_property ("countPercentRepeats")))
169             {
170               Item *double_percent_counter = make_item ("DoublePercentRepeatCounter",
171                                                         percent_event_->self_scm());
172
173               SCM text = scm_number_to_string (count,
174                                                scm_from_int (10));
175               double_percent_counter->set_property ("text", text);
176
177               Side_position_interface::add_support (double_percent_counter,
178                                                     double_percent);
179               double_percent_counter->set_parent (double_percent, Y_AXIS);
180               double_percent_counter->set_parent (double_percent, X_AXIS);
181             }
182           
183           /* forbid breaks on a % line. Should forbid all breaks, really. */
184           context ()->get_score_context ()->set_property ("forbidBreak", SCM_BOOL_T);
185
186           /* No more processing needed. */
187           repeat_sign_type_ = UNKNOWN;
188         }
189     }
190 }
191
192 void
193 Percent_repeat_engraver::finalize ()
194 {
195   if (percent_)
196     {
197       percent_event_->origin ()->warning (_ ("unterminated percent repeat"));
198       percent_->suicide ();
199       percent_counter_->suicide();
200     }
201 }
202
203 void
204 Percent_repeat_engraver::typeset_perc ()
205 {
206   if (percent_)
207     {
208       Grob *col = first_command_column_;
209
210       percent_->set_bound (RIGHT, col);
211       percent_ = 0;
212
213       if (percent_counter_)
214         percent_counter_->set_bound (RIGHT, col);
215       percent_counter_ = 0;
216     }
217 }
218
219
220
221 void
222 Percent_repeat_engraver::stop_translation_timestep ()
223 {
224 }
225
226 ADD_TRANSLATOR (Percent_repeat_engraver,
227                 /* doc */
228                 "Make whole bar and double bar repeats.",
229                 
230                 /* create */
231                 "DoublePercentRepeat "
232                 "DoublePercentRepeatCounter "
233                 "PercentRepeat "
234                 "PercentRepeatCounter ",
235                 
236                 /* accept */
237                 "percent-event ",
238
239                 /* read */
240                 "countPercentRepeats "
241                 "currentCommandColumn "
242                 "measureLength ",
243
244                 /* write */
245                 "forbidBreak "
246                 );