]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
b00eac52f6c8704b9ef79c92f2421fa238dd5df6
[lilypond.git] / lily / percent-repeat-engraver.cc
1 /*
2   percent-repeat-engraver.cc -- implement Percent_repeat_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2000--2007 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   bool check_count_visibility (SCM count);
34 public:
35   TRANSLATOR_DECLARATIONS (Percent_repeat_engraver);
36   
37 protected:
38   Stream_event *percent_event_;
39
40   /// moment (global time) where percent started.
41   Moment stop_mom_;
42   Moment start_mom_;
43
44   enum Repeat_sign_type
45     {
46       UNKNOWN,
47       MEASURE,
48       DOUBLE_MEASURE,
49     };
50   Repeat_sign_type repeat_sign_type_;
51
52   Spanner *percent_;
53   Spanner *percent_counter_;
54
55   
56   Grob *first_command_column_;
57   Moment command_moment_;
58   
59 protected:
60   virtual void finalize ();
61   DECLARE_TRANSLATOR_LISTENER (percent);
62
63   void stop_translation_timestep ();
64   void start_translation_timestep ();
65   void process_music ();
66 };
67
68 Percent_repeat_engraver::Percent_repeat_engraver ()
69 {
70   percent_ = 0;
71   percent_counter_ = 0;
72   percent_event_ = 0;
73
74   first_command_column_ = 0;
75   command_moment_ = Moment (-1);
76 }
77
78 void
79 Percent_repeat_engraver::start_translation_timestep ()
80 {
81   if (now_mom ().main_part_ != command_moment_.main_part_)
82     {
83       first_command_column_ = unsmob_grob (get_property ("currentCommandColumn"));
84       command_moment_ = now_mom ();
85     }
86
87   if (stop_mom_.main_part_ == now_mom ().main_part_)
88     {
89       if (percent_)
90         typeset_perc ();
91       percent_event_ = 0;
92       repeat_sign_type_ = UNKNOWN;
93     }
94 }
95
96 IMPLEMENT_TRANSLATOR_LISTENER (Percent_repeat_engraver, percent);
97 void
98 Percent_repeat_engraver::listen_percent (Stream_event *ev)
99 {
100   if (!percent_event_)
101     {
102       Moment body_length = get_event_length (ev);
103       Moment meas_len (robust_scm2moment (get_property ("measureLength"),
104                                           Moment (1)));
105       if (meas_len == body_length)
106         {
107           repeat_sign_type_ = MEASURE;
108           start_mom_ = now_mom ();
109           stop_mom_ = now_mom () + body_length;
110           get_global_context ()->add_moment_to_process (stop_mom_);
111         }
112       else if (Moment (2) * meas_len == body_length)
113         {
114           repeat_sign_type_ = DOUBLE_MEASURE;
115           start_mom_ = now_mom () + meas_len;
116           stop_mom_ = now_mom () + body_length; /* never used */
117           get_global_context ()->add_moment_to_process (start_mom_);
118         }
119       else
120         {
121           /*
122             don't warn about percent repeats: slash repeats are not
123             exactly 1 or 2 measures long.
124           */
125           return;
126         }
127       percent_event_ = ev;
128     }
129   else
130     /* print a warning: no assignment happens because
131        percent_event_ != 0 */
132     ASSIGN_EVENT_ONCE (percent_event_, ev);
133 }
134
135 void
136 Percent_repeat_engraver::process_music ()
137 {
138   if (percent_event_ && now_mom ().main_part_ == start_mom_.main_part_)
139     {
140       if (repeat_sign_type_ == MEASURE)
141         {
142           if (percent_)
143             typeset_perc ();
144           
145           percent_ = make_spanner ("PercentRepeat", percent_event_->self_scm ());
146
147           Grob *col = first_command_column_;
148           percent_->set_bound (LEFT, col);
149
150           SCM count = percent_event_->get_property ("repeat-count");
151           if (count != SCM_EOL && to_boolean (get_property ("countPercentRepeats"))
152               && check_count_visibility (count))
153             {
154               percent_counter_
155                 = make_spanner ("PercentRepeatCounter", percent_event_->self_scm ());
156
157               SCM text = scm_number_to_string (count, scm_from_int (10));
158               percent_counter_->set_property ("text", text);
159               percent_counter_->set_bound (LEFT, col);
160               Side_position_interface::add_support (percent_counter_,
161                                                     percent_);
162               percent_counter_->set_parent (percent_, Y_AXIS);
163             }
164           else
165             percent_counter_ = 0;
166         }
167       else if (repeat_sign_type_ == DOUBLE_MEASURE)
168         {
169           Item *double_percent = make_item ("DoublePercentRepeat", percent_event_->self_scm ());
170
171           SCM count = percent_event_->get_property ("repeat-count");
172           if (count != SCM_EOL && to_boolean (get_property ("countPercentRepeats"))
173               && check_count_visibility (count))
174             {
175               Item *double_percent_counter = make_item ("DoublePercentRepeatCounter",
176                                                         percent_event_->self_scm ());
177
178               SCM text = scm_number_to_string (count,
179                                                scm_from_int (10));
180               double_percent_counter->set_property ("text", text);
181
182               Side_position_interface::add_support (double_percent_counter,
183                                                     double_percent);
184               double_percent_counter->set_parent (double_percent, Y_AXIS);
185               double_percent_counter->set_parent (double_percent, X_AXIS);
186             }
187           
188           /* forbid breaks on a % line. Should forbid all breaks, really. */
189           context ()->get_score_context ()->set_property ("forbidBreak", SCM_BOOL_T);
190
191           /* No more processing needed. */
192           repeat_sign_type_ = UNKNOWN;
193         }
194     }
195 }
196
197 void
198 Percent_repeat_engraver::finalize ()
199 {
200   if (percent_)
201     {
202       percent_event_->origin ()->warning (_ ("unterminated percent repeat"));
203       percent_->suicide ();
204       percent_counter_->suicide ();
205     }
206 }
207
208 void
209 Percent_repeat_engraver::typeset_perc ()
210 {
211   if (percent_)
212     {
213       Grob *col = first_command_column_;
214
215       percent_->set_bound (RIGHT, col);
216       percent_ = 0;
217
218       if (percent_counter_)
219         percent_counter_->set_bound (RIGHT, col);
220       percent_counter_ = 0;
221     }
222 }
223
224 bool
225 Percent_repeat_engraver::check_count_visibility (SCM count)
226 {
227   SCM proc = get_property ("repeatCountVisibility");
228   return (ly_is_procedure (proc) && to_boolean (scm_call_2 (proc,
229                                                             count,
230                                                             context ()->self_scm ())));
231 }
232
233
234 void
235 Percent_repeat_engraver::stop_translation_timestep ()
236 {
237 }
238
239 ADD_TRANSLATOR (Percent_repeat_engraver,
240                 /* doc */
241                 "Make whole bar and double bar repeats.",
242                 
243                 /* create */
244                 "DoublePercentRepeat "
245                 "DoublePercentRepeatCounter "
246                 "PercentRepeat "
247                 "PercentRepeatCounter ",
248
249                 /* read */
250                 "countPercentRepeats "
251                 "currentCommandColumn "
252                 "measureLength "
253                 "repeatCountVisibility ",
254
255                 /* write */
256                 "forbidBreak "
257                 );