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