]> git.donarmstrong.com Git - lilypond.git/blob - lily/separating-line-group-engraver.cc
(internal_print): only call
[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 struct Spacings
23 {
24   Item *staff_spacing_;
25   Link_array<Item> note_spacings_;
26
27   Spacings ()
28   {
29     staff_spacing_ = 0;
30   }
31
32   bool is_empty () const
33   {
34     return !staff_spacing_ && !note_spacings_.size ();
35   }
36   void clear ()
37   {
38     staff_spacing_ = 0;
39     note_spacings_.clear ();
40   }
41 };
42
43 class Separating_line_group_engraver : public Engraver
44 {
45 protected:
46   Item *break_item_;
47   Item *musical_item_;
48   Item *last_musical_item_;
49
50   Spacings current_spacings_;
51   Spacings last_spacings_;
52
53   Spanner *sep_span_;
54
55   virtual void acknowledge_grob (Grob_info);
56   PRECOMPUTED_VIRTUAL void process_music ();
57   virtual void finalize ();
58   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
59   PRECOMPUTED_VIRTUAL void start_translation_timestep ();
60 public:
61   TRANSLATOR_DECLARATIONS (Separating_line_group_engraver);
62 };
63
64 Separating_line_group_engraver::Separating_line_group_engraver ()
65 {
66   sep_span_ = 0;
67   break_item_ = 0;
68   musical_item_ = 0;
69 }
70
71 void
72 Separating_line_group_engraver::process_music ()
73 {
74
75   if (!sep_span_)
76     {
77       sep_span_ = make_spanner ("SeparatingGroupSpanner", SCM_EOL);
78
79       sep_span_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn")));
80     }
81 }
82 void
83 Separating_line_group_engraver::finalize ()
84 {
85   if (!sep_span_)
86     return;
87
88   SCM ccol = get_property ("currentCommandColumn");
89   Grob *column = unsmob_grob (ccol);
90
91   sep_span_->set_bound (RIGHT, unsmob_grob (ccol));
92   sep_span_ = 0;
93
94   for (int i = 0; i < last_spacings_.note_spacings_.size (); i++)
95     {
96       Pointer_group_interface::add_grob (last_spacings_.note_spacings_[i],
97                                          ly_symbol2scm ("right-items"),
98                                          column);
99     }
100
101   if (last_spacings_.staff_spacing_
102       && last_spacings_.staff_spacing_->get_column () == column)
103     {
104       last_spacings_.staff_spacing_->suicide ();
105     }
106 }
107
108 void
109 Separating_line_group_engraver::acknowledge_grob (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     {
195       Separating_group_spanner::add_spacing_unit (sep_span_, break_item_);
196     }
197
198   if (Item *sp = current_spacings_.staff_spacing_)
199     {
200       /*
201         TODO: should really look at the left-items of following
202         note-spacing grobs.
203       */
204       if (musical_item_)
205         Pointer_group_interface::add_grob (sp, ly_symbol2scm ("right-items"),
206                                            musical_item_);
207     }
208
209   if (!current_spacings_.is_empty ())
210     {
211       last_spacings_ = current_spacings_;
212     }
213
214   current_spacings_.clear ();
215
216   if (musical_item_)
217     {
218       Separating_group_spanner::add_spacing_unit (sep_span_, musical_item_);
219     }
220
221   musical_item_ = 0;
222 }
223
224 #include "translator.icc"
225
226 ADD_TRANSLATOR (Separating_line_group_engraver,
227                 /* descr */ "Generates objects for computing spacing parameters.",
228                 /* creats*/ "SeparationItem SeparatingGroupSpanner StaffSpacing",
229                 /* accepts */ "",
230                 /* acks  */ "item-interface",
231                 /* reads */ "createSpacing",
232                 /* write */ "breakableSeparationItem");