/* dia-canvas-text.c * Copyright (C) 2002-2003 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-text.h" #include "dia-canvas-editable.h" #include "dia-handle.h" #include "dia-shape.h" #include #include #include "diamarshal.h" #include "dia-canvas-i18n.h" /* Key syms */ #include /* Text pasting support: */ #include enum { PROP_FONT = 1, PROP_TEXT, PROP_CURSOR, PROP_HEIGHT, PROP_WIDTH, PROP_EDITABLE, PROP_MARKUP, PROP_MULTILINE, PROP_WRAP_WORD, PROP_COLOR, PROP_ALIGNMENT, PROP_LAYOUT }; static void dia_canvas_text_class_init (DiaCanvasTextClass *klass); static void dia_canvas_text_editable_init (DiaCanvasEditableIface *editable); static void dia_canvas_text_init (DiaCanvasText *item); static void dia_canvas_text_dispose (GObject *object); static void dia_canvas_text_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void dia_canvas_text_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); static void dia_canvas_text_update_shape (DiaCanvasText *text); static void dia_canvas_text_update (DiaCanvasItem *item, gdouble affine[6]); static gboolean dia_canvas_text_get_shape_iter (DiaCanvasItem *item, DiaCanvasIter *iter); static gboolean dia_canvas_text_shape_next (DiaCanvasItem *item, DiaCanvasIter *iter); static DiaShape* dia_canvas_text_shape_value (DiaCanvasItem *item, DiaCanvasIter *iter); static gdouble dia_canvas_text_point (DiaCanvasItem *item, gdouble x, gdouble y); /* Interface functions: */ static DiaShapeText* dia_canvas_text_get_editable_shape (DiaCanvasEditable *editable, gdouble x, gdouble y); static void dia_canvas_text_editable_start_editing (DiaCanvasEditable *editable, DiaShapeText *text_shape); static void dia_canvas_text_editable_editing_done (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *new_text); static void dia_canvas_text_editable_text_changed (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *new_text); static DiaCanvasItemClass *parent_class = NULL; GType dia_canvas_text_get_type (void) { static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof (DiaCanvasTextClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) dia_canvas_text_class_init, (GClassFinalizeFunc) NULL, (gconstpointer) NULL, /* class_data */ sizeof (DiaCanvasText), (guint16) 0, /* n_preallocs */ (GInstanceInitFunc) dia_canvas_text_init, }; static const GInterfaceInfo editable_info = { (GInterfaceInitFunc) dia_canvas_text_editable_init, NULL, NULL, }; object_type = g_type_register_static (DIA_TYPE_CANVAS_ITEM, "DiaCanvasText", &object_info, 0); g_type_add_interface_static (object_type, DIA_TYPE_CANVAS_EDITABLE, &editable_info); } return object_type; } static void dia_canvas_text_class_init (DiaCanvasTextClass *klass) { GObjectClass *object_class; DiaCanvasItemClass *item_class; object_class = (GObjectClass*) klass; item_class = DIA_CANVAS_ITEM_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->dispose = dia_canvas_text_dispose; object_class->get_property = dia_canvas_text_get_property; object_class->set_property = dia_canvas_text_set_property; item_class->update = dia_canvas_text_update; item_class->point = dia_canvas_text_point; item_class->get_shape_iter = dia_canvas_text_get_shape_iter; item_class->shape_next = dia_canvas_text_shape_next; item_class->shape_value = dia_canvas_text_shape_value; g_object_class_install_property (object_class, PROP_FONT, g_param_spec_boxed ("font", _("Font description"), _(""), PANGO_TYPE_FONT_DESCRIPTION, G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_TEXT, g_param_spec_string ("text", _("Text"), _("Text to be displayed"), NULL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_CURSOR, g_param_spec_int ("cursor", _("Cursor"), _("Position of the cursor in the text"), -1, G_MAXINT, 1, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_WIDTH, g_param_spec_double ("width", _("Width"), _("Width of the text"), 0.0, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_HEIGHT, g_param_spec_double ("height", _("Height"), _("Height of the text"), 0.0, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_EDITABLE, g_param_spec_boolean ("editable", _("Editable"), _("Text is editable"), TRUE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_MARKUP, g_param_spec_boolean ("markup", _("Markup"), _("Text has markup symbols"), FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_WRAP_WORD, g_param_spec_boolean ("wrap_word", _("Text wrap word"), _(""), TRUE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_MULTILINE, g_param_spec_boolean ("multiline", _("Multiline"), _("Multiline text"), TRUE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_COLOR, g_param_spec_ulong ("color", _("Color"), _("Color of the text in RGBA"), 0, G_MAXULONG, 0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_ALIGNMENT, g_param_spec_enum ("alignment", _("Text alignmment"), _(""), PANGO_TYPE_ALIGNMENT, PANGO_ALIGN_LEFT, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_LAYOUT, g_param_spec_object ("layout", _("Layout"), _("Layout of the text"), PANGO_TYPE_LAYOUT, G_PARAM_READABLE)); } static void dia_canvas_text_editable_init (DiaCanvasEditableIface *editable) { editable->get_editable_shape = dia_canvas_text_get_editable_shape; editable->start_editing = dia_canvas_text_editable_start_editing; editable->editing_done = dia_canvas_text_editable_editing_done; editable->text_changed = dia_canvas_text_editable_text_changed; } static void dia_canvas_text_init (DiaCanvasText *item) { item->text = g_string_new (NULL); item->width = item->height = 0.0; item->wrap_word = TRUE; item->multiline = TRUE; item->editable = TRUE; item->text_shape = dia_shape_new (DIA_SHAPE_TEXT); DIA_CANVAS_ITEM_FLAGS (item) |= DIA_COMPOSITE; } static void dia_canvas_text_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { DiaCanvasText *text = (DiaCanvasText*) (object); switch (property_id) { case PROP_FONT: dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "font"); if (g_value_get_boxed (value)) dia_shape_text_set_font_description (text->text_shape, g_value_get_boxed (value)); else dia_shape_text_set_font_description (text->text_shape, NULL); dia_canvas_item_request_update (DIA_CANVAS_ITEM (text)); break; case PROP_TEXT: dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "text"); if (g_value_get_string (value)) g_string_assign (text->text, g_value_get_string (value)); else g_string_assign (text->text, ""); dia_canvas_item_request_update (DIA_CANVAS_ITEM (text)); break; case PROP_CURSOR: g_message ("The property 'cursor' of DiaCanvasText is not supported anymore"); break; case PROP_HEIGHT: dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "height"); text->height = g_value_get_double (value); dia_canvas_item_request_update (DIA_CANVAS_ITEM (text)); break; case PROP_WIDTH: dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "width"); text->width = g_value_get_double (value); dia_canvas_item_request_update (DIA_CANVAS_ITEM (text)); break; case PROP_EDITABLE: if (text->markup) { static gboolean is_issued = FALSE; if (!is_issued) { g_warning ("You should not use 'editable' in " "conjunction with 'markup'!"); is_issued = TRUE; } } dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "editable"); text->editable = g_value_get_boolean (value); dia_canvas_item_request_update (DIA_CANVAS_ITEM (text)); break; case PROP_MARKUP: if (text->editable) { static gboolean is_issued = FALSE; if (!is_issued) { g_warning ("You should not use 'editable' in " "conjunction with 'markup'!"); is_issued = TRUE; } } dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "markup"); text->markup = g_value_get_boolean (value); // TODO: convert text to/from marked up text dia_canvas_item_request_update (DIA_CANVAS_ITEM (text)); break; case PROP_WRAP_WORD: dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "wrap-word"); text->wrap_word = g_value_get_boolean (value); dia_canvas_item_request_update (DIA_CANVAS_ITEM (text)); break; case PROP_MULTILINE: dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "multiline"); text->multiline = g_value_get_boolean (value); dia_canvas_item_request_update (DIA_CANVAS_ITEM (text)); break; case PROP_COLOR: dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "color"); dia_shape_set_color (text->text_shape, g_value_get_ulong (value)); dia_canvas_item_request_update (DIA_CANVAS_ITEM (object)); break; case PROP_ALIGNMENT: dia_canvas_item_preserve_property (DIA_CANVAS_ITEM (text), "alignment"); dia_shape_text_set_alignment (text->text_shape, g_value_get_enum (value)); dia_canvas_item_request_update (DIA_CANVAS_ITEM (object)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dia_canvas_text_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_TEXT: if (DIA_CANVAS_TEXT (object)->text) g_value_set_string (value, DIA_CANVAS_TEXT (object)->text->str); else g_value_set_string (value, ""); break; case PROP_CURSOR: g_message ("The property 'cursor' of DiaCanvasText is not supported anymore"); break; case PROP_HEIGHT: g_value_set_double (value, DIA_CANVAS_TEXT (object)->height); break; case PROP_WIDTH: g_value_set_double (value, DIA_CANVAS_TEXT (object)->width); break; case PROP_EDITABLE: g_value_set_boolean (value, DIA_CANVAS_TEXT (object)->editable); break; case PROP_MARKUP: g_value_set_boolean (value, DIA_CANVAS_TEXT (object)->markup); break; case PROP_WRAP_WORD: g_value_set_boolean (value, DIA_CANVAS_TEXT (object)->wrap_word); break; case PROP_MULTILINE: g_value_set_boolean (value, DIA_CANVAS_TEXT (object)->multiline); break; case PROP_COLOR: g_value_set_ulong (value, DIA_CANVAS_TEXT (object)->text_shape->color); break; case PROP_ALIGNMENT: g_value_set_enum (value, ((DiaShapeText*) DIA_CANVAS_TEXT (object)->text_shape)->alignment); break; case PROP_LAYOUT: dia_canvas_text_update_shape (DIA_CANVAS_TEXT (object)); g_value_set_object_take_ownership (value, dia_shape_text_to_pango_layout (DIA_CANVAS_TEXT (object)->text_shape, TRUE)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dia_canvas_text_dispose (GObject *object) { DiaCanvasText *text = (DiaCanvasText *) object; if (text->text) { g_string_free (text->text, TRUE); text->text = NULL; } if (text->text_shape) { dia_shape_free (text->text_shape); text->text_shape = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); } static void dia_canvas_text_update_shape (DiaCanvasText *text) { dia_shape_text_set_static_text (text->text_shape, text->text->str); dia_shape_text_set_markup (text->text_shape, text->markup); dia_shape_text_set_max_width (text->text_shape, text->width); dia_shape_text_set_max_height (text->text_shape, text->height); dia_shape_text_set_wrap_mode (text->text_shape, text->wrap_word ? PANGO_WRAP_WORD : PANGO_WRAP_CHAR); if (text->multiline) // TODO: this causes the cursor placement to malfunction // for centered text... dia_shape_text_set_text_width (text->text_shape, text->width); else dia_shape_text_set_text_width (text->text_shape, 0); /* if (text->editable) dia_shape_text_set_cursor (text->text_shape, text->cursor); else dia_shape_text_set_cursor (text->text_shape, -1); */ } static void dia_canvas_text_update (DiaCanvasItem *item, gdouble affine[6]) { DiaCanvasText *text = (DiaCanvasText*) item; //g_message(G_STRLOC); if (DIA_CANVAS_ITEM_CLASS (parent_class)->update) DIA_CANVAS_ITEM_CLASS (parent_class)->update (item, affine); //g_message (G_STRLOC": need_update = %d", item->flags & DIA_NEED_UPDATE); if (text->text->str) { dia_canvas_text_update_shape (text); item->bounds.top = 0.0; item->bounds.left = 0.0; item->bounds.bottom = text->height; item->bounds.right = text->width; } else { item->bounds.top = 0.0; item->bounds.left = 0.0; item->bounds.bottom = 0.0; item->bounds.right = 0.0; } //g_message (G_STRLOC": need_update = %d", item->flags & DIA_NEED_UPDATE); } static gboolean dia_canvas_text_get_shape_iter (DiaCanvasItem *item, DiaCanvasIter *iter) { iter->data[0] = DIA_CANVAS_TEXT (item)->text_shape; return TRUE; } static gboolean dia_canvas_text_shape_next (DiaCanvasItem *item, DiaCanvasIter *iter) { return FALSE; } static DiaShape* dia_canvas_text_shape_value (DiaCanvasItem *item, DiaCanvasIter *iter) { return iter->data[0]; } static gdouble dia_canvas_text_point (DiaCanvasItem *item, gdouble x, gdouble y) { DiaPoint p; p.x = x; p.y = y; return dia_distance_rectangle_point (&item->bounds, &p); } static DiaShapeText* dia_canvas_text_get_editable_shape (DiaCanvasEditable *editable, gdouble x, gdouble y) { return (DiaShapeText*) (DIA_CANVAS_TEXT (editable)->text_shape); } static void dia_canvas_text_editable_start_editing (DiaCanvasEditable *editable, DiaShapeText *text_shape) { } static void dia_canvas_text_editable_editing_done (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *new_text) { g_object_set (G_OBJECT (editable), "text", new_text, NULL); } static void dia_canvas_text_editable_text_changed (DiaCanvasEditable *editable, DiaShapeText *text_shape, const gchar *new_text) { g_object_set (G_OBJECT (editable), "text", new_text, NULL); dia_canvas_text_update_shape (DIA_CANVAS_TEXT (editable)); }