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