]> git.donarmstrong.com Git - lilypond.git/blob - lily/engraver-group-engraver.cc
* flower
[lilypond.git] / lily / engraver-group-engraver.cc
1 /*
2   engraver-group-engraver.cc -- implement Engraver_group_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "engraver-group-engraver.hh"
10
11 #include "flower-proto.hh"
12 #include "warn.hh"
13 #include "paper-score.hh"
14 #include "grob.hh"
15 #include "context.hh"
16
17 void
18 Engraver_group_engraver::announce_grob (Grob_info info)
19 {
20   announce_infos_.push (info);
21   get_daddy_engraver ()->announce_grob (info);
22 }
23
24 SCM find_acknowledge_engravers (SCM gravlist, SCM meta);
25 SCM find_accept_engravers (SCM gravlist, SCM music_descr);
26
27 void
28 Engraver_group_engraver::acknowledge_grobs ()
29 {
30   if (!announce_infos_.size ())
31     return;
32
33   SCM tab = get_property ("acknowledgeHashTable");
34   SCM name_sym = ly_symbol2scm ("name");
35   SCM meta_sym = ly_symbol2scm ("meta");
36
37   for (int j = 0; j < announce_infos_.size (); j++)
38     {
39       Grob_info info = announce_infos_[j];
40
41       SCM meta = info.grob_->internal_get_property (meta_sym);
42       SCM nm = scm_assoc (name_sym, meta);
43       if (scm_is_pair (nm))
44         nm = scm_cdr (nm);
45       else
46         {
47           /*
48             it's tempting to put an assert for
49             immutable_property_alist_ == '(), but in fact, some
50             engravers (clef-engraver) add some more information to the
51             immutable_property_alist_ (after it has been '()-ed).
52
53             We ignore the grob anyway. He who has no name, shall not
54             be helped.  */
55
56           continue;
57         }
58
59       SCM acklist = scm_hashq_ref (tab, nm, SCM_UNDEFINED);
60       if (acklist == SCM_BOOL_F)
61         {
62           acklist = find_acknowledge_engravers (scm_cons (self_scm (), get_simple_trans_list ()), meta);
63           scm_hashq_set_x (tab, nm, acklist);
64         }
65
66       for (SCM p = acklist; scm_is_pair (p); p = scm_cdr (p))
67         {
68           Translator *t = unsmob_translator (scm_car (p));
69           Engraver *eng = dynamic_cast<Engraver *> (t);
70           if (eng && eng != info.origin_trans_)
71             eng->acknowledge_grob (info);
72         }
73     }
74 }
75
76 /*
77   Ugh. This is slightly expensive. We could/should cache the value of
78   the group count?
79 */
80 int
81 Engraver_group_engraver::pending_grob_count () const
82 {
83   int count = announce_infos_.size ();
84   for (SCM s = context ()->children_contexts ();
85        scm_is_pair (s); s = scm_cdr (s))
86     {
87       Context *c = unsmob_context (scm_car (s));
88       Engraver_group_engraver *group
89         = dynamic_cast<Engraver_group_engraver *> (c->implementation ());
90
91       if (group)
92         count += group->pending_grob_count ();
93     }
94   return count;
95 }
96
97 void
98 Engraver_group_engraver::do_announces ()
99 {
100   do
101     {
102       for (SCM s = context ()->children_contexts ();
103            scm_is_pair (s); s = scm_cdr (s))
104         {
105           Context *c = unsmob_context (scm_car (s));
106           Engraver_group_engraver *group
107             = dynamic_cast<Engraver_group_engraver *> (c->implementation ());
108           if (group)
109             group->do_announces ();
110         }
111
112       do
113         {
114           engraver_each (get_simple_trans_list (),
115                          &Engraver::process_acknowledged_grobs);
116
117           if (announce_infos_.size () == 0)
118             break;
119
120           acknowledge_grobs ();
121           announce_infos_.clear ();
122         }
123       while (1);
124
125     }
126   while (pending_grob_count () > 0);
127
128 }
129
130 void
131 Engraver_group_engraver::initialize ()
132 {
133   SCM tab = scm_make_vector (scm_int2num (61), SCM_BOOL_F);
134   context ()->set_property ("acknowledgeHashTable", tab);
135
136   Translator_group::initialize ();
137 }
138
139 Engraver_group_engraver::Engraver_group_engraver () {}
140
141 ADD_TRANSLATOR (Engraver_group_engraver,
142                 /* descr */ "A group of engravers taken together",
143                 /* creats*/ "",
144                 /* accepts */ "",
145                 /* acks  */ "",
146                 /* reads */ "",
147                 /* write */ "");
148
149 /*****************/
150
151 bool
152 engraver_valid (Translator *tr, SCM ifaces)
153 {
154   SCM ack_ifs = scm_assoc (ly_symbol2scm ("interfaces-acked"), tr->translator_description ());
155   ack_ifs = scm_cdr (ack_ifs);
156   for (SCM s = ifaces; scm_is_pair (s); s = scm_cdr (s))
157     if (scm_c_memq (scm_car (s), ack_ifs) != SCM_BOOL_F)
158       return true;
159   return false;
160 }
161
162 SCM
163 find_acknowledge_engravers (SCM gravlist, SCM meta_alist)
164 {
165   SCM ifaces = scm_cdr (scm_assoc (ly_symbol2scm ("interfaces"), meta_alist));
166
167   SCM l = SCM_EOL;
168   for (SCM s = gravlist; scm_is_pair (s); s = scm_cdr (s))
169     {
170       Translator *tr = unsmob_translator (scm_car (s));
171       if (engraver_valid (tr, ifaces))
172         l = scm_cons (tr->self_scm (), l);
173     }
174   l = scm_reverse_x (l, SCM_EOL);
175
176   return l;
177 }
178
179 /* c&p engraver-group.cc */
180 void
181 recurse_down_engravers (Context *c, Engraver_method ptr, bool context_first)
182 {
183   Engraver_group_engraver *tg
184     = dynamic_cast<Engraver_group_engraver *> (c->implementation ());
185
186   if (!context_first)
187     {
188       engraver_each (tg->get_simple_trans_list (),
189                      ptr);
190
191       (tg->*ptr) ();
192     }
193
194   for (SCM s = c->children_contexts (); scm_is_pair (s);
195        s = scm_cdr (s))
196     {
197       recurse_down_engravers (unsmob_context (scm_car (s)), ptr, context_first);
198     }
199
200   if (context_first)
201     {
202       engraver_each (tg->get_simple_trans_list (),
203                      ptr);
204       (tg->*ptr) ();
205     }
206 }
207
208 void
209 engraver_each (SCM list, Engraver_method method)
210 {
211   for (SCM p = list; scm_is_pair (p); p = scm_cdr (p))
212     {
213       Engraver *e = dynamic_cast<Engraver *> (unsmob_translator (scm_car (p)));
214       if (e)
215         (e->*method) ();
216     }
217 }