/* * GooCanvas. Copyright (C) 2005 Damon Chaplin. * Released under the GNU LGPL license. See COPYING for details. * * goocanvasitemview.c - interface for views of canvas items & groups. */ /** * SECTION:goocanvasitemview * @Title: GooCanvasItemView * @Short_Description: the interface for views of canvas items. * * GooCanvasItemView defines the interface that item views must implement, * and contains methods for operating on item views. */ #include #include #include #include "goocanvasitemview.h" #include "goocanvasview.h" #include "goocanvasmarshal.h" enum { /* Mouse events. */ ENTER_NOTIFY_EVENT, LEAVE_NOTIFY_EVENT, MOTION_NOTIFY_EVENT, BUTTON_PRESS_EVENT, BUTTON_RELEASE_EVENT, /* Keyboard events. */ FOCUS_IN_EVENT, FOCUS_OUT_EVENT, KEY_PRESS_EVENT, KEY_RELEASE_EVENT, GRAB_BROKEN_EVENT, LAST_SIGNAL }; static guint canvas_item_view_signals[LAST_SIGNAL] = { 0 }; static void goo_canvas_item_view_base_init (gpointer g_class); GType goo_canvas_item_view_get_type (void) { static GType canvas_item_view_type = 0; if (!canvas_item_view_type) { static const GTypeInfo canvas_item_view_info = { sizeof (GooCanvasItemViewIface), /* class_size */ goo_canvas_item_view_base_init, /* base_init */ NULL, /* base_finalize */ }; canvas_item_view_type = g_type_register_static (G_TYPE_INTERFACE, "GooCanvasItemView", &canvas_item_view_info, 0); g_type_interface_add_prerequisite (canvas_item_view_type, G_TYPE_OBJECT); } return canvas_item_view_type; } static void goo_canvas_item_view_base_init (gpointer g_iface) { static gboolean initialized = FALSE; if (!initialized) { GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); /* Mouse events. */ /** * GooCanvasItemView::enter-notify-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data, with coordinates translated to canvas * coordinates. * * Emitted when the mouse enters an item view. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[ENTER_NOTIFY_EVENT] = g_signal_new ("enter_notify_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, enter_notify_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GooCanvasItemView::leave-notify-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data, with coordinates translated to canvas * coordinates. * * Emitted when the mouse leaves an item view. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[LEAVE_NOTIFY_EVENT] = g_signal_new ("leave_notify_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, leave_notify_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GooCanvasItemView::motion-notify-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data, with coordinates translated to canvas * coordinates. * * Emitted when the mouse moves within an item view. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[MOTION_NOTIFY_EVENT] = g_signal_new ("motion_notify_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, motion_notify_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GooCanvasItemView::button-press-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data, with coordinates translated to canvas * coordinates. * * Emitted when a mouse button is pressed in an item view. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[BUTTON_PRESS_EVENT] = g_signal_new ("button_press_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, button_press_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GooCanvasItemView::button-release-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data, with coordinates translated to canvas * coordinates. * * Emitted when a mouse button is released in an item view. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[BUTTON_RELEASE_EVENT] = g_signal_new ("button_release_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, button_release_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /* Keyboard events. */ /** * GooCanvasItemView::focus-in-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data. * * Emitted when the item receives the keyboard focus. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[FOCUS_IN_EVENT] = g_signal_new ("focus_in_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, focus_in_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GooCanvasItemView::focus-out-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data. * * Emitted when the item loses the keyboard focus. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[FOCUS_OUT_EVENT] = g_signal_new ("focus_out_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, focus_out_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GooCanvasItemView::key-press-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data. * * Emitted when a key is pressed and the item view has the keyboard * focus. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[KEY_PRESS_EVENT] = g_signal_new ("key_press_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, key_press_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GooCanvasItemView::key-release-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data. * * Emitted when a key is released and the item view has the keyboard * focus. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[KEY_RELEASE_EVENT] = g_signal_new ("key_release_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, key_release_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GooCanvasItemView::grab-broken-event * @view: the item view that received the signal. * @target_view: the target of the event. * @event: the event data. * * Emitted when the item view's keyboard or pointer grab was lost * unexpectedly. * * Returns: %TRUE to stop the signal emission, or %FALSE to let it * continue. */ canvas_item_view_signals[GRAB_BROKEN_EVENT] = g_signal_new ("grab_broken_event", iface_type, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GooCanvasItemViewIface, grab_broken_event), NULL, NULL, goo_canvas_marshal_BOOLEAN__OBJECT_BOXED, G_TYPE_BOOLEAN, 2, GOO_TYPE_CANVAS_ITEM_VIEW, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); g_object_interface_install_property (g_iface, g_param_spec_boolean ("can-focus", _("Can Focus"), _("If the item can take the keyboard focus"), FALSE, G_PARAM_READWRITE)); initialized = TRUE; } } /** * goo_canvas_item_view_get_canvas_view: * @view: a #GooCanvasItemView. * * Returns the #GooCanvasView containing the given #GooCanvasItemView. * * Returns: the #GooCanvasView. **/ GooCanvasView* goo_canvas_item_view_get_canvas_view (GooCanvasItemView *view) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); if (iface->get_canvas_view) { return iface->get_canvas_view (view); } else { GooCanvasItemView *parent_view = iface->get_parent_view (view); if (parent_view) return goo_canvas_item_view_get_canvas_view (parent_view); return NULL; } } /** * goo_canvas_item_view_is_container: * @view: a #GooCanvasItemView. * * Returns %TRUE if the given #GooCanvasItemView is a container, * i.e. it may contain children; * * Returns: %TRUE if the item view is a container. **/ gboolean goo_canvas_item_view_is_container (GooCanvasItemView *view) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); /* Container items must implement get_n_children and normal items don't. */ return iface->get_n_children ? TRUE : FALSE; } /** * goo_canvas_item_view_get_transform: * @view: a #GooCanvasItemView. * * Gets the transformation matrix of an item view. * * Returns: the item view's transformation matrix. **/ cairo_matrix_t* goo_canvas_item_view_get_transform (GooCanvasItemView *view) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); /* If the item view implements get_transform() use that. */ return iface->get_transform ? iface->get_transform (view) : NULL; } /** * goo_canvas_item_view_set_transform: * @view: a #GooCanvasItemView. * @matrix: the new transformation matrix, or %NULL to reset the * transformation to the identity matrix. * * Sets the transformation matrix of an item view. **/ void goo_canvas_item_view_set_transform (GooCanvasItemView *view, cairo_matrix_t *matrix) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); if (iface->set_transform) iface->set_transform (view, matrix); else g_warning ("The %s class doesn't support the set_transform method", G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (view))); } /** * goo_canvas_item_view_get_combined_transform: * @view: a #GooCanvasItemView. * @result: the matrix to store the resulting transform in. * * Gets the total transformation matrix of an item view, which is a combination * of the item's transformation and the item view's transformation. * * Returns: TRUE if there is a transformation. **/ gboolean goo_canvas_item_view_get_combined_transform (GooCanvasItemView *view, cairo_matrix_t *result) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); cairo_matrix_t *view_transform, *item_transform; view_transform = iface->get_transform ? iface->get_transform (view) : NULL; item_transform = goo_canvas_item_get_transform (iface->get_item (view)); if (view_transform && item_transform) { /* The item transform is applied before the view transform. */ cairo_matrix_multiply (result, item_transform, view_transform); } else if (view_transform) { *result = *view_transform; } else if (item_transform) { *result = *item_transform; } else { cairo_matrix_init_identity (result); return FALSE; } return TRUE; } /** * goo_canvas_item_view_get_n_children: * @view: a #GooCanvasItemView. * * Returns the number of children of the given #GooCanvasItemView. * * Returns: the number of children of the #GooCanvasItemView, or 0 if the * view is not a container. **/ gint goo_canvas_item_view_get_n_children (GooCanvasItemView *view) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); /* If the item doesn't implement get_n_children it has no children. */ return iface->get_n_children ? iface->get_n_children (view) : 0; } /** * goo_canvas_item_view_get_child: * @view: a #GooCanvasItemView. * @child_num: the index of the child within the view, counting from 0. * * Returns the child view at the given index, or %NULL if the item has no * children or the index is out of range. * * Returns: the child at the given index. **/ GooCanvasItemView* goo_canvas_item_view_get_child (GooCanvasItemView *view, gint child_num) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); /* If the item doesn't implement get_child we assume it has no children. */ return iface->get_child ? iface->get_child (view, child_num) : NULL; } /** * goo_canvas_item_view_find_child: * @view: a #GooCanvasItemView. * @child: a child view. * * Gets the index of the child item view, counting from 0. * * Returns: the index of the given child item view. **/ gint goo_canvas_item_view_find_child (GooCanvasItemView *view, GooCanvasItemView *child) { GooCanvasItemView *item; int n_children, i; /* Find the current position of item and above. */ n_children = goo_canvas_item_view_get_n_children (view); for (i = 0; i < n_children; i++) { item = goo_canvas_item_view_get_child (view, i); if (child == item) return i; } return -1; } /** * goo_canvas_item_view_request_update: * @view: a #GooCanvasItemView. * * Requests that an update of the item is scheduled. It will be performed * as soon as the application is idle, and before the canvas is redrawn. **/ void goo_canvas_item_view_request_update (GooCanvasItemView *view) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); if (iface->request_update) return iface->request_update (view); else return goo_canvas_item_view_request_update (iface->get_parent_view (view)); } /** * goo_canvas_item_view_get_parent_view: * @view: a #GooCanvasItemView. * * Returns the parent view of the given #GooCanvasItemView. * * Returns: the parent view of the item. **/ GooCanvasItemView* goo_canvas_item_view_get_parent_view (GooCanvasItemView *view) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); return iface->get_parent_view (view); } /** * goo_canvas_item_view_set_parent_view: * @view: a #GooCanvasItemView. * @parent_view: the parent view. * * Sets the parent view of the given #GooCanvasItemView. **/ void goo_canvas_item_view_set_parent_view (GooCanvasItemView *view, GooCanvasItemView *parent_view) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); iface->set_parent_view (view, parent_view); } /** * goo_canvas_item_view_get_item: * @view: a #GooCanvasItemView. * * Returns the item the view is displaying. * * Returns: the #GooCanvasItem that the view is displaying. **/ GooCanvasItem* goo_canvas_item_view_get_item (GooCanvasItemView *view) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); return iface->get_item (view); } /** * goo_canvas_item_view_get_bounds: * @view: a #GooCanvasItemView. * @bounds: a #GooCanvasBounds to return the bounds in. * * Gets the bounds of the item view. * * Note that the bounds includes the entire fill and stroke extents of the * item view, whether they are painted or not. **/ void goo_canvas_item_view_get_bounds (GooCanvasItemView *view, GooCanvasBounds *bounds) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); iface->get_bounds (view, bounds); } /** * goo_canvas_item_view_get_item_view_at: * @view: a #GooCanvasItemView. * @x: the x coordinate of the point. * @y: the y coordinate of the point. * @cr: a cairo contect. * @is_pointer_event: %TRUE if the "pointer-events" properties of items should * be used to determine which parts of the item are tested. * @parent_is_visible: %TRUE if the parent item view is visible (which * implies that all ancestors are also visible). * * Gets the item view at the given point. * * Returns: the item view found at the given point, or %NULL if no item view * was found. **/ GooCanvasItemView* goo_canvas_item_view_get_item_view_at (GooCanvasItemView *view, gdouble x, gdouble y, cairo_t *cr, gboolean is_pointer_event, gboolean parent_is_visible) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); return iface->get_item_view_at (view, x, y, cr, is_pointer_event, parent_is_visible); } /** * goo_canvas_item_view_is_visible: * @view: a #GooCanvasItemView. * * Checks if the item is visible. * * This entails checking the item's own visibility setting, as well as those * of its ancestors. * * Note that this the item may be scrolled off the screen and so may not * be actually visible to the user. * * Returns: %TRUE if the item is visible. **/ gboolean goo_canvas_item_view_is_visible (GooCanvasItemView *view) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); /* If the item doesn't implement this method assume it is visible. */ return iface->is_visible ? iface->is_visible (view) : TRUE; } /** * goo_canvas_item_view_ensure_updated: * @view: a #GooCanvasItemView. * * Updates the canvas immediately, if an update is scheduled. * This ensures that all item bounds are up-to-date. **/ void goo_canvas_item_view_ensure_updated (GooCanvasItemView *view) { GooCanvasView *canvas_view; canvas_view = goo_canvas_item_view_get_canvas_view (view); if (canvas_view) goo_canvas_view_update (canvas_view); } /** * goo_canvas_item_view_update: * @view: a #GooCanvasItemView. * @entire_tree: if the entire subtree should be updated. * @cr: a cairo context. * @bounds: a #GooCanvasBounds to return the new bounds in. * * Updates the item view, if needed, and any children. **/ void goo_canvas_item_view_update (GooCanvasItemView *view, gboolean entire_tree, cairo_t *cr, GooCanvasBounds *bounds) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); iface->update (view, entire_tree, cr, bounds); } /** * goo_canvas_item_view_paint: * @view: a #GooCanvasItemView. * @cr: a cairo context. * @bounds: the bounds that need to be repainted. * @scale: the scale to use to determine whether an item should be painted. * See #GooCanvasItem:visibility-threshold. * * Paints the item view and all children if they intersect the given bounds. * * Note that the @scale argument may be different to the current scale in the * #GooCanvasView, e.g. when the canvas is being printed. **/ void goo_canvas_item_view_paint (GooCanvasItemView *view, cairo_t *cr, GooCanvasBounds *bounds, gdouble scale) { GooCanvasItemViewIface *iface = GOO_CANVAS_ITEM_VIEW_GET_IFACE (view); iface->paint (view, cr, bounds, scale); }