/* * GooCanvas. Copyright (C) 2005-6 Damon Chaplin. * Released under the GNU LGPL license. See COPYING for details. * * goocanvasitemviewsimple.c - abstract base class for simple item views. */ /** * SECTION:goocanvasitemviewsimple * @Title: GooCanvasItemViewSimple * @Short_Description: the base class for the standard canvas item views. * @Stability_Level: * @See_Also: * * #GooCanvasItemViewSimple is used as a base class for the standard canvas * item views. * * It provides default implementations for many of the #GooCanvasItemView * methods. */ #include #include #include "goocanvasitemviewsimple.h" #include "goocanvasview.h" #include "goocanvasatk.h" enum { PROP_0, PROP_CAN_FOCUS }; static void canvas_item_view_interface_init (GooCanvasItemViewIface *iface); static void goo_canvas_item_view_simple_finalize (GObject *object); static void goo_canvas_item_view_simple_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void goo_canvas_item_view_simple_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); G_DEFINE_TYPE_WITH_CODE (GooCanvasItemViewSimple, goo_canvas_item_view_simple, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM_VIEW, canvas_item_view_interface_init)) static void goo_canvas_item_view_simple_class_init (GooCanvasItemViewSimpleClass *klass) { GObjectClass *gobject_class = (GObjectClass*) klass; gobject_class->finalize = goo_canvas_item_view_simple_finalize; gobject_class->get_property = goo_canvas_item_view_simple_get_property; gobject_class->set_property = goo_canvas_item_view_simple_set_property; atk_registry_set_factory_type (atk_get_default_registry (), GOO_TYPE_CANVAS_ITEM_VIEW_SIMPLE, goo_canvas_item_view_accessible_factory_get_type ()); g_object_class_override_property (gobject_class, PROP_CAN_FOCUS, "can-focus"); } static void goo_canvas_item_view_simple_init (GooCanvasItemViewSimple *view) { GooCanvasBounds *bounds = &view->bounds; bounds->x1 = bounds->y1 = bounds->x2 = bounds->y2 = 0; view->flags = GOO_CANVAS_ITEM_VIEW_NEED_UPDATE; } static void goo_canvas_item_view_simple_finalize (GObject *object) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) object; /* Remove the view from the GooCanvasView hash table. */ goo_canvas_view_unregister_item_view (simple_view->canvas_view, (GooCanvasItem*) simple_view->item); /* Unref the item. */ g_object_unref (simple_view->item); simple_view->item = NULL; if (simple_view->transform) g_free (simple_view->transform); G_OBJECT_CLASS (goo_canvas_item_view_simple_parent_class)->finalize (object); } static void goo_canvas_item_view_simple_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GooCanvasItemViewSimple *view = (GooCanvasItemViewSimple*) object; switch (prop_id) { case PROP_CAN_FOCUS: g_value_set_boolean (value, view->flags & GOO_CANVAS_ITEM_VIEW_CAN_FOCUS); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void goo_canvas_item_view_simple_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GooCanvasItemViewSimple *view = (GooCanvasItemViewSimple*) object; switch (prop_id) { case PROP_CAN_FOCUS: if (g_value_get_boolean (value)) view->flags |= GOO_CANVAS_ITEM_VIEW_CAN_FOCUS; else view->flags &= ~GOO_CANVAS_ITEM_VIEW_CAN_FOCUS; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GooCanvasItemView* goo_canvas_item_view_simple_get_parent_view (GooCanvasItemView *view) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) view; return simple_view->parent_view; } static void goo_canvas_item_view_simple_set_parent_view (GooCanvasItemView *view, GooCanvasItemView *parent_view) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) view; simple_view->parent_view = parent_view; } static GooCanvasItem* goo_canvas_item_view_simple_get_item (GooCanvasItemView *view) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) view; return (GooCanvasItem*) simple_view->item; } static cairo_matrix_t* goo_canvas_item_view_simple_get_transform (GooCanvasItemView *view) { return GOO_CANVAS_ITEM_VIEW_SIMPLE (view)->transform; } static void goo_canvas_item_view_simple_request_update (GooCanvasItemViewSimple *simple_view, gboolean recompute_bounds) { if (recompute_bounds) { if (!(simple_view->flags & GOO_CANVAS_ITEM_VIEW_NEED_UPDATE)) { simple_view->flags |= GOO_CANVAS_ITEM_VIEW_NEED_UPDATE; goo_canvas_item_view_request_update (simple_view->parent_view); } } else { goo_canvas_view_request_redraw (simple_view->canvas_view, &simple_view->bounds); } } static void goo_canvas_item_view_simple_set_transform (GooCanvasItemView *view, cairo_matrix_t *transform) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) view; if (transform) { if (!simple_view->transform) simple_view->transform = g_new (cairo_matrix_t, 1); *simple_view->transform = *transform; } else { g_free (simple_view->transform); simple_view->transform = NULL; } goo_canvas_item_view_simple_request_update (simple_view, TRUE); } static void goo_canvas_item_view_simple_get_bounds (GooCanvasItemView *view, GooCanvasBounds *bounds) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) view; if (simple_view->flags & GOO_CANVAS_ITEM_VIEW_NEED_UPDATE) goo_canvas_item_view_ensure_updated (view); *bounds = simple_view->bounds; } static GooCanvasItemView* goo_canvas_item_view_simple_get_item_view_at (GooCanvasItemView *view, gdouble x, gdouble y, cairo_t *cr, gboolean is_pointer_event, gboolean parent_visible) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) view; GooCanvasItemSimple *simple = simple_view->item; GooCanvasItemView *found_view = NULL; double user_x = x, user_y = y; GooCanvasPointerEvents pointer_events = GOO_CANVAS_EVENTS_ALL; if (simple_view->flags & GOO_CANVAS_ITEM_VIEW_NEED_UPDATE) goo_canvas_item_view_ensure_updated (view); /* Check if the item should receive events. */ if (is_pointer_event) { if (simple->pointer_events == GOO_CANVAS_EVENTS_NONE) return NULL; if (simple->pointer_events & GOO_CANVAS_EVENTS_VISIBLE_MASK && (!parent_visible || simple->visibility == GOO_CANVAS_ITEM_INVISIBLE || (simple->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD && simple_view->canvas_view->scale < simple->visibility_threshold))) return NULL; pointer_events = simple->pointer_events; } cairo_save (cr); if (simple->transform) cairo_transform (cr, simple->transform); if (simple_view->transform) cairo_transform (cr, simple_view->transform); cairo_device_to_user (cr, &user_x, &user_y); /* Use the virtual method subclasses define to create the path. */ GOO_CANVAS_ITEM_VIEW_SIMPLE_GET_CLASS (view)->create_path (simple, cr); if (goo_canvas_item_simple_check_in_path (simple, user_x, user_y, cr, pointer_events)) found_view = view; cairo_restore (cr); return found_view; } static gboolean goo_canvas_item_view_simple_is_visible (GooCanvasItemView *view) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) view; GooCanvasItemSimple *simple = simple_view->item; if (simple->visibility == GOO_CANVAS_ITEM_INVISIBLE || (simple->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD && simple_view->canvas_view->scale < simple->visibility_threshold)) return FALSE; if (simple_view->parent_view) return goo_canvas_item_view_is_visible (simple_view->parent_view); return FALSE; } static void goo_canvas_item_view_simple_update (GooCanvasItemView *view, gboolean entire_tree, cairo_t *cr, GooCanvasBounds *bounds) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) view; GooCanvasItemSimple *simple = simple_view->item; if (entire_tree || (simple_view->flags & GOO_CANVAS_ITEM_VIEW_NEED_UPDATE)) { simple_view->flags &= ~GOO_CANVAS_ITEM_VIEW_NEED_UPDATE; cairo_save (cr); if (simple->transform) cairo_transform (cr, simple->transform); if (simple_view->transform) cairo_transform (cr, simple_view->transform); /* Request a redraw of the existing bounds. */ goo_canvas_view_request_redraw (simple_view->canvas_view, &simple_view->bounds); /* Use the virtual method subclasses define to create the path. */ GOO_CANVAS_ITEM_VIEW_SIMPLE_GET_CLASS (view)->create_path (simple, cr); /* Compute the new bounds. */ goo_canvas_item_simple_get_path_bounds (simple, cr, &simple_view->bounds); /* Request a redraw of the new bounds. */ goo_canvas_view_request_redraw (simple_view->canvas_view, &simple_view->bounds); cairo_restore (cr); } *bounds = simple_view->bounds; } static void goo_canvas_item_view_simple_paint (GooCanvasItemView *view, cairo_t *cr, GooCanvasBounds *bounds, gdouble scale) { GooCanvasItemViewSimple *simple_view = (GooCanvasItemViewSimple*) view; GooCanvasItemSimple *simple = simple_view->item; /* Check if the item should be visible. */ if (simple->visibility == GOO_CANVAS_ITEM_INVISIBLE || (simple->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD && scale < simple->visibility_threshold)) return; cairo_save (cr); if (simple->transform) cairo_transform (cr, simple->transform); if (simple_view->transform) cairo_transform (cr, simple_view->transform); /* Use the virtual method subclasses define to create the path. */ GOO_CANVAS_ITEM_VIEW_SIMPLE_GET_CLASS (view)->create_path (simple, cr); goo_canvas_item_simple_paint_path (simple, cr); cairo_restore (cr); } static void canvas_item_view_interface_init (GooCanvasItemViewIface *iface) { iface->get_parent_view = goo_canvas_item_view_simple_get_parent_view; iface->set_parent_view = goo_canvas_item_view_simple_set_parent_view; iface->get_item = goo_canvas_item_view_simple_get_item; iface->get_transform = goo_canvas_item_view_simple_get_transform; iface->set_transform = goo_canvas_item_view_simple_set_transform; iface->get_bounds = goo_canvas_item_view_simple_get_bounds; iface->get_item_view_at = goo_canvas_item_view_simple_get_item_view_at; iface->is_visible = goo_canvas_item_view_simple_is_visible; iface->update = goo_canvas_item_view_simple_update; iface->paint = goo_canvas_item_view_simple_paint; } /** * goo_canvas_item_view_simple_item_changed: * @item: the #GooCanvasItem that has changed. * @recompute_bounds: %TRUE if the bounds need to be recomputed. * @simple_view: the item view. * * This function is intended to be used by subclasses of * #GooCanvasItemViewSimple only. * * It is used as a callback for the "changed" signal of the canvas items. * It requests an update or redraw of the item view as appropriate. **/ void goo_canvas_item_view_simple_item_changed (GooCanvasItem *item, gboolean recompute_bounds, GooCanvasItemViewSimple *simple_view) { goo_canvas_item_view_simple_request_update (simple_view, recompute_bounds); } static void goo_canvas_item_view_simple_title_changed (GooCanvasItemSimple *simple, GParamSpec *pspec, GooCanvasItemViewSimple *simple_view) { AtkObject *accessible; accessible = atk_gobject_accessible_for_object (G_OBJECT (simple_view)); atk_object_set_name (accessible, simple->title); } static void goo_canvas_item_view_simple_description_changed (GooCanvasItemSimple *simple, GParamSpec *pspec, GooCanvasItemViewSimple *simple_view) { AtkObject *accessible; accessible = atk_gobject_accessible_for_object (G_OBJECT (simple_view)); atk_object_set_description (accessible, simple->description); } /** * goo_canvas_item_view_simple_setup_accessibility: * @simple_view: a #GooCanvasItemViewSimple. * * Sets the accessible name and description of the view based on the "title" * and "description" settings of the underlying canvas item. * * It also connects to the "notify::title" and "notify::description" signals * to update the name and description when they are changed. **/ void goo_canvas_item_view_simple_setup_accessibility (GooCanvasItemViewSimple *simple_view) { GooCanvasItemSimple *simple = simple_view->item; AtkObject *accessible; accessible = atk_gobject_accessible_for_object (G_OBJECT (simple_view)); if (simple->title) atk_object_set_name (accessible, simple->title); if (simple->description) atk_object_set_description (accessible, simple->description); g_signal_connect (simple, "notify::title", G_CALLBACK (goo_canvas_item_view_simple_title_changed), simple_view); g_signal_connect (simple, "notify::description", G_CALLBACK (goo_canvas_item_view_simple_description_changed), simple_view); }