1507
|
1 /* Paranormal - A highly customizable audio visualization library
|
|
2 * Copyright (C) 2001 Jamie Gennis <jgennis@mindspring.com>
|
|
3 *
|
|
4 * This library is free software; you can redistribute it and/or
|
|
5 * modify it under the terms of the GNU Library General Public
|
|
6 * License as published by the Free Software Foundation; either
|
|
7 * version 2 of the License, or (at your option) any later version.
|
|
8 *
|
|
9 * This library is distributed in the hope that it will be useful,
|
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12 * Library General Public License for more details.
|
|
13 *
|
|
14 * You should have received a copy of the GNU Library General Public
|
|
15 * License along with this library; if not, write to the Free
|
|
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
17 */
|
|
18
|
|
19 #include <glib.h>
|
|
20 #include "pncontainer.h"
|
|
21 #include "pnactuatorfactory.h"
|
|
22 #include "pnerror.h"
|
|
23 #include "pnxml.h"
|
|
24
|
|
25 static void pn_container_class_init (PnContainerClass *class);
|
|
26 static void pn_container_init (PnContainer *container,
|
|
27 PnContainerClass *class);
|
|
28 /* PnObject methods */
|
|
29 static void pn_container_destroy (PnObject *object);
|
|
30
|
|
31 /* PnUserObject methods */
|
|
32 static void pn_container_save_thyself (PnUserObject *user_object,
|
|
33 xmlNodePtr node);
|
|
34 static void pn_container_load_thyself (PnUserObject *user_object,
|
|
35 xmlNodePtr node);
|
|
36
|
|
37 /* PnActuator methods */
|
|
38 static void pn_container_prepare (PnContainer *container,
|
|
39 PnImage *image);
|
|
40
|
|
41 /* PnContainer methods */
|
|
42 static gboolean pn_container_real_add_actuator (PnContainer *container,
|
|
43 PnActuator *actuator,
|
|
44 gint position);
|
|
45
|
|
46 static PnActuatorClass *parent_class = NULL;
|
|
47
|
|
48 GType
|
|
49 pn_container_get_type (void)
|
|
50 {
|
|
51 static GType container_type = 0;
|
|
52
|
|
53 if (! container_type)
|
|
54 {
|
|
55 static const GTypeInfo container_info =
|
|
56 {
|
|
57 sizeof (PnContainerClass),
|
|
58 NULL, /* base_init */
|
|
59 NULL, /* base_finalize */
|
|
60 (GClassInitFunc) pn_container_class_init,
|
|
61 NULL, /* class_finalize */
|
|
62 NULL, /* class_data */
|
|
63 sizeof (PnContainer),
|
|
64 0, /* n_preallocs */
|
|
65 (GInstanceInitFunc) pn_container_init
|
|
66 };
|
|
67
|
|
68 /* FIXME: should this be dynamic? */
|
|
69 container_type = g_type_register_static (PN_TYPE_ACTUATOR,
|
|
70 "PnContainer",
|
|
71 &container_info,
|
|
72 G_TYPE_FLAG_ABSTRACT);
|
|
73 }
|
|
74 return container_type;
|
|
75 }
|
|
76
|
|
77 static void
|
|
78 pn_container_class_init (PnContainerClass *class)
|
|
79 {
|
|
80 PnObjectClass *object_class;
|
|
81 PnUserObjectClass *user_object_class;
|
|
82 PnActuatorClass *actuator_class;
|
|
83
|
|
84 parent_class = g_type_class_peek_parent (class);
|
|
85
|
|
86 object_class = (PnObjectClass *) class;
|
|
87 user_object_class = (PnUserObjectClass *) class;
|
|
88 actuator_class = (PnActuatorClass *) class;
|
|
89
|
|
90 /* PnObject signals */
|
|
91 object_class->destroy = pn_container_destroy;
|
|
92
|
|
93 /* PnUserObject methods */
|
|
94 user_object_class->save_thyself = pn_container_save_thyself;
|
|
95 user_object_class->load_thyself = pn_container_load_thyself;
|
|
96
|
|
97 /* PnActuator methods */
|
|
98 actuator_class->prepare = (PnActuatorPrepFunc) pn_container_prepare;
|
|
99
|
|
100 /* PnContainer methods */
|
|
101 class->add_actuator = pn_container_real_add_actuator;
|
|
102 }
|
|
103
|
|
104 static void
|
|
105 pn_container_init (PnContainer *container, PnContainerClass *class)
|
|
106 {
|
|
107 container->actuators = g_array_new (FALSE, FALSE, sizeof (PnActuator *));
|
|
108 }
|
|
109
|
|
110 static void
|
|
111 pn_container_destroy (PnObject *object)
|
|
112 {
|
|
113 PnContainer *container;
|
|
114
|
|
115 g_return_if_fail (object != NULL);
|
|
116 g_return_if_fail (PN_IS_CONTAINER (object));
|
|
117
|
|
118 container = (PnContainer *) object;
|
|
119
|
|
120 pn_container_remove_all_actuators (container);
|
|
121 }
|
|
122
|
|
123 static void
|
|
124 pn_container_save_thyself (PnUserObject *user_object, xmlNodePtr node)
|
|
125 {
|
|
126 PnContainer *container;
|
|
127 PnActuator *actuator;
|
|
128 xmlNodePtr actuators_node, actuator_node;
|
|
129 guint i;
|
|
130
|
|
131 g_return_if_fail (user_object != NULL);
|
|
132 g_return_if_fail (PN_IS_CONTAINER (user_object));
|
|
133 g_return_if_fail (node != NULL);
|
|
134
|
|
135 container = (PnContainer *) user_object;
|
|
136
|
|
137 actuators_node = xmlNewChild (node, NULL, "Actuators", NULL);
|
|
138
|
|
139 /* Save the actuators */
|
|
140 for (i=0; i<container->actuators->len; i++)
|
|
141 {
|
|
142 actuator = g_array_index (container->actuators, PnActuator *, i);
|
|
143 actuator_node = xmlNewChild (actuators_node, NULL, "BUG", NULL);
|
|
144 pn_user_object_save_thyself (PN_USER_OBJECT (actuator), actuator_node);
|
|
145 }
|
|
146
|
|
147 if (PN_USER_OBJECT_CLASS (parent_class)->save_thyself)
|
|
148 PN_USER_OBJECT_CLASS (parent_class)->save_thyself (user_object, node);
|
|
149 }
|
|
150
|
|
151 static void
|
|
152 pn_container_load_thyself (PnUserObject *user_object, const xmlNodePtr node)
|
|
153 {
|
|
154 PnContainer *container;
|
|
155 xmlNodePtr actuators_node, actuator_node;
|
|
156 PnActuator *actuator;
|
|
157
|
|
158 g_return_if_fail (user_object != NULL);
|
|
159 g_return_if_fail (PN_IS_CONTAINER (user_object));
|
|
160 g_return_if_fail (node != NULL);
|
|
161
|
|
162 container = (PnContainer *) user_object;
|
|
163
|
|
164 /* FIXME: should these 'xmlChildrenNode' be 'xmlRootNode'? */
|
|
165
|
|
166 /* find the 'actuators' node */
|
|
167 for (actuators_node = node->xmlChildrenNode; actuators_node; actuators_node = actuators_node->next)
|
|
168 if (g_strcasecmp (actuators_node->name, "Actuators") == 0)
|
|
169 break;
|
|
170
|
|
171 /* load each of the actuators */
|
|
172 if (actuators_node)
|
|
173 {
|
|
174 for (actuator_node = actuators_node->xmlChildrenNode; actuator_node; actuator_node = actuator_node->next)
|
|
175 {
|
1529
|
176 if (!g_strcasecmp(actuator_node->name, "text"))
|
|
177 continue;
|
|
178
|
1507
|
179 actuator = pn_actuator_factory_new_actuator_from_xml (actuator_node);
|
|
180 if (actuator)
|
|
181 /* FIXME: Should this be pn_container_real_add_actuator? */
|
|
182 pn_container_add_actuator (container, actuator, PN_POSITION_TAIL);
|
|
183 else
|
|
184 pn_error ("unknown actuator ecountered in container \"%s\": %s",
|
|
185 node->name,
|
|
186 actuator_node->name);
|
|
187 }
|
|
188 }
|
|
189
|
|
190 if (PN_USER_OBJECT_CLASS (parent_class)->load_thyself)
|
|
191 PN_USER_OBJECT_CLASS (parent_class)->load_thyself (user_object, node);
|
|
192 }
|
|
193
|
|
194 static void
|
|
195 pn_container_prepare (PnContainer *container, PnImage *image)
|
|
196 {
|
|
197 guint i;
|
|
198
|
|
199 g_return_if_fail (container != NULL);
|
|
200 g_return_if_fail (PN_IS_CONTAINER (container));
|
|
201 g_return_if_fail (image != NULL);
|
|
202 g_return_if_fail (PN_IS_IMAGE (image));
|
|
203
|
|
204 for (i=0; i<container->actuators->len; i++)
|
|
205 pn_actuator_prepare (g_array_index (container->actuators, PnActuator *, i), image);
|
|
206 }
|
|
207
|
|
208 static gboolean
|
|
209 pn_container_real_add_actuator (PnContainer *container, PnActuator *actuator, gint position)
|
|
210 {
|
|
211 g_return_val_if_fail (container != NULL, FALSE);
|
|
212 g_return_val_if_fail (PN_IS_CONTAINER (container), FALSE);
|
|
213 g_return_val_if_fail (actuator != NULL, FALSE);
|
|
214 g_return_val_if_fail (PN_IS_ACTUATOR (actuator), FALSE);
|
|
215 g_return_val_if_fail (position >= PN_POSITION_TAIL, FALSE);
|
|
216
|
|
217 if (position == PN_POSITION_TAIL || position >= container->actuators->len)
|
|
218 position = container->actuators->len;
|
|
219
|
|
220 /* Just pass it on to the GArray insert function */
|
|
221 g_array_insert_val (container->actuators, position, actuator);
|
|
222
|
|
223 pn_object_ref (PN_OBJECT (actuator));
|
|
224 pn_object_sink (PN_OBJECT (actuator));
|
|
225
|
|
226 return TRUE;
|
|
227 }
|
|
228
|
|
229 /**
|
|
230 * pn_container_add_actuator
|
|
231 * @container: a #PnContainer
|
|
232 * @actuator: the #PnActuator to add
|
|
233 * @position: the position at which to add the actuator
|
|
234 *
|
|
235 * Adds @actuator to @container. @position is the zero-based index
|
|
236 * in the list of actuators that the newly added actuator should have,
|
|
237 * or it can be the value %PN_POSITION_HEAD or %PN_POSITION_TAIL.
|
|
238 *
|
|
239 * Returns: %TRUE on success; %FALSE on failure
|
|
240 */
|
|
241 gboolean
|
|
242 pn_container_add_actuator (PnContainer *container, PnActuator *actuator, gint position)
|
|
243 {
|
|
244 g_return_val_if_fail (container != NULL, FALSE);
|
|
245 g_return_val_if_fail (PN_IS_CONTAINER (container), FALSE);
|
|
246 g_return_val_if_fail (actuator != NULL, FALSE);
|
|
247 g_return_val_if_fail (PN_IS_ACTUATOR (actuator), FALSE);
|
|
248 g_return_val_if_fail (position >= PN_POSITION_TAIL, FALSE);
|
|
249
|
|
250 if (PN_CONTAINER_GET_CLASS (container)->add_actuator)
|
|
251 return PN_CONTAINER_GET_CLASS (container)->add_actuator (container, actuator, position);
|
|
252 else
|
|
253 return FALSE;
|
|
254 }
|
|
255
|
|
256 /**
|
|
257 * pn_container_remove_actuator
|
|
258 * @container: a #PnContainer
|
|
259 * @actuator: the #PnActuator to remove
|
|
260 *
|
|
261 * Removes the first occurence of @actuator in @container's list
|
|
262 * of contained actuators.
|
|
263 */
|
|
264 /* FIXME: what is the most convenient way to remove actuators? */
|
|
265 /* Note: Only removes the first one in the array */
|
|
266 void
|
|
267 pn_container_remove_actuator (PnContainer *container, PnActuator *actuator)
|
|
268 {
|
|
269 guint i;
|
|
270
|
|
271 g_return_if_fail (container != NULL);
|
|
272 g_return_if_fail (PN_IS_CONTAINER (container));
|
|
273 g_return_if_fail (actuator != NULL);
|
|
274 g_return_if_fail (PN_IS_ACTUATOR (actuator));
|
|
275
|
|
276 for (i=0; i<container->actuators->len; i++)
|
|
277 if (g_array_index (container->actuators, PnActuator *, i) == actuator)
|
|
278 {
|
|
279 g_array_remove_index (container->actuators, i);
|
|
280 pn_object_unref (PN_OBJECT (actuator));
|
|
281 return;
|
|
282 }
|
|
283 }
|
|
284
|
|
285 /**
|
|
286 * pn_container_remove_all_actuators
|
|
287 * @container: a #PnContainer
|
|
288 *
|
|
289 * Removes all actuators from @container's list of contained actuators.
|
|
290 */
|
|
291 void
|
|
292 pn_container_remove_all_actuators (PnContainer *container)
|
|
293 {
|
|
294 guint i;
|
|
295
|
|
296 g_return_if_fail (container != NULL);
|
|
297 g_return_if_fail (PN_IS_CONTAINER (container));
|
|
298
|
|
299 for (i=0; i<container->actuators->len; i++)
|
|
300 pn_object_unref (g_array_index (container->actuators, PnObject *, i));
|
|
301
|
|
302 g_array_set_size (container->actuators, 0);
|
|
303 }
|