2
* GooCanvas. Copyright (C) 2005 Damon Chaplin.
3
* Released under the GNU LGPL license. See COPYING for details.
5
* goocanvasgroup.c - group item.
9
* SECTION:goocanvasgroup
10
* @Title: GooCanvasGroup
11
* @Short_Description: a group of items.
13
* #GooCanvasGroup represents a group of items. Groups can be nested to
14
* any depth, to create a hierarchy of items. Items are ordered within each
15
* group, with later items being displayed above earlier items.
17
* #GooCanvasGroup is a subclass of #GooCanvasItemSimple and so
18
* inherits all of the style properties such as "stroke-color", "fill-color"
19
* and "line-width". Setting a style property on a #GooCanvasGroup will affect
20
* all children of the #GooCanvasGroup (unless the children override the
23
* #GooCanvasGroup implements the #GooCanvasItem interface, so you can use
24
* the #GooCanvasItem functions such as goo_canvas_item_raise() and
25
* goo_canvas_item_rotate(), and the properties such as "visibility" and
28
* If the #GooCanvasGroup:width and #GooCanvasGroup:height properties are
29
* set to positive values then the group is clipped to the given size.
31
* To create a #GooCanvasGroup use goo_canvas_group_new().
33
* To get or set the properties of an existing #GooCanvasGroup, use
34
* g_object_get() and g_object_set().
37
#include <glib/gi18n-lib.h>
39
#include "goocanvasprivate.h"
40
#include "goocanvasgroup.h"
41
#include "goocanvasitemmodel.h"
42
#include "goocanvas.h"
43
#include "goocanvasmarshal.h"
44
#include "goocanvasatk.h"
46
typedef struct _GooCanvasGroupPrivate GooCanvasGroupPrivate;
47
struct _GooCanvasGroupPrivate {
54
#define GOO_CANVAS_GROUP_GET_PRIVATE(group) \
55
(G_TYPE_INSTANCE_GET_PRIVATE ((group), GOO_TYPE_CANVAS_GROUP, GooCanvasGroupPrivate))
56
#define GOO_CANVAS_GROUP_MODEL_GET_PRIVATE(group) \
57
(G_TYPE_INSTANCE_GET_PRIVATE ((group), GOO_TYPE_CANVAS_GROUP_MODEL, GooCanvasGroupPrivate))
68
static void goo_canvas_group_dispose (GObject *object);
69
static void goo_canvas_group_finalize (GObject *object);
70
static void goo_canvas_group_get_property (GObject *object,
74
static void goo_canvas_group_set_property (GObject *object,
78
static void canvas_item_interface_init (GooCanvasItemIface *iface);
80
G_DEFINE_TYPE_WITH_CODE (GooCanvasGroup, goo_canvas_group,
81
GOO_TYPE_CANVAS_ITEM_SIMPLE,
82
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM,
83
canvas_item_interface_init))
86
goo_canvas_group_install_common_properties (GObjectClass *gobject_class)
88
g_object_class_install_property (gobject_class, PROP_X,
89
g_param_spec_double ("x",
91
_("The x coordinate of the group"),
96
g_object_class_install_property (gobject_class, PROP_Y,
97
g_param_spec_double ("y",
99
_("The y coordinate of the group"),
104
g_object_class_install_property (gobject_class, PROP_WIDTH,
105
g_param_spec_double ("width",
107
_("The width of the group, or -1 to use the default width"),
112
g_object_class_install_property (gobject_class, PROP_HEIGHT,
113
g_param_spec_double ("height",
115
_("The height of the group, or -1 to use the default height"),
122
goo_canvas_group_class_init (GooCanvasGroupClass *klass)
124
GObjectClass *gobject_class = (GObjectClass*) klass;
126
g_type_class_add_private (gobject_class, sizeof (GooCanvasGroupPrivate));
128
gobject_class->dispose = goo_canvas_group_dispose;
129
gobject_class->finalize = goo_canvas_group_finalize;
130
gobject_class->get_property = goo_canvas_group_get_property;
131
gobject_class->set_property = goo_canvas_group_set_property;
133
/* Register our accessible factory, but only if accessibility is enabled. */
134
if (!ATK_IS_NO_OP_OBJECT_FACTORY (atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET)))
136
atk_registry_set_factory_type (atk_get_default_registry (),
137
GOO_TYPE_CANVAS_GROUP,
138
goo_canvas_item_accessible_factory_get_type ());
141
goo_canvas_group_install_common_properties (gobject_class);
146
goo_canvas_group_init (GooCanvasGroup *group)
148
GooCanvasGroupPrivate* priv = GOO_CANVAS_GROUP_GET_PRIVATE (group);
150
group->items = g_ptr_array_sized_new (8);
160
* goo_canvas_group_new:
161
* @parent: the parent item, or %NULL. If a parent is specified, it will assume
162
* ownership of the item, and the item will automatically be freed when it is
163
* removed from the parent. Otherwise call g_object_unref() to free it.
164
* @...: optional pairs of property names and values, and a terminating %NULL.
166
* Creates a new group item.
168
* Return value: a new group item.
171
goo_canvas_group_new (GooCanvasItem *parent,
175
GooCanvasGroup *group;
177
const char *first_property;
179
item = g_object_new (GOO_TYPE_CANVAS_GROUP, NULL);
180
group = (GooCanvasGroup*) item;
182
va_start (var_args, parent);
183
first_property = va_arg (var_args, char*);
185
g_object_set_valist (G_OBJECT (item), first_property, var_args);
190
goo_canvas_item_add_child (parent, item, -1);
191
g_object_unref (item);
199
goo_canvas_group_dispose (GObject *object)
201
GooCanvasGroup *group = (GooCanvasGroup*) object;
204
/* Unref all the items in the group. */
205
for (i = 0; i < group->items->len; i++)
207
GooCanvasItem *item = group->items->pdata[i];
208
goo_canvas_item_set_parent (item, NULL);
209
g_object_unref (item);
212
g_ptr_array_set_size (group->items, 0);
214
G_OBJECT_CLASS (goo_canvas_group_parent_class)->dispose (object);
219
goo_canvas_group_finalize (GObject *object)
221
GooCanvasGroup *group = (GooCanvasGroup*) object;
223
g_ptr_array_free (group->items, TRUE);
225
G_OBJECT_CLASS (goo_canvas_group_parent_class)->finalize (object);
229
/* Gets the private data to use, from the model or from the item itself. */
230
static GooCanvasGroupPrivate*
231
goo_canvas_group_get_private (GooCanvasGroup *group)
233
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) group;
236
return GOO_CANVAS_GROUP_MODEL_GET_PRIVATE (simple->model);
238
return GOO_CANVAS_GROUP_GET_PRIVATE (group);
243
goo_canvas_group_get_common_property (GObject *object,
244
GooCanvasGroupPrivate *priv,
252
g_value_set_double (value, priv->x);
255
g_value_set_double (value, priv->y);
258
g_value_set_double (value, priv->width);
261
g_value_set_double (value, priv->height);
264
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
270
goo_canvas_group_get_property (GObject *object,
275
GooCanvasGroup *group = (GooCanvasGroup*) object;
276
GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
278
goo_canvas_group_get_common_property (object, priv, prop_id, value, pspec);
282
goo_canvas_group_set_common_property (GObject *object,
283
GooCanvasGroupPrivate *priv,
291
priv->x = g_value_get_double (value);
294
priv->y = g_value_get_double (value);
297
priv->width = g_value_get_double (value);
300
priv->height = g_value_get_double (value);
303
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
309
goo_canvas_group_set_property (GObject *object,
314
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
315
GooCanvasGroup *group = (GooCanvasGroup*) object;
316
GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
320
g_warning ("Can't set property of a canvas item with a model - set the model property instead");
324
goo_canvas_group_set_common_property (object, priv, prop_id, value, pspec);
325
goo_canvas_item_simple_changed (simple, TRUE);
329
goo_canvas_group_add_child (GooCanvasItem *item,
330
GooCanvasItem *child,
333
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
334
GooCanvasGroup *group = (GooCanvasGroup*) item;
335
AtkObject *atk_obj, *child_atk_obj;
337
g_object_ref (child);
341
goo_canvas_util_ptr_array_insert (group->items, child, position);
345
position = group->items->len;
346
g_ptr_array_add (group->items, child);
349
goo_canvas_item_set_parent (child, item);
350
goo_canvas_item_set_is_static (child, simple->simple_data->is_static);
352
/* Emit the "children_changed" ATK signal, if ATK is enabled. */
353
atk_obj = atk_gobject_accessible_for_object (G_OBJECT (item));
354
if (!ATK_IS_NO_OP_OBJECT (atk_obj))
356
child_atk_obj = atk_gobject_accessible_for_object (G_OBJECT (child));
357
g_signal_emit_by_name (atk_obj, "children_changed::add",
358
position, child_atk_obj);
361
goo_canvas_item_request_update (item);
366
goo_canvas_group_move_child (GooCanvasItem *item,
370
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
371
GooCanvasGroup *group = (GooCanvasGroup*) item;
372
GooCanvasItem *child;
373
GooCanvasBounds bounds;
375
/* Request a redraw of the item's bounds. */
376
child = group->items->pdata[old_position];
379
goo_canvas_item_get_bounds (child, &bounds);
380
goo_canvas_request_item_redraw (simple->canvas, &bounds,
381
simple->simple_data->is_static);
384
goo_canvas_util_ptr_array_move (group->items, old_position, new_position);
386
goo_canvas_item_request_update (item);
391
goo_canvas_group_remove_child (GooCanvasItem *item,
394
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
395
GooCanvasGroup *group = (GooCanvasGroup*) item;
396
GooCanvasItem *child;
397
GooCanvasBounds bounds;
398
AtkObject *atk_obj, *child_atk_obj;
400
g_return_if_fail (child_num < group->items->len);
402
/* Request a redraw of the item's bounds. */
403
child = group->items->pdata[child_num];
406
goo_canvas_item_get_bounds (child, &bounds);
407
goo_canvas_request_item_redraw (simple->canvas, &bounds,
408
simple->simple_data->is_static);
411
/* Emit the "children_changed" ATK signal, if ATK is enabled. */
412
atk_obj = atk_gobject_accessible_for_object (G_OBJECT (item));
413
if (!ATK_IS_NO_OP_OBJECT (atk_obj))
415
child_atk_obj = atk_gobject_accessible_for_object (G_OBJECT (child));
416
g_signal_emit_by_name (atk_obj, "children_changed::remove",
417
child_num, child_atk_obj);
420
g_ptr_array_remove_index (group->items, child_num);
422
goo_canvas_item_set_parent (child, NULL);
423
g_object_unref (child);
425
goo_canvas_item_request_update (item);
430
goo_canvas_group_get_n_children (GooCanvasItem *item)
432
GooCanvasGroup *group = (GooCanvasGroup*) item;
434
return group->items->len;
438
static GooCanvasItem*
439
goo_canvas_group_get_child (GooCanvasItem *item,
442
GooCanvasGroup *group = (GooCanvasGroup*) item;
444
if (child_num < group->items->len)
445
return group->items->pdata[child_num];
450
/* This is only used to set the canvas of the root group. It isn't normally
453
goo_canvas_group_set_canvas (GooCanvasItem *item,
456
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
457
GooCanvasGroup *group = (GooCanvasGroup*) item;
460
if (simple->canvas == canvas)
463
simple->canvas = canvas;
465
/* Recursively set the canvas of all child items. */
466
for (i = 0; i < group->items->len; i++)
468
GooCanvasItem *item = group->items->pdata[i];
469
goo_canvas_item_set_canvas (item, canvas);
475
goo_canvas_group_set_is_static (GooCanvasItem *item,
478
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
479
GooCanvasItemSimpleData *simple_data = simple->simple_data;
480
GooCanvasGroup *group = (GooCanvasGroup*) item;
483
if (simple_data->is_static == is_static)
486
simple_data->is_static = is_static;
488
/* Recursively set the canvas of all child items. */
489
for (i = 0; i < group->items->len; i++)
491
GooCanvasItem *item = group->items->pdata[i];
492
goo_canvas_item_set_is_static (item, is_static);
498
on_model_child_added (GooCanvasGroupModel *model,
500
GooCanvasGroup *group)
502
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) group;
503
GooCanvasItem *item = (GooCanvasItem*) group;
504
GooCanvasItemModel *child_model;
505
GooCanvasItem *child;
507
/* Create a canvas item for the model. */
508
child_model = goo_canvas_item_model_get_child ((GooCanvasItemModel*) model,
510
child = goo_canvas_create_item (simple->canvas, child_model);
511
goo_canvas_item_add_child (item, child, position);
512
g_object_unref (child);
517
on_model_child_moved (GooCanvasGroupModel *model,
520
GooCanvasGroup *group)
522
goo_canvas_item_move_child ((GooCanvasItem*) group, old_position,
528
on_model_child_removed (GooCanvasGroupModel *model,
530
GooCanvasGroup *group)
532
goo_canvas_item_remove_child ((GooCanvasItem*) group, child_num);
537
goo_canvas_group_set_model (GooCanvasItem *item,
538
GooCanvasItemModel *model)
540
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
541
GooCanvasGroup *group = (GooCanvasGroup*) item;
544
/* Do the default GooCanvasItemSimple code first. */
545
goo_canvas_item_simple_set_model (simple, model);
547
/* Now add our own handlers. */
548
g_signal_connect (model, "child-added",
549
G_CALLBACK (on_model_child_added), group);
550
g_signal_connect (model, "child-moved",
551
G_CALLBACK (on_model_child_moved), group);
552
g_signal_connect (model, "child-removed",
553
G_CALLBACK (on_model_child_removed), group);
555
/* Recursively create child items for any children. */
556
n_children = goo_canvas_item_model_get_n_children (model);
557
for (i = 0; i < n_children; i++)
558
on_model_child_added ((GooCanvasGroupModel*) simple->model, i, group);
563
goo_canvas_group_request_update (GooCanvasItem *item)
565
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
567
if (!simple->need_update)
569
simple->need_update = TRUE;
572
goo_canvas_item_request_update (simple->parent);
573
else if (simple->canvas)
574
goo_canvas_request_update (simple->canvas);
580
goo_canvas_group_update (GooCanvasItem *item,
581
gboolean entire_tree,
583
GooCanvasBounds *bounds)
585
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
586
GooCanvasGroup *group = (GooCanvasGroup*) item;
587
GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
588
GooCanvasBounds child_bounds;
589
gboolean initial_bounds = TRUE;
592
if (entire_tree || simple->need_update)
594
if (simple->need_entire_subtree_update)
597
simple->need_update = FALSE;
598
simple->need_entire_subtree_update = FALSE;
600
goo_canvas_item_simple_check_style (simple);
602
simple->bounds.x1 = simple->bounds.y1 = 0.0;
603
simple->bounds.x2 = simple->bounds.y2 = 0.0;
606
if (simple->simple_data->transform)
607
cairo_transform (cr, simple->simple_data->transform);
609
cairo_translate (cr, priv->x, priv->y);
611
for (i = 0; i < group->items->len; i++)
613
GooCanvasItem *child = group->items->pdata[i];
615
goo_canvas_item_update (child, entire_tree, cr, &child_bounds);
617
/* If the child has non-empty bounds, compute the union. */
618
if (child_bounds.x1 < child_bounds.x2
619
&& child_bounds.y1 < child_bounds.y2)
623
simple->bounds.x1 = child_bounds.x1;
624
simple->bounds.y1 = child_bounds.y1;
625
simple->bounds.x2 = child_bounds.x2;
626
simple->bounds.y2 = child_bounds.y2;
627
initial_bounds = FALSE;
631
simple->bounds.x1 = MIN (simple->bounds.x1, child_bounds.x1);
632
simple->bounds.y1 = MIN (simple->bounds.y1, child_bounds.y1);
633
simple->bounds.x2 = MAX (simple->bounds.x2, child_bounds.x2);
634
simple->bounds.y2 = MAX (simple->bounds.y2, child_bounds.y2);
642
*bounds = simple->bounds;
647
goo_canvas_group_get_items_at (GooCanvasItem *item,
651
gboolean is_pointer_event,
652
gboolean parent_visible,
655
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
656
GooCanvasItemSimpleData *simple_data = simple->simple_data;
657
GooCanvasGroup *group = (GooCanvasGroup*) item;
658
GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
659
gboolean visible = parent_visible;
662
if (simple->need_update)
663
goo_canvas_item_ensure_updated (item);
665
/* Skip the item if the point isn't in the item's bounds. */
666
if (simple->bounds.x1 > x || simple->bounds.x2 < x
667
|| simple->bounds.y1 > y || simple->bounds.y2 < y)
670
if (simple_data->visibility <= GOO_CANVAS_ITEM_INVISIBLE
671
|| (simple_data->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD
672
&& simple->canvas->scale < simple_data->visibility_threshold))
675
/* Check if the group should receive events. */
677
&& (simple_data->pointer_events == GOO_CANVAS_EVENTS_NONE
678
|| ((simple_data->pointer_events & GOO_CANVAS_EVENTS_VISIBLE_MASK)
683
if (simple_data->transform)
684
cairo_transform (cr, simple_data->transform);
686
cairo_translate (cr, priv->x, priv->y);
688
/* If the group has a clip path, check if the point is inside it. */
689
if (simple_data->clip_path_commands)
691
double user_x = x, user_y = y;
693
cairo_device_to_user (cr, &user_x, &user_y);
694
goo_canvas_create_path (simple_data->clip_path_commands, cr);
695
cairo_set_fill_rule (cr, simple_data->clip_fill_rule);
696
if (!cairo_in_fill (cr, user_x, user_y))
703
if (priv->width > 0.0 && priv->height > 0.0)
705
double user_x = x, user_y = y;
707
cairo_device_to_user (cr, &user_x, &user_y);
708
if (user_x < 0.0 || user_x >= priv->width
709
|| user_y < 0.0 || user_y >= priv->height)
716
/* Step up from the bottom of the children to the top, adding any items
717
found to the start of the list. */
718
for (i = 0; i < group->items->len; i++)
720
GooCanvasItem *child = group->items->pdata[i];
722
found_items = goo_canvas_item_get_items_at (child, x, y, cr,
723
is_pointer_event, visible,
733
goo_canvas_group_paint (GooCanvasItem *item,
735
const GooCanvasBounds *bounds,
738
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
739
GooCanvasItemSimpleData *simple_data = simple->simple_data;
740
GooCanvasGroup *group = (GooCanvasGroup*) item;
741
GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
744
/* Skip the item if the bounds don't intersect the expose rectangle. */
745
if (simple->bounds.x1 > bounds->x2 || simple->bounds.x2 < bounds->x1
746
|| simple->bounds.y1 > bounds->y2 || simple->bounds.y2 < bounds->y1)
749
/* Check if the item should be visible. */
750
if (simple_data->visibility <= GOO_CANVAS_ITEM_INVISIBLE
751
|| (simple_data->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD
752
&& simple->canvas->scale < simple_data->visibility_threshold))
755
/* Paint all the items in the group. */
757
if (simple_data->transform)
758
cairo_transform (cr, simple_data->transform);
760
cairo_translate (cr, priv->x, priv->y);
762
/* Clip with the group's clip path, if it is set. */
763
if (simple_data->clip_path_commands)
765
goo_canvas_create_path (simple_data->clip_path_commands, cr);
766
cairo_set_fill_rule (cr, simple_data->clip_fill_rule);
770
if (priv->width > 0.0 && priv->height > 0.0)
772
cairo_rectangle (cr, 0.0, 0.0, priv->width, priv->height);
776
for (i = 0; i < group->items->len; i++)
778
GooCanvasItem *child = group->items->pdata[i];
779
goo_canvas_item_paint (child, cr, bounds, scale);
786
canvas_item_interface_init (GooCanvasItemIface *iface)
788
iface->set_canvas = goo_canvas_group_set_canvas;
789
iface->get_n_children = goo_canvas_group_get_n_children;
790
iface->get_child = goo_canvas_group_get_child;
791
iface->request_update = goo_canvas_group_request_update;
793
iface->add_child = goo_canvas_group_add_child;
794
iface->move_child = goo_canvas_group_move_child;
795
iface->remove_child = goo_canvas_group_remove_child;
797
iface->get_items_at = goo_canvas_group_get_items_at;
798
iface->update = goo_canvas_group_update;
799
iface->paint = goo_canvas_group_paint;
801
iface->set_model = goo_canvas_group_set_model;
802
iface->set_is_static = goo_canvas_group_set_is_static;
807
* SECTION:goocanvasgroupmodel
808
* @Title: GooCanvasGroupModel
809
* @Short_Description: a model for a group of items.
811
* #GooCanvasGroupModel represents a group of items. Groups can be nested to
812
* any depth, to create a hierarchy of items. Items are ordered within each
813
* group, with later items being displayed above earlier items.
815
* #GooCanvasGroupModel is a subclass of #GooCanvasItemModelSimple and so
816
* inherits all of the style properties such as "stroke-color", "fill-color"
817
* and "line-width". Setting a style property on a #GooCanvasGroupModel will
818
* affect all children of the #GooCanvasGroupModel (unless the children
819
* override the property setting).
821
* #GooCanvasGroupModel implements the #GooCanvasItemModel interface, so you
822
* can use the #GooCanvasItemModel functions such as
823
* goo_canvas_item_model_raise() and goo_canvas_item_model_rotate(), and the
824
* properties such as "visibility" and "pointer-events".
826
* To create a #GooCanvasGroupModel use goo_canvas_group_model_new().
828
* To get or set the properties of an existing #GooCanvasGroupModel, use
829
* g_object_get() and g_object_set().
831
* To respond to events such as mouse clicks on the group you must connect
832
* to the signal handlers of the corresponding #GooCanvasGroup objects.
833
* (See goo_canvas_get_item() and #GooCanvas::item-created.)
835
static void item_model_interface_init (GooCanvasItemModelIface *iface);
836
static void goo_canvas_group_model_dispose (GObject *object);
837
static void goo_canvas_group_model_finalize (GObject *object);
838
static void goo_canvas_group_model_get_property (GObject *object,
842
static void goo_canvas_group_model_set_property (GObject *object,
847
G_DEFINE_TYPE_WITH_CODE (GooCanvasGroupModel, goo_canvas_group_model,
848
GOO_TYPE_CANVAS_ITEM_MODEL_SIMPLE,
849
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM_MODEL,
850
item_model_interface_init))
854
goo_canvas_group_model_class_init (GooCanvasGroupModelClass *klass)
856
GObjectClass *gobject_class = (GObjectClass*) klass;
857
g_type_class_add_private (gobject_class, sizeof (GooCanvasGroupPrivate));
859
gobject_class->dispose = goo_canvas_group_model_dispose;
860
gobject_class->finalize = goo_canvas_group_model_finalize;
861
gobject_class->get_property = goo_canvas_group_model_get_property;
862
gobject_class->set_property = goo_canvas_group_model_set_property;
864
goo_canvas_group_install_common_properties (gobject_class);
869
goo_canvas_group_model_init (GooCanvasGroupModel *gmodel)
871
GooCanvasGroupPrivate *priv = GOO_CANVAS_GROUP_MODEL_GET_PRIVATE (gmodel);
872
gmodel->children = g_ptr_array_sized_new (8);
882
* goo_canvas_group_model_new:
883
* @parent: the parent model, or %NULL. If a parent is specified, it will
884
* assume ownership of the item, and the item will automatically be freed when
885
* it is removed from the parent. Otherwise call g_object_unref() to free it.
886
* @...: optional pairs of property names and values, and a terminating %NULL.
888
* Creates a new group item.
890
* Return value: a new group model.
893
goo_canvas_group_model_new (GooCanvasItemModel *parent,
896
GooCanvasItemModel *model;
897
GooCanvasGroupModel *gmodel;
899
const char *first_property;
901
model = g_object_new (GOO_TYPE_CANVAS_GROUP_MODEL, NULL);
902
gmodel = (GooCanvasGroupModel*) model;
904
va_start (var_args, parent);
905
first_property = va_arg (var_args, char*);
907
g_object_set_valist (G_OBJECT (model), first_property, var_args);
912
goo_canvas_item_model_add_child (parent, model, -1);
913
g_object_unref (model);
921
goo_canvas_group_model_dispose (GObject *object)
923
GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) object;
926
/* Unref all the items in the group. */
927
for (i = 0; i < gmodel->children->len; i++)
929
GooCanvasItemModel *child = gmodel->children->pdata[i];
930
goo_canvas_item_model_set_parent (child, NULL);
931
g_object_unref (child);
934
g_ptr_array_set_size (gmodel->children, 0);
936
G_OBJECT_CLASS (goo_canvas_group_model_parent_class)->dispose (object);
941
goo_canvas_group_model_finalize (GObject *object)
943
GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) object;
945
g_ptr_array_free (gmodel->children, TRUE);
947
G_OBJECT_CLASS (goo_canvas_group_model_parent_class)->finalize (object);
950
static void goo_canvas_group_model_get_property (GObject *object,
955
GooCanvasGroupModel *model = (GooCanvasGroupModel*) object;
956
GooCanvasGroupPrivate *priv = GOO_CANVAS_GROUP_MODEL_GET_PRIVATE (model);
958
goo_canvas_group_get_common_property (object, priv, prop_id, value, pspec);
961
static void goo_canvas_group_model_set_property (GObject *object,
966
GooCanvasGroupModel *model = (GooCanvasGroupModel*) object;
967
GooCanvasGroupPrivate *priv = GOO_CANVAS_GROUP_MODEL_GET_PRIVATE (model);
969
goo_canvas_group_set_common_property (object, priv, prop_id, value, pspec);
970
g_signal_emit_by_name (model, "changed", TRUE);
973
extern void _goo_canvas_item_model_emit_child_added (GooCanvasItemModel *model,
977
goo_canvas_group_model_add_child (GooCanvasItemModel *model,
978
GooCanvasItemModel *child,
981
GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) model;
983
g_object_ref (child);
987
goo_canvas_util_ptr_array_insert (gmodel->children, child, position);
991
position = gmodel->children->len;
992
g_ptr_array_add (gmodel->children, child);
995
goo_canvas_item_model_set_parent (child, model);
997
_goo_canvas_item_model_emit_child_added (model, position);
1002
goo_canvas_group_model_move_child (GooCanvasItemModel *model,
1006
GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) model;
1008
goo_canvas_util_ptr_array_move (gmodel->children, old_position,
1011
g_signal_emit_by_name (gmodel, "child-moved", old_position, new_position);
1016
goo_canvas_group_model_remove_child (GooCanvasItemModel *model,
1019
GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) model;
1020
GooCanvasItemModel *child;
1022
child = gmodel->children->pdata[child_num];
1023
goo_canvas_item_model_set_parent (child, NULL);
1025
g_ptr_array_remove_index (gmodel->children, child_num);
1027
g_signal_emit_by_name (gmodel, "child-removed", child_num);
1029
g_object_unref (child);
1034
goo_canvas_group_model_get_n_children (GooCanvasItemModel *model)
1036
GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) model;
1038
return gmodel->children->len;
1042
static GooCanvasItemModel*
1043
goo_canvas_group_model_get_child (GooCanvasItemModel *model,
1046
GooCanvasGroupModel *gmodel = (GooCanvasGroupModel*) model;
1048
if (child_num < gmodel->children->len)
1049
return gmodel->children->pdata[child_num];
1054
static GooCanvasItem*
1055
goo_canvas_group_model_create_item (GooCanvasItemModel *model,
1058
GooCanvasItem *item;
1060
item = goo_canvas_group_new (NULL, NULL);
1061
/* Note that we set the canvas before the model, since we may need the
1062
canvas to create any child items. */
1063
goo_canvas_item_set_canvas (item, canvas);
1064
goo_canvas_item_set_model (item, model);
1071
item_model_interface_init (GooCanvasItemModelIface *iface)
1073
iface->add_child = goo_canvas_group_model_add_child;
1074
iface->move_child = goo_canvas_group_model_move_child;
1075
iface->remove_child = goo_canvas_group_model_remove_child;
1076
iface->get_n_children = goo_canvas_group_model_get_n_children;
1077
iface->get_child = goo_canvas_group_model_get_child;
1079
iface->create_item = goo_canvas_group_model_create_item;