Make sure to get the timing tree in sane state after an internal jump
[laugh.git] / src / laugh-animate.c
blob05cc824b59b708d2b6aaadea4f3420dbc4abaa1b
1 /*
2 * Laugh.
4 * An glib SMIL library.
6 * Authored By Koos Vriezen <koos.vriezen@gmail.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 #include <string.h>
25 #include <glib/gprintf.h>
27 #include "laugh-animate.h"
29 #define LAUGH_ANIMATE_GET_PRIVATE(obj) \
30 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LAUGH_TYPE_ANIMATE, LaughAnimatePrivate))
33 struct _LaughAnimatePrivate
35 LaughRoleTiming *timing_role;
36 const char *changed_attribute;
37 LaughNode *target;
38 LaughNodeAttributeId attribute;
41 static gpointer laugh_animate_parent_class = ((void *)0);
43 static void laugh_animate_finalize (GObject *object)
45 G_OBJECT_CLASS (laugh_animate_parent_class)->finalize (object);
48 static void laugh_animate_dispose (GObject *object)
50 LaughAnimate *self = LAUGH_ANIMATE(object);
51 LaughRoleTiming *role = self->priv->timing_role;
53 G_OBJECT_CLASS (laugh_animate_parent_class)->dispose (object);
55 laugh_timing_role_delete (role);
58 static void
59 _laugh_animate_init (LaughNode *node, LaughInitializer *initializer)
61 LaughAnimate *self = (LaughAnimate *) node;
62 LaughNode *child;
63 LaughRoleTiming *parent_segment = initializer->parent_segment;
65 if (node->attributes)
66 g_hash_table_foreach (node->attributes, laugh_attributes_set, node);
68 laugh_timing_role_child_add(initializer->parent_segment, self->priv->timing_role);
70 initializer->parent_segment = self->priv->timing_role;
72 for (child = node->first_child; child; child = child->next_sibling)
73 laugh_node_init (child, initializer);
75 initializer->parent_segment = parent_segment;
78 static void _laugh_animate_set_attribute (LaughNode *node,
79 LaughNodeAttributeId att, const gchar *value, gpointer *undo)
81 const gchar *val = value;
82 LaughAnimate *self = (LaughAnimate *)node;
84 laugh_node_base_set_attribute (node, att, val, undo);
85 g_printf ("_laugh_animate_set_attribute %s=%s\n", laugh_attribute_from_id (att), val);
87 if (!value && undo)
88 val = *(const gchar **)undo;
90 laugh_timing_setting_set_attribute (self->priv->timing_role, att, val);
93 static void _laugh_animate_target_destroyed (gpointer data, GObject *obj)
95 LaughAnimatePrivate *priv = (LaughAnimatePrivate *) data;
96 (void) obj;
98 priv->target = NULL;
101 static void _laugh_animate_start (LaughNode *node)
103 LaughAnimate *self = (LaughAnimate *)node;
104 LaughAnimatePrivate *priv = self->priv;
105 const gchar *elm = laugh_node_get_attribute(node, LaughAttrIdTargetElement);
106 const gchar *to = laugh_node_get_attribute (node, LaughAttrIdTo);
108 if (!elm)
109 elm = laugh_node_get_attribute (node, LaughAttrIdTarget);
110 if (!elm) {
111 g_printerr ("start '%s' no target\n", laugh_tag_from_id (node->id));
112 return;
115 priv->target = laugh_document_get_element_by_id (node->document,
116 laugh_document_id_from_string (node->document, elm));
117 if (!priv->target) {
118 g_printerr ("start '%s' element \"%s\" not found\n",
119 laugh_tag_from_id (node->id), elm);
120 return;
122 g_object_weak_ref ((GObject *) priv->target,
123 _laugh_animate_target_destroyed, priv);
125 switch (node->id) {
126 case LaughTagIdSet: {
127 const gchar *att = laugh_node_get_attribute (node, LaughAttrIdAttr);
129 if (!att)
130 att = laugh_node_get_attribute (node, LaughAttrIdAttrName);
131 if (!att) {
132 g_printerr ("start 'set' no attribute name set");
133 break;
135 priv->attribute = laugh_attribute_from_string (att);
136 if (to) {
137 laugh_node_set_attribute (priv->target,
138 priv->attribute, to, &priv->changed_attribute);
139 } /*TODO what to do if 'to' not specified*/
140 break;
142 default:
143 break;
147 static void _laugh_animate_stop (LaughNode *node)
149 LaughAnimate *self = (LaughAnimate *)node;
150 LaughAnimatePrivate *priv = self->priv;
152 if (!priv->target)
153 return;
155 g_object_weak_unref ((GObject *) priv->target,
156 _laugh_animate_target_destroyed, priv);
158 switch (node->id) {
159 case LaughTagIdSet:
160 if (priv->attribute)
161 laugh_node_set_attribute (priv->target,
162 priv->attribute, NULL, &priv->changed_attribute);
163 break;
164 default:
165 break;
168 priv->target = NULL;
171 static LaughRole *_laugh_animate_role (LaughNode *node, LaughRoleType type)
173 LaughAnimate *self = (LaughAnimate *) node;
175 switch (type) {
176 case LaughRoleTypeTiming:
177 return (LaughRole *) self->priv->timing_role;
178 default:
179 return NULL;
183 static void laugh_animate_class_init (LaughAnimateClass *klass)
185 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
186 LaughNodeClass *node_class = (LaughNodeClass *) klass;
188 laugh_animate_parent_class = g_type_class_peek_parent (klass);
190 gobject_class->finalize = laugh_animate_finalize;
191 gobject_class->dispose = laugh_animate_dispose;
192 node_class->init = _laugh_animate_init;
193 node_class->set_attribute = _laugh_animate_set_attribute;
194 node_class->start = _laugh_animate_start;
195 node_class->stop = _laugh_animate_stop;
196 node_class->role = _laugh_animate_role;
198 g_type_class_add_private (gobject_class, sizeof (LaughAnimatePrivate));
201 static
202 void laugh_animate_instance_init (GTypeInstance *instance, gpointer g_class)
204 LaughAnimate *self = (LaughAnimate *)instance;
206 self->priv = LAUGH_ANIMATE_GET_PRIVATE (self);
208 self->priv->timing_role = laugh_timing_role_new ((LaughNode *) self);
211 GType laugh_animate_get_type (void)
213 static GType type = 0;
214 if (type == 0) {
215 static const GTypeInfo info = {
216 sizeof (LaughAnimateClass),
217 NULL, /* base_init */
218 NULL, /* base_finalize */
219 (GClassInitFunc) laugh_animate_class_init, /* class_init */
220 NULL, /* class_finalize */
221 NULL, /* class_data */
222 sizeof (LaughAnimate),
223 0, /* n_preallocs */
224 laugh_animate_instance_init /* instance_init */
226 type = g_type_register_static (LAUGH_TYPE_NODE,
227 "LaughAnimateType",
228 &info, 0);
230 return type;
233 LaughNode *laugh_animate_new (LaughDocument *doc, LaughNodeTagId id,
234 GHashTable *attributes)
236 LaughNode *n = (LaughNode *)g_object_new(LAUGH_TYPE_ANIMATE, NULL);
238 laugh_node_base_construct (doc, n, id, attributes);
240 return n;