]> git.donarmstrong.com Git - lilypond.git/blob - lily/separating-line-group-engraver.cc
Nitpick run.
[lilypond.git] / lily / separating-line-group-engraver.cc
1 /*
2   '  separating-line-group-engraver.cc -- implement Separating_line_group_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "engraver.hh"
10
11 #include "separating-group-spanner.hh"
12 #include "separation-item.hh"
13 #include "paper-column.hh"
14 #include "output-def.hh"
15 #include "axis-group-interface.hh"
16 #include "note-spacing.hh"
17 #include "accidental-placement.hh"
18 #include "context.hh"
19 #include "grob-array.hh"
20 #include "pointer-group-interface.hh"
21
22 #include "translator.icc"
23
24 struct Spacings
25 {
26   Item *staff_spacing_;
27   Link_array<Item> note_spacings_;
28
29   Spacings ()
30   {
31     staff_spacing_ = 0;
32   }
33
34   bool is_empty () const
35   {
36     return !staff_spacing_ && !note_spacings_.size ();
37   }
38   void clear ()
39   {
40     staff_spacing_ = 0;
41     note_spacings_.clear ();
42   }
43 };
44
45 class Separating_line_group_engraver : public Engraver
46 {
47 protected:
48   Item *break_item_;
49   Item *musical_item_;
50   Item *last_musical_item_;
51
52   Spacings current_spacings_;
53   Spacings last_spacings_;
54
55   Spanner *sep_span_;
56
57   DECLARE_ACKNOWLEDGER (item);
58   void process_music ();
59   virtual void finalize ();
60   void stop_translation_timestep ();
61   void start_translation_timestep ();
62 public:
63   TRANSLATOR_DECLARATIONS (Separating_line_group_engraver);
64 };
65
66 Separating_line_group_engraver::Separating_line_group_engraver ()
67 {
68   sep_span_ = 0;
69   break_item_ = 0;
70   musical_item_ = 0;
71 }
72
73 void
74 Separating_line_group_engraver::process_music ()
75 {
76
77   if (!sep_span_)
78     {
79       sep_span_ = make_spanner ("SeparatingGroupSpanner", SCM_EOL);
80
81       sep_span_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn")));
82     }
83 }
84 void
85 Separating_line_group_engraver::finalize ()
86 {
87   if (!sep_span_)
88     return;
89
90   SCM ccol = get_property ("currentCommandColumn");
91   Grob *column = unsmob_grob (ccol);
92
93   sep_span_->set_bound (RIGHT, unsmob_grob (ccol));
94   sep_span_ = 0;
95
96   for (int i = 0; i < last_spacings_.note_spacings_.size (); i++)
97     {
98       Pointer_group_interface::add_grob (last_spacings_.note_spacings_[i],
99                                          ly_symbol2scm ("right-items"),
100                                          column);
101     }
102
103   if (last_spacings_.staff_spacing_
104       && last_spacings_.staff_spacing_->get_column () == column)
105     last_spacings_.staff_spacing_->suicide ();
106 }
107
108 void
109 Separating_line_group_engraver::acknowledge_item (Grob_info i)
110 {
111   Item *it = dynamic_cast<Item *> (i.grob ());
112   if (!it)
113     return;
114   if (it->get_parent (X_AXIS)
115       && it->get_parent (X_AXIS)
116       ->has_extent_callback (Axis_group_interface::group_extent_callback_proc, X_AXIS))
117     return;
118
119   if (to_boolean (it->get_property ("no-spacing-rods")))
120     return;
121
122   if (Note_spacing::has_interface (it))
123     {
124       current_spacings_.note_spacings_.push (it);
125       return;
126     }
127
128   bool ib = Item::is_breakable (it);
129   Item *&p_ref_ (ib ? break_item_
130                  : musical_item_);
131
132   if (!p_ref_)
133     {
134       p_ref_ = make_item ("SeparationItem", SCM_EOL);
135
136       if (ib)
137         {
138           p_ref_->set_property ("breakable", SCM_BOOL_T);
139           context ()->set_property ("breakableSeparationItem", p_ref_->self_scm ());
140         }
141
142       if (to_boolean (get_property ("createSpacing"))
143           && p_ref_ == break_item_)
144         {
145           Item *it = make_item ("StaffSpacing", SCM_EOL);
146           current_spacings_.staff_spacing_ = it;
147           Pointer_group_interface::add_grob (it, ly_symbol2scm ("left-items"),
148                                              break_item_);
149
150           if (int i = last_spacings_.note_spacings_.size ())
151             {
152               for (; i--;)
153                 Pointer_group_interface::add_grob (last_spacings_.note_spacings_[i],
154                                                    ly_symbol2scm ("right-items"),
155                                                    break_item_);
156             }
157           else if (last_spacings_.staff_spacing_)
158             {
159               SCM ri = last_spacings_.staff_spacing_->get_object ("right-items");
160               Grob_array *ga = unsmob_grob_array (ri);
161               if (!ga)
162                 {
163                   SCM ga_scm = Grob_array::make_array ();
164                   last_spacings_.staff_spacing_->set_object ("right-items", ga_scm);
165                   ga = unsmob_grob_array (ga_scm);
166                 }
167
168               ga->clear ();
169               ga->add (break_item_);
170             }
171         }
172     }
173
174   if (Accidental_placement::has_interface (it))
175     Separation_item::add_conditional_item (p_ref_, it);
176   else
177     Separation_item::add_item (p_ref_, it);
178 }
179
180 void
181 Separating_line_group_engraver::start_translation_timestep ()
182 {
183   if (break_item_)
184     {
185       context ()->unset_property (ly_symbol2scm ("breakableSeparationItem"));
186       break_item_ = 0;
187     }
188 }
189
190 void
191 Separating_line_group_engraver::stop_translation_timestep ()
192 {
193   if (break_item_)
194     Separating_group_spanner::add_spacing_unit (sep_span_, break_item_);
195
196   if (Item *sp = current_spacings_.staff_spacing_)
197     {
198       /*
199         TODO: should really look at the left-items of following
200         note-spacing grobs.
201       */
202       if (musical_item_)
203         Pointer_group_interface::add_grob (sp, ly_symbol2scm ("right-items"),
204                                            musical_item_);
205     }
206
207   if (!current_spacings_.is_empty ())
208     last_spacings_ = current_spacings_;
209
210   current_spacings_.clear ();
211
212   if (musical_item_)
213     Separating_group_spanner::add_spacing_unit (sep_span_, musical_item_);
214
215   musical_item_ = 0;
216 }
217
218 ADD_ACKNOWLEDGER (Separating_line_group_engraver, item);
219 ADD_TRANSLATOR (Separating_line_group_engraver,
220                 /* doc */ "Generates objects for computing spacing parameters.",
221                 /* create */ "SeparationItem SeparatingGroupSpanner StaffSpacing",
222                 /* accept */ "",
223                 /* read */ "createSpacing",
224                 /* write */ "breakableSeparationItem");