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