/* dia-canvas-view-item.c * Copyright (C) 2000 Arjan Molenaar * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "dia-canvas-view.h" #include "dia-canvas-iter.h" #include "dia-canvas-groupable.h" #include "dia-canvas-editable.h" #include "dia-handle-layer.h" #include "dia-shape.h" #include "dia-shape-art.h" //#include "dia-shape-x.h" #include "dia-shape-view-info.h" #include #include #include #include #include #include "dia-canvas-i18n.h" //#define D(msg) G_STMT_START { g_print (G_STRLOC": "); g_print msg; g_print ("\n"); } G_STMT_END #define D(msg) /** * uta_dup: * @uta: * * Make a copy of @uta. * * Return value: A new ArtUta instance. **/ static ArtUta* uta_dup (ArtUta *uta) { ArtUta *new_uta = art_new (ArtUta, 1); *new_uta = *uta; new_uta->utiles = art_new (ArtUtaBbox, uta->width * uta->height); memcpy (new_uta->utiles, uta->utiles, uta->width * uta->height * sizeof(ArtUtaBbox)); return new_uta; } /* Memory allocation: * - In every DiaShape (DiaShapeViewInfo) * - handles */ /*#define DIA_CANVAS_VIEW_EVENTS GDK_ALL_EVENTS_MASK #define DIA_CANVAS_VIEW_EVENTS GDK_POINTER_MOTION_MASK \ | GDK_POINTER_MOTION_HINT_MASK \ | GDK_BUTTON_MOTION_MASK \ | GDK_BUTTON1_MOTION_MASK \ | GDK_BUTTON2_MOTION_MASK \ | GDK_BUTTON3_MOTION_MASK \ | GDK_BUTTON_PRESS_MASK \ | GDK_BUTTON_RELEASE_MASK \ | GDK_KEY_PRESS_MASK \ | GDK_KEY_RELEASE_MASK */ #define DIA_CANVAS_VIEW_EVENTS (GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK) #define DIA_CANVAS_VIEW_ITEM_USE_GRAB //#define BB_DEBUG #ifdef BB_DEBUG # include # include # include # include # include #endif enum { PROP_ITEM = 1, PROP_VISIBLE }; /* Invariants (constraints that should *always* be true). */ #define INVARIANT() \ g_assert (((DiaCanvasViewItem*)item)->item != NULL); \ g_assert (DIA_IS_CANVAS_ITEM (((DiaCanvasViewItem*)item)->item)); static void dia_canvas_view_item_init (DiaCanvasViewItem *canvas_item); static void dia_canvas_view_item_class_init (DiaCanvasViewItemClass *klass); static void dia_canvas_view_item_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void dia_canvas_view_item_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void dia_canvas_view_item_dispose (GObject *object); static void item_move_cb (DiaCanvasItem *item, gdouble dx, gdouble dy, gboolean interactive, DiaCanvasViewItem *vitem); static void item_notify_affine_cb (DiaCanvasViewItem *item); static void item_need_update_cb (DiaCanvasItem *item, GnomeCanvasItem *vitem); static void item_z_order_cb (DiaCanvasItem *item, gint positions, DiaCanvasViewItem *vitem); static void item_state_changed_cb (DiaCanvasItem *item, gint new_state, DiaCanvasViewItem *vitem); static gboolean item_has_state_cb (DiaCanvasItem *item, gint state, DiaCanvasViewItem *vitem); static void edit_item_start_editing_cb (DiaCanvasEditable *editable, DiaShapeText *text_shape, DiaCanvasViewItem *vitem); static void edit_item_editing_done_cb (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *new_text, DiaCanvasViewItem *vitem); static void group_item_add_cb (DiaCanvasItem *group, DiaCanvasItem *item, DiaCanvasViewItem *vitem); static void group_item_remove_cb (DiaCanvasItem *group, DiaCanvasItem *item, GnomeCanvasGroup *vgroup); /* GnomeCanvasItem signals */ static void dia_canvas_view_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags); static void dia_canvas_view_item_realize (GnomeCanvasItem *item); static void dia_canvas_view_item_unrealize (GnomeCanvasItem *item); static void dia_canvas_view_item_map (GnomeCanvasItem *item); static void dia_canvas_view_item_unmap (GnomeCanvasItem *item); static void dia_canvas_view_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height); static void dia_canvas_view_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf); static double dia_canvas_view_item_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item); static void dia_canvas_view_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2); static void empty_canvas_view_item (DiaCanvasViewItem *vitem); static GnomeCanvasGroupClass *parent_class = NULL; GtkType dia_canvas_view_item_get_type (void) { static GtkType canvas_item_type = 0; if (!canvas_item_type) { static const GtkTypeInfo canvas_item_info = { "DiaCanvasViewItem", sizeof (DiaCanvasViewItem), sizeof (DiaCanvasViewItemClass), (GtkClassInitFunc) dia_canvas_view_item_class_init, (GtkObjectInitFunc) dia_canvas_view_item_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; canvas_item_type = gtk_type_unique (gnome_canvas_group_get_type (), &canvas_item_info); } return canvas_item_type; } static void dia_canvas_view_item_class_init (DiaCanvasViewItemClass *klass) { GObjectClass *object_class; GtkObjectClass *widget_class; GnomeCanvasItemClass *item_class; object_class = (GObjectClass*) klass; widget_class = (GtkObjectClass*) klass; item_class = (GnomeCanvasItemClass*) klass; parent_class = g_type_class_peek_parent (klass); object_class->dispose = dia_canvas_view_item_dispose; object_class->get_property = dia_canvas_view_item_get_property; object_class->set_property = dia_canvas_view_item_set_property; g_object_class_install_property (object_class, PROP_ITEM, g_param_spec_object ("item", _("Item"), _("DiaCanvasItem that should be visualized"), DIA_TYPE_CANVAS_ITEM, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_VISIBLE, g_param_spec_boolean ("visible", _("Visible"), _("Whether the canvas item is visible"), TRUE, G_PARAM_READWRITE)); item_class->update = dia_canvas_view_item_update; item_class->realize = dia_canvas_view_item_realize; item_class->unrealize = dia_canvas_view_item_unrealize; item_class->map = dia_canvas_view_item_map; item_class->unmap = dia_canvas_view_item_unmap; item_class->draw = dia_canvas_view_item_draw; item_class->render = dia_canvas_view_item_render; item_class->point = dia_canvas_view_item_point; item_class->bounds = dia_canvas_view_item_bounds; } static void dia_canvas_view_item_init (DiaCanvasViewItem *item) { item->item = NULL; GTK_OBJECT_SET_FLAGS (item, GNOME_CANVAS_ITEM_VISIBLE | GNOME_CANVAS_ITEM_NEED_UPDATE | GNOME_CANVAS_ITEM_NEED_AFFINE | GNOME_CANVAS_ITEM_NEED_VIS | GNOME_CANVAS_ITEM_AFFINE_FULL | DIA_CANVAS_VIEW_ITEM_VISIBLE); item->redraw_area = NULL; item->n_handle_pos = 0; item->handle_pos = NULL; item->view_info = NULL; item->event_time = GDK_CURRENT_TIME; } static void dia_canvas_view_item_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { DiaCanvasViewItem *item = DIA_CANVAS_VIEW_ITEM (object); switch (property_id) { case PROP_ITEM: if (item->item) { g_error ("Setting an item while already an item is set!"); } else { GObject *citem = g_value_get_object (value); g_return_if_fail (citem != NULL); item->item = (DiaCanvasItem*) citem; g_signal_connect (citem, "move", G_CALLBACK (item_move_cb), item); g_signal_connect_swapped (citem, "notify::affine", G_CALLBACK (item_notify_affine_cb), item); g_signal_connect (citem, "need_update", G_CALLBACK (item_need_update_cb), item); g_signal_connect (citem, "z_order", G_CALLBACK (item_z_order_cb), item); g_signal_connect (citem, "state_changed", G_CALLBACK (item_state_changed_cb), item); g_signal_connect (citem, "has_state", G_CALLBACK (item_has_state_cb), item); /* Make sure the visibility is set correctly: */ if (DIA_CANVAS_ITEM_FLAGS (citem) & DIA_VISIBLE) GTK_OBJECT_SET_FLAGS (item, GNOME_CANVAS_ITEM_VISIBLE); else GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_VISIBLE); /* Connect some extra signals if DiaCanvasItem is * editable... */ //if (DIA_IS_CANVAS_EDITABLE (citem)) { //g_signal_connect_after (G_OBJECT (citem), // "start_editing", // G_CALLBACK (edit_item_start_editing_cb), // item); //g_signal_connect_after (G_OBJECT (citem), // "editing_done", // G_CALLBACK (edit_item_editing_done_cb), // item); //} /* If our item is a group, notify the CanvasViewItem * that a new object has to be added, if a new object * is added to the DiaCanvas. */ if (DIA_IS_CANVAS_GROUPABLE (citem)) { //g_message (G_STRLOC": Adding group signals"); g_signal_connect_after (G_OBJECT (citem), "add", G_CALLBACK (group_item_add_cb), item); g_signal_connect_after (G_OBJECT (citem), "remove", G_CALLBACK (group_item_remove_cb), item); } /* Point directly to the transformation! */ GNOME_CANVAS_ITEM (item)->xform = ((DiaCanvasItem*) citem)->affine; GTK_OBJECT_SET_FLAGS (GTK_OBJECT (item), GNOME_CANVAS_ITEM_AFFINE_FULL); gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (item)); } break; case PROP_VISIBLE: if (g_value_get_boolean (value)) { GTK_OBJECT_SET_FLAGS (object, DIA_CANVAS_VIEW_ITEM_VISIBLE); if (DIA_CANVAS_ITEM_VISIBLE (item->item)) GTK_OBJECT_SET_FLAGS (object, GNOME_CANVAS_ITEM_VISIBLE); gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (item)); } else { DiaCanvasView *view = DIA_CANVAS_VIEW (GNOME_CANVAS_ITEM(object)->canvas); GTK_OBJECT_UNSET_FLAGS (object, GNOME_CANVAS_ITEM_VISIBLE | DIA_CANVAS_VIEW_ITEM_VISIBLE); if (view) dia_canvas_view_unselect (view, item); gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (item)); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dia_canvas_view_item_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { DiaCanvasViewItem *item = DIA_CANVAS_VIEW_ITEM (object); switch (property_id) { case PROP_ITEM: g_value_set_object (value, (GObject*) DIA_CANVAS_VIEW_ITEM (item)->item); break; case PROP_VISIBLE: g_value_set_boolean (value, (GTK_OBJECT_FLAGS (object) & DIA_CANVAS_VIEW_ITEM_VISIBLE) != 0); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dia_canvas_view_item_dispose (GObject *object) { DiaCanvasViewItem *vitem = (DiaCanvasViewItem*) object; //g_message ("%s: begin (%x)", G_STRLOC, (int)object); if (vitem->item) { empty_canvas_view_item (vitem); } /* Reset the transformation, since it's pointing to the * transformation in DiaCanvasItem::affine! */ ((GnomeCanvasItem*) object)->xform = NULL; if (GNOME_CANVAS_ITEM (vitem)->canvas) { DiaCanvasView *canvas = DIA_CANVAS_VIEW (GNOME_CANVAS_ITEM (vitem)->canvas); canvas->selected_items = g_list_remove (canvas->selected_items, vitem); /* If the object is set as focused object, unset it. */ if (canvas->focus_item == vitem) canvas->focus_item = NULL; } /* Make sure that removing the item from its parent does not result * in a total freeing of the object. */ if (G_OBJECT_CLASS (parent_class)->dispose) G_OBJECT_CLASS (parent_class)->dispose (object); } static void item_move_cb (DiaCanvasItem *item, gdouble dx, gdouble dy, gboolean interactive, DiaCanvasViewItem *vitem) { DiaCanvasView *view = DIA_CANVAS_VIEW (((GnomeCanvasItem* )vitem)->canvas); if (interactive && (view == dia_canvas_view_get_active_view ())) { gdouble i2w[6]; /* First transform the dx, dy to world coordinates. */ dia_canvas_item_affine_i2w (DIA_CANVAS_ITEM (item->parent), i2w); i2w[4] = dx * i2w[0] + dy * i2w[2]; i2w[5] = dx * i2w[1] + dy * i2w[3]; dia_canvas_view_move (view, i2w[4], i2w[5], vitem); } GTK_OBJECT_SET_FLAGS (vitem, DIA_CANVAS_VIEW_ITEM_UPDATE_SHAPES); gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (vitem)); } static void item_notify_affine_cb (DiaCanvasViewItem *item) { GTK_OBJECT_SET_FLAGS (item, DIA_CANVAS_VIEW_ITEM_UPDATE_SHAPES); } /** * item_need_update_cb: * @item: * @vitem: * * This function is called for every CanvasViewItem. This way ViewItems are * notified that the need updating. **/ static void item_need_update_cb (DiaCanvasItem *item, GnomeCanvasItem *vitem) { g_assert (DIA_IS_CANVAS_ITEM (item)); g_assert (GNOME_IS_CANVAS_ITEM (vitem)); gnome_canvas_item_request_update (vitem); } static void item_z_order_cb (DiaCanvasItem *item, gint positions, DiaCanvasViewItem *vitem) { g_assert (DIA_IS_CANVAS_ITEM (item)); g_assert (GNOME_IS_CANVAS_ITEM (vitem)); if (positions < 0) gnome_canvas_item_lower (GNOME_CANVAS_ITEM (vitem), -positions); else if (positions > 0) gnome_canvas_item_raise (GNOME_CANVAS_ITEM (vitem), positions); /* Both items should be on the same position now. */ g_assert (dia_canvas_groupable_pos (DIA_CANVAS_GROUPABLE (item->parent), item) == g_list_index (GNOME_CANVAS_GROUP (GNOME_CANVAS_ITEM (vitem)->parent)->item_list, vitem)); } static void item_state_changed_cb (DiaCanvasItem *item, gint new_state, DiaCanvasViewItem *vitem) { DiaCanvasView *view; gboolean need_update = FALSE; g_assert (DIA_IS_CANVAS_ITEM (item)); g_assert (GNOME_IS_CANVAS_ITEM (vitem)); view = DIA_CANVAS_VIEW (GNOME_CANVAS_ITEM (vitem)->canvas); /* Make the view item visible only if the canvas item is visible * and the view item is allowed to be shown. */ if (DIA_CANVAS_ITEM_FLAGS (item) & DIA_VISIBLE && GTK_OBJECT_FLAGS(vitem) & DIA_CANVAS_VIEW_ITEM_VISIBLE) { if (!(GTK_OBJECT_FLAGS(vitem) & GNOME_CANVAS_ITEM_VISIBLE)) { GTK_OBJECT_SET_FLAGS (vitem, GNOME_CANVAS_ITEM_VISIBLE); need_update = TRUE; } } else { if (GTK_OBJECT_FLAGS(vitem) & GNOME_CANVAS_ITEM_VISIBLE) { GTK_OBJECT_UNSET_FLAGS (vitem, GNOME_CANVAS_ITEM_VISIBLE); dia_canvas_view_unselect (view, vitem); need_update = TRUE; } } if (view && view == dia_canvas_view_get_active_view () && new_state != DIA_UI_STATE_UNCHANGED && GTK_OBJECT_FLAGS(vitem) & GNOME_CANVAS_ITEM_VISIBLE) { if (new_state == DIA_UI_STATE_GRABBED) { #ifdef DIA_CANVAS_VIEW_ITEM_USE_GRAB gnome_canvas_item_grab (GNOME_CANVAS_ITEM (vitem), DIA_CANVAS_VIEW_EVENTS, NULL, vitem->event_time); #endif need_update = TRUE; } else { gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (vitem), vitem->event_time); need_update = TRUE; } if (new_state == DIA_UI_STATE_GRABBED || new_state == DIA_UI_STATE_FOCUSED) { /* Only select if the item is not yet focused: * a composite object might hold the focus. * (item is automatically selected) */ if (!dia_canvas_view_item_is_focused (vitem)) dia_canvas_view_focus (view, vitem); need_update = TRUE; } else if (new_state == DIA_UI_STATE_SELECTED) { /* In case we're dealing with a focused item, * just unfocus, else explicitly select it. */ if (dia_canvas_view_item_is_focused (vitem)) dia_canvas_view_focus (view, NULL); else dia_canvas_view_select (view, vitem); need_update = TRUE; } else { dia_canvas_view_unselect (view, vitem); need_update = TRUE; } } if (need_update) gnome_canvas_item_request_update ((GnomeCanvasItem*) vitem); } static gboolean item_has_state_cb (DiaCanvasItem *item, gint state, DiaCanvasViewItem *vitem) { static guint has_state_signal_id = 0; gboolean retval = TRUE; DiaCanvasView *view; g_assert (DIA_IS_CANVAS_ITEM (item)); g_assert (GNOME_IS_CANVAS_ITEM (vitem)); view = DIA_CANVAS_VIEW (GNOME_CANVAS_ITEM (vitem)->canvas); if (view != dia_canvas_view_get_active_view ()) return FALSE; /* g_message (G_STRLOC": have active view. request %s", (state & DIA_UI_STATE_GRABBED) ? "grabbed" : ((state & DIA_UI_STATE_FOCUSED) ? "focused" : ((state & DIA_UI_STATE_SELECTED) ? "selected" : "unknown"))); */ switch (state) { case DIA_UI_STATE_SELECTED: retval = DIA_CANVAS_VIEW_ITEM_SELECT(vitem); break; case DIA_UI_STATE_FOCUSED: retval = DIA_CANVAS_VIEW_ITEM_FOCUS(vitem); break; case DIA_UI_STATE_GRABBED: retval = DIA_CANVAS_VIEW_ITEM_GRAB(vitem); break; default: break; } /* We are the active view, so stop further emission: */ if (has_state_signal_id == 0) has_state_signal_id = g_signal_lookup ("has_state", DIA_TYPE_CANVAS_ITEM); g_signal_stop_emission (item, has_state_signal_id, 0); return retval ? TRUE : FALSE; } #if 0 /* * Signals for DiaCanvasEditables */ static void edit_item_start_editing_cb (DiaCanvasEditable *editable, DiaShapeText *text_shape, DiaCanvasViewItem *vitem) { DiaCanvasView *view = DIA_CANVAS_VIEW (GNOME_CANVAS_ITEM (vitem)->canvas); g_assert (vitem->item == (DiaCanvasItem*) editable); if (view == dia_canvas_view_get_active_view ()) dia_canvas_view_start_editing (view, vitem, text_shape); } static void edit_item_editing_done_cb (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *text, DiaCanvasViewItem *vitem) { } #endif /* * Signals for DiaCanvasGroupables */ static void group_item_add_cb (DiaCanvasItem *group, DiaCanvasItem *item, DiaCanvasViewItem *vitem) { /* So, `item' is added to `group' and now we should create a * new child to `vitem'. */ g_assert (DIA_IS_CANVAS_GROUPABLE (group)); g_assert (DIA_IS_CANVAS_ITEM (item)); g_assert (GNOME_IS_CANVAS_ITEM (vitem)); //g_message (G_STRLOC); if (item->parent == group) dia_canvas_view_item_add_items (GNOME_CANVAS_GROUP (vitem), item); } static void group_item_remove_cb (DiaCanvasItem *group, DiaCanvasItem *item, GnomeCanvasGroup *vgroup) { GList *l; DiaCanvasViewItem *vitem = NULL; g_assert (DIA_IS_CANVAS_GROUPABLE (group)); g_assert (DIA_IS_CANVAS_ITEM (item)); g_assert (GNOME_IS_CANVAS_ITEM (vgroup)); /* Do nothing if the canvas item has not been removed. */ if (item->parent == group) return; //g_message (G_STRLOC); for (l = vgroup->item_list; l != NULL; l = l->next) { if (DIA_CANVAS_VIEW_ITEM (l->data)->item == item) { vitem = l->data; break; } } g_assert (vitem != NULL); empty_canvas_view_item (vitem); gtk_object_destroy (GTK_OBJECT (vitem)); } /* static void remove_view_info_from_shapes (DiaCanvasViewItem *item) { DiaCanvasIter iter; if (dia_canvas_item_get_shape_iter (item->item, &iter)) do { DiaShape *shape = dia_canvas_item_shape_value (item->item, &iter); DiaShapeViewInfo *view_info; view_info = dia_shape_get_view_info (shape, item); if (view_info) dia_shape_view_info_remove (shape, view_info); } while (dia_canvas_item_shape_next (item->item, &iter)); } */ static void empty_canvas_view_item (DiaCanvasViewItem *item) { GSList *l; if (!item->item) return; // if (GNOME_CANVAS_ITEM (item)->canvas->grabbed_item == GNOME_CANVAS_ITEM (item)) // gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (item), // item->event_time); g_signal_handlers_disconnect_matched (item->item, G_SIGNAL_MATCH_DATA, 0, /* signal_id */ 0, /* detail */ NULL, /* closure */ NULL, /* func */ item /* data */); /* Remove view info from shapes! * Do this for normal state, for selected, focused and grabbed states. */ //remove_view_info_from_shapes (item); for (l = item->view_info; l != NULL; l = g_slist_next(l)) { //g_message (G_STRLOC": freeing view_info %p from item %p", l->data, item); dia_shape_view_info_free (item, l->data); } g_slist_free (item->view_info); item->view_info = NULL; /* Request a redraw for the removed area: */ if (item->redraw_area) { /* item->redraw_area is freed here: */ gnome_canvas_request_redraw_uta (GNOME_CANVAS_ITEM (item)->canvas, item->redraw_area); item->redraw_area = NULL; } /* Request a redraw of the regions where the handles were, only if the * handle layer is still in business. */ if (DIA_CANVAS_VIEW (GNOME_CANVAS_ITEM (item)->canvas)->handle_layer) dia_handle_layer_update_handles ((DiaHandleLayer*) DIA_CANVAS_VIEW (GNOME_CANVAS_ITEM (item)->canvas)->handle_layer, item); g_free (item->handle_pos); item->n_handle_pos = 0; item->item = NULL; } update_view_info (DiaCanvasViewItem *item) { GSList *old_view_info = item->view_info; GSList *new_view_info = NULL; GSList *l, *next; gboolean found; DiaShapeViewInfo *view_info; DiaCanvasIter iter; DiaCanvasItem *diaitem = item->item; if (dia_canvas_item_get_shape_iter (diaitem, &iter)) do { DiaShape *shape = dia_canvas_item_shape_value (diaitem, &iter); if (shape) { // for each item in the old list // check if the shape is the current shape // if so, unlink the element, // add it to the new list // if no entry was found, create a new one found = FALSE; for (l = old_view_info; l != NULL; l = next) { next = l->next; if (((DiaShapeViewInfo*) l->data)->shape == shape) { found = TRUE; old_view_info = g_slist_remove_link (old_view_info, l); new_view_info = g_slist_concat (new_view_info, l); break; } } if (!found) new_view_info = g_slist_append (new_view_info, dia_shape_view_info_new(shape)); } } while (dia_canvas_item_shape_next (diaitem, &iter)); // Remove all remaining entries in old_view_info for (l = old_view_info; l != NULL; l = l->next) { dia_shape_view_info_free (item, l->data); } if (old_view_info) g_slist_free (old_view_info); item->view_info = new_view_info; } /** * affine_clip: * @clip: * @affine: * @irect: OUT * * Generate a clip box in canvas coordinates (@irect), given a item * relative clip rectangle (@clip) and an affine matrix (@affine). * * Return value: TRUE if we have a clip path, FALSE if @clip contains no * clip path (left == right and top == bottom). **/ static inline gboolean affine_clip (ArtDRect *clip, gdouble *affine, ArtIRect *irect) { ArtDRect drect; art_drect_affine_transform (&drect, clip, affine); art_drect_to_irect (irect, &drect); return (art_irect_empty (irect) ? FALSE : TRUE); } /* GnomeCanvasItem signals */ /* clip_path is in canvas coordinates... */ static void dia_canvas_view_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip, int flags) { DiaCanvasItem *diaitem; DiaCanvasViewItem *cvitem; GnomeCanvas *canvas; DiaCanvasIter iter; gboolean free_clip = FALSE; ArtSVP *new_clip; D((" ")); INVARIANT (); canvas = item->canvas; if (!DIA_CANVAS_VIEW (canvas)->canvas) return; diaitem = DIA_CANVAS_VIEW_ITEM (item)->item; cvitem = DIA_CANVAS_VIEW_ITEM (item); g_assert (DIA_IS_CANVAS_ITEM (diaitem)); //g_message (G_STRLOC": BoundingBox (%x): %f, %f, %f, %f", //(int)diaitem, item->x1, item->y1, item->x2, item->y2); dia_handle_layer_update_handles ((DiaHandleLayer*) DIA_CANVAS_VIEW (canvas)->handle_layer, cvitem); //dia_canvas_view_item_update_item_state (cvitem); if (cvitem->redraw_area) { /* redraw_area is freed here: */ gnome_canvas_request_redraw_uta (item->canvas, cvitem->redraw_area); cvitem->redraw_area = NULL; } /* Update our view_info */ update_view_info (cvitem); if (dia_canvas_item_get_shape_iter (diaitem, &iter)) do { DiaShape *shape = dia_canvas_item_shape_value (diaitem, &iter); if (shape) { /* update render info */ new_clip = dia_shape_art_update (shape, DIA_CANVAS_VIEW_ITEM (item), affine, clip, flags); if (new_clip && clip && free_clip) { art_svp_free (clip); } if (new_clip) { clip = new_clip; free_clip = TRUE; } } } while (dia_canvas_item_shape_next (diaitem, &iter)); if (GNOME_CANVAS_ITEM_CLASS (parent_class)->update) GNOME_CANVAS_ITEM_CLASS (parent_class)->update (item, affine, clip, flags); GTK_OBJECT_UNSET_FLAGS (item, DIA_CANVAS_VIEW_ITEM_UPDATE_SHAPES); if (clip && free_clip) art_svp_free (clip); /* Update the bounding box, taking into account the possible * affine transformation. */ if (affine) { dia_canvas_item_bb_affine (diaitem, affine, &item->x1, &item->y1, &item->x2, &item->y2); } else { item->x1 = diaitem->bounds.left; item->y1 = diaitem->bounds.top; item->x2 = diaitem->bounds.right; item->y2 = diaitem->bounds.bottom; } } static void dia_canvas_view_item_realize (GnomeCanvasItem *item) { INVARIANT (); D((" ")); if (!item->canvas->aa) { DIA_CANVAS_VIEW_ITEM (item)->gc = gdk_gc_new (item->canvas->layout.bin_window); } if (GNOME_CANVAS_ITEM_CLASS (parent_class)->realize) (* GNOME_CANVAS_ITEM_CLASS (parent_class)->realize) (item); } static void dia_canvas_view_item_unrealize (GnomeCanvasItem *item) { //INVARIANT (); D((" ")); if (!item->canvas->aa) { gdk_gc_unref (DIA_CANVAS_VIEW_ITEM (item)->gc); DIA_CANVAS_VIEW_ITEM (item)->gc = NULL; } if (GNOME_CANVAS_ITEM_CLASS (parent_class)->unrealize) (* GNOME_CANVAS_ITEM_CLASS (parent_class)->unrealize) (item); } static void dia_canvas_view_item_map (GnomeCanvasItem *item) { INVARIANT (); if (GNOME_CANVAS_ITEM_CLASS (parent_class)->map) (* GNOME_CANVAS_ITEM_CLASS (parent_class)->map) (item); } static void dia_canvas_view_item_unmap (GnomeCanvasItem *item) { //INVARIANT (); if (GNOME_CANVAS_ITEM_CLASS (parent_class)->unmap) (* GNOME_CANVAS_ITEM_CLASS (parent_class)->unmap) (item); } static void dia_canvas_view_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) { #ifdef DIACANVAS_ENABLE_X DiaCanvasIter iter; DiaCanvasItem *diaitem; INVARIANT (); D((" ")); diaitem = DIA_CANVAS_VIEW_ITEM (item)->item; //dia_canvas_view_item_update_item_state ((DiaCanvasViewItem*) item); if (dia_canvas_item_get_shape_iter (diaitem, &iter)) do { DiaShape *shape = dia_canvas_item_shape_value (diaitem, &iter); DiaShapeVisibility vis = dia_shape_get_visibility (shape); if ((vis == DIA_SHAPE_VISIBLE) || ((vis == DIA_SHAPE_VISIBLE_IF_SELECTED) && DIA_CANVAS_VIEW_ITEM_SELECT (item)) || ((vis == DIA_SHAPE_VISIBLE_IF_FOCUSED) && DIA_CANVAS_VIEW_ITEM_FOCUS (item)) || ((vis == DIA_SHAPE_VISIBLE_IF_GRABBED) && DIA_CANVAS_VIEW_ITEM_GRAB (item))) dia_shape_x_render (shape, DIA_CANVAS_VIEW_ITEM (item), drawable, x, y, width, height); } while (dia_canvas_item_shape_next (diaitem, &iter)); //dia_canvas_view_item_reset_item_state (item); if (GNOME_CANVAS_ITEM_CLASS (parent_class)->draw) GNOME_CANVAS_ITEM_CLASS (parent_class)->draw (item, drawable, x, y, width, height); #endif } static void dia_canvas_view_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) { DiaCanvasIter iter; DiaCanvasItem *diaitem; DiaCanvasView *view; D((" ")); INVARIANT (); g_assert (DIA_IS_CANVAS_VIEW_ITEM (item)); diaitem = DIA_CANVAS_VIEW_ITEM (item)->item; view = DIA_CANVAS_VIEW (item->canvas); gnome_canvas_buf_ensure_buf (buf); if (!view->canvas) return; //dia_canvas_view_item_update_item_state ((DiaCanvasViewItem*) item); if (dia_canvas_item_get_shape_iter (diaitem, &iter)) do { DiaShape *shape = dia_canvas_item_shape_value (diaitem, &iter); DiaShapeVisibility vis = dia_shape_get_visibility (shape); if ((vis == DIA_SHAPE_VISIBLE) || ((vis == DIA_SHAPE_VISIBLE_IF_SELECTED) && DIA_CANVAS_VIEW_ITEM_SELECT (item)) || ((vis == DIA_SHAPE_VISIBLE_IF_FOCUSED) && DIA_CANVAS_VIEW_ITEM_FOCUS (item)) || ((vis == DIA_SHAPE_VISIBLE_IF_GRABBED) && DIA_CANVAS_VIEW_ITEM_GRAB (item))) { if (shape != (DiaShape*) view->edited_shape) dia_shape_art_render (shape, DIA_CANVAS_VIEW_ITEM (item), buf); } } while (dia_canvas_item_shape_next (diaitem, &iter)); //dia_canvas_view_item_reset_item_state (item); #ifdef BB_DEBUG G_STMT_START { ArtVpath path[6]; ArtSVP *svp; path[0].code = ART_MOVETO; path[0].x = item->x1; path[0].y = item->y1; path[1].code = ART_LINETO; path[1].x = item->x1; path[1].y = item->y2; path[2].code = ART_LINETO; path[2].x = item->x2; path[2].y = item->y2; path[3].code = ART_LINETO; path[3].x = item->x2; path[3].y = item->y1; path[4].code = ART_LINETO; path[4].x = item->x1; path[4].y = item->y1; path[5].code = ART_END; path[5].x = 0.0; path[5].y = 0.0; svp = art_svp_vpath_stroke (path, ART_PATH_STROKE_JOIN_MITER, ART_PATH_STROKE_CAP_BUTT, 1.0, 4, 0.25); gnome_canvas_render_svp (buf, svp, 0x88888888); art_free (svp); } G_STMT_END; #endif /* BB_DEBUG */ //if (GNOME_CANVAS_ITEM_CLASS (parent_class)->render) GNOME_CANVAS_ITEM_CLASS (parent_class)->render (item, buf); D(("done.")); } static double dia_canvas_view_item_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item) { double dist1 = G_MAXDOUBLE, dist2 = G_MAXDOUBLE; DiaCanvasItemClass *citem_class; GnomeCanvasItem *actual_item1 = NULL, *actual_item2 = NULL; INVARIANT (); citem_class = DIA_CANVAS_ITEM_GET_CLASS (DIA_CANVAS_VIEW_ITEM (item)->item); if (!citem_class->point) return G_MAXDOUBLE; if (DIA_CANVAS_ITEM_INTERACTIVE (DIA_CANVAS_VIEW_ITEM (item)->item)) { dist1 = citem_class->point (DIA_CANVAS_VIEW_ITEM (item)->item, x, y); actual_item1 = item; } dist2 = ((GnomeCanvasItemClass*) parent_class)->point (item, x, y, cx, cy, &actual_item2); if (!actual_item2 || dist1 < dist2) { *actual_item = actual_item1; return dist1; } *actual_item = actual_item2; return dist2; } static void dia_canvas_view_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) { DiaCanvasItem *citem; INVARIANT (); D((" ")); citem = DIA_CANVAS_VIEW_ITEM (item)->item; dia_canvas_item_update_now (DIA_CANVAS_VIEW_ITEM (item)->item); if (item->canvas->need_update) gnome_canvas_update_now (item->canvas); *x1 = item->x1; *y1 = item->y1; *x2 = item->x2; *y2 = item->y2; } /** * dia_canvas_view_item_emit_event: * @item: * @event: * * Send a #DiaEvent to the #DiaCanvasItem refered to by @item. * * Return value: TRUE if the event is handled, FALSE otherwise. **/ gboolean dia_canvas_view_item_emit_event (DiaCanvasViewItem *item, gpointer event) { static guint event_signal_id = 0; gboolean retval = FALSE; g_return_val_if_fail (DIA_IS_CANVAS_VIEW_ITEM (item), FALSE); g_return_val_if_fail (DIA_IS_CANVAS_ITEM (item->item), FALSE); g_return_val_if_fail (event != NULL, FALSE); //if (event_signal_id == 0) // event_signal_id = g_signal_lookup ("event", // DIA_TYPE_CANVAS_ITEM); //dia_canvas_view_item_update_item_state (item); //g_signal_emit (G_OBJECT (item->item), event_signal_id, 0, event, &retval); //dia_canvas_view_item_reset_item_state (item); item->event_time = GDK_CURRENT_TIME; return retval; } /** * dia_canvas_view_item_request_redraw_uta: * @item: A canvas view item. * @uta: Microtile array that specifies the area to be redrawn. It will * be freed by this function, so the argument you pass will be invalid * after you call this function. * * Informs a canvas that the specified area, given as a microtile array, needs * to be repainted. To be used only by item implementations. * * The interface is the same as gnome_canvas_request_redraw_uta(). This * function is also called to update the canvas' redraw area. **/ void dia_canvas_view_item_request_redraw_uta (DiaCanvasViewItem *item, ArtUta *uta) { //ArtIRect visible; GnomeCanvas *canvas; g_return_if_fail (DIA_IS_CANVAS_VIEW_ITEM (item)); g_return_if_fail (uta != NULL); canvas = GNOME_CANVAS_ITEM (item)->canvas; if (!(canvas && GTK_WIDGET_DRAWABLE (canvas))) { art_uta_free (uta); return; } /* get_visible_region (canvas, &visible); from gnome-canvas.c: */ /* visible.x0 = canvas->layout.hadjustment->value - canvas->zoom_xofs; visible.y0 = canvas->layout.vadjustment->value - canvas->zoom_yofs; visible.x1 = visible.x0 + GTK_WIDGET (canvas)->allocation.width; visible.y1 = visible.y0 + GTK_WIDGET (canvas)->allocation.height; */ if (item->redraw_area) { ArtUta *new_uta; //new_uta = uta_union_clip (item->redraw_area, uta, &visible); new_uta = art_uta_union (item->redraw_area, uta); art_uta_free (item->redraw_area); item->redraw_area = new_uta; } else { item->redraw_area = uta_dup (uta); } /* here uta is freed: */ gnome_canvas_request_redraw_uta (canvas, uta); } /** * dia_canvas_view_item_add_items: * @item: * @vitem: * * Add an item to the #DiaCanvasView's tree and connect some signals so it * can automatically update itself when something changes * * @vitem is of type #GnomeCanvasGroup, since the real root item of the * #DiaCanvasView is actually a #GnomeCanvasGroup. * * This function is used internally. * * So, @item is added to the canvas and now we should create a new child * to @vitem in order to update the #DiaCanvasView (#GnomeCanvas). */ void dia_canvas_view_item_add_items (GnomeCanvasGroup *vitem, DiaCanvasItem *item) { DiaCanvasViewItem *new_vitem; gint item_index, vitem_index; DiaCanvasIter iter; g_assert (DIA_IS_CANVAS_ITEM (item)); g_assert (GNOME_IS_CANVAS_GROUP (vitem)); new_vitem = (DiaCanvasViewItem*) gnome_canvas_item_new (GNOME_CANVAS_GROUP (vitem), DIA_TYPE_CANVAS_VIEW_ITEM, "item", item, NULL); g_assert (new_vitem != NULL); //gnome_canvas_item_request_update (item); /* Move the newly created DiaCanvasViewItem to the right place in * the item list (but not for the root item ;-). */ if (item->parent) { item_index = dia_canvas_groupable_pos (DIA_CANVAS_GROUPABLE (item->parent), item); vitem_index = g_list_index (vitem->item_list, new_vitem); /* New items are always added on the top, so if the * vitem's index is higher that item's there's something * very wrong! */ //g_assert (item_index <= vitem_index); if (item_index > vitem_index) { g_error("item index (%d) > view item index (%d)", item_index, vitem_index); g_assert_not_reached(); } if (item_index < vitem_index) { gnome_canvas_item_lower (GNOME_CANVAS_ITEM (new_vitem), vitem_index - item_index); } } /* If item itself has children, add them also */ if (DIA_IS_CANVAS_GROUPABLE (item) && dia_canvas_groupable_get_iter (DIA_CANVAS_GROUPABLE (item), &iter)) do { DiaCanvasItem *val = dia_canvas_groupable_value (DIA_CANVAS_GROUPABLE (item), &iter); if (val) dia_canvas_view_item_add_items (GNOME_CANVAS_GROUP (new_vitem), val); } while (dia_canvas_groupable_next (DIA_CANVAS_GROUPABLE (item), &iter)); } static gint do_foreach (DiaCanvasViewItem *item, DiaCanvasViewItemForeachFunc func, gpointer data) { GList *l; gint result = TRUE; if (!func (item, data)) return FALSE; for (l = GNOME_CANVAS_GROUP (item)->item_list; l != NULL; l = l->next) if (DIA_IS_CANVAS_VIEW_ITEM (l->data)) result &= dia_canvas_view_item_foreach ((DiaCanvasViewItem*) l->data, func, data); return result; } /** * dia_canvas_view_item_foreach: * @item: * @func: * @data: * * Call @func for each canvas view item. If @func returns %FALSE, no more * items are called. * * Return value: **/ gint dia_canvas_view_item_foreach (DiaCanvasViewItem *item, DiaCanvasViewItemForeachFunc func, gpointer data) { g_return_val_if_fail (DIA_IS_CANVAS_VIEW_ITEM (item), FALSE); g_return_val_if_fail (func != NULL, FALSE); return do_foreach (item, func, data); } /** * dia_canvas_view_item_is_focused: * @item: * * Check if an item has the focus. If the real focus is held by a child object * of @item and the child has the #DIA_COMPOSITE flag, TRUE is returned. * * Return value: TRUE/FALSE. **/ gboolean dia_canvas_view_item_is_focused (DiaCanvasViewItem *item) { DiaCanvasViewItem *focus_item; g_return_val_if_fail (DIA_IS_CANVAS_VIEW_ITEM (item), FALSE); focus_item = DIA_CANVAS_VIEW (GNOME_CANVAS_ITEM (item)->canvas)->focus_item; if (!focus_item) return FALSE; do { if (item == focus_item) return TRUE; else if (DIA_CANVAS_ITEM_COMPOSITE (focus_item->item)) focus_item = (DiaCanvasViewItem*) GNOME_CANVAS_ITEM (focus_item)->parent; else return FALSE; } while (focus_item != NULL); return FALSE; } gboolean dia_canvas_view_item_is_selected (DiaCanvasViewItem *item) { GList *sel_items; g_return_val_if_fail (DIA_IS_CANVAS_VIEW_ITEM (item), FALSE); sel_items = DIA_CANVAS_VIEW(GNOME_CANVAS_ITEM (item)->canvas)->selected_items; if (!sel_items) return FALSE; /* find non composite parent item */ while (DIA_CANVAS_ITEM_COMPOSITE (item->item)) item = (DiaCanvasViewItem*) GNOME_CANVAS_ITEM (item)->parent; return g_list_find (sel_items, item) ? TRUE : FALSE; }