]> git.donarmstrong.com Git - lilypond.git/blob - lily/multi-measure-rest-engraver.cc
* mf/GNUmakefile: always trace pfa fonts.
[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   Rational last_main_moment_;
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 (is_direction (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       
172       if (last_rest_)
173         {
174           add_bound_item (last_rest_,it);
175           for (int i = 0; i < last_numbers_.size(); i++)
176             add_bound_item (last_numbers_[i], it);
177         }      
178     }
179 }
180
181 void
182 Multi_measure_rest_engraver::stop_translation_timestep ()
183 {
184   SCM smp = get_property ("measurePosition");
185   Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
186
187   if (mmrest_ && (now_mom () >= start_moment_) 
188       && !mp.to_bool ()
189       && mmrest_->get_bound (LEFT) && mmrest_->get_bound (RIGHT))
190     {
191       typeset_grob (mmrest_);
192       for (int i = 0 ; i < numbers_.size(); i++)
193         {
194           typeset_grob (numbers_[i]);
195           Side_position_interface::add_staff_support (numbers_[i]);
196         }
197       
198       /*
199         we must keep mmrest_ around to set measure-count, so
200         no mmrest_ = 0 here. 
201        */
202     }
203
204   if (last_rest_)
205     {
206       /* sanity check */
207       if (last_rest_->get_bound (LEFT) && last_rest_->get_bound (RIGHT)
208           && last_rest_->get_bound (LEFT) != last_rest_->get_bound (RIGHT))
209         {
210           typeset_grob (last_rest_);
211
212           for (int i = 0; i < last_numbers_.size ();i++)
213             {
214               typeset_grob (last_numbers_[i]);
215               Side_position_interface::add_staff_support (last_numbers_[i]);
216             }
217         }
218       last_rest_ = 0;
219       last_numbers_.clear();
220     }
221
222   if (new_req_)
223     {
224       busy_span_req_ = new_req_;
225       new_req_ =0;
226     }
227
228   text_events_.clear ();
229 }
230
231 void
232 Multi_measure_rest_engraver::start_translation_timestep ()
233 {
234   SCM smp = get_property ("measurePosition");
235   Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
236
237   Moment now =now_mom ();
238   if (mmrest_
239       && now.main_part_ != last_main_moment_
240       && mp.main_part_ == Rational (0))
241     {
242       last_rest_ = mmrest_;
243       last_numbers_ = numbers_;
244       
245       int cur = gh_scm2int (get_property ("currentBarNumber"));
246       int num = cur - start_measure_;
247       last_rest_->set_grob_property ("measure-count", gh_int2scm (num));
248
249       SCM sml = get_property ("measureLength");
250       Rational ml = (unsmob_moment (sml)) ? unsmob_moment (sml)->main_part_ : Rational (1);
251       if (ml >= Rational (2))
252         {
253           last_rest_->set_grob_property ("use-breve-rest", SCM_BOOL_T);
254         }
255
256       mmrest_ = 0;
257       numbers_.clear ();
258       
259       Grob * last = last_numbers_.size() ? last_numbers_[0] : 0;
260       if (last && last->get_grob_property ("text") == SCM_EOL)
261         {
262           SCM thres = get_property ("restNumberThreshold");
263           int t = 1;
264           if (gh_number_p (thres))
265             t = gh_scm2int (thres);
266       
267           if (num <= t)
268             last->suicide();
269           else 
270             {
271               SCM text
272                 = scm_number_to_string (gh_int2scm (num), SCM_MAKINUM (10));
273               last->set_grob_property ("text", text);
274             }
275         }
276     }
277
278   last_main_moment_ = now.main_part_;
279 }
280
281 void
282 Multi_measure_rest_engraver::finalize ()
283 {
284   if (mmrest_)
285     {
286       typeset_grob (mmrest_);
287     }
288   if (last_rest_)
289     {
290       typeset_grob (last_rest_);
291     }
292
293   for (int i = 0; i < last_numbers_.size ();i++)
294     typeset_grob (last_numbers_[i]);
295
296   for (int i = 0; i < numbers_.size ();i++)
297     typeset_grob (numbers_[i]);
298
299 }
300
301 ENTER_DESCRIPTION(Multi_measure_rest_engraver,
302 /* descr */
303                   "Engraves multi-measure rests that are produced with @code{R}.  Reads "
304 "measurePosition and currentBarNumber to determine what number to print "
305 "over the MultiMeasureRest.  Reads measureLength to determine if it "
306 "should use a whole rest or a breve rest to represent 1 measure "
307                   ,
308 /* creats*/       "MultiMeasureRest MultiMeasureRestNumber MultiMeasureRestText",
309 /* accepts */     "multi-measure-rest-event multi-measure-text-event",
310 /* acks  */      "",
311 /* reads */       "currentBarNumber restNumberThreshold currentCommandColumn measurePosition measureLength",
312 /* write */       "");