]> git.donarmstrong.com Git - lilypond.git/blob - lily/span-bar-stub-engraver.cc
Issue 4550 (1/2) Avoid "using namespace std;" in included files
[lilypond.git] / lily / span-bar-stub-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2011--2015 Mike Solomon <mike@mikesolomon.org>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <algorithm>
21
22 #include "align-interface.hh"
23 #include "context.hh"
24 #include "grob.hh"
25 #include "grob-properties.hh"
26 #include "item.hh"
27 #include "pointer-group-interface.hh"
28 #include "engraver.hh"
29
30 #include "translator.icc"
31
32 using std::vector;
33
34 /*
35   The Span_bar_stub_engraver creates SpanBarStub grobs in the contexts
36   that a grouping context contains.  For example, if a PianoStaff contains
37   two Staffs, a Dynamics, and a Lyrics, SpanBarStubs will be created in
38   all contexts that do not have bar lines (Dynamics and Lyrics).
39
40   We only want to create these SpanBarStubs in contexts that the SpanBar
41   traverses.  However, Contexts do not contain layout information and it
42   is thus difficult to know if they will eventually be above or below other
43   Contexts.  To determine this we use the VerticalAxisGroup created in the
44   Context.  We relate VerticalAxisGroups to Contexts in the variable
45   axis_groups_ and weed out unused contexts after each translation timestep.
46
47   Note that SpanBarStubs exist for pure height calculations ONLY.
48   They should never be visually present on the page and should never
49   be engraved in contexts where BarLines are engraved.
50 */
51
52 class Span_bar_stub_engraver : public Engraver
53 {
54   vector<Grob *> spanbars_;
55   SCM axis_groups_;
56
57 public:
58   TRANSLATOR_DECLARATIONS (Span_bar_stub_engraver);
59 protected:
60   DECLARE_ACKNOWLEDGER (span_bar);
61   DECLARE_ACKNOWLEDGER (hara_kiri_group_spanner);
62   void process_acknowledged ();
63   void stop_translation_timestep ();
64   virtual void derived_mark () const;
65 };
66
67 Span_bar_stub_engraver::Span_bar_stub_engraver ()
68 {
69   axis_groups_ = SCM_EOL;
70 }
71
72 void
73 Span_bar_stub_engraver::derived_mark () const
74 {
75   scm_gc_mark (axis_groups_);
76 }
77
78 void
79 Span_bar_stub_engraver::acknowledge_span_bar (Grob_info i)
80 {
81   spanbars_.push_back (i.grob ());
82 }
83
84 void
85 Span_bar_stub_engraver::acknowledge_hara_kiri_group_spanner (Grob_info i)
86 {
87   axis_groups_ = scm_cons (scm_cons (i.grob ()->self_scm (), i.context ()->self_scm ()), axis_groups_);
88 }
89
90 void
91 Span_bar_stub_engraver::process_acknowledged ()
92 {
93   if (!spanbars_.size ())
94     return;
95
96   if (!scm_is_pair (axis_groups_))
97     {
98       programming_error ("At least one vertical axis group needs to be created in the first time step.");
99       return;
100     }
101   Grob *vertical_alignment = Grob::get_root_vertical_alignment (unsmob<Grob> (scm_caar (axis_groups_)));
102   if (!vertical_alignment) // we are at the beginning of a score, so no need for stubs
103     return;
104
105   for (vsize i = 0; i < spanbars_.size (); i++)
106     {
107       extract_grob_set (spanbars_[i], "elements", bars);
108       vector<vsize> bar_axis_indices;
109       for (vsize j = 0; j < bars.size (); j++)
110         {
111           int i = Grob::get_vertical_axis_group_index (bars[j]);
112           if (i >= 0)
113             bar_axis_indices.push_back ((vsize) i);
114         }
115       vector<Context *> affected_contexts;
116       vector<Grob *> y_parents;
117       vector<bool> keep_extent;
118       for (SCM s = axis_groups_; scm_is_pair (s); s = scm_cdr (s))
119         {
120           Context *c = unsmob<Context> (scm_cdar (s));
121           Grob *g = unsmob<Grob> (scm_caar (s));
122           if (!c || !g)
123             continue;
124           if (c->is_removable ())
125             continue;
126
127           vsize j = Grob::get_vertical_axis_group_index (g);
128           if (j > bar_axis_indices[0]
129               && j < bar_axis_indices.back ()
130               && find (bar_axis_indices.begin (), bar_axis_indices.end (), j) == bar_axis_indices.end ())
131             {
132               vsize k = 0;
133               for (; k < bar_axis_indices.size (); k++)
134                 if (bar_axis_indices[k] > j)
135                   break;
136
137               k--;
138
139               if (c && c->get_parent_context ())
140                 {
141                   keep_extent.push_back (to_boolean (bars[k]->get_property ("allow-span-bar")));
142                   y_parents.push_back (g);
143                   affected_contexts.push_back (c);
144                 }
145             }
146         }
147
148       for (vsize j = 0; j < affected_contexts.size (); j++)
149         {
150           Item *it = new Item (Grob_property_info (affected_contexts[j], ly_symbol2scm ("SpanBarStub")).updated ());
151           it->set_parent (spanbars_[i], X_AXIS);
152           Grob_info gi = make_grob_info (it, spanbars_[i]->self_scm ());
153           gi.rerouting_daddy_context_ = affected_contexts[j];
154           announce_grob (gi);
155           if (!keep_extent[j])
156             it->suicide ();
157         }
158     }
159
160   spanbars_.clear ();
161 }
162
163 // removes all unused contexts
164 void
165 Span_bar_stub_engraver::stop_translation_timestep ()
166 {
167   SCM axis_groups = SCM_EOL;
168   for (SCM s = axis_groups_; scm_is_pair (s); s = scm_cdr (s))
169     {
170       Context *c = unsmob<Context> (scm_cdar (s));
171       Grob *g = unsmob<Grob> (scm_caar (s));
172       if (!c || !g)
173         continue;
174       if (c->is_removable ())
175         continue;
176       axis_groups = scm_cons (scm_car (s), axis_groups);
177     }
178   axis_groups_ = axis_groups;
179 }
180
181 ADD_ACKNOWLEDGER (Span_bar_stub_engraver, span_bar);
182 ADD_ACKNOWLEDGER (Span_bar_stub_engraver, hara_kiri_group_spanner);
183 ADD_TRANSLATOR (Span_bar_stub_engraver,
184                 /* doc */
185                 "Make stubs for span bars in all contexts that the span bars cross.",
186
187                 /* create */
188                 "SpanBarStub ",
189
190                 /* read */
191                 "",
192
193                 /* write */
194                 ""
195                );