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