Use scalar instead of embedded_scm for context mod overrides.
[lilypond/mpolesky.git] / lily / figured-bass-engraver.cc
blob09a13a62d6c19b05473e25e00c9a3bdf01837cba
1 /*
2 figured-bass-engraver.cc -- implement Figured_bass_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2005--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
8 */
10 #include "engraver.hh"
12 #include "align-interface.hh"
13 #include "axis-group-interface.hh"
14 #include "context.hh"
15 #include "grob-array.hh"
16 #include "item.hh"
17 #include "pointer-group-interface.hh"
18 #include "spanner.hh"
19 #include "stream-event.hh"
20 #include "text-interface.hh"
22 #include "translator.icc"
24 struct Figure_group
26 Spanner *group_;
27 Spanner *continuation_line_;
29 SCM number_;
30 SCM alteration_;
31 SCM augmented_;
32 SCM diminished_;
33 SCM augmented_slash_;
34 SCM text_;
36 Item *figure_item_;
37 Stream_event *current_event_;
38 bool force_no_continuation_;
40 Figure_group ()
42 figure_item_ = 0;
43 force_no_continuation_ = false;
44 continuation_line_ = 0;
45 number_ = SCM_EOL;
46 alteration_ = SCM_EOL;
47 augmented_ = SCM_EOL;
48 diminished_ = SCM_EOL;
49 augmented_slash_ = SCM_EOL;
50 text_ = SCM_EOL;
51 group_ = 0;
52 current_event_ = 0;
54 bool is_continuation () const
56 return
57 current_event_
58 && !force_no_continuation_
59 && ly_is_equal (number_,
60 current_event_->get_property ("figure"))
61 && ly_is_equal (alteration_,
62 current_event_->get_property ("alteration"))
63 && ly_is_equal (augmented_,
64 current_event_->get_property ("augmented"))
65 && ly_is_equal (diminished_,
66 current_event_->get_property ("diminished"))
67 && ly_is_equal (augmented_slash_,
68 current_event_->get_property ("augmented-slash"))
69 && ly_is_equal (text_,
70 current_event_->get_property ("text"));
74 struct Figured_bass_engraver : public Engraver
76 TRANSLATOR_DECLARATIONS (Figured_bass_engraver);
77 void clear_spanners ();
78 void add_brackets ();
79 void create_grobs ();
81 void center_continuations (vector<Spanner*> const &consecutive_lines);
82 void center_repeated_continuations ();
83 protected:
84 vector<Figure_group> groups_;
85 Spanner *alignment_;
86 vector<Stream_event *> new_events_;
87 bool continuation_;
88 bool new_event_found_;
90 Moment stop_moment_;
91 Stream_event *rest_event_;
93 DECLARE_TRANSLATOR_LISTENER (rest);
94 DECLARE_TRANSLATOR_LISTENER (bass_figure);
96 virtual void derived_mark () const;
98 void start_translation_timestep ();
99 void stop_translation_timestep ();
100 void process_music ();
103 void
104 Figured_bass_engraver::derived_mark () const
106 for (vsize i = 0; i < groups_.size (); i++)
108 scm_gc_mark (groups_[i].number_);
109 scm_gc_mark (groups_[i].alteration_);
110 scm_gc_mark (groups_[i].augmented_);
111 scm_gc_mark (groups_[i].diminished_);
112 scm_gc_mark (groups_[i].augmented_slash_);
113 scm_gc_mark (groups_[i].text_);
117 void
118 Figured_bass_engraver::stop_translation_timestep ()
120 if (groups_.empty ()
121 || now_mom ().main_part_ < stop_moment_.main_part_
122 || now_mom ().grace_part_ < Rational (0))
123 return ;
125 bool found = false;
126 for (vsize i = 0; !found && i < groups_.size (); i++)
127 found = found || groups_[i].current_event_;
129 if (!found)
130 clear_spanners ();
133 Figured_bass_engraver::Figured_bass_engraver ()
135 alignment_ = 0;
136 continuation_ = false;
137 rest_event_ = 0;
138 new_event_found_ = false;
141 void
142 Figured_bass_engraver::start_translation_timestep ()
144 if (now_mom ().main_part_ < stop_moment_.main_part_
145 || now_mom ().grace_part_ < Rational (0))
146 return ;
148 rest_event_ = 0;
149 new_events_.clear ();
150 for (vsize i = 0; i < groups_.size (); i++)
151 groups_[i].current_event_ = 0;
153 continuation_ = false;
158 IMPLEMENT_TRANSLATOR_LISTENER (Figured_bass_engraver, rest);
159 void
160 Figured_bass_engraver::listen_rest (Stream_event *ev)
162 if (to_boolean (get_property ("ignoreFiguredBassRest")))
164 new_event_found_ = true;
167 No ASSIGN_EVENT_ONCE () ; otherwise we get warnings about
168 polyphonic rests.
170 rest_event_ = ev;
174 IMPLEMENT_TRANSLATOR_LISTENER (Figured_bass_engraver, bass_figure);
175 void
176 Figured_bass_engraver::listen_bass_figure (Stream_event *ev)
178 new_event_found_ = true;
179 Moment stop = now_mom () + get_event_length (ev, now_mom ());
180 stop_moment_ = max (stop_moment_, stop);
182 if (to_boolean (get_property ("useBassFigureExtenders")))
184 SCM fig = ev->get_property ("figure");
185 SCM txt = ev->get_property ("text");
186 for (vsize i = 0; i < groups_.size (); i++)
188 if (!groups_[i].current_event_
189 && ly_is_equal (groups_[i].number_, fig)
190 && ly_is_equal (groups_[i].text_, txt))
192 groups_[i].current_event_ = ev;
193 groups_[i].force_no_continuation_
194 = to_boolean (ev->get_property ("no-continuation"));
195 continuation_ = true;
196 return;
200 new_events_.push_back (ev);
203 void
204 Figured_bass_engraver::center_continuations (vector<Spanner*> const &consecutive_lines)
206 if (consecutive_lines.size () == 2)
208 vector<Grob*> left_figs;
209 for (vsize j = consecutive_lines.size (); j--;)
210 left_figs.push_back (consecutive_lines[j]->get_bound (LEFT));
212 SCM ga = Grob_array::make_array ();
213 unsmob_grob_array (ga)->set_array (left_figs);
215 for (vsize j = consecutive_lines.size (); j--;)
216 consecutive_lines[j]->set_object ("figures",
217 unsmob_grob_array (ga)->smobbed_copy ());
221 void
222 Figured_bass_engraver::center_repeated_continuations ()
224 vector<Spanner*> consecutive_lines;
225 for (vsize i = 0; i <= groups_.size (); i++)
227 if (i < groups_.size ()
228 && groups_[i].continuation_line_
229 && (consecutive_lines.empty ()
230 || (consecutive_lines[0]->get_bound (LEFT)->get_column ()
231 == groups_[i].continuation_line_->get_bound (LEFT)->get_column ()
232 && consecutive_lines[0]->get_bound (RIGHT)->get_column ()
233 == groups_[i].continuation_line_->get_bound (RIGHT)->get_column ())))
234 consecutive_lines.push_back (groups_[i].continuation_line_);
235 else
237 center_continuations (consecutive_lines);
238 consecutive_lines.clear ();
243 void
244 Figured_bass_engraver::clear_spanners ()
246 if (!alignment_)
247 return;
249 if (alignment_)
251 announce_end_grob (alignment_, SCM_EOL);
252 alignment_ = 0;
255 if (to_boolean (get_property ("figuredBassCenterContinuations")))
256 center_repeated_continuations ();
258 for (vsize i = 0; i < groups_.size (); i++)
260 if (groups_[i].group_)
262 announce_end_grob (groups_[i].group_ , SCM_EOL);
263 groups_[i].group_ = 0;
266 if (groups_[i].continuation_line_)
268 announce_end_grob (groups_[i].continuation_line_ , SCM_EOL);
269 groups_[i].continuation_line_ = 0;
273 /* Check me, groups_.clear () ? */
276 void
277 Figured_bass_engraver::add_brackets ()
279 vector<Grob*> encompass;
280 bool inside = false;
281 for (vsize i = 0; i < groups_.size (); i ++)
283 if (!groups_[i].current_event_)
284 continue;
286 if (to_boolean (groups_[i].current_event_->get_property ("bracket-start")))
287 inside = true;
289 if (inside && groups_[i].figure_item_)
290 encompass.push_back (groups_[i].figure_item_);
292 if (to_boolean (groups_[i].current_event_->get_property ("bracket-stop")))
294 inside = false;
296 Item * brack = make_item ("BassFigureBracket", groups_[i].current_event_->self_scm ());
297 for (vsize j = 0; j < encompass.size (); j++)
299 Pointer_group_interface::add_grob (brack,
300 ly_symbol2scm ("elements"),
301 encompass[j]);
303 encompass.clear ();
308 void
309 Figured_bass_engraver::process_music ()
311 if (alignment_ && !to_boolean (get_property ("useBassFigureExtenders")))
312 clear_spanners ();
314 if (rest_event_)
316 clear_spanners ();
317 groups_.clear ();
318 return;
321 if (!continuation_
322 && new_events_.empty ())
324 clear_spanners ();
325 groups_.clear ();
326 return;
329 if (!new_event_found_)
330 return;
332 new_event_found_ = false;
335 Don't need to sync alignments, if we're not using extenders.
337 bool use_extenders = to_boolean (get_property ("useBassFigureExtenders"));
338 if (!use_extenders)
340 clear_spanners ();
343 if (!continuation_)
345 clear_spanners ();
346 groups_.clear ();
349 vsize k = 0;
350 for (vsize i = 0; i < new_events_.size (); i++)
352 while (k < groups_.size ()
353 && groups_[k].current_event_)
354 k++;
356 if (k >= groups_.size ())
358 Figure_group group;
359 groups_.push_back (group);
362 groups_[k].current_event_ = new_events_[i];
363 groups_[k].figure_item_ = 0;
364 k++;
367 for (vsize i = 0; i < groups_.size (); i++)
369 if (!groups_[i].is_continuation ())
371 groups_[i].number_ = SCM_BOOL_F;
372 groups_[i].alteration_ = SCM_BOOL_F;
373 groups_[i].augmented_ = SCM_BOOL_F;
374 groups_[i].diminished_ = SCM_BOOL_F;
375 groups_[i].augmented_slash_ = SCM_BOOL_F;
376 groups_[i].text_ = SCM_BOOL_F;
380 if (use_extenders)
382 vector<int> junk_continuations;
383 for (vsize i = 0; i < groups_.size (); i++)
385 Figure_group &group = groups_[i];
387 if (group.is_continuation ())
389 if (!group.continuation_line_)
391 Spanner * line
392 = make_spanner ("BassFigureContinuation", SCM_EOL);
393 Item * item = group.figure_item_;
394 group.continuation_line_ = line;
395 line->set_bound (LEFT, item);
398 Don't add as child. This will cache the wrong
399 (pre-break) stencil when callbacks are triggered.
401 line->set_parent (group.group_, Y_AXIS);
402 Pointer_group_interface::add_grob (line, ly_symbol2scm ("figures"), item);
404 group.figure_item_ = 0;
407 else if (group.continuation_line_)
408 junk_continuations.push_back (i);
412 Ugh, repeated code.
414 vector<Spanner*> consecutive;
415 if (to_boolean (get_property ("figuredBassCenterContinuations")))
417 for (vsize i = 0; i <= junk_continuations.size (); i++)
419 if (i < junk_continuations.size ()
420 && (i == 0 || junk_continuations[i-1] == junk_continuations[i] - 1))
421 consecutive.push_back (groups_[junk_continuations[i]].continuation_line_);
422 else
424 center_continuations (consecutive);
425 consecutive.clear ();
426 if (i < junk_continuations.size ())
427 consecutive.push_back (groups_[junk_continuations[i]].continuation_line_);
431 for (vsize i = 0; i < junk_continuations.size (); i++)
432 groups_[junk_continuations[i]].continuation_line_ = 0;
435 create_grobs ();
436 add_brackets ();
439 void
440 Figured_bass_engraver::create_grobs ()
442 Grob *muscol
443 = dynamic_cast<Item*> (unsmob_grob (get_property ("currentMusicalColumn")));
444 if (!alignment_)
446 alignment_ = make_spanner ("BassFigureAlignment", SCM_EOL);
447 alignment_->set_bound (LEFT, muscol);
449 alignment_->set_bound (RIGHT, muscol);
451 SCM proc = get_property ("figuredBassFormatter");
452 for (vsize i = 0; i < groups_.size (); i++)
454 Figure_group &group = groups_[i];
456 if (group.current_event_)
458 Item *item
459 = make_item ("BassFigure",
460 group.current_event_->self_scm ());
463 SCM fig = group.current_event_->get_property ("figure");
464 if (!group.group_)
466 group.group_ = make_spanner ("BassFigureLine", SCM_EOL);
467 group.group_->set_bound (LEFT, muscol);
468 Align_interface::add_element (alignment_,
469 group.group_);
472 if (scm_memq (fig, get_property ("implicitBassFigures")) != SCM_BOOL_F)
474 item->set_property ("transparent", SCM_BOOL_T);
475 item->set_property ("implicit", SCM_BOOL_T);
478 group.number_ = fig;
479 group.alteration_ = group.current_event_->get_property ("alteration");
480 group.augmented_ = group.current_event_->get_property ("augmented");
481 group.diminished_ = group.current_event_->get_property ("diminished");
482 group.augmented_slash_ = group.current_event_->get_property ("augmented-slash");
483 group.text_ = group.current_event_->get_property ("text");
485 SCM text = group.text_;
486 if (!Text_interface::is_markup (text)
487 && ly_is_procedure (proc))
489 text = scm_call_3 (proc, fig, group.current_event_->self_scm (),
490 context ()->self_scm ());
493 item->set_property ("text", text);
495 Axis_group_interface::add_element (group.group_, item);
496 group.figure_item_ = item;
499 if (group.continuation_line_)
502 UGH should connect to the bass staff, and get the note heads.
504 group.figure_item_->set_property ("transparent", SCM_BOOL_T);
505 group.continuation_line_->set_bound (RIGHT, group.figure_item_);
508 if (groups_[i].group_)
509 groups_[i].group_->set_bound (RIGHT, muscol);
515 ADD_TRANSLATOR (Figured_bass_engraver,
516 /* doc */
517 "Make figured bass numbers.",
519 /* create */
520 "BassFigure "
521 "BassFigureAlignment "
522 "BassFigureBracket "
523 "BassFigureContinuation "
524 "BassFigureLine ",
526 /* read */
527 "figuredBassAlterationDirection "
528 "figuredBassCenterContinuations "
529 "figuredBassFormatter "
530 "implicitBassFigures "
531 "useBassFigureExtenders "
532 "ignoreFiguredBassRest ",
534 /* write */