summaryrefslogtreecommitdiff
path: root/src/sheet/textbox-item.c
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2018-07-12 23:03:42 +0200
committerRuben Undheim <ruben.undheim@gmail.com>2018-07-12 23:03:42 +0200
commit1eb59a5d9eedcb2fde4cfcd8f3cf87edf18e71e4 (patch)
tree4d3a9112d9887ea16ab5dda07a7a791f15d3278f /src/sheet/textbox-item.c
New upstream version 0.70
Diffstat (limited to 'src/sheet/textbox-item.c')
-rw-r--r--src/sheet/textbox-item.c699
1 files changed, 699 insertions, 0 deletions
diff --git a/src/sheet/textbox-item.c b/src/sheet/textbox-item.c
new file mode 100644
index 0000000..2354c55
--- /dev/null
+++ b/src/sheet/textbox-item.c
@@ -0,0 +1,699 @@
+/*
+ * textbox-item.c
+ *
+ *
+ * Author:
+ * Richard Hult <rhult@hem.passagen.se>
+ * Ricardo Markiewicz <rmarkie@fi.uba.ar>
+ * Andres de Barbara <adebarbara@fi.uba.ar>
+ *
+ * Web page: http://arrakis.lug.fi.uba.ar/
+ *
+ * Copyright (C) 1999-2001 Richard Hult
+ * Copyright (C) 2003,2006 Ricardo Markiewicz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * TextboxItem object: the graphical representation of a textbox.
+ *
+ * Author:
+ * Richard Hult (rhult@hem2.passagen.se)
+ *
+ * (C) 1999, 2000 Richard Hult, http://www.dtek.chalmers.se/~d4hult/oregano/
+ */
+
+#include <math.h>
+#include <gnome.h>
+#include <glade/glade.h>
+#include "cursors.h"
+#include "sheet-private.h"
+#include "sheet-pos.h"
+#include "textbox-item.h"
+#include "textbox.h"
+#include "dialogs.h"
+
+#define NORMAL_COLOR "black"
+#define SELECTED_COLOR "green"
+#define TEXTBOX_FONT "Arial 10"
+
+static void textbox_item_class_init (TextboxItemClass *klass);
+static void textbox_item_init (TextboxItem *item);
+static void textbox_item_destroy (GtkObject *object);
+static void textbox_item_moved (SheetItem *object);
+
+static void textbox_rotated_callback (ItemData *data, int angle,
+ SheetItem *sheet_item);
+static void textbox_flipped_callback (ItemData *data, gboolean horizontal,
+ SheetItem *sheet_item);
+static void textbox_moved_callback (ItemData *data, SheetPos *pos,
+ SheetItem *item);
+static void textbox_text_changed_callback (ItemData *data, gchar *new_text,
+ SheetItem *item);
+static void textbox_font_changed_callback (ItemData *data, gchar *new_font,
+ SheetItem *item);
+
+static void textbox_item_paste (SchematicView *sv, ItemData *data);
+static void selection_changed (TextboxItem *item, gboolean select,
+ gpointer user_data);
+static int select_idle_callback (TextboxItem *item);
+static int deselect_idle_callback (TextboxItem *item);
+static gboolean is_in_area (SheetItem *object, SheetPos *p1, SheetPos *p2);
+inline static void get_cached_bounds (TextboxItem *item, SheetPos *p1,
+ SheetPos *p2);
+
+static void textbox_item_place (SheetItem *item, SchematicView *sv);
+static void textbox_item_place_ghost (SheetItem *item, SchematicView *sv);
+
+static void edit_cmd (GtkWidget *widget, SchematicView *sv);
+static void edit_textbox (SheetItem *sheet_item);
+
+typedef struct {
+ GtkDialog *dialog;
+ GtkFontSelection *font;
+ GtkEntry *entry;
+} TextboxPropDialog;
+
+static TextboxPropDialog *prop_dialog = NULL;
+static SheetItemClass *textbox_item_parent_class = NULL;
+
+/* Use EDIT!! */
+static const char *textbox_item_context_menu =
+"<ui>"
+" <popup name='ItemMenu'>"
+" <menuitem action='EditText'/>"
+" </popup>"
+"</ui>";
+
+static GtkActionEntry action_entries[] = {
+ {"EditText", GTK_STOCK_PROPERTIES, N_("_Edit the text..."), NULL,
+ N_("Edit the text"),G_CALLBACK (edit_cmd)}
+};
+
+enum {
+ TEXTBOX_ITEM_ARG_0,
+ TEXTBOX_ITEM_ARG_NAME
+};
+
+struct _TextboxItemPriv {
+ guint cache_valid : 1;
+
+ guint highlight : 1;
+
+ // FIXME: More members.
+ GnomeCanvasItem *text_canvas_item;
+
+ /*
+ * Cached bounding box. This is used to make
+ * the rubberband selection a bit faster.
+ */
+ SheetPos bbox_start;
+ SheetPos bbox_end;
+};
+
+GType
+textbox_item_get_type ()
+{
+ static GType textbox_item_type = 0;
+
+ if (!textbox_item_type) {
+ static const GTypeInfo textbox_item_info = {
+ sizeof(TextboxItemClass),
+ NULL,
+ NULL,
+ (GClassInitFunc)textbox_item_class_init,
+ NULL,
+ NULL,
+ sizeof(TextboxItem),
+ 0,
+ (GInstanceInitFunc)textbox_item_init,
+ NULL
+ };
+
+ textbox_item_type = g_type_register_static(TYPE_SHEET_ITEM,
+ "TextboxItem", &textbox_item_info, 0);
+ }
+ return textbox_item_type;
+}
+
+static void
+textbox_item_class_init (TextboxItemClass *textbox_item_class)
+{
+ GObjectClass *object_class;
+ GtkObjectClass *gtk_object_class;
+ SheetItemClass *sheet_item_class;
+
+ object_class = G_OBJECT_CLASS(textbox_item_class);
+ gtk_object_class = GTK_OBJECT_CLASS(textbox_item_class);
+ sheet_item_class = SHEET_ITEM_CLASS(textbox_item_class);
+ textbox_item_parent_class =
+ g_type_class_peek_parent(textbox_item_class);
+
+ gtk_object_class->destroy = textbox_item_destroy;
+
+ sheet_item_class->moved = textbox_item_moved;
+ sheet_item_class->paste = textbox_item_paste;
+ sheet_item_class->is_in_area = is_in_area;
+ sheet_item_class->selection_changed = (gpointer) selection_changed;
+ sheet_item_class->edit_properties = edit_textbox;
+ sheet_item_class->place = textbox_item_place;
+ sheet_item_class->place_ghost = textbox_item_place_ghost;
+}
+
+static void
+textbox_item_init (TextboxItem *item)
+{
+ TextboxItemPriv *priv;
+
+ priv = g_new0 (TextboxItemPriv, 1);
+ item->priv = priv;
+
+ priv->highlight = FALSE;
+ priv->cache_valid = FALSE;
+
+ sheet_item_add_menu (SHEET_ITEM (item), textbox_item_context_menu,
+ action_entries, G_N_ELEMENTS (action_entries));
+}
+
+static void
+textbox_item_destroy (GtkObject *object)
+{
+ TextboxItem *textbox;
+ TextboxItemPriv *priv;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_TEXTBOX_ITEM (object));
+
+ textbox = TEXTBOX_ITEM (object);
+ priv = textbox->priv;
+
+ if (priv) {
+ if (priv->text_canvas_item) {
+ gtk_object_destroy(GTK_OBJECT(priv->text_canvas_item));
+ }
+ textbox->priv = NULL;
+ g_free (priv);
+ }
+
+ if (GTK_OBJECT_CLASS(textbox_item_parent_class)->destroy){
+ GTK_OBJECT_CLASS(textbox_item_parent_class)->destroy(object);
+ }
+}
+
+/*
+ * textbox_item_moved
+ *
+ * "moved" signal handler. Invalidates the bounding box cache.
+ */
+static void
+textbox_item_moved (SheetItem *object)
+{
+ TextboxItem *item;
+ TextboxItemPriv *priv;
+
+ item = TEXTBOX_ITEM (object);
+ priv = item->priv;
+
+ priv->cache_valid = FALSE;
+}
+
+TextboxItem *
+textbox_item_new (Sheet *sheet, Textbox *textbox)
+{
+ TextboxItem *item;
+ TextboxItemPriv *priv;
+ SheetPos pos;
+
+ g_return_val_if_fail(sheet != NULL, NULL);
+ g_return_val_if_fail(IS_SHEET(sheet), NULL);
+
+ item_data_get_pos(ITEM_DATA(textbox), &pos);
+
+ item = TEXTBOX_ITEM(gnome_canvas_item_new (
+ sheet->object_group,
+ textbox_item_get_type(),
+ "data", textbox,
+ "x", (double) pos.x,
+ "y", (double) pos.y,
+ NULL));
+
+ priv = item->priv;
+
+ priv->text_canvas_item = gnome_canvas_item_new (
+ GNOME_CANVAS_GROUP (item),
+ gnome_canvas_text_get_type (),
+ "x", 0.0,
+ "y", 0.0,
+ "text", textbox_get_text (textbox),
+ "fill_color", NORMAL_COLOR,
+ "anchor", GTK_ANCHOR_SW,
+ "font", TEXTBOX_FONT,
+ NULL);
+
+ g_signal_connect_object(G_OBJECT (textbox),
+ "rotated", G_CALLBACK(textbox_rotated_callback),
+ G_OBJECT(item), 0);
+ g_signal_connect_object(G_OBJECT (textbox),
+ "flipped", G_CALLBACK(textbox_flipped_callback),
+ G_OBJECT(item), 0);
+ g_signal_connect_object(G_OBJECT (textbox),
+ "moved", G_CALLBACK(textbox_moved_callback),
+ G_OBJECT(item), 0);
+ g_signal_connect_object(G_OBJECT (textbox),
+ "text_changed", G_CALLBACK(textbox_text_changed_callback),
+ G_OBJECT(item), 0);
+ g_signal_connect_object(G_OBJECT (textbox),
+ "font_changed", G_CALLBACK(textbox_font_changed_callback),
+ G_OBJECT(item), 0);
+
+ textbox_update_bbox (textbox);
+
+ return item;
+}
+
+void
+textbox_item_signal_connect_placed (TextboxItem *textbox_item,
+ SchematicView *sv)
+{
+ g_signal_connect (
+ G_OBJECT (textbox_item),
+ "event",
+ G_CALLBACK(sheet_item_event),
+ sv);
+}
+
+static void
+textbox_rotated_callback (ItemData *data, int angle, SheetItem *sheet_item)
+{
+ TextboxItem *item;
+
+ g_return_if_fail (sheet_item != NULL);
+ g_return_if_fail (IS_TEXTBOX_ITEM (sheet_item));
+
+ item = TEXTBOX_ITEM (sheet_item);
+
+ item->priv->cache_valid = FALSE;
+}
+
+static void
+textbox_flipped_callback (ItemData *data,
+ gboolean horizontal, SheetItem *sheet_item)
+{
+ TextboxItem *item;
+
+ g_return_if_fail (sheet_item != NULL);
+ g_return_if_fail (IS_TEXTBOX_ITEM (sheet_item));
+
+ item = TEXTBOX_ITEM (sheet_item);
+
+ item->priv->cache_valid = FALSE;
+}
+
+static int
+select_idle_callback (TextboxItem *item)
+{
+ SheetPos bbox_start, bbox_end;
+ TextboxItemPriv *priv = item->priv;
+
+ get_cached_bounds (item, &bbox_start, &bbox_end);
+ gnome_canvas_item_set (GNOME_CANVAS_ITEM (priv->text_canvas_item),
+ "fill_color", SELECTED_COLOR, NULL);
+
+ priv->highlight = TRUE;
+
+ return FALSE;
+}
+
+static int
+deselect_idle_callback (TextboxItem *item)
+{
+ TextboxItemPriv *priv = item->priv;
+
+ gnome_canvas_item_set (GNOME_CANVAS_ITEM (priv->text_canvas_item),
+ "fill_color", NORMAL_COLOR, NULL);
+
+ priv->highlight = FALSE;
+
+ return FALSE;
+}
+
+static void
+selection_changed (TextboxItem *item, gboolean select, gpointer user_data)
+{
+ if (select)
+ gtk_idle_add ((gpointer) select_idle_callback, item);
+ else
+ gtk_idle_add ((gpointer) deselect_idle_callback, item);
+}
+
+static gboolean
+is_in_area (SheetItem *object, SheetPos *p1, SheetPos *p2)
+{
+ TextboxItem *item;
+ SheetPos bbox_start, bbox_end;
+
+ item = TEXTBOX_ITEM (object);
+
+ get_cached_bounds (item, &bbox_start, &bbox_end);
+
+ if (p1->x < bbox_start.x &&
+ p2->x > bbox_end.x &&
+ p1->y < bbox_start.y &&
+ p2->y > bbox_end.y)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * Retrieves the bounding box. We use a caching scheme for this
+ * since it's too expensive to calculate it every time we need it.
+ */
+inline static void
+get_cached_bounds (TextboxItem *item, SheetPos *p1, SheetPos *p2)
+{
+ PangoFontDescription *font;
+ PangoFontMetrics *font_metric;
+ int width;
+ int rbearing;
+ int lbearing;
+ int ascent, descent;
+ SheetPos pos;
+
+ TextboxItemPriv *priv;
+ priv = item->priv;
+
+ if (!priv->cache_valid) {
+ SheetPos start_pos, end_pos;
+
+ font = pango_font_description_from_string(TEXTBOX_FONT);
+
+ item_data_get_pos (sheet_item_get_data (SHEET_ITEM (item)),
+ &pos);
+
+ start_pos.x = pos.x;
+ start_pos.y = pos.y-5;// - font->ascent;
+ end_pos.x = pos.x+5; // + rbearing;
+ end_pos.y = pos.y+5; // + font->descent;
+
+ priv->bbox_start = start_pos;
+ priv->bbox_end = end_pos;
+ priv->cache_valid = TRUE;
+ pango_font_description_free(font);
+ }
+
+ memcpy (p1, &priv->bbox_start, sizeof (SheetPos));
+ memcpy (p2, &priv->bbox_end, sizeof (SheetPos));
+
+}
+
+static void
+textbox_item_paste (SchematicView *sv, ItemData *data)
+{
+ g_return_if_fail (sv != NULL);
+ g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (IS_TEXTBOX (data));
+
+ schematic_view_add_ghost_item (sv, data);
+}
+
+/**
+ * This is called when the textbox data was moved. Update the view accordingly.
+ */
+static void
+textbox_moved_callback (ItemData *data, SheetPos *pos, SheetItem *item)
+{
+ TextboxItem *textbox_item;
+
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (IS_ITEM_DATA (data));
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (IS_TEXTBOX_ITEM (item));
+
+ if (pos == NULL)
+ return;
+
+ textbox_item = TEXTBOX_ITEM (item);
+
+ /*
+ * Move the canvas item and invalidate the bbox cache.
+ */
+ gnome_canvas_item_move (GNOME_CANVAS_ITEM (item), pos->x, pos->y);
+ textbox_item->priv->cache_valid = FALSE;
+}
+
+static void
+textbox_text_changed_callback (ItemData *data,
+ gchar *new_text, SheetItem *item)
+{
+ TextboxItem *textbox_item;
+
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (IS_ITEM_DATA (data));
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (IS_TEXTBOX_ITEM (item));
+
+ textbox_item = TEXTBOX_ITEM (item);
+
+ gnome_canvas_item_set (
+ GNOME_CANVAS_ITEM ( textbox_item->priv->text_canvas_item ),
+ "text", new_text, NULL );
+
+}
+
+static void
+textbox_font_changed_callback (ItemData *data,
+ gchar *new_font, SheetItem *item)
+{
+ TextboxItem *textbox_item;
+
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (IS_ITEM_DATA (data));
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (IS_TEXTBOX_ITEM (item));
+ g_return_if_fail (new_font != NULL);
+
+ textbox_item = TEXTBOX_ITEM (item);
+
+ gnome_canvas_item_set (
+ GNOME_CANVAS_ITEM (textbox_item->priv->text_canvas_item),
+ "font", new_font, NULL);
+}
+
+static void
+textbox_item_place (SheetItem *item, SchematicView *sv)
+{
+ textbox_item_signal_connect_placed (TEXTBOX_ITEM (item), sv);
+
+ g_signal_connect (
+ G_OBJECT (item),
+ "double_clicked",
+ G_CALLBACK(edit_textbox),
+ item);
+}
+
+static void
+textbox_item_place_ghost (SheetItem *item, SchematicView *sv)
+{
+// textbox_item_signal_connect_placed (TEXTBOX_ITEM (item));
+}
+
+static gboolean
+create_textbox_event (Sheet *sheet, GdkEvent *event, SchematicView *sv)
+{
+ switch (event->type) {
+ case GDK_3BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ return TRUE;
+
+ case GDK_BUTTON_PRESS:
+ if (event->button.button == 4 || event->button.button == 5)
+ return FALSE;
+
+ if (event->button.button == 1) {
+ if (sheet->state == SHEET_STATE_TEXTBOX_WAIT)
+ sheet->state = SHEET_STATE_TEXTBOX_START;
+
+ return TRUE;
+ } else
+ return FALSE;
+
+ case GDK_BUTTON_RELEASE:
+ if (event->button.button == 4 || event->button.button == 5)
+ return FALSE;
+
+ if (sheet->state == SHEET_STATE_TEXTBOX_START) {
+ Textbox *textbox;
+ SheetPos pos;
+
+ sheet->state = SHEET_STATE_NONE;
+
+ pos.x = event->button.x;
+ pos.y = event->button.y;
+
+ textbox = textbox_new (NULL);
+ item_data_set_pos (ITEM_DATA (textbox), &pos);
+ textbox_set_text (textbox, _("Label"));
+
+ schematic_add_item (schematic_view_get_schematic (sv),
+ ITEM_DATA (textbox));
+
+ g_signal_emit_by_name(G_OBJECT(sheet),
+ "reset_tool", NULL);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (sheet),
+ G_CALLBACK(create_textbox_event), sv);
+ }
+
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ void
+textbox_item_cancel_listen (SchematicView *sv)
+{
+ Sheet *sheet;
+
+ g_return_if_fail (sv != NULL);
+ g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
+
+ sheet = schematic_view_get_sheet (sv);
+
+ sheet->state = SHEET_STATE_NONE;
+ g_signal_handlers_disconnect_by_func (G_OBJECT (sheet), G_CALLBACK(create_textbox_event), sv);
+}
+
+void
+textbox_item_listen (SchematicView *sv)
+{
+ Sheet *sheet;
+
+ g_return_if_fail (sv != NULL);
+ g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
+
+// schematic_view_disconnect_handler (sv);
+ sheet = schematic_view_get_sheet (sv);
+
+ /*
+ * Connect to a signal handler that will
+ * let the user create a new textbox.
+ */
+ sheet->state = SHEET_STATE_TEXTBOX_WAIT;
+ g_signal_connect(G_OBJECT(sheet),
+ "event", G_CALLBACK(create_textbox_event), sv);
+}
+
+/*
+ * Go through the properties and commit the changes.
+ */
+static void
+edit_dialog_ok(TextboxItem *item)
+{
+ TextboxItemPriv *priv;
+ Textbox *textbox;
+ const gchar *value;
+
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (IS_TEXTBOX_ITEM (item));
+
+ priv = item->priv;
+ textbox = TEXTBOX (sheet_item_get_data (SHEET_ITEM (item)));
+
+ value = gtk_entry_get_text(GTK_ENTRY(prop_dialog->entry));
+
+ textbox_set_text(textbox, value);
+ textbox_set_font(textbox,
+ gtk_font_selection_get_font_name(prop_dialog->font));
+}
+
+static void
+edit_textbox (SheetItem *sheet_item)
+{
+ Sheet *sheet;
+ TextboxItem *item;
+ TextboxItemPriv *priv;
+ Textbox *textbox;
+ char *msg, *value;
+ GladeXML *gui;
+
+ g_return_if_fail (sheet_item != NULL);
+ g_return_if_fail (IS_TEXTBOX_ITEM (sheet_item));
+
+ item = TEXTBOX_ITEM (sheet_item);
+ priv = item->priv;
+ textbox = TEXTBOX (sheet_item_get_data (sheet_item));
+
+ if (!g_file_test (OREGANO_GLADEDIR "/textbox-properties-dialog.glade",
+ G_FILE_TEST_EXISTS)) {
+ msg = g_strdup_printf (
+ _("The file %s could not be found. You might need to reinstall Oregano to fix this."),
+ OREGANO_GLADEDIR "/textbox-properties-dialog.glade");
+ oregano_error (_("Could not create textbox properties dialog"));
+ g_free (msg);
+ return;
+ }
+
+ gui = glade_xml_new (
+ OREGANO_GLADEDIR "/textbox-properties-dialog.glade",
+ NULL, NULL);
+ if (!gui) {
+ oregano_error (_("Could not create textbox properties dialog"));
+ return;
+ }
+
+ prop_dialog = g_new0 (TextboxPropDialog, 1);
+ prop_dialog->dialog = GTK_DIALOG (
+ glade_xml_get_widget (gui, "textbox-properties-dialog"));
+ prop_dialog->font = GTK_FONT_SELECTION (
+ glade_xml_get_widget (gui, "font_selector"));
+ prop_dialog->entry = GTK_ENTRY (glade_xml_get_widget (gui, "entry"));
+
+ value = textbox_get_font (textbox);
+ gtk_font_selection_set_font_name (
+ GTK_FONT_SELECTION (prop_dialog->font), value);
+
+ value = textbox_get_text(textbox);
+ gtk_entry_set_text (GTK_ENTRY (prop_dialog->entry), value);
+
+ sheet = sheet_item_get_sheet (SHEET_ITEM (item));
+ sheet_dialog_set_parent (sheet, (GtkDialog*) prop_dialog->dialog);
+
+ gtk_dialog_set_default_response (
+ GTK_DIALOG (prop_dialog->dialog), GTK_RESPONSE_OK);
+
+ gtk_dialog_run( GTK_DIALOG (prop_dialog->dialog));
+
+ edit_dialog_ok(item);
+
+ /* Clean the dialog */
+ gtk_widget_destroy(GTK_WIDGET(prop_dialog->dialog));
+ prop_dialog = NULL;
+}
+
+static void
+edit_cmd (GtkWidget *widget, SchematicView *sv)
+{
+ GList *list;
+
+ list = schematic_view_get_selection (sv);
+ if ((list != NULL) && IS_TEXTBOX_ITEM (list->data))
+ edit_textbox (list->data);
+}