2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1999--2015 Glen Prideaux <glenprideaux@iname.com>,
5 Han-Wen Nienhuys <hanwen@xs4all.nl>,
6 Jan Nieuwenhuizen <janneke@gnu.org>
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.
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.
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/>.
23 #include "engraver.hh"
24 #include "international.hh"
26 #include "lyric-extender.hh"
27 #include "note-head.hh"
28 #include "pointer-group-interface.hh"
29 #include "stream-event.hh"
32 #include "translator.icc"
34 void completize_extender (Spanner *sp);
36 class Extender_engraver : public Engraver
40 Spanner *pending_extender_;
43 TRANSLATOR_DECLARATIONS (Extender_engraver);
46 void listen_extender (Stream_event *);
47 void listen_completize_extender (Stream_event *);
48 void acknowledge_lyric_syllable (Grob_info);
50 virtual void finalize ();
52 void stop_translation_timestep ();
53 void process_music ();
56 Extender_engraver::Extender_engraver (Context *c)
60 pending_extender_ = 0;
65 Extender_engraver::listen_extender (Stream_event *ev)
67 ASSIGN_EVENT_ONCE (ev_, ev);
71 A CompletizeExtenderEvent is sent at the end of each lyrics block
72 to ensure any pending extender can be correctly terminated if the lyrics
73 end before the associated voice (this prevents the right bound being extended
74 to the next note-column if no lyric follows the extender)
77 Extender_engraver::listen_completize_extender (Stream_event * /* ev */)
79 if (pending_extender_)
81 completize_extender (pending_extender_);
82 pending_extender_ = 0;
87 Extender_engraver::process_music ()
90 extender_ = make_spanner ("LyricExtender", ev_->self_scm ());
94 Extender_engraver::acknowledge_lyric_syllable (Grob_info i)
96 Item *item = i.item ();
98 extender_->set_bound (LEFT, item);
100 if (pending_extender_)
102 pending_extender_->set_object ("next", item->self_scm ());
103 completize_extender (pending_extender_);
104 pending_extender_ = 0;
109 Extender_engraver::stop_translation_timestep ()
111 if (extender_ || pending_extender_)
113 Context *voice = get_voice_to_lyrics (context ());
114 Grob *h = voice ? get_current_note_head (voice) : 0;
120 Pointer_group_interface::add_grob (extender_,
121 ly_symbol2scm ("heads"), h);
124 if (pending_extender_)
126 Pointer_group_interface::add_grob (pending_extender_,
127 ly_symbol2scm ("heads"), h);
132 if (pending_extender_
133 && !to_boolean (get_property ("extendersOverRests")))
135 completize_extender (pending_extender_);
136 pending_extender_ = 0;
141 pending_extender_ = extender_;
150 completize_extender (Spanner *sp)
152 if (!sp->get_bound (RIGHT))
154 extract_item_set (sp, "heads", heads);
156 sp->set_bound (RIGHT, heads.back ());
161 Extender_engraver::finalize ()
165 completize_extender (extender_);
167 if (!extender_->get_bound (RIGHT))
168 extender_->warning (_ ("unterminated extender"));
172 if (pending_extender_)
174 completize_extender (pending_extender_);
176 if (!pending_extender_->get_bound (RIGHT))
177 pending_extender_->warning (_ ("unterminated extender"));
178 pending_extender_ = 0;
183 Extender_engraver::boot ()
185 ADD_LISTENER (Extender_engraver, extender);
186 ADD_LISTENER (Extender_engraver, completize_extender);
187 ADD_ACKNOWLEDGER (Extender_engraver, lyric_syllable);
190 ADD_TRANSLATOR (Extender_engraver,
192 "Create lyric extenders.",
198 "extendersOverRests ",