]> git.donarmstrong.com Git - lilypond.git/blob - lily/engraver-group.cc
Neil's patch for hairpin to bar line.
[lilypond.git] / lily / engraver-group.cc
1 /*
2   engraver-group.cc -- implement Engraver_group
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "context.hh"
10 #include "dispatcher.hh"
11 #include "engraver-group.hh"
12 #include "grob.hh"
13 #include "paper-score.hh"
14 #include "translator-dispatch-list.hh"
15 #include "warn.hh"
16
17 IMPLEMENT_LISTENER (Engraver_group, override);
18 void
19 Engraver_group::override (SCM sev)
20 {
21   Stream_event *ev = unsmob_stream_event (sev);
22   
23   execute_general_pushpop_property (context (),
24                                     ev->get_property ("symbol"),
25                                     ev->get_property ("property-path"),
26                                     ev->get_property ("value"));
27 }
28
29 IMPLEMENT_LISTENER (Engraver_group, revert);
30 void
31 Engraver_group::revert (SCM sev)
32 {
33   Stream_event *ev = unsmob_stream_event (sev);
34   
35   execute_general_pushpop_property (context (),
36                                     ev->get_property ("symbol"),
37                                     ev->get_property ("property-path"),
38                                     SCM_UNDEFINED);
39 }
40
41 void
42 Engraver_group::connect_to_context (Context *c)
43 {
44   Translator_group::connect_to_context (c);
45   c->event_source ()->add_listener (GET_LISTENER (override), ly_symbol2scm ("Override"));
46   c->event_source ()->add_listener (GET_LISTENER (revert), ly_symbol2scm ("Revert"));
47 }
48
49 void
50 Engraver_group::disconnect_from_context ()
51 {
52   context ()->event_source ()->remove_listener (GET_LISTENER (override), ly_symbol2scm ("Override"));
53   context ()->event_source ()->remove_listener (GET_LISTENER (revert), ly_symbol2scm ("Revert"));
54   Translator_group::disconnect_from_context ();
55 }
56
57 void
58 Engraver_group::announce_grob (Grob_info info)
59 {
60   announce_infos_.push_back (info);
61
62   Engraver_group *dad_eng
63     = context_->get_parent_context ()
64     ? dynamic_cast<Engraver_group *> (context_->get_parent_context ()->implementation ())
65     : 0;
66
67   if (dad_eng)
68     dad_eng->announce_grob (info);
69 }
70
71 void
72 Engraver_group::acknowledge_grobs ()
73 {
74   if (!announce_infos_.size ())
75     return;
76
77   SCM name_sym = ly_symbol2scm ("name");
78   SCM meta_sym = ly_symbol2scm ("meta");
79
80   for (vsize j = 0; j < announce_infos_.size (); j++)
81     {
82       Grob_info info = announce_infos_[j];
83       
84       SCM meta = info.grob ()->internal_get_property (meta_sym);
85       SCM nm = scm_assoc (name_sym, meta);
86       if (scm_is_pair (nm))
87         nm = scm_cdr (nm);
88       else
89         continue;
90
91       SCM acklist = scm_hashq_ref (acknowledge_hash_table_drul_[info.start_end ()],
92                                    nm, SCM_BOOL_F);
93       
94       Engraver_dispatch_list *dispatch
95         = Engraver_dispatch_list::unsmob (acklist);
96
97       if (acklist == SCM_BOOL_F)
98         {
99           SCM ifaces
100             = scm_cdr (scm_assoc (ly_symbol2scm ("interfaces"), meta));
101           acklist = Engraver_dispatch_list::create (get_simple_trans_list (),
102                                                     ifaces, info.start_end ());
103
104           dispatch
105             = Engraver_dispatch_list::unsmob (acklist);
106
107           scm_hashq_set_x (acknowledge_hash_table_drul_[info.start_end ()], nm, acklist);
108         }
109
110       if (dispatch)
111         dispatch->apply (info);
112     }
113 }
114
115 /*
116   Ugh. This is slightly expensive. We could/should cache the value of
117   the group count?
118 */
119 int
120 Engraver_group::pending_grob_count () const
121 {
122   int count = announce_infos_.size ();
123   for (SCM s = context_->children_contexts ();
124        scm_is_pair (s); s = scm_cdr (s))
125     {
126       Context *c = unsmob_context (scm_car (s));
127       Engraver_group *group
128         = dynamic_cast<Engraver_group *> (c->implementation ());
129
130       if (group)
131         count += group->pending_grob_count ();
132     }
133   return count;
134 }
135
136 void
137 Engraver_group::do_announces ()
138 {
139   do
140     {
141       /*
142         DOCME: why is this inside the loop? 
143        */
144       for (SCM s = context ()->children_contexts ();
145            scm_is_pair (s); s = scm_cdr (s))
146         {
147           Context *c = unsmob_context (scm_car (s));
148           Engraver_group *group
149             = dynamic_cast<Engraver_group *> (c->implementation ());
150           if (group)
151             group->do_announces ();
152         }
153
154       
155       while (1)
156         {
157           precomputed_translator_foreach (PROCESS_ACKNOWLEDGED);
158           if (announce_infos_.size () == 0)
159             break;
160
161           acknowledge_grobs ();
162           announce_infos_.clear ();
163         }
164     }
165   while (pending_grob_count () > 0);
166 }
167
168 Engraver_group::Engraver_group ()
169 {
170   acknowledge_hash_table_drul_[LEFT] 
171     = acknowledge_hash_table_drul_[RIGHT] 
172     = SCM_EOL;
173   
174   acknowledge_hash_table_drul_[LEFT] = scm_c_make_hash_table (61);
175   acknowledge_hash_table_drul_[RIGHT] = scm_c_make_hash_table (61);
176 }
177
178 #include "translator.icc"
179
180 ADD_TRANSLATOR_GROUP (Engraver_group,
181                       /* doc */
182                       "A group of engravers taken together.",
183
184                       /* create */
185                       "",
186
187                       /* read */
188                       "",
189
190                       /* write */
191                       ""
192                       );
193
194 void
195 Engraver_group::derived_mark () const
196 {
197   scm_gc_mark (acknowledge_hash_table_drul_[LEFT]);
198   scm_gc_mark (acknowledge_hash_table_drul_[RIGHT]);
199 }