2 translator-property.cc -- implement manipulation of
4 immutable Grob property lists.
6 source file of the GNU LilyPond music typesetter
8 (c) 2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
16 #include "engraver.hh"
19 Grob descriptions (ie. alists with layout properties) are
20 represented as a (ALIST . BASED-ON) pair, where BASED-ON is the
21 alist defined in a parent context. BASED-ON should always be a tail
27 Push or pop (depending on value of VAL) a single entry (ELTPROP . VAL)
28 entry from a translator property list by name of PROP
33 execute_pushpop_property (Context * trg,
34 SCM prop, SCM eltprop, SCM val)
36 if (scm_is_symbol (prop) && scm_is_symbol (eltprop))
38 if (val != SCM_UNDEFINED)
41 Context * where = trg->where_defined (prop);
51 SCM base = updated_grob_properties (trg, prop);
52 prev = scm_cons (base, base);
53 trg->internal_set_property (prop, prev);
56 prev = trg->internal_get_property (prop);
58 if (!scm_is_pair (prev))
60 programming_error ("Grob definition should be cons.");
64 SCM prev_alist = scm_car (prev);
66 if (scm_is_pair (prev_alist) || prev_alist == SCM_EOL)
68 bool ok = type_check_assignment (eltprop, val, ly_symbol2scm ("backend-type?"));
74 scm_set_car_x (prev, scm_acons (eltprop, val, prev_alist));
81 else if (trg->where_defined (prop) == trg)
83 SCM prev = trg->internal_get_property (prop);
84 SCM prev_alist = scm_car (prev);
85 SCM daddy = scm_cdr (prev);
87 SCM new_alist = SCM_EOL;
88 SCM *tail = &new_alist;
90 while (prev_alist != daddy)
92 if (ly_c_equal_p (scm_caar (prev_alist), eltprop))
94 prev_alist = scm_cdr (prev_alist);
99 *tail = scm_cons (scm_car (prev_alist), SCM_EOL);
100 tail = SCM_CDRLOC (*tail);
101 prev_alist = scm_cdr (prev_alist);
104 if (new_alist == SCM_EOL && prev_alist == daddy)
105 trg->unset_property (prop);
109 trg->internal_set_property (prop, scm_cons (new_alist, daddy));
115 warning ("Need symbol arguments for \\override and \\revert");
116 if (internal_type_checking_global_b)
122 PRE_INIT_OPS is in the order specified, and hence must be reversed.
125 apply_property_operations (Context *tg, SCM pre_init_ops)
127 SCM correct_order = scm_reverse (pre_init_ops);
128 for (SCM s = correct_order; scm_is_pair (s); s = scm_cdr (s))
130 SCM entry = scm_car (s);
131 SCM type = scm_car (entry);
132 entry = scm_cdr (entry);
134 if (type == ly_symbol2scm ("push") || type == ly_symbol2scm ("poppush"))
136 SCM val = scm_cddr (entry);
137 val = scm_is_pair (val) ? scm_car (val) : SCM_UNDEFINED;
139 execute_pushpop_property (tg, scm_car (entry), scm_cadr (entry), val);
141 else if (type == ly_symbol2scm ("assign"))
143 tg->internal_set_property (scm_car (entry), scm_cadr (entry));
149 Return the object alist for SYM, checking if its base in enclosing
150 contexts has changed. The alist is updated if necessary.
153 updated_grob_properties (Context * tg, SCM sym)
155 assert (scm_is_symbol (sym));
157 tg = tg->where_defined (sym);
162 = (tg->get_parent_context ())
163 ? updated_grob_properties (tg->get_parent_context (), sym)
166 SCM props = tg->internal_get_property (sym);
168 if (!scm_is_pair (props))
170 programming_error ("grob props not a pair?");
174 SCM based_on = scm_cdr (props);
175 if (based_on == daddy_props)
177 return scm_car (props);
181 SCM copy = daddy_props;
183 SCM p = scm_car (props);
184 while (p != based_on)
186 *tail = scm_cons (scm_car (p), daddy_props);
187 tail = SCM_CDRLOC (*tail);
191 scm_set_car_x (props, copy);
192 scm_set_cdr_x (props, daddy_props);
199 make_item_from_properties (Translator *tr, SCM x, SCM cause)
201 Context *tg = tr->context ();
203 SCM props = updated_grob_properties (tg, x);
204 Item *it= new Item (props);
206 dynamic_cast<Engraver*>(tr)->announce_grob (it, cause);
212 make_spanner_from_properties (Translator *tr, SCM x, SCM cause)
214 Context *tg = tr->context ();
216 SCM props = updated_grob_properties (tg, x);
217 Spanner *it= new Spanner (props);
219 dynamic_cast<Engraver*>(tr)->announce_grob (it, cause);