]> git.donarmstrong.com Git - lilypond.git/blob - lily/dynamic-align-engraver.cc
Revert "bad"
[lilypond.git] / lily / dynamic-align-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2008--2011 Han-Wen Nienhuys <hanwen@lilypond.org>
5
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <set>
22
23 #include "engraver.hh"
24
25 #include "axis-group-interface.hh"
26 #include "directional-element-interface.hh"
27 #include "item.hh"
28 #include "side-position-interface.hh"
29 #include "spanner.hh"
30 #include "stream-event.hh"
31
32 #include "translator.icc"
33
34 class Dynamic_align_engraver : public Engraver
35 {
36   TRANSLATOR_DECLARATIONS (Dynamic_align_engraver);
37   DECLARE_TRANSLATOR_LISTENER (break_span);
38   DECLARE_ACKNOWLEDGER (note_column);
39   DECLARE_ACKNOWLEDGER (dynamic);
40   DECLARE_END_ACKNOWLEDGER (dynamic);
41
42 protected:
43   virtual void stop_translation_timestep ();
44
45 private:
46   void create_line_spanner (Stream_event *cause);
47   Spanner *line_;
48   vector<Spanner *> ended_;
49   vector<Spanner *> started_;
50   vector<Grob *> scripts_;
51   vector<Grob *> support_;
52
53   set<Spanner *> running_;
54
55   bool early_end_;
56 };
57
58 Dynamic_align_engraver::Dynamic_align_engraver ()
59 {
60   line_ = 0;
61   early_end_ = false;
62 }
63
64 ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
65 ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column);
66 ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
67
68 void
69 Dynamic_align_engraver::create_line_spanner (Stream_event *event)
70 {
71   if (!line_)
72     line_ = make_spanner ("DynamicLineSpanner",
73                           event ? event->self_scm () : SCM_EOL);
74 }
75
76 void
77 Dynamic_align_engraver::acknowledge_end_dynamic (Grob_info info)
78 {
79   if (Spanner::has_interface (info.grob ()))
80     ended_.push_back (info.spanner ());
81 }
82
83 void
84 Dynamic_align_engraver::acknowledge_note_column (Grob_info info)
85 {
86   support_.push_back (info.grob ());
87 }
88
89 IMPLEMENT_TRANSLATOR_LISTENER (Dynamic_align_engraver, break_span);
90 void
91 Dynamic_align_engraver::listen_break_span (Stream_event *event)
92 {
93   if (event->in_event_class ("break-dynamic-span-event"))
94     early_end_ = true;
95 }
96
97 void
98 Dynamic_align_engraver::acknowledge_dynamic (Grob_info info)
99 {
100   Stream_event *cause = info.event_cause ();
101   create_line_spanner (cause);
102   if (Spanner::has_interface (info.grob ()))
103     {
104       started_.push_back (info.spanner ());
105       /*
106         If we are using text spans instead of hairpins and the line
107         is hidden, end the alignment spanner early: this allows dynamics
108         to be spaced individually instead of being linked together.
109       */
110       if (info.grob ()->internal_has_interface (ly_symbol2scm ("dynamic-text-spanner-interface"))
111           && (info.grob ()->get_property ("style") == ly_symbol2scm ("none")))
112         early_end_ = true;
113     }
114   else if (info.item ())
115     scripts_.push_back (info.item ());
116   else
117     info.grob ()->programming_error ("unknown dynamic grob");
118
119   Axis_group_interface::add_element (line_, info.grob ());
120
121   if (cause)
122     {
123       if (Direction d = to_dir (cause->get_property ("direction")))
124         set_grob_direction (line_, d);
125     }
126 }
127
128 void
129 Dynamic_align_engraver::stop_translation_timestep ()
130 {
131   for (vsize i = 0; i < started_.size (); i++)
132     running_.insert (started_[i]);
133   for (vsize i = 0; i < ended_.size (); i++)
134     {
135       Spanner *sp = ended_[i];
136
137       set<Spanner *>::iterator it = running_.find (sp);
138       if (it != running_.end ())
139         running_.erase (it);
140       else
141         started_[i]->programming_error ("lost track of this dynamic spanner");
142     }
143
144   bool end = line_ && (running_.empty ()
145                        || early_end_);
146   Direction d = LEFT;
147   do
148     {
149       if (line_
150           && ((d == LEFT && !line_->get_bound (LEFT))
151               || (end && d == RIGHT && !line_->get_bound (RIGHT))))
152         {
153           vector<Spanner *> const &spanners
154             = (d == LEFT) ? started_ : ended_;
155
156           Grob *bound = 0;
157           if (scripts_.size ())
158             bound = scripts_[0];
159           else if (spanners.size ())
160             bound = spanners[0]->get_bound (d);
161           else
162             {
163               bound = unsmob_grob (get_property ("currentMusicalColumn"));
164               if (!early_end_)
165                 programming_error ("started DynamicLineSpanner but have no left bound");
166             }
167
168           line_->set_bound (d, bound);
169         }
170     }
171   while (flip (&d) != LEFT);
172
173   for (vsize i = 0; line_ && i < support_.size (); i++)
174     Side_position_interface::add_support (line_, support_[i]);
175
176   if (end)
177     {
178       line_ = 0;
179       early_end_ = false;
180     }
181
182   ended_.clear ();
183   started_.clear ();
184   scripts_.clear ();
185   support_.clear ();
186 }
187
188 ADD_TRANSLATOR (Dynamic_align_engraver,
189                 /* doc */
190                 "Align hairpins and dynamic texts on a horizontal line.",
191
192                 /* create */
193                 "DynamicLineSpanner ",
194
195                 /* read */
196                 "currentMusicalColumn ",
197
198                 /* write */
199                 ""
200                 );