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.
25 * SECTION:laugh-layout
26 * @short_description: DOM layout classes.
33 #include "laugh-layout.h"
38 #include <glib/gprintf.h>
39 #include <clutter/clutter-group.h>
40 #include <clutter/clutter-rectangle.h>
42 #define LAUGH_LAYOUT_GET_PRIVATE(obj) \
43 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LAUGH_TYPE_LAYOUT, LaughLayoutPrivate))
46 struct _LaughLayoutPrivate
48 ClutterActor
*region_actor
;
49 ClutterActor
*background_actor
;
50 ClutterColor bg_color
;
54 static gpointer laugh_layout_parent_class
= ((void *)0);
56 static void laugh_layout_finalize (GObject
*object
)
58 G_OBJECT_CLASS (laugh_layout_parent_class
)->finalize (object
);
61 static void laugh_layout_dispose (GObject
*object
)
63 LaughLayout
*layout
= LAUGH_LAYOUT(object
);
64 LaughLayoutPrivate
*priv
= layout
->priv
;
66 if (priv
->background_actor
)
67 clutter_actor_destroy (priv
->background_actor
);
68 if (priv
->region_actor
)
69 clutter_actor_destroy (priv
->region_actor
);
71 G_OBJECT_CLASS (laugh_layout_parent_class
)->dispose (object
);
74 void _lauch_layout_mime_type (LaughIO
*io
, const gchar
*mime
, gpointer d
)
76 g_printf ("lauch_layout_mime_type: %s\n", mime
);
77 if (strncmp (mime
, "image/", 6)) {
78 LaughNode
*node
= LAUGH_NODE (d
);
80 g_printerr ("region background not an image\n");
83 g_object_unref (G_OBJECT (io
));
85 laugh_node_base_emit_initialized (node
);
90 _lauch_layout_completed (LaughIO
*io
, gsize sz
, gpointer data
, gpointer d
)
92 LaughNode
*node
= LAUGH_NODE (d
);
94 g_printf ("_lauch_layout_completed: %u\n", sz
);
96 /* create Pixbuf and ClutterActor*/
100 g_object_unref (G_OBJECT (io
));
102 laugh_node_base_emit_initialized (node
);
105 static void _lauch_layout_actor_destroyed (ClutterActor
*actor
, gpointer data
)
107 LaughLayoutPrivate
*priv
= (LaughLayoutPrivate
*)data
;
109 if (actor
== priv
->background_actor
)
110 priv
->background_actor
= NULL
;
111 else if (actor
== priv
->region_actor
)
112 priv
->region_actor
= NULL
;
116 _laugh_layout_create_background (LaughLayoutPrivate
*priv
, guint w
, guint h
)
118 if (priv
->background_actor
)
119 clutter_actor_destroy (priv
->background_actor
);
121 if (priv
->bg_color
.alpha
> 0) {
122 priv
->background_actor
= clutter_rectangle_new ();
123 clutter_rectangle_set_color (
124 CLUTTER_RECTANGLE (priv
->background_actor
),
126 clutter_actor_set_size (priv
->background_actor
, w
, h
);
127 clutter_actor_set_position (priv
->background_actor
, 0, 0);
128 clutter_container_add_actor (CLUTTER_CONTAINER (priv
->region_actor
),
129 priv
->background_actor
);
130 clutter_actor_show (priv
->background_actor
);
131 g_signal_connect (G_OBJECT (priv
->background_actor
), "destroy",
132 (GCallback
) _lauch_layout_actor_destroyed
, (gpointer
) priv
);
134 priv
->background_actor
= NULL
;
138 static void _laugh_layout_init (LaughNode
*node
, LaughInitializer
*initializer
)
141 ClutterActor
*region_actor
;
142 ClutterContainer
*parent_actor
= initializer
->parent_region
;
143 guint pw
= initializer
->parent_width
;
144 guint ph
= initializer
->parent_height
;
146 if (node
->attributes
)
147 g_hash_table_foreach (node
->attributes
, laugh_attributes_set
, node
);
150 LaughLayout
*self
= LAUGH_LAYOUT (node
);
151 LaughLayoutPrivate
*priv
= self
->priv
;
154 region_actor
= clutter_group_new ();
155 priv
->region_actor
= region_actor
;
156 g_signal_connect (G_OBJECT (region_actor
), "destroy",
157 (GCallback
) _lauch_layout_actor_destroyed
, (gpointer
) priv
);
159 if (LaughTagIdLayout
!= node
->id
) {
160 laugh_size_setting_get(&self
->size_setting
, pw
, ph
, &x
, &y
, &w
, &h
);
161 initializer
->parent_width
= w
;
162 initializer
->parent_height
= h
;
163 clutter_actor_set_size (region_actor
, w
, h
);
164 clutter_actor_set_position (region_actor
, x
, y
);
165 clutter_actor_set_clip (region_actor
, 0, 0, w
, h
);
168 _laugh_layout_create_background (priv
, w
, h
);
171 case LaughTagIdRootLayout
:
172 if (node
->parent_node
&&
173 LaughTagIdLayout
== node
->parent_node
->id
) {
174 LaughLayout
*layout
= LAUGH_LAYOUT (node
->parent_node
);
175 ClutterActor
*layout_actor
= layout
->priv
->region_actor
;
176 float xscale
= pw
/ w
;
177 float yscale
= ph
/ h
;
178 clutter_actor_set_clip (layout_actor
, 0, 0, w
, h
);
179 if (xscale
> yscale
) {
180 clutter_actor_set_scale (layout_actor
, yscale
, yscale
);
182 clutter_actor_set_scale (layout_actor
, xscale
, xscale
);
186 case LaughTagIdRegion
:
190 clutter_container_add_actor (parent_actor
, region_actor
);
191 clutter_actor_show (region_actor
);
193 initializer
->parent_region
= CLUTTER_CONTAINER (region_actor
);
196 for (child
= node
->first_child
; child
; child
= child
->next_sibling
)
197 laugh_node_init (child
, initializer
);
199 initializer
->parent_region
= parent_actor
;
200 initializer
->parent_width
= pw
;
201 initializer
->parent_height
= ph
;
204 static void _laugh_layout_set_attribute (LaughNode
*node
,
205 LaughNodeAttributeId att
, const gchar
*val
, gpointer
*undo
)
207 const gchar
*value
= val
;
208 gboolean need_sizing
= FALSE
;
209 LaughLayout
*self
= (LaughLayout
*)node
;
211 laugh_node_base_set_attribute (node
, att
, val
, undo
);
212 g_printf ("_laugh_layout_set_attribute %s=%s\n", laugh_attribute_from_id (att
), value
);
215 val
= *(const gchar
**)undo
;
218 case LaughAttrIdLeft
:
219 laugh_size_set_string (&self
->size_setting
.left
, value
);
223 laugh_size_set_string (&self
->size_setting
.top
, value
);
226 case LaughAttrIdWidth
:
227 laugh_size_set_string (&self
->size_setting
.width
, value
);
230 case LaughAttrIdHeight
:
231 laugh_size_set_string (&self
->size_setting
.height
, value
);
234 case LaughAttrIdRight
:
235 laugh_size_set_string (&self
->size_setting
.right
, value
);
238 case LaughAttrIdBottom
:
239 laugh_size_set_string (&self
->size_setting
.bottom
, value
);
242 case LaughAttrIdBgColor
:
243 case LaughAttrIdBgColor1
:
244 /*TODO destory existing CluttorActor */
245 /*TODO create CluttorActor */
246 if (!clutter_color_parse (value
, &self
->priv
->bg_color
)) {
247 g_printerr ("parse color %s failed\n", value
);
248 self
->priv
->bg_color
.alpha
= 0;
251 case LaughAttrIdBgImage
:
252 /*TODO destory existing CluttorActor */
254 self
->priv
->io
= laugh_io_new (value
);
256 g_signal_connect (G_OBJECT (self
->priv
->io
), "mime-type",
257 (GCallback
) _lauch_layout_mime_type
, (gpointer
) node
);
258 g_signal_connect (G_OBJECT (self
->priv
->io
), "completed",
259 (GCallback
) _lauch_layout_completed
, (gpointer
) node
);
261 laugh_io_open (self
->priv
->io
);
264 /*TODO showBackground */
266 break; /* kill warning: enumeration value not handled in switch*/
268 /*TODO if (node->state > LaughStateInit && need_sizing)*/
271 static void laugh_layout_class_init (LaughLayoutClass
*klass
)
273 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
274 LaughNodeClass
*node_class
= (LaughNodeClass
*) klass
;
276 laugh_layout_parent_class
= g_type_class_peek_parent (klass
);
278 gobject_class
->finalize
= laugh_layout_finalize
;
279 gobject_class
->dispose
= laugh_layout_dispose
;
280 node_class
->init
= _laugh_layout_init
;
281 node_class
->set_attribute
= _laugh_layout_set_attribute
;
283 g_type_class_add_private (gobject_class
, sizeof (LaughLayoutPrivate
));
287 void laugh_layout_instance_init (GTypeInstance
*instance
, gpointer g_class
)
289 LaughLayout
*self
= (LaughLayout
*)instance
;
291 self
->priv
= LAUGH_LAYOUT_GET_PRIVATE (self
);
293 self
->priv
->bg_color
.alpha
= 0;
296 GType
laugh_layout_get_type (void)
298 static GType type
= 0;
300 static const GTypeInfo info
= {
301 sizeof (LaughLayoutClass
),
302 NULL
, /* base_init */
303 NULL
, /* base_finalize */
304 (GClassInitFunc
) laugh_layout_class_init
, /* class_init */
305 NULL
, /* class_finalize */
306 NULL
, /* class_data */
307 sizeof (LaughLayout
),
309 laugh_layout_instance_init
/* instance_init */
311 type
= g_type_register_static (LAUGH_TYPE_NODE
,
318 void laugh_size_set_string (LaughSize
*size
, const gchar
*value
)
324 p
= strchr (value
, '%');
326 size
->abs_size
= 0.0;
327 size
->perc_size
= strtod (value
, &ep
);
328 size
->is_set
= ep
!= value
;
330 size
->abs_size
= strtod (value
, &ep
);
331 size
->perc_size
= 0.0;
332 size
->is_set
= ep
!= value
;
335 size
->is_set
= FALSE
;
339 float laugh_size_get (LaughSize
*size
, float relative_to
)
341 return size
->abs_size
+ size
->perc_size
* relative_to
/ 100;
344 void laugh_size_setting_get (LaughSizeSetting
*sizes
, float pw
, float ph
,
345 float *x
, float *y
, float *w
, float *h
) {
346 if (sizes
->left
.is_set
) {
347 *x
= laugh_size_get (&sizes
->left
, pw
);
348 } else if (sizes
->width
.is_set
) {
349 if (sizes
->right
.is_set
)
351 laugh_size_get (&sizes
->width
, pw
) -
352 laugh_size_get (&sizes
->right
, pw
);
359 if (sizes
->top
.is_set
) {
360 *y
= laugh_size_get (&sizes
->top
, ph
);
361 } else if (sizes
->height
.is_set
) {
362 if (sizes
->bottom
.is_set
)
364 laugh_size_get (&sizes
->height
, ph
) -
365 laugh_size_get (&sizes
->bottom
, ph
);
372 if (sizes
->width
.is_set
)
373 *w
= laugh_size_get (&sizes
->width
, pw
);
374 else if (sizes
->right
.is_set
)
375 *w
= pw
- *x
-laugh_size_get (&sizes
->right
, pw
);
381 if (sizes
->height
.is_set
)
382 *h
= laugh_size_get (&sizes
->height
, ph
);
383 else if (sizes
->bottom
.is_set
)
384 *h
= ph
- *y
- laugh_size_get (&sizes
->bottom
, ph
);
391 LaughNode
*laugh_layout_new (LaughDocument
*doc
, LaughNodeTagId id
,
392 GHashTable
*attributes
)
394 LaughNode
*node
= LAUGH_NODE(g_object_new (LAUGH_TYPE_LAYOUT
, NULL
));
396 laugh_node_base_construct (doc
, node
, id
, attributes
);
401 #ifdef LAIGH_TEST_SIZES
402 /* gcc laugh-dom.c laugh-io.c laugh-layout.c -o sizestest `pkg-config --libs --cflags glib-2.0 gio-2.0 gthread-2.0` -lexpat -DLAIGH_TEST_SIZES */
403 void test_sizes (float pw
, float ph
,
404 const gchar
*left
, const gchar
*top
,
405 const gchar
*width
, const gchar
*height
,
406 const gchar
*right
, const gchar
*bottom
)
408 LaughSizeSetting sizes
;
410 memset (&sizes
, 0, sizeof (LaughSizeSetting
));
412 laugh_size_set_string (&sizes
.left
, left
);
414 laugh_size_set_string (&sizes
.top
, top
);
416 laugh_size_set_string (&sizes
.width
, width
);
418 laugh_size_set_string (&sizes
.height
, height
);
420 laugh_size_set_string (&sizes
.right
, right
);
422 laugh_size_set_string (&sizes
.bottom
, bottom
);
423 laugh_size_setting_get (&sizes
, pw
, ph
, &x
, &y
, &w
, &h
);
424 g_printf ("left %s top %s width %s height %s right %s bottom %s\n"
425 "\t(%.1fx%.1f) => [%.1f, %.1f %.1fx%.1f]\n",
427 left
, top
, width
, height
, right
, bottom
,
433 test_sizes (320, 240, "50", "30", "200", "180", NULL
, NULL
);
434 test_sizes (320, 240, "50", "30", NULL
, NULL
, "40", "20");
435 test_sizes (320, 240, "50", "30", "50%", "60%", NULL
, NULL
);
436 test_sizes (320, 240, "50", "30", NULL
, NULL
, "10%", "20%");