]> git.donarmstrong.com Git - lilypond.git/blob - lily/dynamic-align-engraver.cc
Merge branch 'master' of ssh://jomand@git.sv.gnu.org/srv/git/lilypond into lilypond...
[lilypond.git] / lily / dynamic-align-engraver.cc
1 /* 
2   dynamic-align-engraver.cc -- implement Dynamic_align_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2008--2009 Han-Wen Nienhuys <hanwen@lilypond.org>
7   
8 */
9
10 #include <set>
11
12 #include "engraver.hh"
13
14 #include "axis-group-interface.hh"
15 #include "directional-element-interface.hh"
16 #include "item.hh"
17 #include "side-position-interface.hh"
18 #include "spanner.hh"
19 #include "stream-event.hh"
20
21 #include "translator.icc"
22
23 class Dynamic_align_engraver : public Engraver
24 {
25   TRANSLATOR_DECLARATIONS (Dynamic_align_engraver);
26   DECLARE_ACKNOWLEDGER (note_column);
27   DECLARE_ACKNOWLEDGER (dynamic);
28   DECLARE_END_ACKNOWLEDGER (dynamic);
29
30 protected:
31   virtual void stop_translation_timestep ();
32
33 private:
34   void create_line_spanner (Stream_event *cause);
35   Spanner* line_;
36
37   vector<Spanner*> ended_;
38   vector<Spanner*> started_;
39   vector<Grob*> scripts_;
40   vector<Grob*> support_;
41   
42   set<Spanner*> running_;
43 };
44
45 Dynamic_align_engraver::Dynamic_align_engraver ()
46 {
47   line_ = 0;
48 }
49
50 ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
51 ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column);
52 ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
53
54 void
55 Dynamic_align_engraver::create_line_spanner (Stream_event* event)
56 {
57   if (!line_)
58     line_ = make_spanner ("DynamicLineSpanner",
59                           event ? event->self_scm() : SCM_EOL);
60 }
61
62 void
63 Dynamic_align_engraver::acknowledge_end_dynamic (Grob_info info)
64 {
65   if (Spanner::has_interface(info.grob()))
66     ended_.push_back (info.spanner ());
67 }
68
69 void
70 Dynamic_align_engraver::acknowledge_note_column (Grob_info info)
71 {
72   support_.push_back (info.grob ());
73 }
74
75 void
76 Dynamic_align_engraver::acknowledge_dynamic (Grob_info info)
77 {
78   Stream_event *cause = info.event_cause ();
79   create_line_spanner (cause);
80   if (Spanner::has_interface(info.grob()))
81     started_.push_back (info.spanner ());
82   else if (info.item())
83     scripts_.push_back (info.item());
84   else
85     info.grob ()->programming_error ("Unknown dynamic grob.");
86
87   Axis_group_interface::add_element (line_, info.grob ());
88
89   if (cause)
90     {
91       if (Direction d = to_dir (cause->get_property ("direction")))
92         set_grob_direction (line_, d);
93     }
94 }
95
96 void
97 Dynamic_align_engraver::stop_translation_timestep ()
98 {
99   for (vsize i = 0; i < started_.size(); i++)
100     running_.insert (started_[i]);
101   for (vsize i = 0; i < ended_.size(); i++)
102     {
103       Spanner *sp = ended_[i];
104
105       set<Spanner*>::iterator it  = running_.find (sp);
106       if (it != running_.end())
107         running_.erase (it);
108       else
109         started_[i]->programming_error ("Lost track of this dynamic spanner.");
110     }
111
112   bool end = line_ && running_.empty ();
113   Direction d = LEFT;
114   do
115     {
116       if (line_
117           && ((d == LEFT && !line_->get_bound (LEFT))
118               || (end && d == RIGHT && !line_->get_bound (RIGHT))))
119         {
120           vector<Spanner*> const &spanners =
121             (d == LEFT) ? started_ : ended_;
122           
123           Grob *bound = 0;
124           if (scripts_.size())
125             bound = scripts_[0];
126           else if (spanners.size())
127             bound = spanners[0]->get_bound (d);
128           else
129             {
130               programming_error ("Started DynamicLineSpanner but have no left bound.");
131               bound = unsmob_grob (get_property ("currentMusicalColumn"));
132             }
133
134           line_->set_bound (d, bound);
135         }
136     }
137   while (flip (&d) != LEFT);
138
139   for (vsize i = 0; line_ && i < support_.size (); i++)
140     Side_position_interface::add_support (line_, support_[i]);
141
142   if (end) 
143     line_ = 0;
144
145   ended_.clear ();
146   started_.clear ();
147   scripts_.clear ();
148   support_.clear ();
149 }
150
151
152 ADD_TRANSLATOR (Dynamic_align_engraver,
153                 /* doc */
154                 "Align hairpins and dynamic texts on a horizontal line",
155
156                 /* create */
157                 "DynamicLineSpanner ",
158
159                 /* read */
160                 "currentMusicalColumn ",
161
162                 /* write */
163                 ""
164                 );