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