]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
e76bbaeb086c017c8c7b13ac8da8477e70e029ea
[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           /*
121             don't warn about percent repeats: slash repeats are not
122             exactly 1 or 2 measures long.
123            */
124           return;
125         }
126       percent_event_ = ev;
127     }
128   else
129     /* print a warning: no assignment happens because
130        percent_event_ != 0 */
131     ASSIGN_EVENT_ONCE (percent_event_, ev);
132 }
133
134 void
135 Percent_repeat_engraver::process_music ()
136 {
137   if (percent_event_ && now_mom ().main_part_ == start_mom_.main_part_)
138     {
139       if (repeat_sign_type_ == MEASURE)
140         {
141           if (percent_)
142             typeset_perc ();
143           
144           percent_ = make_spanner ("PercentRepeat", percent_event_->self_scm ());
145
146           Grob *col = first_command_column_;
147           percent_->set_bound (LEFT, col);
148
149           SCM count = percent_event_->get_property ("repeat-count");
150           if (count != SCM_EOL && to_boolean (get_property ("countPercentRepeats")))
151             {
152               percent_counter_
153                 = make_spanner ("PercentRepeatCounter", percent_event_->self_scm ());
154
155               SCM text = scm_number_to_string (count, scm_from_int (10));
156               percent_counter_->set_property ("text", text);
157               percent_counter_->set_bound (LEFT, col);
158               Side_position_interface::add_support (percent_counter_,
159                                                     percent_);
160               percent_counter_->set_parent (percent_, Y_AXIS);
161             }
162           else
163             percent_counter_ = 0;
164         }
165       else if (repeat_sign_type_ == DOUBLE_MEASURE)
166         {
167           Item *double_percent = make_item ("DoublePercentRepeat", percent_event_->self_scm ());
168
169           SCM count = percent_event_->get_property ("repeat-count");
170           if (count != SCM_EOL
171               && to_boolean (get_property ("countPercentRepeats")))
172             {
173               Item *double_percent_counter = make_item ("DoublePercentRepeatCounter",
174                                                         percent_event_->self_scm());
175
176               SCM text = scm_number_to_string (count,
177                                                scm_from_int (10));
178               double_percent_counter->set_property ("text", text);
179
180               Side_position_interface::add_support (double_percent_counter,
181                                                     double_percent);
182               double_percent_counter->set_parent (double_percent, Y_AXIS);
183               double_percent_counter->set_parent (double_percent, X_AXIS);
184             }
185           
186           /* forbid breaks on a % line. Should forbid all breaks, really. */
187           context ()->get_score_context ()->set_property ("forbidBreak", SCM_BOOL_T);
188
189           /* No more processing needed. */
190           repeat_sign_type_ = UNKNOWN;
191         }
192     }
193 }
194
195 void
196 Percent_repeat_engraver::finalize ()
197 {
198   if (percent_)
199     {
200       percent_event_->origin ()->warning (_ ("unterminated percent repeat"));
201       percent_->suicide ();
202       percent_counter_->suicide();
203     }
204 }
205
206 void
207 Percent_repeat_engraver::typeset_perc ()
208 {
209   if (percent_)
210     {
211       Grob *col = first_command_column_;
212
213       percent_->set_bound (RIGHT, col);
214       percent_ = 0;
215
216       if (percent_counter_)
217         percent_counter_->set_bound (RIGHT, col);
218       percent_counter_ = 0;
219     }
220 }
221
222
223
224 void
225 Percent_repeat_engraver::stop_translation_timestep ()
226 {
227 }
228
229 ADD_TRANSLATOR (Percent_repeat_engraver,
230                 /* doc */
231                 "Make whole bar and double bar repeats.",
232                 
233                 /* create */
234                 "DoublePercentRepeat "
235                 "DoublePercentRepeatCounter "
236                 "PercentRepeat "
237                 "PercentRepeatCounter ",
238                 
239                 /* accept */
240                 "percent-event ",
241
242                 /* read */
243                 "countPercentRepeats "
244                 "currentCommandColumn "
245                 "measureLength ",
246
247                 /* write */
248                 "forbidBreak "
249                 );