]> git.donarmstrong.com Git - lilypond.git/blob - lily/extender-engraver.cc
Admin: run yearly grand-replace.
[lilypond.git] / lily / extender-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1999--2011 Glen Prideaux <glenprideaux@iname.com>,
5   Han-Wen Nienhuys <hanwen@xs4all.nl>,
6   Jan Nieuwenhuizen <janneke@gnu.org>
7
8   LilyPond is free software: you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation, either version 3 of the License, or
11   (at your option) any later version.
12
13   LilyPond is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "context.hh"
23 #include "engraver.hh"
24 #include "international.hh"
25 #include "item.hh"
26 #include "lyric-extender.hh"
27 #include "note-head.hh"
28 #include "pointer-group-interface.hh"
29 #include "stream-event.hh"
30 #include "warn.hh"
31 #include "spanner.hh"
32 #include "translator.icc"
33
34 void completize_extender (Spanner *sp);
35
36 class Extender_engraver : public Engraver
37 {
38   Stream_event *ev_;
39   Spanner *extender_;
40   Spanner *pending_extender_;
41
42 public:
43   TRANSLATOR_DECLARATIONS (Extender_engraver);
44
45 protected:
46   DECLARE_TRANSLATOR_LISTENER (extender);
47   DECLARE_TRANSLATOR_LISTENER (completize_extender);
48   DECLARE_ACKNOWLEDGER (lyric_syllable);
49
50   virtual void finalize ();
51
52   void stop_translation_timestep ();
53   void process_music ();
54 };
55
56 Extender_engraver::Extender_engraver ()
57 {
58   extender_ = 0;
59   pending_extender_ = 0;
60   ev_ = 0;
61 }
62
63 IMPLEMENT_TRANSLATOR_LISTENER (Extender_engraver, extender);
64 void
65 Extender_engraver::listen_extender (Stream_event *ev)
66 {
67   ASSIGN_EVENT_ONCE (ev_, ev);
68 }
69
70
71 /*
72   A CompletizeExtenderEvent is sent at the end of each lyrics block
73   to ensure any pending extender can be correctly terminated if the lyrics
74   end before the associated voice (this prevents the right bound being extended
75   to the next note-column if no lyric follows the extender)
76 */
77 IMPLEMENT_TRANSLATOR_LISTENER (Extender_engraver, completize_extender);
78 void
79 Extender_engraver::listen_completize_extender (Stream_event * /* ev */)
80 {
81   if (pending_extender_)
82     {
83       completize_extender (pending_extender_);
84       pending_extender_ = 0;
85     }
86 }
87
88 void
89 Extender_engraver::process_music ()
90 {
91   if (ev_)
92     extender_ = make_spanner ("LyricExtender", ev_->self_scm ());
93 }
94
95 void
96 Extender_engraver::acknowledge_lyric_syllable (Grob_info i)
97 {
98   Item *item = i.item ();
99   if (extender_)
100     extender_->set_bound (LEFT, item);
101
102   if (pending_extender_)
103     {
104       pending_extender_->set_object ("next", item->self_scm ());
105       completize_extender (pending_extender_);
106       pending_extender_ = 0;
107     }
108 }
109
110 void
111 Extender_engraver::stop_translation_timestep ()
112 {
113   if (extender_ || pending_extender_)
114     {
115       Context *voice = get_voice_to_lyrics (context ());
116       Grob *h = voice ? get_current_note_head (voice, to_boolean (get_property ("includeGraceNotes"))) : 0;
117
118       if (h)
119         {
120           if (extender_)
121             {
122               Pointer_group_interface::add_grob (extender_,
123                                                  ly_symbol2scm ("heads"), h);
124             }
125
126           if (pending_extender_)
127             {
128               Pointer_group_interface::add_grob (pending_extender_,
129                                                  ly_symbol2scm ("heads"), h);
130             }
131         }
132       else
133         {
134           if (pending_extender_
135               && !get_property ("extendersOverRests"))
136             {
137               completize_extender (pending_extender_);
138               pending_extender_ = 0;
139             }
140         }
141       if (extender_)
142         {
143           pending_extender_ = extender_;
144           extender_ = 0;
145         }
146     }
147
148   ev_ = 0;
149 }
150
151 void
152 completize_extender (Spanner *sp)
153 {
154   if (!sp->get_bound (RIGHT))
155     {
156       extract_item_set (sp, "heads", heads);
157       if (heads.size ())
158         sp->set_bound (RIGHT, heads.back ());
159     }
160 }
161
162 void
163 Extender_engraver::finalize ()
164 {
165   if (extender_)
166     {
167       completize_extender (extender_);
168
169       if (!extender_->get_bound (RIGHT))
170         extender_->warning (_ ("unterminated extender"));
171       extender_ = 0;
172     }
173
174   if (pending_extender_)
175     {
176       completize_extender (pending_extender_);
177
178       if (!pending_extender_->get_bound (RIGHT))
179         pending_extender_->warning (_ ("unterminated extender"));
180       pending_extender_ = 0;
181     }
182 }
183
184 ADD_ACKNOWLEDGER (Extender_engraver, lyric_syllable);
185 ADD_TRANSLATOR (Extender_engraver,
186                 /* doc */
187                 "Create lyric extenders.",
188
189                 /* create */
190                 "LyricExtender ",
191
192                 /* read */
193                 "extendersOverRests "
194                 "includeGraceNotes ",
195
196                 /* write */
197                 ""
198                 );