]> git.donarmstrong.com Git - lilypond.git/blob - lily/context-property.cc
* scm/define-context-properties.scm (Module): change definition of
[lilypond.git] / lily / context-property.cc
1 /*   
2    translator-property.cc -- implement manipulation of immutable Grob
3    property lists.
4
5    source file of the GNU LilyPond music typesetter
6
7    (c) 2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
8  */
9
10 #include "main.hh"
11 #include "context.hh"
12 #include "warn.hh"
13 #include "item.hh"
14 #include "spanner.hh"
15 #include "engraver.hh"
16
17 /*
18   Grob descriptions (ie. alists with layout properties) are
19   represented as a (ALIST . BASED-ON) pair, where BASED-ON is the
20   alist defined in a parent context. BASED-ON should always be a tail
21   of ALIST.
22   
23   */
24
25 /*
26   Push or pop (depending on value of VAL) a single entry (ELTPROP . VAL)
27   entry from a translator property list by name of PROP
28 */
29
30
31 void
32 execute_pushpop_property (Context * trg,
33                           SCM prop, SCM eltprop, SCM val)
34 {
35   if (scm_is_symbol (prop) && scm_is_symbol (eltprop))
36     {
37       if (val != SCM_UNDEFINED)
38         {
39           SCM prev = SCM_EOL;
40           Context * where = trg->where_defined (prop);
41
42           /*
43             Don't mess with MIDI.
44            */
45           if (!where)
46             return ;
47           
48           if (where != trg)
49             {
50               SCM base = updated_grob_properties (trg, prop);
51               prev = scm_cons (base, base); 
52               trg->internal_set_property (prop, prev);
53             }
54           else
55             prev = trg->internal_get_property (prop);
56           
57           if (!scm_is_pair (prev))
58             {
59               programming_error ("Grob definition should be cons.");
60               return ;
61             }
62
63           SCM prev_alist = scm_car (prev);
64           
65           if (scm_is_pair (prev_alist) || prev_alist == SCM_EOL)
66             {
67               bool ok = type_check_assignment (eltprop, val, ly_symbol2scm ("backend-type?"));
68
69               /*
70                tack onto alist:
71               */
72               if (ok)
73                 scm_set_car_x (prev, scm_acons (eltprop, val, prev_alist));
74             }
75           else
76             {
77               // warning here.
78             }
79         }
80       else if (trg->where_defined (prop) == trg)
81         {
82           SCM prev = trg->internal_get_property (prop);
83           SCM prev_alist = scm_car (prev);
84           SCM daddy = scm_cdr (prev);
85           
86           SCM new_alist = SCM_EOL;
87           SCM *tail = &new_alist;
88
89           while (prev_alist != daddy)
90             {
91               if (ly_c_equal_p (scm_caar (prev_alist), eltprop))
92                 {
93                   prev_alist = scm_cdr (prev_alist);
94                   break ;
95                 }
96
97               
98               *tail = scm_cons (scm_car (prev_alist), SCM_EOL);
99               tail = SCM_CDRLOC (*tail);
100               prev_alist = scm_cdr (prev_alist);
101             }
102
103           if (new_alist == SCM_EOL && prev_alist == daddy)
104             trg->unset_property (prop);
105           else
106             {
107               *tail = prev_alist;
108               trg->internal_set_property (prop, scm_cons (new_alist, daddy));
109             }
110         }
111     }
112   else
113     {
114       warning ("Need symbol arguments for \\override and \\revert");
115       if (internal_type_checking_global_b)
116         assert (false);
117     }
118 }
119
120 /*
121   PRE_INIT_OPS is in the order specified, and hence must be reversed.
122  */
123 void
124 apply_property_operations (Context *tg, SCM pre_init_ops)
125 {
126   SCM correct_order = scm_reverse (pre_init_ops);
127   for (SCM s = correct_order; scm_is_pair (s); s = scm_cdr (s))
128     {
129       SCM entry = scm_car (s);
130       SCM type = scm_car (entry);
131       entry = scm_cdr (entry); 
132       
133       if (type == ly_symbol2scm ("push") || type == ly_symbol2scm ("poppush"))
134         {
135           SCM val = scm_cddr (entry);
136           val = scm_is_pair (val) ? scm_car (val) : SCM_UNDEFINED;
137
138           execute_pushpop_property (tg, scm_car (entry), scm_cadr (entry), val);
139         }
140       else if (type == ly_symbol2scm ("assign"))
141         {
142           tg->internal_set_property (scm_car (entry), scm_cadr (entry));
143         }
144     }
145 }
146
147 /*
148   Return the object alist for SYM, checking if its base in enclosing
149   contexts has changed. The alist is updated if necessary. 
150    */
151 SCM
152 updated_grob_properties (Context * tg, SCM sym)
153 {
154   assert (scm_is_symbol (sym));
155   
156   tg = tg->where_defined (sym);
157   if (!tg)
158     return SCM_EOL;
159   
160   SCM daddy_props
161     = (tg->get_parent_context ())
162     ? updated_grob_properties (tg->get_parent_context (), sym)
163     : SCM_EOL;
164   
165   SCM props  = tg->internal_get_property (sym);
166
167   if (!scm_is_pair (props))
168     {
169       programming_error ("grob props not a pair?");
170       return SCM_EOL;
171     }
172
173   SCM based_on = scm_cdr (props);
174   if (based_on == daddy_props)
175     {
176       return scm_car (props);
177     }
178   else
179     {
180       SCM copy = daddy_props;
181       SCM * tail = &copy;
182       SCM p = scm_car (props);
183       while  (p != based_on)
184         {
185           *tail = scm_cons (scm_car (p), daddy_props);
186           tail = SCM_CDRLOC (*tail);
187           p = scm_cdr (p);
188         }
189       
190       scm_set_car_x (props, copy);
191       scm_set_cdr_x (props, daddy_props);
192
193       return copy;
194     }
195 }
196
197 Item*
198 make_item_from_properties (Translator *tr, SCM x, SCM cause)
199 {
200   Context *tg = tr->context ();
201   
202   SCM props = updated_grob_properties (tg, x);
203   Item *it= new Item (props);
204
205   dynamic_cast<Engraver*>(tr)->announce_grob (it, cause);
206   
207   return it;
208 }
209
210 Spanner*
211 make_spanner_from_properties (Translator *tr, SCM x, SCM cause)
212 {
213   Context *tg = tr->context ();
214   
215   SCM props = updated_grob_properties (tg, x);
216   Spanner *it= new Spanner (props);
217
218   dynamic_cast<Engraver*>(tr)->announce_grob (it, cause);
219   
220   return it;
221 }