/* * GooCanvas. Copyright (C) 2005 Damon Chaplin. * Released under the GNU LGPL license. See COPYING for details. * * goocanvasgroup.c - group item. */ /** * SECTION:goocanvasgroup * @Title: GooCanvasGroup * @Short_Description: a group of items. * * #GooCanvasGroup represents a group of items. Groups can be nested to any * depth, to create a hierarchy of items. Items are ordered within each group, * with later items being displayed above earlier items. * * #GooCanvasGroup implements the #GooCanvasItem interface, so you can use the * #GooCanvasItem functions such as goo_canvas_item_raise() and * goo_canvas_item_rotate(), and the properties such as "visibility" and * "pointer-events". * * To create a #GooCanvasGroup use goo_canvas_group_new(). * * To get or set the properties of an existing #GooCanvasGroup, use * g_object_get() and g_object_set(). * * To respond to events such as mouse clicks on the group you must connect * to the signal handlers of the corresponding #GooCanvasGroupView objects. * (See goo_canvas_view_get_item_view() and #GooCanvasView::item-view-created.) */ #include #include #include #include "goocanvasprivate.h" #include "goocanvasgroup.h" #include "goocanvasgroupview.h" #include "goocanvasmarshal.h" enum { PROP_0, PROP_TRANSFORM, PROP_VISIBILITY, PROP_VISIBILITY_THRESHOLD, PROP_POINTER_EVENTS, PROP_TITLE, PROP_DESCRIPTION }; static void goo_canvas_group_finalize (GObject *object); static void canvas_item_interface_init (GooCanvasItemIface *iface); static void goo_canvas_group_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void goo_canvas_group_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE (GooCanvasGroup, goo_canvas_group, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM, canvas_item_interface_init)) static void goo_canvas_group_class_init (GooCanvasGroupClass *klass) { GObjectClass *gobject_class = (GObjectClass*) klass; gobject_class->finalize = goo_canvas_group_finalize; gobject_class->get_property = goo_canvas_group_get_property; gobject_class->set_property = goo_canvas_group_set_property; g_object_class_override_property (gobject_class, PROP_VISIBILITY, "visibility"); g_object_class_override_property (gobject_class, PROP_VISIBILITY_THRESHOLD, "visibility-threshold"); g_object_class_override_property (gobject_class, PROP_TRANSFORM, "transform"); g_object_class_override_property (gobject_class, PROP_POINTER_EVENTS, "pointer-events"); g_object_class_override_property (gobject_class, PROP_TITLE, "title"); g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description"); } static void goo_canvas_group_init (GooCanvasGroup *group) { group->items = g_ptr_array_sized_new (8); cairo_matrix_init_identity (&group->transform); group->pointer_events = GOO_CANVAS_EVENTS_VISIBLE_PAINTED; } /** * goo_canvas_group_new: * @parent: the parent item, or %NULL. If a parent is specified, it will assume * ownership of the item, and the item will automatically be freed when it is * removed from the parent. Otherwise call g_object_unref() to free it. * * Creates a new group item. * * Return value: a new group item. **/ GooCanvasItem* goo_canvas_group_new (GooCanvasItem *parent) { GooCanvasItem *item; GooCanvasGroup *group; item = g_object_new (GOO_TYPE_CANVAS_GROUP, NULL); group = GOO_CANVAS_GROUP (item); if (parent) { goo_canvas_item_add_child (parent, item, -1); g_object_unref (item); group->model = goo_canvas_item_get_model (parent); } return item; } /** * goo_canvas_group_set_model: * @group: a #GooCanvasGroup. * @model: the #GooCanvasModel of the group. * * Sets the model of the group. * * This is only intended to be used by implementors of #GooCanvasModel, to set * the model of the root group. **/ void goo_canvas_group_set_model (GooCanvasGroup *group, GooCanvasModel *model) { /* Note that we don't ref the model, to avoid reference cycles. */ group->model = model; } static void goo_canvas_group_finalize (GObject *object) { GooCanvasGroup *group = (GooCanvasGroup*) object; gint i; /* Unref all the items in the group. */ for (i = 0; i < group->items->len; i++) { GooCanvasItem *item = group->items->pdata[i]; g_object_unref (item); } g_ptr_array_free (group->items, TRUE); G_OBJECT_CLASS (goo_canvas_group_parent_class)->finalize (object); } static void goo_canvas_group_add_child (GooCanvasItem *group_item, GooCanvasItem *item, gint position) { GooCanvasGroup *group = GOO_CANVAS_GROUP (group_item); g_object_ref (item); if (position >= 0) { goo_canvas_util_ptr_array_insert (group->items, item, position); } else { position = group->items->len; g_ptr_array_add (group->items, item); } goo_canvas_item_set_parent (item, group_item); g_signal_emit_by_name (group, "child-added", position); } static void goo_canvas_group_move_child (GooCanvasItem *group_item, gint old_position, gint new_position) { GooCanvasGroup *group = GOO_CANVAS_GROUP (group_item); goo_canvas_util_ptr_array_move (group->items, old_position, new_position); g_signal_emit_by_name (group, "child-moved", old_position, new_position); } static void goo_canvas_group_remove_child (GooCanvasItem *group_item, gint child_num) { GooCanvasGroup *group = GOO_CANVAS_GROUP (group_item); GooCanvasItem *item; item = group->items->pdata[child_num]; goo_canvas_item_set_parent (item, NULL); g_object_unref (item); g_ptr_array_remove_index (group->items, child_num); g_signal_emit_by_name (group, "child-removed", child_num); } static gint goo_canvas_group_get_n_children (GooCanvasItem *group_item) { GooCanvasGroup *group = GOO_CANVAS_GROUP (group_item); return group->items->len; } static GooCanvasItem* goo_canvas_group_get_child (GooCanvasItem *group_item, gint child_num) { GooCanvasGroup *group = GOO_CANVAS_GROUP (group_item); return group->items->pdata[child_num]; } static GooCanvasModel* goo_canvas_group_get_model (GooCanvasItem *item) { GooCanvasGroup *group = GOO_CANVAS_GROUP (item); if (!group->model && group->parent) group->model = goo_canvas_item_get_model (group->parent); return group->model; } static GooCanvasItem* goo_canvas_group_get_parent (GooCanvasItem *item) { return GOO_CANVAS_GROUP (item)->parent; } static void goo_canvas_group_set_parent (GooCanvasItem *item, GooCanvasItem *parent) { GOO_CANVAS_GROUP (item)->parent = parent; if (!parent) GOO_CANVAS_GROUP (item)->model = NULL; } static cairo_matrix_t* goo_canvas_group_get_transform (GooCanvasItem *item) { return &GOO_CANVAS_GROUP (item)->transform; } static void goo_canvas_group_set_transform (GooCanvasItem *item, cairo_matrix_t *transform) { GooCanvasGroup *group = GOO_CANVAS_GROUP (item); if (transform) group->transform = *transform; else cairo_matrix_init_identity (&group->transform); g_signal_emit_by_name (group, "changed", TRUE); } static GooCanvasItemView* goo_canvas_group_create_view (GooCanvasItem *group_item, GooCanvasView *canvas_view, GooCanvasItemView *parent_view) { return goo_canvas_group_view_new (canvas_view, parent_view, group_item); } static void canvas_item_interface_init (GooCanvasItemIface *iface) { iface->add_child = goo_canvas_group_add_child; iface->move_child = goo_canvas_group_move_child; iface->remove_child = goo_canvas_group_remove_child; iface->get_n_children = goo_canvas_group_get_n_children; iface->get_child = goo_canvas_group_get_child; iface->get_model = goo_canvas_group_get_model; iface->get_parent = goo_canvas_group_get_parent; iface->set_parent = goo_canvas_group_set_parent; iface->get_transform = goo_canvas_group_get_transform; iface->set_transform = goo_canvas_group_set_transform; iface->create_view = goo_canvas_group_create_view; } static void goo_canvas_group_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GooCanvasGroup *group = (GooCanvasGroup*) object; switch (prop_id) { case PROP_TRANSFORM: g_value_set_boxed (value, &group->transform); break; case PROP_VISIBILITY: g_value_set_enum (value, group->visibility); break; case PROP_VISIBILITY_THRESHOLD: g_value_set_double (value, group->visibility_threshold); break; case PROP_POINTER_EVENTS: g_value_set_flags (value, group->pointer_events); break; case PROP_TITLE: g_value_set_string (value, group->title); break; case PROP_DESCRIPTION: g_value_set_string (value, group->description); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void goo_canvas_group_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GooCanvasGroup *group = (GooCanvasGroup*) object; cairo_matrix_t *transform; switch (prop_id) { case PROP_TRANSFORM: transform = g_value_get_boxed (value); group->transform = *transform; break; case PROP_VISIBILITY: group->visibility = g_value_get_enum (value); break; case PROP_VISIBILITY_THRESHOLD: group->visibility_threshold = g_value_get_double (value); break; case PROP_POINTER_EVENTS: group->pointer_events = g_value_get_flags (value); break; case PROP_TITLE: g_free (group->title); group->title = g_value_dup_string (value); break; case PROP_DESCRIPTION: g_free (group->description); group->description = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } g_signal_emit_by_name (group, "changed", TRUE); }