]> git.donarmstrong.com Git - lilypond.git/blob - lily/multi-measure-rest-engraver.cc
* lily/multi-measure-rest-engraver.cc (class
[lilypond.git] / lily / multi-measure-rest-engraver.cc
1 /*
2   multi_measure_rest-engraver.cc -- implement Multi_measure_rest_engraver
3
4   (c) 1998--2003 Jan Nieuwenhuizen <janneke@gnu.org>
5        Han-Wen Nienhuys <hanwen@cs.uu.nl>
6 */
7
8 #include "event.hh"
9 #include "multi-measure-rest.hh"
10 #include "paper-column.hh"
11 #include "engraver-group-engraver.hh"
12 #include "side-position-interface.hh"
13 #include "staff-symbol-referencer.hh"
14 #include "engraver.hh"
15 #include "moment.hh"
16 #include "spanner.hh"
17
18 /**
19    The name says it all: make multi measure rests 
20
21 */
22 class Multi_measure_rest_engraver : public Engraver
23 {
24 public:
25   TRANSLATOR_DECLARATIONS(Multi_measure_rest_engraver);
26
27 protected:
28   virtual bool try_music (Music*);
29   virtual void process_music ();
30   virtual void stop_translation_timestep ();
31   virtual void start_translation_timestep ();
32   virtual void finalize ();
33
34 private:
35   Music * new_req_;
36   Music * busy_span_req_;
37   Music * stop_req_;
38   Link_array<Music> text_events_;
39   int start_measure_;
40   Moment start_moment_;
41   
42
43   Spanner *mmrest_;
44   Link_array<Spanner> numbers_;
45
46   Link_array<Spanner> last_numbers_;
47   Spanner *last_rest_;
48 };
49
50 Multi_measure_rest_engraver::Multi_measure_rest_engraver ()
51 {
52   start_measure_ = 0;
53   mmrest_ = 0;
54   last_rest_ =0;
55   new_req_ = busy_span_req_ = stop_req_ =0;
56 }
57
58 bool
59 Multi_measure_rest_engraver::try_music (Music* req)
60 {
61   if (req->is_mus_type ("multi-measure-rest-event"))
62     {
63       Direction d = to_dir (req->get_mus_property ("span-direction"));
64       if (d == STOP)
65         {
66           stop_req_ = req;
67         }
68       else if (d == START&& !new_req_)
69         {
70           new_req_ = req;
71         }
72       return true;
73     }
74   else if (req->is_mus_type ("multi-measure-text-event"))
75     {
76       text_events_.push (req);
77       return true;
78     }
79   return false;
80 }
81
82 void
83 Multi_measure_rest_engraver::process_music ()
84 {
85   if (new_req_ && stop_req_)
86     stop_req_ = 0;
87
88   if (new_req_)
89     start_moment_ = now_mom ();
90
91   if (stop_req_)
92     {
93       busy_span_req_ =0;
94       stop_req_ = 0;
95     }
96   
97   if (new_req_)
98     {
99       busy_span_req_ = new_req_;
100       new_req_ =0;
101     }
102
103   if (busy_span_req_ && !mmrest_)
104     {
105       mmrest_ = new Spanner (get_property ("MultiMeasureRest"));
106
107       if (text_events_.size())
108         {
109           for (int i = 0; i < text_events_.size(); i++)
110             {
111               Spanner *sp
112                 = new Spanner (get_property ("MultiMeasureRestText"));
113
114               Music* e = text_events_[i];
115               SCM t = e->get_mus_property ("text");
116               SCM dir = e->get_mus_property ("direction");
117               sp->set_grob_property ("text",t);
118               if (ly_dir_p (dir))
119                 sp->set_grob_property ("direction",dir);
120               
121               numbers_.push (sp);
122               announce_grob (sp, e->self_scm());
123             }
124
125           /*
126             Stack different scripts.
127            */
128           Direction d = DOWN; 
129           do {
130             Grob *last =0;
131             for (int i=0; i <numbers_.size(); i++)
132               {
133                 if (gh_int2scm (d) == numbers_[i]->get_grob_property ("direction"))
134                   {
135                     if (last)
136                       Side_position_interface::add_support (numbers_[i], last);
137                     last = numbers_[i];
138                   }
139               }
140           } while (flip (&d) != DOWN);
141         }
142       else
143         {
144           Spanner *sp
145             = new Spanner (get_property ("MultiMeasureRestNumber"));
146           numbers_.push (sp);
147           announce_grob (sp, busy_span_req_->self_scm());
148         }
149
150       for (int i =0 ; i < numbers_.size(); i++)
151         {
152           Side_position_interface::add_support (numbers_[i], mmrest_);
153           numbers_[i]->set_parent (mmrest_, Y_AXIS);
154         }
155       
156       announce_grob (mmrest_, busy_span_req_->self_scm());
157       start_measure_
158         = gh_scm2int (get_property ("currentBarNumber"));
159     }
160
161   if (gh_string_p (get_property ("whichBar")))
162     {
163       Grob *cmc = unsmob_grob (get_property( "currentCommandColumn"));
164       Item *it = dynamic_cast<Item*> (cmc);
165       if (mmrest_)
166         {
167           add_bound_item (mmrest_, it);
168           for (int i = 0; i < numbers_.size(); i++)
169             add_bound_item (numbers_[i], it);
170         }
171       if (last_rest_)
172         {
173           add_bound_item (last_rest_,it);
174           for (int i = 0; i < last_numbers_.size(); i++)
175             add_bound_item (last_numbers_[i], it);
176         }      
177     }
178 }
179
180 void
181 Multi_measure_rest_engraver::stop_translation_timestep ()
182 {
183   SCM smp = get_property ("measurePosition");
184   Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
185
186   if (mmrest_ && (now_mom () >= start_moment_) 
187       && !mp.to_bool ()
188       && mmrest_->get_bound (LEFT) && mmrest_->get_bound (RIGHT))
189     {
190       typeset_grob (mmrest_);
191       for (int i = 0 ; i < numbers_.size(); i++)
192         {
193           typeset_grob (numbers_[i]);
194           Side_position_interface::add_staff_support (numbers_[i]);
195         }
196       
197       /*
198         we must keep mmrest_ around to set measure-count, so
199         no mmrest_ = 0 here. 
200        */
201     }
202
203   if (last_rest_)
204     {
205       /* sanity check */
206       if (last_rest_->get_bound (LEFT) && last_rest_->get_bound (RIGHT)
207           && last_rest_->get_bound (LEFT) != last_rest_->get_bound (RIGHT))
208         {
209           typeset_grob (last_rest_);
210
211           /*
212             huh ? add-staff-support ?
213           */
214           for (int i = 0; i < last_numbers_.size ();i++)
215             typeset_grob (last_numbers_[i]);
216         }
217       last_rest_ = 0;
218       last_numbers_.clear();
219     }
220
221   if (new_req_)
222     {
223       busy_span_req_ = new_req_;
224       new_req_ =0;
225     }
226
227   text_events_.clear ();
228 }
229
230 void
231 Multi_measure_rest_engraver::start_translation_timestep ()
232 {
233   SCM smp = get_property ("measurePosition");
234   Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
235   
236   if (mmrest_ && !mp.to_bool ())
237     {
238       last_rest_ = mmrest_;
239       last_numbers_ = numbers_;
240
241       int cur = gh_scm2int (get_property ("currentBarNumber"));
242       int num = cur - start_measure_;
243       last_rest_->set_grob_property ("measure-count", gh_int2scm (num));
244
245       SCM sml = get_property ("measureLength");
246       Rational ml = (unsmob_moment (sml)) ? unsmob_moment (sml)->main_part_ : Rational (1);
247       if (ml >= Rational (2))
248         {
249           last_rest_->set_grob_property ("use-breve-rest", SCM_BOOL_T);
250         }
251
252       mmrest_ = 0;
253
254       Grob * last = last_numbers_.size() ? last_numbers_[0] : 0;
255       if (last && last->get_grob_property ("text") == SCM_EOL)
256         {
257           SCM thres = get_property ("restNumberThreshold");
258           int t = 1;
259           if (gh_number_p (thres))
260             t = gh_scm2int (thres);
261       
262           if (num <= t)
263             last->suicide();
264           else 
265             {
266               SCM text
267                 = scm_number_to_string (gh_int2scm (num), SCM_MAKINUM (10));
268               last->set_grob_property ("text", text);
269             }
270         }
271     }
272 }
273
274 void
275 Multi_measure_rest_engraver::finalize ()
276 {
277   if (mmrest_)
278     {
279       typeset_grob (mmrest_);
280     }
281   if (last_rest_)
282     {
283       typeset_grob (last_rest_);
284     }
285
286   for (int i = 0; i < last_numbers_.size ();i++)
287     typeset_grob (last_numbers_[i]);
288
289   for (int i = 0; i < numbers_.size ();i++)
290     typeset_grob (numbers_[i]);
291
292 }
293
294 ENTER_DESCRIPTION(Multi_measure_rest_engraver,
295 /* descr */
296                   "Engraves multi-measure rests that are produced with @code{R}.  Reads "
297 "measurePosition and currentBarNumber to determine what number to print "
298 "over the MultiMeasureRest.  Reads measureLength to determine if it "
299 "should use a whole rest or a breve rest to represent 1 measure "
300                   ,
301 /* creats*/       "MultiMeasureRest MultiMeasureRestNumber MultiMeasureRestText",
302 /* accepts */     "multi-measure-rest-event multi-measure-text-event",
303 /* acks  */      "",
304 /* reads */       "currentBarNumber restNumberThreshold currentCommandColumn measurePosition measureLength",
305 /* write */       "");