]> git.donarmstrong.com Git - lilypond.git/blob - lily/extender-engraver.cc
19e04062793b19d531f6a73b5b3f646772eaf602
[lilypond.git] / lily / extender-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1999--2012 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   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)
75 */
76 IMPLEMENT_TRANSLATOR_LISTENER (Extender_engraver, completize_extender);
77 void
78 Extender_engraver::listen_completize_extender (Stream_event * /* ev */)
79 {
80   if (pending_extender_)
81     {
82       completize_extender (pending_extender_);
83       pending_extender_ = 0;
84     }
85 }
86
87 void
88 Extender_engraver::process_music ()
89 {
90   if (ev_)
91     extender_ = make_spanner ("LyricExtender", ev_->self_scm ());
92 }
93
94 void
95 Extender_engraver::acknowledge_lyric_syllable (Grob_info i)
96 {
97   Item *item = i.item ();
98   if (extender_)
99     extender_->set_bound (LEFT, item);
100
101   if (pending_extender_)
102     {
103       pending_extender_->set_object ("next", item->self_scm ());
104       completize_extender (pending_extender_);
105       pending_extender_ = 0;
106     }
107 }
108
109 void
110 Extender_engraver::stop_translation_timestep ()
111 {
112   if (extender_ || pending_extender_)
113     {
114       Context *voice = get_voice_to_lyrics (context ());
115       Grob *h = voice ? get_current_note_head (voice, to_boolean (get_property ("includeGraceNotes"))) : 0;
116
117       if (h)
118         {
119           if (extender_)
120             {
121               Pointer_group_interface::add_grob (extender_,
122                                                  ly_symbol2scm ("heads"), h);
123             }
124
125           if (pending_extender_)
126             {
127               Pointer_group_interface::add_grob (pending_extender_,
128                                                  ly_symbol2scm ("heads"), h);
129             }
130         }
131       else
132         {
133           if (pending_extender_
134               && !get_property ("extendersOverRests"))
135             {
136               completize_extender (pending_extender_);
137               pending_extender_ = 0;
138             }
139         }
140       if (extender_)
141         {
142           pending_extender_ = extender_;
143           extender_ = 0;
144         }
145     }
146
147   ev_ = 0;
148 }
149
150 void
151 completize_extender (Spanner *sp)
152 {
153   if (!sp->get_bound (RIGHT))
154     {
155       extract_item_set (sp, "heads", heads);
156       if (heads.size ())
157         sp->set_bound (RIGHT, heads.back ());
158     }
159 }
160
161 void
162 Extender_engraver::finalize ()
163 {
164   if (extender_)
165     {
166       completize_extender (extender_);
167
168       if (!extender_->get_bound (RIGHT))
169         extender_->warning (_ ("unterminated extender"));
170       extender_ = 0;
171     }
172
173   if (pending_extender_)
174     {
175       completize_extender (pending_extender_);
176
177       if (!pending_extender_->get_bound (RIGHT))
178         pending_extender_->warning (_ ("unterminated extender"));
179       pending_extender_ = 0;
180     }
181 }
182
183 ADD_ACKNOWLEDGER (Extender_engraver, lyric_syllable);
184 ADD_TRANSLATOR (Extender_engraver,
185                 /* doc */
186                 "Create lyric extenders.",
187
188                 /* create */
189                 "LyricExtender ",
190
191                 /* read */
192                 "extendersOverRests "
193                 "includeGraceNotes ",
194
195                 /* write */
196                 ""
197                );