/* dia-canvas-view.c * Copyright (C) 2000, 2001 James Henstridge, 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 "dia-canvas-view.h" #include #include #include #include #include #include #include "dia-canvas-editable.h" #include "dia-default-tool.h" #include "dia-handle-layer.h" #include "dia-canvas-i18n.h" //#include "dia-shape-art.h" //#include "dia-shape-x.h" #include "diamarshal.h" enum { FOCUS_ITEM, SELECT_ITEM, UNSELECT_ITEM, LAST_SIGNAL }; enum { PROP_AA = 1, PROP_CANVAS, PROP_ACTIVE_VIEW, PROP_ZOOM, PROP_TOOL, PROP_DEFAULT_TOOL }; //#define D(msg) G_STMT_START { g_print (G_STRLOC": "); g_print msg; g_print ("\n"); } G_STMT_END #define D(msg) #define MIN_TEXT_VIEW_WIDTH (15) #define MIN_TEXT_VIEW_HEIGHT (15) static void dia_canvas_view_init (DiaCanvasView *canvas_view); static void dia_canvas_view_class_init (DiaCanvasViewClass *klass); static void dia_canvas_view_destroy (GtkObject *object); static void dia_canvas_view_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec); static void dia_canvas_view_get_property (GObject *gobject, guint property_id, GValue *value, GParamSpec *pspec); /* Events the CanvasView should react on: */ static void dia_canvas_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gboolean dia_canvas_view_button_press (GtkWidget *widget, GdkEventButton *event); static gboolean dia_canvas_view_button_release (GtkWidget *widget, GdkEventButton *event); static gboolean dia_canvas_view_motion_notify (GtkWidget *widget, GdkEventMotion *event); static gboolean dia_canvas_view_key_press (GtkWidget *widget, GdkEventKey *event); static gboolean dia_canvas_view_key_release (GtkWidget *widget, GdkEventKey *event); static gboolean dia_canvas_view_focus_in (GtkWidget *widget, GdkEventFocus *event); static gboolean dia_canvas_view_focus_out (GtkWidget *widget, GdkEventFocus *event); static void dia_canvas_view_draw_background (GnomeCanvas *canvas, GdkDrawable *drawable, int x, int y, int width, int height); static void dia_canvas_view_render_background (GnomeCanvas *canvas, GnomeCanvasBuf *buf); static void redraw_view_cb (DiaCanvas *canvas, DiaCanvasView *view); static void update_extents (DiaCanvasView *view); static void empty_canvas_view (DiaCanvasView *view); static GnomeCanvasClass *parent_class = NULL; static DiaCanvasView *active_view = NULL; static guint canvas_view_signals[LAST_SIGNAL] = { 0 }; GtkType dia_canvas_view_get_type (void) { static GtkType canvas_view_type = 0; if (!canvas_view_type) { static const GtkTypeInfo canvas_view_info = { "DiaCanvasView", sizeof (DiaCanvasView), sizeof (DiaCanvasViewClass), (GtkClassInitFunc) dia_canvas_view_class_init, (GtkObjectInitFunc) dia_canvas_view_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; canvas_view_type = gtk_type_unique (gnome_canvas_get_type (), &canvas_view_info); } return canvas_view_type; } static void dia_canvas_view_class_init (DiaCanvasViewClass *klass) { GObjectClass *gobject_class; GtkObjectClass *object_class; GtkWidgetClass *widget_class; GnomeCanvasClass *canvas_class; gobject_class = (GObjectClass*) klass; object_class = (GtkObjectClass*) klass; widget_class = (GtkWidgetClass*) klass; canvas_class = (GnomeCanvasClass*) klass; parent_class = g_type_class_peek_parent (klass); gobject_class->set_property = dia_canvas_view_set_property; gobject_class->get_property = dia_canvas_view_get_property; object_class->destroy = dia_canvas_view_destroy; widget_class->size_allocate = dia_canvas_view_size_allocate; widget_class->button_press_event = dia_canvas_view_button_press; widget_class->button_release_event = dia_canvas_view_button_release; widget_class->motion_notify_event = dia_canvas_view_motion_notify; widget_class->key_press_event = dia_canvas_view_key_press; widget_class->key_release_event = dia_canvas_view_key_release; widget_class->focus_in_event = dia_canvas_view_focus_in; widget_class->focus_out_event = dia_canvas_view_focus_out; canvas_class->draw_background = dia_canvas_view_draw_background; canvas_class->render_background = dia_canvas_view_render_background; klass->focus_item = NULL; klass->select_item = NULL; klass->unselect_item = NULL; canvas_view_signals[FOCUS_ITEM] = g_signal_new ("focus_item", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(DiaCanvasViewClass, focus_item), NULL, NULL, dia_marshal_VOID__OBJECT, G_TYPE_NONE, 1, DIA_TYPE_CANVAS_VIEW_ITEM); canvas_view_signals[SELECT_ITEM] = g_signal_new ("select_item", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(DiaCanvasViewClass, select_item), NULL, NULL, dia_marshal_VOID__OBJECT, G_TYPE_NONE, 1, DIA_TYPE_CANVAS_VIEW_ITEM); canvas_view_signals[UNSELECT_ITEM] = g_signal_new ("unselect_item", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(DiaCanvasViewClass, unselect_item), NULL, NULL, dia_marshal_VOID__OBJECT, G_TYPE_NONE, 1, DIA_TYPE_CANVAS_VIEW_ITEM); g_object_class_install_property (gobject_class, PROP_AA, g_param_spec_boolean ("aa", _("Anti-aliasing"), _("Set the canvas to anti-alias or X render mode. Only during initialization. You should also have pushed the right colormap (gdk_rgb_get_cmap() for AA, gdk_imlib_cmap() for X)."), FALSE, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_CANVAS, g_param_spec_object ("canvas", _("Canvas"), _("Canvas to be displayed in the view"), DIA_TYPE_CANVAS, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_ACTIVE_VIEW, g_param_spec_object ("active_view", _("Active view"), _("Returns the active view, even if the view itself is not the active view."), DIA_TYPE_CANVAS_VIEW, G_PARAM_READABLE)); g_object_class_install_property (gobject_class, PROP_ZOOM, g_param_spec_double ("zoom", _("Zoom"), _("Set the zoom factor"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_TOOL, g_param_spec_object ("tool", _("Tool"), _("Set a tool, may be NULL"), DIA_TYPE_TOOL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_DEFAULT_TOOL, g_param_spec_object ("default-tool", _("Default tool"), _("Set a tool"), DIA_TYPE_TOOL, G_PARAM_READWRITE)); } static void dia_canvas_view_init (DiaCanvasView *view) { g_object_set (G_OBJECT (view), "hadjustment", gtk_adjustment_new (0.0 /* value */, 0.0 /* lower */, 0.0 /* upper */, 20.0 /* step_incr */, 0.0 /* page_incr */, 0.0 /* page_size */), "vadjustment", gtk_adjustment_new (0.0 /* value */, 0.0 /* lower */, 0.0 /* upper */, 20.0 /* step_incr */, 0.0 /* page_incr */, 0.0 /* page_size */), NULL); view->canvas = NULL; view->root_item = NULL; view->tool = NULL; view->default_tool = dia_default_tool_new (); view->handle_layer = gnome_canvas_item_new (GNOME_CANVAS_GROUP (GNOME_CANVAS (view)->root), dia_handle_layer_get_type (), NULL); g_object_ref (G_OBJECT (view->handle_layer)); view->focus_item = NULL; view->selected_items = NULL; view->text_view = NULL; view->edited_item = NULL; view->edited_shape = NULL; view->last_item = NULL; view->button_press_handled = FALSE; } static void dia_canvas_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { DiaCanvasView *view = (DiaCanvasView*) object; switch (property_id) { case PROP_AA: if (!GTK_WIDGET_REALIZED (object)) GNOME_CANVAS (view)->aa = g_value_get_boolean (value); else g_error ("Only set AA before the widget is realized."); break; case PROP_CANVAS: if (view->canvas) dia_canvas_view_unset_canvas (view); if (g_value_get_object (value)) dia_canvas_view_set_canvas (view, g_value_get_object (value)); dia_canvas_view_request_update (view); break; case PROP_ZOOM: dia_canvas_view_set_zoom (view, g_value_get_double (value)); break; case PROP_TOOL: dia_canvas_view_set_tool (view, g_value_get_object (value)); break; case PROP_DEFAULT_TOOL: dia_canvas_view_set_default_tool (view, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void dia_canvas_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { DiaCanvasView *view = (DiaCanvasView*) object; switch (property_id) { case PROP_AA: g_value_set_boolean (value, GNOME_CANVAS (view)->aa); break; case PROP_CANVAS: g_value_set_object (value, view->canvas); break; case PROP_ACTIVE_VIEW: g_value_set_object (value, active_view); break; case PROP_ZOOM: g_value_set_double (value, dia_canvas_view_get_zoom (view)); break; case PROP_TOOL: g_value_set_object (value, dia_canvas_view_get_tool (view)); break; case PROP_DEFAULT_TOOL: g_value_set_object (value, dia_canvas_view_get_default_tool (view)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void dia_canvas_view_destroy (GtkObject *object) { DiaCanvasView *view = (DiaCanvasView*) object; //g_message (G_STRLOC": begin (%x).", (guint) object); if (view->tool) { g_object_unref (G_OBJECT (view->tool)); view->tool = NULL; } if (view->default_tool) { g_object_unref (G_OBJECT (view->default_tool)); view->default_tool = NULL; } if (view->handle_layer) { g_object_unref (G_OBJECT (view->handle_layer)); view->handle_layer = NULL; } if (view->text_view) { g_object_unref (G_OBJECT (view->text_view)); view->text_view = NULL; view->edited_item = NULL; view->edited_shape = NULL; } if (view->canvas) { dia_canvas_view_unset_canvas (view); } //g_message (G_STRLOC": calling parent."); GTK_OBJECT_CLASS (parent_class)->destroy (object); } static void dia_canvas_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { DiaCanvasView *view = DIA_CANVAS_VIEW (widget); (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation); /* Now adjust the size of the layout, so that it contains the canvas * in a nice way. */ update_extents (view); } static gboolean dia_canvas_view_button_press (GtkWidget *widget, GdkEventButton *event) { DiaCanvasView *view = (DiaCanvasView*) widget; gboolean result = FALSE; /* Ensure we have the right active view: the FocusIn event may * come after this event... */ active_view = view; /* Do nothing if we're currently editing a canvas item and the button * is pressed inside the text view... */ //if (view->text_view // && gtk_widget_is_focus (GTK_WIDGET (view->text_view))) // return FALSE; gtk_widget_grab_focus (widget); if (!view->canvas) return FALSE; gnome_canvas_window_to_world (GNOME_CANVAS (view), event->x, event->y, &event->x, &event->y); if (view->tool && dia_tool_button_press (view->tool, view, event)) return TRUE; //dia_canvas_push_undo (view->canvas, NULL); if (view->default_tool && dia_tool_button_press (view->default_tool, view, event)) return TRUE; return FALSE; } static gboolean dia_canvas_view_button_release (GtkWidget *widget, GdkEventButton *event) { DiaCanvasView *view = (DiaCanvasView*) widget; gboolean result = FALSE; if (!view->canvas) return FALSE; gnome_canvas_window_to_world (GNOME_CANVAS (view), event->x, event->y, &event->x, &event->y); if (view->tool && dia_tool_button_release (view->tool, view, event)) return TRUE; if (view->default_tool && dia_tool_button_release (view->default_tool, view, event)) return TRUE; return FALSE; } static gboolean dia_canvas_view_motion_notify (GtkWidget *widget, GdkEventMotion *event) { DiaCanvasView *view = (DiaCanvasView*) widget; if (!view->canvas) return FALSE; gnome_canvas_window_to_world (GNOME_CANVAS (view), event->x, event->y, &event->x, &event->y); if (view->tool && dia_tool_motion_notify (view->tool, view, event)) return TRUE; if (view->default_tool && dia_tool_motion_notify (view->default_tool, view, event)) return TRUE; return FALSE; } static gboolean dia_canvas_view_key_press (GtkWidget *widget, GdkEventKey *event) { DiaCanvasView *view = (DiaCanvasView*) widget; /* Do not handle keys if we are editing text in the text view. */ if (view->text_view && gtk_widget_is_focus (GTK_WIDGET (view->text_view))) return FALSE; if (!view->canvas) return FALSE; if (view->tool && dia_tool_key_press (view->tool, view, event)) return TRUE; if (view->default_tool && dia_tool_key_press (view->default_tool, view, event)) return TRUE; return FALSE; } static gboolean dia_canvas_view_key_release (GtkWidget *widget, GdkEventKey *event) { DiaCanvasView *view = (DiaCanvasView*) widget; gboolean result = FALSE; /* Do not handle keys if we are editing text in the text view. */ if (view->text_view && gtk_widget_is_focus (GTK_WIDGET (view->text_view))) return FALSE; if (!view->canvas) return FALSE; if (view->tool && dia_tool_key_release (view->tool, view, event)) return TRUE; if (view->default_tool && dia_tool_key_release (view->default_tool, view, event)) return TRUE; return FALSE; } static gboolean dia_canvas_view_focus_in (GtkWidget *widget, GdkEventFocus *event) { DiaCanvasView *view = (DiaCanvasView*) widget; gboolean result = FALSE; //g_message(G_STRLOC); active_view = view; /* Update all shapes: we want to give the focused item its focused * state "back". */ if (view->focus_item) { DiaCanvasItem *diaitem = view->focus_item->item; DiaCanvasIter iter; if (dia_canvas_item_get_shape_iter (diaitem, &iter)) do { dia_shape_request_update (dia_canvas_item_shape_value (diaitem, &iter)); } while (dia_canvas_item_shape_next (diaitem, &iter)); gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (view->focus_item)); result = TRUE; } if (GTK_WIDGET_CLASS(parent_class)->focus_in_event) result = (* GTK_WIDGET_CLASS(parent_class)->focus_in_event) (widget, event); return result; } static gboolean dia_canvas_view_focus_out (GtkWidget *widget, GdkEventFocus *event) { DiaCanvasView *view = (DiaCanvasView*) widget; gboolean result = FALSE; //g_message(G_STRLOC); //active_view = NULL; /* Update all shapes of the focused item: we want to remove the * focused appearance of the item. */ if (view->focus_item) { DiaCanvasItem *diaitem = view->focus_item->item; DiaCanvasIter iter; if (dia_canvas_item_get_shape_iter (diaitem, &iter)) do { dia_shape_request_update (dia_canvas_item_shape_value (diaitem, &iter)); } while (dia_canvas_item_shape_next (diaitem, &iter)); gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (view->focus_item)); result = TRUE; } if (GTK_WIDGET_CLASS(parent_class)->focus_out_event) result = (* GTK_WIDGET_CLASS(parent_class)->focus_out_event) (widget, event); return result; } static inline void calc_grid_start (DiaCanvas *diac, GnomeCanvas *canvas, int x, int y, gdouble *sx, gdouble *sy, gdouble *intx, gdouble *inty) { register gdouble ofsx, ofsy; *intx = diac->interval_x * canvas->pixels_per_unit; *inty = diac->interval_y * canvas->pixels_per_unit; while (*intx < 4) *intx *= 2; while (*inty < 4) *inty *= 2; /* For the offset we should take into account the GnomeCanvas' upper * left coordinate, since GtkLayout only uses positive coordinates. */ ofsx = (diac->offset_x - canvas->scroll_x1 + floor (canvas->scroll_x1 / diac->interval_x) * diac->interval_x) * canvas->pixels_per_unit; ofsy = (diac->offset_y - canvas->scroll_y1 + floor (canvas->scroll_y1 / diac->interval_y) * diac->interval_y) * canvas->pixels_per_unit; *sx = floor ((x - ofsx) / *intx) * *intx + ofsx; *sy = floor ((y - ofsy) / *inty) * *inty + ofsy; } static void dia_canvas_view_draw_background (GnomeCanvas *canvas, GdkDrawable *drawable, int dx, int dy, int width, int height) { DiaCanvas *diac = ((DiaCanvasView*) canvas)->canvas; GdkColor c; gdouble intx, inty, sx, sy; register gdouble x, y; if (!diac) { parent_class->draw_background (canvas, drawable, dx, dy, width, height); return; } calc_grid_start (diac, canvas, dx, dy, &sx, &sy, &intx, &inty); c.pixel = gnome_canvas_get_color_pixel (canvas, diac->grid_bg | 0xff); gdk_gc_set_foreground (canvas->pixmap_gc, &c); gdk_draw_rectangle (drawable, canvas->pixmap_gc, TRUE, 0, 0, width, height); c.pixel = gnome_canvas_get_color_pixel (canvas, diac->grid_color); gdk_gc_set_foreground (canvas->pixmap_gc, &c); for (y = sy - dy; y < height; y += inty) { for (x = sx - dx; x < width; x += intx) { register gint ix, iy; ix = (int) (x + 0.5); iy = (int) (y + 0.5); gdk_draw_point (drawable, canvas->pixmap_gc, ix, iy); } } } static void dia_canvas_view_render_background (GnomeCanvas *canvas, GnomeCanvasBuf *buf) { DiaCanvas *diac = ((DiaCanvasView*) canvas)->canvas; gdouble intx, inty, sx, sy; register gdouble x, y; if (!diac) { if (parent_class->render_background) parent_class->render_background (canvas, buf); else if (parent_class->draw_background) parent_class->draw_background (canvas, GTK_WIDGET (canvas)->window, buf->rect.x0, buf->rect.y0, buf->rect.x1 - buf->rect.x0, buf->rect.y1 - buf->rect.y0); return; } calc_grid_start (diac, canvas, buf->rect.x0, buf->rect.y0, &sx, &sy, &intx, &inty); buf->bg_color = diac->grid_bg | 0xff; gnome_canvas_buf_ensure_buf (buf); buf->is_bg = FALSE; for (y = sy; y < buf->rect.y1; y += inty) { for (x = sx; x < buf->rect.x1; x += intx) { register gint ix, iy; ix = (int) (x + 0.5); iy = (int) (y + 0.5); if ((ix >= buf->rect.x0) && (ix < buf->rect.x1) && (iy >= buf->rect.y0) && (iy < buf->rect.y1)) { guchar *p = buf->buf + (iy - buf->rect.y0) * buf->buf_rowstride + (ix - buf->rect.x0) * 3; *p++ = DIA_COLOR_RED(diac->grid_color); *p++ = DIA_COLOR_GREEN(diac->grid_color); *p = DIA_COLOR_BLUE(diac->grid_color); } } } } static void redraw_view_cb (DiaCanvas *canvas, DiaCanvasView *view) { gnome_canvas_request_redraw (GNOME_CANVAS (view), G_MININT, G_MININT, G_MAXINT, G_MAXINT); } /** * update_extents: * @view * * Update the canvas view's size so that it always keeps (0, 0) in the upper * left corner. If the canvas extents are dynamic, the size of the view is * always one width/height larger than the extents of the canvas. * * Static extents are set to the maximum of the extents of view size. */ static void update_extents (DiaCanvasView *view) { GnomeCanvas *canvas = (GnomeCanvas*) view; gdouble width, height; g_assert (DIA_IS_CANVAS_VIEW (view)); width = GTK_WIDGET (view)->allocation.width / canvas->pixels_per_unit; height = GTK_WIDGET (view)->allocation.height / canvas->pixels_per_unit; if (view->canvas) { DiaRectangle *extents = &view->canvas->extents; if (view->canvas->static_extents) { width = MAX(extents->right, width); height = MAX(extents->bottom, height); } else { width += extents->right; height += extents->bottom; } } gnome_canvas_set_scroll_region (canvas, 0.0, 0.0, width, height); } /** * dia_canvas_view_set_canvas: * @view: * @canvas: * * Set the canvas to be visualized by @view. You can only set a canvas if * the view doesn't already have a canvas. **/ void dia_canvas_view_set_canvas (DiaCanvasView *view, DiaCanvas *canvas) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (view->canvas == NULL); g_return_if_fail (DIA_IS_CANVAS (canvas)); g_object_ref (canvas); view->canvas = canvas; g_signal_connect_swapped (G_OBJECT (canvas), "notify::extents", G_CALLBACK (update_extents), view); g_signal_connect (G_OBJECT (canvas), "redraw_view", G_CALLBACK (redraw_view_cb), view); /* Create DiaCanvasViewItems for all items already in the canvas */ dia_canvas_view_item_add_items (GNOME_CANVAS_GROUP (GNOME_CANVAS (view)->root), canvas->root); view->root_item = DIA_CANVAS_VIEW_ITEM (g_list_last (GNOME_CANVAS_GROUP (GNOME_CANVAS (view)->root)->item_list)->data); /* Automatically set root_item to NULL on destruction. */ g_object_add_weak_pointer (G_OBJECT (view->root_item), (gpointer) &view->root_item); /* Make sure the HandleLayer is on top: */ if (view->handle_layer) gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM (view->handle_layer)); g_assert (view->root_item != NULL); g_assert (DIA_IS_CANVAS_VIEW_ITEM (view->root_item)); /* Make sure the extents of the canvas are set up properly. */ update_extents (view); /* * Don't know why it won't show a canvas imediately after a * set_canvas() is done while the canvas is still visible... */ gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view), GNOME_CANVAS (view)->pixels_per_unit); g_object_notify (G_OBJECT (view), "canvas"); } /** * dia_canvas_view_get_canvas: * @view: * * Get the #DiaCanvas that is displayed in the @view. * * Return value: The canvas. **/ DiaCanvas* dia_canvas_view_get_canvas (DiaCanvasView *view) { g_return_val_if_fail (DIA_IS_CANVAS_VIEW (view), NULL); return view->canvas; } static void empty_canvas_view (DiaCanvasView *view) { /* Remove canvas items from GnomeCanvas::root::item_list too! */ if (view->root_item) { gtk_object_destroy (GTK_OBJECT (view->root_item)); view->root_item = NULL; } g_list_free (view->selected_items); view->selected_items = NULL; view->focus_item = NULL; view->last_item = NULL; g_object_unref (view->canvas); view->canvas = NULL; gnome_canvas_request_redraw (GNOME_CANVAS (view), G_MININT, G_MININT, G_MAXINT, G_MAXINT); } /** * dia_canvas_view_unset_canvas: * @view: * * Disconnect the view from it's #DiaCanvas. **/ void dia_canvas_view_unset_canvas (DiaCanvasView *view) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (DIA_IS_CANVAS (view->canvas)); //g_message (G_STRLOC); //if (view->root_item) // g_object_remove_weak_pointer (G_OBJECT (view->root_item), // view->root_item); g_signal_handlers_disconnect_matched (view->canvas, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view); //g_object_weak_unref (G_OBJECT (view->canvas), // (GWeakNotify) empty_canvas_view, // view); empty_canvas_view (view); g_object_notify (G_OBJECT (view), "canvas"); } /** * dia_canvas_view_new: * @canvas: A #DiaCanvas that contains data that is to be visualized (may * be NULL). * @aa: OBSOLETE. An Anti-alias canvas is created anyway. * * Create a new DiaCanvasView object. In most cases you want to set @aa to TRUE, * since it has the most complete renderer and the best quality. * * Return value: A newly create DiaCanvasView. **/ GtkWidget* dia_canvas_view_new (DiaCanvas *canvas, gboolean aa) { GtkWidget *view; gtk_widget_push_colormap (gdk_rgb_get_cmap ()); view = g_object_new (DIA_TYPE_CANVAS_VIEW, "aa", TRUE, "canvas", canvas, NULL); gtk_widget_pop_colormap (); g_assert (view != NULL); return view; } /** * dia_canvas_view_aa_new: * * Create a new anti-aliased canvas. Note that no #DiaCanvas object is yet * connected to the canvas view. * * Return value: A newly created #DiaCanvasView. **/ GtkWidget* dia_canvas_view_aa_new (void) { GtkWidget *view; gtk_widget_push_colormap (gdk_rgb_get_cmap ()); view = g_object_new (DIA_TYPE_CANVAS_VIEW, "aa", TRUE, NULL); gtk_widget_pop_colormap (); return view; } /** * dia_canvas_view_get_zoom: * @view: * * Get the zoom factor for the view. * * Return value: **/ gdouble dia_canvas_view_get_zoom (DiaCanvasView *view) { g_return_val_if_fail (DIA_IS_CANVAS_VIEW (view), 1.0); return GNOME_CANVAS (view)->pixels_per_unit; } /** * dia_canvas_view_set_zoom: * @view: * @zoom: * * Set the zoom factor for the canvas. 1.0 means 100%. **/ void dia_canvas_view_set_zoom (DiaCanvasView *view, gdouble zoom) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (zoom > 0.0); if (GNOME_CANVAS (view)->pixels_per_unit == zoom) return; gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view), zoom); update_extents (view); dia_canvas_view_request_update (view); g_object_notify (G_OBJECT (view), "zoom"); } /** * dia_canvas_view_get_tool: * @view: * * Return value: The tool or %NULL if no tool is set. **/ DiaTool* dia_canvas_view_get_tool (DiaCanvasView *view) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); return view->tool; } /** * dia_canvas_view_set_tool: * @view: * @tool: The #DiaTool * * Set a tool to use by this canvas view. Tools are used to override the * default behavior of the view. @tool may be %NULL, so the tool is removed * from the view. **/ void dia_canvas_view_set_tool (DiaCanvasView *view, DiaTool *tool) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (DIA_IS_TOOL (tool) || tool == NULL); if (view->tool) { g_object_unref (view->tool); } view->tool = tool; if (view->tool) { g_object_ref (view->tool); } g_object_notify (G_OBJECT (view), "tool"); } /** * dia_canvas_view_get_default_tool: * @view: * * * * Return value: the default tool **/ DiaTool* dia_canvas_view_get_default_tool (DiaCanvasView *view) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); return view->default_tool; } /** * dia_canvas_view_set_default_tool: * @view: * @default_tool: * * Set the default tool for the view. The default tool is used to do the * default behavior for the view, such as moving handles and editing the * diagram items. * * This tool is used if no tool is set via dia_canvas_view_set_tool(). **/ void dia_canvas_view_set_default_tool (DiaCanvasView *view, DiaTool *default_tool) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (DIA_IS_TOOL (default_tool)); if (view->default_tool) g_object_unref (view->default_tool); view->default_tool = default_tool; if (view->default_tool) g_object_ref (view->default_tool); g_object_notify (G_OBJECT (view), "tool"); } /* Select @item. only interactive items are selected. * TRUE is returned, so read_select can also be used by * dia_canvas_view_foreach(). */ static gint real_select (DiaCanvasViewItem *item, gpointer data) { DiaCanvasView *view = data; if (!DIA_CANVAS_ITEM_INTERACTIVE(item->item)) return TRUE; /* Find the uppermost canvas view item that should be selected. */ while (DIA_CANVAS_ITEM_COMPOSITE (item->item)) item = DIA_CANVAS_VIEW_ITEM (GNOME_CANVAS_ITEM (item)->parent); if (!g_list_find (view->selected_items, item)) { view->selected_items = g_list_append (view->selected_items, item); gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (item)); g_signal_emit(view, canvas_view_signals[SELECT_ITEM], 0, item); } return TRUE; } /** * dia_canvas_view_select: * @view: * @item: * * Select @item. If the item is a composite item (item->item has DIA_COMPOSITE * set), the parent is selected. **/ void dia_canvas_view_select (DiaCanvasView *view, DiaCanvasViewItem *item) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (DIA_IS_CANVAS_VIEW_ITEM (item)); real_select (item, view); } static gint real_select_rectangle (DiaCanvasViewItem *item, gpointer data) { if (g_list_find (data, item->item)) real_select (item, DIA_CANVAS_VIEW (GNOME_CANVAS_ITEM (item)->canvas)); return TRUE; } /** * dia_canvas_view_select_rectangle: * @view: * @rect: * * Select all object whose bounding box is within @rect. **/ void dia_canvas_view_select_rectangle (DiaCanvasView *view, DiaRectangle *rect) { GList *objs; g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (rect != NULL); objs = dia_canvas_find_objects_in_rectangle (view->canvas, rect); if (objs) { dia_canvas_view_item_foreach (view->root_item, real_select_rectangle, objs); g_list_free (objs); } } /** * dia_canvas_view_select_all: * @view: * * Select all items on the canvas. **/ void dia_canvas_view_select_all (DiaCanvasView *view) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); dia_canvas_view_item_foreach (view->root_item, real_select, view); } static gint real_unselect (DiaCanvasViewItem *item, gpointer view) { /* Find the owning item in case of a composite object. */ while (DIA_CANVAS_ITEM_COMPOSITE (item->item)) item = DIA_CANVAS_VIEW_ITEM (GNOME_CANVAS_ITEM (item)->parent); if (DIA_CANVAS_VIEW_ITEM_SELECT (item)) { DIA_CANVAS_VIEW (view)->selected_items = g_list_remove (DIA_CANVAS_VIEW (view)->selected_items, item); if (DIA_CANVAS_VIEW_ITEM_FOCUS (item)) dia_canvas_view_focus (view, NULL); //gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (item)); dia_canvas_item_request_update (item->item); g_signal_emit (view, canvas_view_signals[UNSELECT_ITEM], 0, item); } return TRUE; } /** * dia_canvas_view_unselect: * @view: #DiaCanvasView * @root: item to unselect. * * Unselect @root and all children of @root. If one of the selected items * has the focus, it is de-focused. **/ void dia_canvas_view_unselect (DiaCanvasView *view, DiaCanvasViewItem *root) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (DIA_IS_CANVAS_VIEW_ITEM (root)); dia_canvas_view_item_foreach (root, real_unselect, view); } /** * dia_canvas_view_unselect_all: * @view: * * Do a dia_canvas_view_unselect() for all items in the canvas view. **/ void dia_canvas_view_unselect_all (DiaCanvasView *view) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); dia_canvas_view_unselect (view, view->root_item); } /** * dia_canvas_view_focus: * @view: * @item: Item to focus, may be NULL (no focused object). * * Set the focus to @item. If @item is not an interactive item, the focus * is set to NULL. **/ void dia_canvas_view_focus (DiaCanvasView *view, DiaCanvasViewItem *item) { gboolean retval = TRUE; //DiaEvent ev; g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail ((item == NULL) || DIA_IS_CANVAS_VIEW_ITEM (item)); if (view->focus_item == item) return; /* Unfocus focused object */ if (view->focus_item) { // TODO: What to do with focus in/out events? //ev.type = DIA_EVENT_FOCUS_OUT; //dia_canvas_view_item_emit_event (view->focus_item, &ev); //gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (view->focus_item)); dia_canvas_item_request_update (view->focus_item->item); } /* Set default return value to TRUE, so the focus event will be * emited, even if the item == NULL or non-interactive. */ retval = TRUE; if (item && DIA_CANVAS_ITEM_INTERACTIVE (item->item)) { view->focus_item = item; dia_canvas_view_select (view, item); //ev.type = DIA_EVENT_FOCUS_IN; //dia_canvas_view_item_emit_event (item, &ev); } else { view->focus_item = NULL; } //if (retval) g_signal_emit (view, canvas_view_signals[FOCUS_ITEM], 0, view->focus_item); } /* We determine if the parent is in the selected items list by traversing * the view-items. */ static gboolean parent_in_selected_items_list (GList *selected_items, GnomeCanvasItem *item) { if (g_list_find (selected_items, item->parent)) return TRUE; else if (item->parent) return parent_in_selected_items_list (selected_items, item->parent); return FALSE; } /** * dia_canvas_view_move: * @view: * @dx: movement * @dy: * @originator: the object that recieved the event resulting in the movement. * * Move all selected items. **/ void dia_canvas_view_move (DiaCanvasView *view, gdouble dx, gdouble dy, DiaCanvasViewItem *originator) { GList *l; gdouble w2i[6]; g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail ((originator == NULL) || DIA_IS_CANVAS_VIEW_ITEM (originator)); for (l = view->selected_items; l != NULL; l = l->next) { DiaCanvasItem *item = DIA_CANVAS_VIEW_ITEM (l->data)->item; if (!DIA_CANVAS_ITEM_GET_CLASS (item)->move || (l->data == (gpointer) originator) || !item->parent || parent_in_selected_items_list (view->selected_items, l->data)) continue; dia_canvas_item_affine_w2i (DIA_CANVAS_ITEM (item->parent), w2i); w2i[4] = dx * w2i[0] + dy * w2i[2]; w2i[5] = dx * w2i[1] + dy * w2i[3]; dia_canvas_item_move (item, w2i[4], w2i[5]); } } static gint real_request_update (DiaCanvasViewItem *item, gpointer data) { GTK_OBJECT_SET_FLAGS (item, DIA_CANVAS_VIEW_ITEM_UPDATE_SHAPES); gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (item)); return TRUE; } /** * dia_canvas_view_request_update: * @view: * * Request an update for all items on the canvas. All shapes will be set * to update state too. **/ void dia_canvas_view_request_update (DiaCanvasView *view) { g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); if (view->root_item) dia_canvas_view_item_foreach (view->root_item, real_request_update, NULL); } static gint real_find_view_item (DiaCanvasViewItem *item, gpointer data) { DiaCanvasItem **citem = data; if (item->item == *citem) { DiaCanvasViewItem **vitem = data; *vitem = item; return FALSE; } return TRUE; } /** * dia_canvas_view_find_view_item: * @view: * @item: Item to find. * * Find the #DiaCanvasViewItem that visualizes @item. * * Return value: The view item or NULL. **/ DiaCanvasViewItem* dia_canvas_view_find_view_item (DiaCanvasView *view, DiaCanvasItem *item) { gpointer data = item; g_return_val_if_fail (DIA_IS_CANVAS_VIEW (view), NULL); g_return_val_if_fail (DIA_IS_CANVAS_ITEM (item), NULL); dia_canvas_view_item_foreach (view->root_item, real_find_view_item, &data); if (DIA_IS_CANVAS_VIEW_ITEM (data)) return data; return NULL; } /** * dia_canvas_view_gdk_event_to_dia_event: * @view: * @item: * @gdk_event: The GdkEvent as it was received by the view. * @dia_event: * * DEPRICATED * * Convert a GdkEvent to a #DiaEvent. #DiaCanvasItem's can recieve mouse and * keyboard events. * * A transformation is done from the window coorsinates to item coordinates. **/ void dia_canvas_view_gdk_event_to_dia_event (DiaCanvasView *view, DiaCanvasViewItem *item, GdkEvent *gdk_event, gpointer dia_event) { /* switch (gdk_event->type) { case GDK_BUTTON_PRESS: dia_event->type = DIA_EVENT_BUTTON_PRESS; break; case GDK_2BUTTON_PRESS: dia_event->type = DIA_EVENT_2BUTTON_PRESS; break; case GDK_3BUTTON_PRESS: dia_event->type = DIA_EVENT_3BUTTON_PRESS; break; case GDK_BUTTON_RELEASE: dia_event->type = DIA_EVENT_BUTTON_RELEASE; break; case GDK_MOTION_NOTIFY: dia_event->type = DIA_EVENT_MOTION; break; case GDK_KEY_PRESS: dia_event->type = DIA_EVENT_KEY_PRESS; break; case GDK_KEY_RELEASE: dia_event->type = DIA_EVENT_KEY_RELEASE; break; default: g_assert_not_reached (); } switch (dia_event->type) { case DIA_EVENT_BUTTON_PRESS: case DIA_EVENT_2BUTTON_PRESS: case DIA_EVENT_3BUTTON_PRESS: case DIA_EVENT_BUTTON_RELEASE: gnome_canvas_window_to_world (GNOME_CANVAS (view), gdk_event->button.x, gdk_event->button.y, &dia_event->button.x, &dia_event->button.y); gnome_canvas_item_w2i (GNOME_CANVAS_ITEM (item), &dia_event->button.x, &dia_event->button.y); dia_canvas_snap_to_grid (view->canvas, &dia_event->button.x, &dia_event->button.y); dia_event->button.modifier = (DiaEventMask) gdk_event->button.state; dia_event->button.button = gdk_event->button.button; break; case DIA_EVENT_MOTION: gnome_canvas_window_to_world (GNOME_CANVAS (view), gdk_event->motion.x, gdk_event->motion.y, &dia_event->motion.x, &dia_event->motion.y); gnome_canvas_item_w2i (GNOME_CANVAS_ITEM (item), &dia_event->motion.x, &dia_event->motion.y); dia_canvas_snap_to_grid (view->canvas, &dia_event->motion.x, &dia_event->motion.y); dia_event->motion.modifier = (DiaEventMask) gdk_event->motion.state; if (item == view->last_item) { dia_event->motion.dx = dia_event->motion.x - view->old_x; dia_event->motion.dy = dia_event->motion.y - view->old_y; } else { dia_event->motion.dx = 0.0; dia_event->motion.dy = 0.0; view->last_item = item; } view->old_x = dia_event->motion.x; view->old_y = dia_event->motion.y; break; case DIA_EVENT_KEY_PRESS: case DIA_EVENT_KEY_RELEASE: dia_event->key.keyval = gdk_event->key.keyval; dia_event->key.length = gdk_event->key.length; dia_event->key.string = gdk_event->key.string; dia_event->key.modifier = (DiaEventMask) gdk_event->key.state; break; default: break; } */ } /** * Update the text properties (font, alignment, etc.). */ static void dia_canvas_view_update_text_view (DiaCanvasView *view) { GtkWidget *text_view; DiaCanvasViewItem *item; DiaShapeText *text_shape; gint width = -1, height = -1; gdouble affine[6]; ArtPoint p = { 0.0, 0.0 }; g_return_if_fail (DIA_IS_CANVAS_VIEW_ITEM (view->edited_item)); g_return_if_fail (view->edited_shape != NULL); text_view = GTK_WIDGET (view->text_view); item = view->edited_item; text_shape = view->edited_shape; /* set position, width and height */ gnome_canvas_item_i2c_affine (GNOME_CANVAS_ITEM (item), affine); art_affine_multiply (affine, affine, text_shape->affine); art_affine_point (&p, &p, affine); gtk_layout_move (GTK_LAYOUT (view), text_view, (gint) p.x, (gint) p.y); #ifdef ENABLE_DEBUG g_message (G_STRLOC": creating text view at (%f, %f)", p.x, p.y); #endif /* ENABLE_DEBUG */ if (text_shape->max_width < G_MAXINT) { if (text_shape->text_width > 0.0) { gint text_width = (gint) (text_shape->text_width + 0.5); width = MIN (text_width, text_shape->max_width); } else width = text_shape->max_width; width = MAX (MIN (width, GTK_WIDGET (view)->allocation.width), MIN_TEXT_VIEW_WIDTH); } if (text_shape->max_height < G_MAXINT) { height = MAX (MIN (text_shape->max_height, GTK_WIDGET (view)->allocation.height), MIN_TEXT_VIEW_HEIGHT); } gtk_widget_set_size_request (text_view, width, height); } static gboolean idle_text_view_focus_out_cb(gpointer data) { dia_canvas_view_editing_done (data); return FALSE; } static gint text_view_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, DiaCanvasView *view) { #ifdef ENABLE_DEBUG //g_message (G_STRLOC": Received a Focus-Out event..."); #endif g_assert (GTK_IS_TEXT_VIEW (widget)); g_assert (DIA_CANVAS_VIEW (view)); //dia_canvas_view_editing_done (view); g_idle_add (idle_text_view_focus_out_cb, view); return FALSE; } static void text_buffer_changed_cb (GtkTextBuffer *buffer, DiaCanvasView *view) { GtkTextIter start, end; gchar *str; g_assert (GTK_IS_TEXT_BUFFER (buffer)); g_assert (DIA_CANVAS_VIEW (view)); if (!view->edited_item || !view->edited_shape) return; gtk_text_buffer_get_bounds (buffer, &start, &end); str = gtk_text_buffer_get_text (buffer, &start, &end, TRUE); dia_canvas_editable_text_changed (DIA_CANVAS_EDITABLE (view->edited_item->item), view->edited_shape, str); dia_canvas_view_update_text_view (view); g_free (str); } /** * dia_canvas_view_start_editing: * @view: * @item: * @x: * @y: * * Start interactive editing of the text in @text_shape. This function * starts the editing widget (a #GtkTextView) and puts it over the text * being edited. #DiaCanvasItem's that are edited should implement the * #DiaCanvasEditable interface. * * Call dia_canvas_view_editing_done() to end the interactive editing. * * While editing the #DiaShape refered to by @text_shape may not be destroyed. **/ void dia_canvas_view_start_editing (DiaCanvasView *view, DiaCanvasViewItem *item, gdouble x, gdouble y) { GtkWidget *text_view; GtkTextBuffer *text_buffer; GtkTextIter start, end; GtkTextMark *mark; DiaShapeText *text_shape = NULL; g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (DIA_IS_CANVAS_VIEW_ITEM (item)); g_return_if_fail (DIA_IS_CANVAS_EDITABLE (item->item)); //g_return_if_fail (text_shape != NULL); //g_return_if_fail (((DiaShape*) text_shape)->type == DIA_SHAPE_TEXT); g_return_if_fail (view->edited_item == NULL); g_return_if_fail (view->edited_shape == NULL); /* Let's see if we may edit and if there is a text shape to use as * a blueprint */ if (dia_canvas_editable_is_editable (DIA_CANVAS_EDITABLE (item->item))) { gdouble ix = x, iy = y; dia_canvas_item_affine_point_w2i (item->item, &ix, &iy); text_shape = dia_canvas_editable_get_editable_shape (DIA_CANVAS_EDITABLE (item->item), ix, iy); if (!text_shape) return; } /* If the item has the `grab' on events, make sure to ungrab it first */ if (GNOME_CANVAS (view)->grabbed_item && DIA_IS_CANVAS_VIEW_ITEM (GNOME_CANVAS (view)->grabbed_item)) dia_canvas_item_ungrab (DIA_CANVAS_VIEW_ITEM (GNOME_CANVAS (view)->grabbed_item)->item); if (view->text_view) { text_view = GTK_WIDGET (view->text_view); } else { text_view = gtk_text_view_new (); view->text_view = g_object_ref (text_view); gtk_layout_put (GTK_LAYOUT (view), text_view, 0, 0); gtk_container_set_resize_mode (GTK_CONTAINER (text_view), GTK_RESIZE_IMMEDIATE); g_signal_connect (text_view, "focus-out-event", G_CALLBACK (text_view_focus_out_cb), view); } /* Create a new, empty text buffer. This ensures that old settings * do not spoil the text display. */ text_buffer = gtk_text_buffer_new (NULL); gtk_text_view_set_buffer (view->text_view, text_buffer); g_signal_connect (text_buffer, "changed", G_CALLBACK (text_buffer_changed_cb), view); /* Set the text */ if (text_shape->text) gtk_text_buffer_set_text (text_buffer, text_shape->text, -1); /* set font */ if (text_shape->font_desc) gtk_widget_modify_font (text_view, text_shape->font_desc); /* select the text */ gtk_text_buffer_get_bounds (text_buffer, &start, &end); gtk_text_buffer_place_cursor (text_buffer, &start); mark = gtk_text_buffer_get_selection_bound (text_buffer); gtk_text_buffer_move_mark (text_buffer, mark, &end); /* We still have a reference to our text buffer */ g_object_unref (text_buffer); gtk_text_view_set_cursor_visible (view->text_view, TRUE); /* justify + alignment, wrap_mode, line_spacing */ if (text_shape->justify) { gtk_text_view_set_justification (view->text_view, GTK_JUSTIFY_FILL); } else { GtkJustification j = 0; switch (text_shape->alignment) { case PANGO_ALIGN_LEFT: j = GTK_JUSTIFY_LEFT; break; case PANGO_ALIGN_CENTER: j = GTK_JUSTIFY_CENTER; break; case PANGO_ALIGN_RIGHT: j = GTK_JUSTIFY_RIGHT; break; default: g_assert_not_reached (); } gtk_text_view_set_justification (view->text_view, j); } switch (text_shape->wrap_mode) { case DIA_WRAP_CHAR: gtk_text_view_set_wrap_mode (view->text_view, GTK_WRAP_CHAR); break; case DIA_WRAP_WORD: gtk_text_view_set_wrap_mode (view->text_view, GTK_WRAP_WORD); break; case DIA_WRAP_NONE: default: gtk_text_view_set_wrap_mode (view->text_view, GTK_WRAP_NONE); } gtk_text_view_set_pixels_inside_wrap (view->text_view, (int) (text_shape->line_spacing + 0.5)); gtk_text_view_set_pixels_below_lines (view->text_view, (int) (text_shape->line_spacing + 0.5)); /* Set those after we set the text, this will prevent the * DiaCanvasEditable::text_changed signal from being emited. */ view->edited_item = item; view->edited_shape = text_shape; gtk_widget_show (text_view); dia_canvas_view_update_text_view (view); gtk_widget_grab_focus (text_view); } /** * dia_canvas_view_editing_done: * @view: * * This function should be called if a piece of text is being edited. * The editing will end after this function is called. **/ void dia_canvas_view_editing_done (DiaCanvasView *view) { GtkTextBuffer *text_buffer; GtkTextIter start, end; gchar *str; g_return_if_fail (DIA_IS_CANVAS_VIEW (view)); g_return_if_fail (GTK_IS_TEXT_VIEW (view->text_view)); g_return_if_fail (DIA_IS_CANVAS_VIEW_ITEM (view->edited_item)); g_return_if_fail (DIA_IS_CANVAS_ITEM (view->edited_item->item)); g_return_if_fail (view->edited_shape != NULL); g_return_if_fail (((DiaShape*) view->edited_shape)->type == DIA_SHAPE_TEXT); text_buffer = gtk_text_view_get_buffer (view->text_view); gtk_text_buffer_get_bounds (text_buffer, &start, &end); str = gtk_text_buffer_get_text (text_buffer, &start, &end, TRUE); dia_canvas_editable_editing_done (DIA_CANVAS_EDITABLE (view->edited_item->item), view->edited_shape, str); g_free (str); view->edited_item = NULL; view->edited_shape = NULL; /* Seems to crash: */ //gtk_widget_hide (GTK_WIDGET (view->text_view)); /* Maybe this will work: */ gtk_container_remove (GTK_CONTAINER (view), GTK_WIDGET (view->text_view)); g_object_unref (view->text_view); view->text_view = NULL; } /** * dia_canvas_view_get_active_view: * * This function returns the view that was last edited (by mouse click or * key event). * * Return value: The last used view. **/ DiaCanvasView* dia_canvas_view_get_active_view (void) { if (G_IS_OBJECT (active_view)) return active_view; return NULL; }