]> git.donarmstrong.com Git - lilypond.git/blob - lily/extender-engraver.cc
* input/regression/lyric-extender.ly: Fix and add test.
[lilypond.git] / lily / extender-engraver.cc
1 /*
2   extender-engraver.cc -- implement Extender_engraver
3
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999--2004 Glen Prideaux <glenprideaux@iname.com>,
7                   Han-Wen Nienhuys <hanwen@cs.uu.nl>,
8                   Jan Nieuwenhuizen <janneke@gnu.org>
9 */
10
11 #include "context.hh"
12 #include "engraver.hh"
13 #include "group-interface.hh"
14 #include "item.hh"
15 #include "lyric-extender.hh"
16 #include "note-head.hh"
17 #include "warn.hh"
18
19 class Extender_engraver : public Engraver
20 {
21   Music *ev_;
22   Spanner *extender_;
23   Spanner *pending_extender_;
24
25 public:
26   TRANSLATOR_DECLARATIONS (Extender_engraver);
27
28 protected:
29   virtual void acknowledge_grob (Grob_info);
30   virtual void finalize ();
31   virtual bool try_music (Music*);
32   virtual void stop_translation_timestep ();
33   virtual void process_music ();
34 };
35
36
37 Extender_engraver::Extender_engraver ()
38 {
39   extender_ = 0;
40   pending_extender_ = 0;
41   ev_ = 0;
42 }
43
44 bool
45 Extender_engraver::try_music (Music *r)
46 {
47   if (!ev_)
48     {
49       ev_ = r;
50       return true;
51     }
52   return false;
53 }
54
55 void
56 Extender_engraver::process_music ()
57 {
58   if (ev_)
59     extender_ = make_spanner ("LyricExtender", ev_->self_scm ());
60 }
61
62 void
63 Extender_engraver::acknowledge_grob (Grob_info i)
64 {
65   Item *item = dynamic_cast<Item*> (i.grob_);
66
67   if (item
68       && item->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")))
69     {
70       if (extender_)
71         extender_->set_bound (LEFT, item);
72
73       if (pending_extender_)
74         pending_extender_->set_bound (RIGHT, item);
75     }
76 }
77
78 void
79 Extender_engraver::stop_translation_timestep ()
80 {
81   if (pending_extender_ && pending_extender_->get_bound (RIGHT))
82     pending_extender_ = 0;
83
84   if (extender_ || pending_extender_)
85     {
86       Context *voice = get_voice_to_lyrics (context ());
87       Grob *h = voice ? get_current_note_head (voice) : 0;
88       Grob *r = voice ? get_current_rest (voice) : 0;
89
90       if (h)
91         {
92           if (extender_)
93             Pointer_group_interface::add_grob (extender_,
94                                                ly_symbol2scm ("heads"), h);
95           if (pending_extender_)
96             Pointer_group_interface::add_grob (pending_extender_,
97                                                ly_symbol2scm ("heads"), h);
98         }
99       else if (r && pending_extender_)
100         /* Rest: stop right here. */
101         pending_extender_->set_bound (RIGHT, r);
102  
103       if (extender_ && !r)
104         {
105           pending_extender_ = extender_;
106           extender_ = 0;
107         }
108     }
109
110   ev_ = 0;
111 }
112
113 void
114 completize_extender (Spanner *sp)
115 {
116   if (!sp->get_bound (RIGHT))
117     {
118       SCM heads = sp->get_property ("heads");
119       if (ly_c_pair_p (heads))
120         {
121           Item *it = dynamic_cast<Item*> (unsmob_grob (ly_car (heads)));
122           if (it)
123             sp->set_bound (RIGHT, it);
124         }
125     }
126 }
127
128 void
129 Extender_engraver::finalize ()
130 {
131   if (extender_)
132     {
133       completize_extender (extender_);
134
135       if (!extender_->get_bound (RIGHT))
136         extender_->warning (_ ("unterminated extender"));
137       extender_ = 0;
138     }
139
140   if (pending_extender_)
141     {
142       completize_extender (pending_extender_);
143
144       if (!pending_extender_->get_bound (RIGHT))
145         pending_extender_->warning (_ ("unterminated extender"));
146       pending_extender_ =0;
147     }
148 }
149
150
151 ENTER_DESCRIPTION (Extender_engraver,
152 /* descr */       "Create lyric extenders",
153 /* creats*/       "LyricExtender",
154 /* accepts */     "extender-event",
155 /* acks  */       "lyric-syllable-interface",
156 /* reads */       "",
157 /* write */       "");