]> git.donarmstrong.com Git - lilypond.git/blob - lily/span-bar-stub-engraver.cc
9cf52dc98f05052fbe207e266cb064fd92811b08
[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--2014 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 /*
31   The Span_bar_stub_engraver creates SpanBarStub grobs in the contexts
32   that a grouping context contains.  For example, if a PianoStaff contains
33   two Staffs, a Dynamics, and a Lyrics, SpanBarStubs will be created in
34   all contexts that do not have bar lines (Dynamics and Lyrics).
35
36   We only want to create these SpanBarStubs in contexts that the SpanBar
37   traverses.  However, Contexts do not contain layout information and it
38   is thus difficult to know if they will eventually be above or below other
39   Contexts.  To determine this we use the VerticalAxisGroup created in the
40   Context.  We relate VerticalAxisGroups to Contexts in the variable
41   axis_groups_ and weed out unused contexts after each translation timestep.
42
43   Note that SpanBarStubs exist for pure height calculations ONLY.
44   They should never be visually present on the page and should never
45   be engraved in contexts where BarLines are engraved.
46 */
47
48 class Span_bar_stub_engraver : public Engraver
49 {
50   vector<Grob *> spanbars_;
51   SCM axis_groups_;
52
53 public:
54   TRANSLATOR_DECLARATIONS (Span_bar_stub_engraver);
55 protected:
56   DECLARE_ACKNOWLEDGER (span_bar);
57   DECLARE_ACKNOWLEDGER (hara_kiri_group_spanner);
58   void process_acknowledged ();
59   void stop_translation_timestep ();
60   virtual void derived_mark () const;
61 };
62
63 Span_bar_stub_engraver::Span_bar_stub_engraver ()
64 {
65   axis_groups_ = SCM_EOL;
66 }
67
68 void
69 Span_bar_stub_engraver::derived_mark () const
70 {
71   scm_gc_mark (axis_groups_);
72 }
73
74 void
75 Span_bar_stub_engraver::acknowledge_span_bar (Grob_info i)
76 {
77   spanbars_.push_back (i.grob ());
78 }
79
80 void
81 Span_bar_stub_engraver::acknowledge_hara_kiri_group_spanner (Grob_info i)
82 {
83   axis_groups_ = scm_cons (scm_cons (i.grob ()->self_scm (), i.context ()->self_scm ()), axis_groups_);
84 }
85
86 void
87 Span_bar_stub_engraver::process_acknowledged ()
88 {
89   if (!spanbars_.size ())
90     return;
91
92   if (!scm_is_pair (axis_groups_))
93     {
94       programming_error ("At least one vertical axis group needs to be created in the first time step.");
95       return;
96     }
97   Grob *vertical_alignment = Grob::get_root_vertical_alignment (Grob::unsmob (scm_caar (axis_groups_)));
98   if (!vertical_alignment) // we are at the beginning of a score, so no need for stubs
99     return;
100
101   for (vsize i = 0; i < spanbars_.size (); i++)
102     {
103       extract_grob_set (spanbars_[i], "elements", bars);
104       vector<vsize> bar_axis_indices;
105       for (vsize j = 0; j < bars.size (); j++)
106         {
107           int i = Grob::get_vertical_axis_group_index (bars[j]);
108           if (i >= 0)
109             bar_axis_indices.push_back ((vsize) i);
110         }
111       vector<Context *> affected_contexts;
112       vector<Grob *> y_parents;
113       vector<bool> keep_extent;
114       for (SCM s = axis_groups_; scm_is_pair (s); s = scm_cdr (s))
115         {
116           Context *c = Context::unsmob (scm_cdar (s));
117           Grob *g = Grob::unsmob (scm_caar (s));
118           if (!c || !g)
119             continue;
120           if (c->is_removable ())
121             continue;
122
123           vsize j = Grob::get_vertical_axis_group_index (g);
124           if (j > bar_axis_indices[0]
125               && j < bar_axis_indices.back ()
126               && find (bar_axis_indices.begin (), bar_axis_indices.end (), j) == bar_axis_indices.end ())
127             {
128               vsize k = 0;
129               for (; k < bar_axis_indices.size (); k++)
130                 if (bar_axis_indices[k] > j)
131                   break;
132
133               k--;
134
135               if (c && c->get_parent_context ())
136                 {
137                   keep_extent.push_back (to_boolean (bars[k]->get_property ("allow-span-bar")));
138                   y_parents.push_back (g);
139                   affected_contexts.push_back (c);
140                 }
141             }
142         }
143
144       for (vsize j = 0; j < affected_contexts.size (); j++)
145         {
146           Item *it = new Item (Grob_property_info (affected_contexts[j], ly_symbol2scm ("SpanBarStub")).updated ());
147           it->set_parent (spanbars_[i], X_AXIS);
148           Grob_info gi = make_grob_info (it, spanbars_[i]->self_scm ());
149           gi.rerouting_daddy_context_ = affected_contexts[j];
150           announce_grob (gi);
151           if (!keep_extent[j])
152             it->suicide ();
153         }
154     }
155
156   spanbars_.clear ();
157 }
158
159 // removes all unused contexts
160 void
161 Span_bar_stub_engraver::stop_translation_timestep ()
162 {
163   SCM axis_groups = SCM_EOL;
164   for (SCM s = axis_groups_; scm_is_pair (s); s = scm_cdr (s))
165     {
166       Context *c = Context::unsmob (scm_cdar (s));
167       Grob *g = Grob::unsmob (scm_caar (s));
168       if (!c || !g)
169         continue;
170       if (c->is_removable ())
171         continue;
172       axis_groups = scm_cons (scm_car (s), axis_groups);
173     }
174   axis_groups_ = axis_groups;
175 }
176
177 #include "translator.icc"
178
179 ADD_ACKNOWLEDGER (Span_bar_stub_engraver, span_bar);
180 ADD_ACKNOWLEDGER (Span_bar_stub_engraver, hara_kiri_group_spanner);
181 ADD_TRANSLATOR (Span_bar_stub_engraver,
182                 /* doc */
183                 "Make stubs for span bars in all contexts that the span bars cross.",
184
185                 /* create */
186                 "SpanBarStub ",
187
188                 /* read */
189                 "",
190
191                 /* write */
192                 ""
193                );