2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2004--2010 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
21 #include "engraver.hh"
22 #include "international.hh"
25 #include "simple-closure.hh"
30 like execute_general_pushpop_property(), but typecheck
31 grob_property_path and context_property.
34 general_pushpop_property (Context
*context
,
36 SCM grob_property_path
,
39 if (!scm_is_symbol (context_property
)
40 || !scm_is_symbol (scm_car (grob_property_path
)))
42 warning (_ ("need symbol arguments for \\override and \\revert"));
43 if (do_internal_type_checking_global
)
47 sloppy_general_pushpop_property (context
, context_property
,
48 grob_property_path
, new_value
);
53 Grob descriptions (ie. alists with layout properties) are
54 represented as a (ALIST . BASED-ON) pair, where BASED-ON is the
55 alist defined in a parent context. BASED-ON should always be a tail
58 Push or pop (depending on value of VAL) a single entry from a
59 translator property list by name of PROP. GROB_PROPERTY_PATH
60 indicates nested alists, eg. '(beamed-stem-lengths details)
64 execute_override_property (Context
*context
,
66 SCM grob_property_path
,
69 SCM current_context_val
= SCM_EOL
;
71 Context
*where
= context
->where_defined (context_property
,
72 ¤t_context_val
);
82 SCM base
= updated_grob_properties (context
, context_property
);
83 current_context_val
= scm_cons (base
, base
);
84 context
->set_property (context_property
, current_context_val
);
87 if (!scm_is_pair (current_context_val
))
89 programming_error ("Grob definition should be cons");
93 SCM target_alist
= scm_car (current_context_val
);
96 If the car is a list, the property path comes from a nested override
97 using list syntax inside a \context block
99 if (scm_is_pair (scm_car (grob_property_path
)))
100 grob_property_path
= scm_car (grob_property_path
);
102 SCM symbol
= scm_car (grob_property_path
);
103 if (scm_is_pair (scm_cdr (grob_property_path
)))
105 new_value
= nested_property_alist (ly_assoc_get (symbol
, target_alist
,
107 scm_cdr (grob_property_path
),
111 /* it's tempting to replace the head of the list if it's the same
112 property. However, we have to keep this info around, in case we have to
115 target_alist
= scm_acons (symbol
, new_value
, target_alist
);
118 if (!ly_is_procedure (new_value
)
119 && !is_simple_closure (new_value
))
120 ok
= type_check_assignment (symbol
, new_value
,
121 ly_symbol2scm ("backend-type?"));
124 tack onto alist. We can use set_car, since
125 updated_grob_properties () in child contexts will check
126 for changes in the car.
130 scm_set_car_x (current_context_val
, target_alist
);
135 do a pop (indicated by new_value==SCM_UNDEFINED) or push
138 sloppy_general_pushpop_property (Context
*context
,
139 SCM context_property
,
140 SCM grob_property_path
,
143 if (new_value
== SCM_UNDEFINED
)
144 execute_revert_property (context
, context_property
,
147 execute_override_property (context
, context_property
,
153 Revert the property given by property_path.
156 execute_revert_property (Context
*context
,
157 SCM context_property
,
158 SCM grob_property_path
)
160 SCM current_context_val
= SCM_EOL
;
161 if (context
->where_defined (context_property
, ¤t_context_val
)
164 SCM current_alist
= scm_car (current_context_val
);
165 SCM daddy
= scm_cdr (current_context_val
);
167 if (!scm_is_pair (grob_property_path
)
168 || !scm_is_symbol (scm_car (grob_property_path
)))
170 programming_error ("Grob property path should be list of symbols.");
174 SCM symbol
= scm_car (grob_property_path
);
175 if (scm_is_pair (scm_cdr (grob_property_path
)))
177 SCM current_sub_alist
= ly_assoc_get (symbol
, current_alist
, SCM_EOL
);
179 = nested_property_revert_alist (current_sub_alist
,
180 scm_cdr (grob_property_path
));
182 if (scm_is_pair (current_alist
)
183 && scm_caar (current_alist
) == symbol
184 && current_alist
!= daddy
)
185 current_alist
= scm_cdr (current_alist
);
187 current_alist
= scm_acons (symbol
, new_val
, current_alist
);
188 scm_set_car_x (current_context_val
, current_alist
);
192 SCM new_alist
= evict_from_alist (symbol
, current_alist
, daddy
);
194 if (new_alist
== daddy
)
195 context
->unset_property (context_property
);
197 context
->set_property (context_property
,
198 scm_cons (new_alist
, daddy
));
203 Convenience: a push/pop grob property using a single grob_property
207 execute_pushpop_property (Context
*context
,
208 SCM context_property
,
212 general_pushpop_property (context
, context_property
,
213 scm_list_1 (grob_property
),
218 PRE_INIT_OPS is in the order specified, and hence must be reversed.
221 apply_property_operations (Context
*tg
, SCM pre_init_ops
)
223 SCM correct_order
= scm_reverse (pre_init_ops
);
224 for (SCM s
= correct_order
; scm_is_pair (s
); s
= scm_cdr (s
))
226 SCM entry
= scm_car (s
);
227 SCM type
= scm_car (entry
);
228 entry
= scm_cdr (entry
);
230 if (type
== ly_symbol2scm ("push"))
232 SCM context_prop
= scm_car (entry
);
233 SCM val
= scm_cadr (entry
);
234 SCM grob_prop_path
= scm_cddr (entry
);
235 sloppy_general_pushpop_property (tg
, context_prop
, grob_prop_path
, val
);
237 else if (type
== ly_symbol2scm ("pop"))
239 SCM context_prop
= scm_car (entry
);
240 SCM val
= SCM_UNDEFINED
;
241 SCM grob_prop_path
= scm_cdr (entry
);
242 sloppy_general_pushpop_property (tg
, context_prop
, grob_prop_path
, val
);
244 else if (type
== ly_symbol2scm ("assign"))
245 tg
->set_property (scm_car (entry
), scm_cadr (entry
));
250 Return the object alist for SYM, checking if its base in enclosing
251 contexts has changed. The alist is updated if necessary.
254 updated_grob_properties (Context
*tg
, SCM sym
)
256 assert (scm_is_symbol (sym
));
259 tg
= tg
->where_defined (sym
, &props
);
264 = (tg
->get_parent_context ())
265 ? updated_grob_properties (tg
->get_parent_context (), sym
)
268 if (!scm_is_pair (props
))
270 programming_error ("grob props not a pair?");
274 SCM based_on
= scm_cdr (props
);
275 if (based_on
== daddy_props
)
276 return scm_car (props
);
279 SCM copy
= daddy_props
;
281 SCM p
= scm_car (props
);
282 while (p
!= based_on
)
284 *tail
= scm_cons (scm_car (p
), daddy_props
);
285 tail
= SCM_CDRLOC (*tail
);
289 scm_set_car_x (props
, copy
);
290 scm_set_cdr_x (props
, daddy_props
);