diff options
Diffstat (limited to 'plug-ins/imagemap/imap_rectangle.c')
-rw-r--r-- | plug-ins/imagemap/imap_rectangle.c | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/plug-ins/imagemap/imap_rectangle.c b/plug-ins/imagemap/imap_rectangle.c new file mode 100644 index 0000000..fa4c3a9 --- /dev/null +++ b/plug-ins/imagemap/imap_rectangle.c @@ -0,0 +1,538 @@ +/* + * This is a plug-in for GIMP. + * + * Generates clickable image maps. + * + * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl + * + * 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 3 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, see <https://www.gnu.org/licenses/>. + * + */ + +#include "config.h" + +#include <stdlib.h> /* abs */ + +#include <gtk/gtk.h> + +#include <libgimp/gimp.h> +#include <libgimp/gimpui.h> + +#include "imap_main.h" +#include "imap_misc.h" +#include "imap_object_popup.h" +#include "imap_rectangle.h" +#include "imap_stock.h" +#include "imap_table.h" + +#include "libgimp/stdplugins-intl.h" + + +static gboolean rectangle_is_valid(Object_t *obj); +static Object_t *rectangle_clone(Object_t *obj); +static void rectangle_assign(Object_t *obj, Object_t *des); +static void rectangle_normalize(Object_t *obj); +static void rectangle_draw(Object_t *obj, cairo_t *cr); +static void rectangle_draw_sashes(Object_t *obj, cairo_t *cr); +static MoveSashFunc_t rectangle_near_sash(Object_t *obj, gint x, gint y); +static gboolean rectangle_point_is_on(Object_t *obj, gint x, gint y); +static void rectangle_get_dimensions(Object_t *obj, gint *x, gint *y, + gint *width, gint *height); +static void rectangle_resize(Object_t *obj, gint percentage_x, + gint percentage_y); +static void rectangle_move(Object_t *obj, gint dx, gint dy); +static gpointer rectangle_create_info_widget(GtkWidget *frame); +static void rectangle_fill_info_tab(Object_t *obj, gpointer data); +static void rectangle_set_initial_focus(Object_t *obj, gpointer data); +static void rectangle_update(Object_t *obj, gpointer data); +static void rectangle_write_csim(Object_t *obj, gpointer param, + OutputFunc_t output); +static void rectangle_write_cern(Object_t *obj, gpointer param, + OutputFunc_t output); +static void rectangle_write_ncsa(Object_t *obj, gpointer param, + OutputFunc_t output); +static const gchar* rectangle_get_stock_icon_name(void); + +static ObjectClass_t rectangle_class = { + N_("_Rectangle"), + NULL, /* info_dialog */ + + rectangle_is_valid, + NULL, /* rectangle_destruct */ + rectangle_clone, + rectangle_assign, + rectangle_normalize, + rectangle_draw, + rectangle_draw_sashes, + rectangle_near_sash, + rectangle_point_is_on, + rectangle_get_dimensions, + rectangle_resize, + rectangle_move, + rectangle_create_info_widget, + rectangle_fill_info_tab, /* rectangle_update_info_widget */ + rectangle_fill_info_tab, + rectangle_set_initial_focus, + rectangle_update, + rectangle_write_csim, + rectangle_write_cern, + rectangle_write_ncsa, + object_do_popup, + rectangle_get_stock_icon_name +}; + +Object_t* +create_rectangle(gint x, gint y, gint width, gint height) +{ + Rectangle_t *rectangle = g_new(Rectangle_t, 1); + rectangle->x = x; + rectangle->y = y; + rectangle->width = width; + rectangle->height = height; + return object_init(&rectangle->obj, &rectangle_class); +} + +static void +draw_any_rectangle(cairo_t *cr, gint x, gint y, gint w, gint h) +{ + if (w < 0) { + x += w; + w = -w; + } + if (h < 0) { + y += h; + h = -h; + } + draw_rectangle(cr, FALSE, x, y, w, h); +} + +static gboolean +rectangle_is_valid(Object_t *obj) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + return rectangle->width && rectangle->height; +} + +static Object_t* +rectangle_clone(Object_t *obj) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + Rectangle_t *clone = g_new(Rectangle_t, 1); + + clone->x = rectangle->x; + clone->y = rectangle->y; + clone->width = rectangle->width; + clone->height = rectangle->height; + return &clone->obj; +} + +static void +rectangle_assign(Object_t *obj, Object_t *des) +{ + Rectangle_t *src_rectangle = ObjectToRectangle(obj); + Rectangle_t *des_rectangle = ObjectToRectangle(des); + des_rectangle->x = src_rectangle->x; + des_rectangle->y = src_rectangle->y; + des_rectangle->width = src_rectangle->width; + des_rectangle->height = src_rectangle->height; +} + +static void +rectangle_normalize(Object_t *obj) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + if (rectangle->width < 0) { + rectangle->x += rectangle->width; + rectangle->width = -rectangle->width; + } + if (rectangle->height < 0) { + rectangle->y += rectangle->height; + rectangle->height = -rectangle->height; + } +} + +static void +rectangle_draw(Object_t *obj, cairo_t *cr) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + draw_any_rectangle(cr, rectangle->x, rectangle->y, + rectangle->width, rectangle->height); +} + +static void +rectangle_draw_sashes(Object_t *obj, cairo_t *cr) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + draw_sash(cr, rectangle->x, rectangle->y); + draw_sash(cr, rectangle->x + rectangle->width / 2, rectangle->y); + draw_sash(cr, rectangle->x + rectangle->width, rectangle->y); + draw_sash(cr, rectangle->x, rectangle->y + rectangle->height / 2); + draw_sash(cr, rectangle->x + rectangle->width, + rectangle->y + rectangle->height / 2); + draw_sash(cr, rectangle->x, rectangle->y + rectangle->height); + draw_sash(cr, rectangle->x + rectangle->width / 2, + rectangle->y + rectangle->height); + draw_sash(cr, rectangle->x + rectangle->width, + rectangle->y + rectangle->height); +} + +static void +MoveUpperSash(Object_t *obj, gint dx, gint dy) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->y += dy; + rectangle->height -= dy; +} + +static void +MoveLeftSash(Object_t *obj, gint dx, gint dy) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->x += dx; + rectangle->width -= dx; +} + +static void +MoveRightSash(Object_t *obj, gint dx, gint dy) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->width += dx; +} + +static void +MoveLowerSash(Object_t *obj, gint dx, gint dy) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->height += dy; +} + +static void +MoveUpperLeftSash(Object_t *obj, gint dx, gint dy) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->x += dx; + rectangle->y += dy; + rectangle->width -= dx; + rectangle->height -= dy; +} + +static void +MoveUpperRightSash(Object_t *obj, gint dx, gint dy) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->y += dy; + rectangle->width += dx; + rectangle->height -= dy; +} + +static void +MoveLowerLeftSash(Object_t *obj, gint dx, gint dy) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->x += dx; + rectangle->width -= dx; + rectangle->height += dy; +} + +static void +MoveLowerRightSash(Object_t *obj, gint dx, gint dy) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->width += dx; + rectangle->height += dy; +} + +static MoveSashFunc_t +rectangle_near_sash(Object_t *obj, gint x, gint y) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + if (near_sash(rectangle->x, rectangle->y, x, y)) + return MoveUpperLeftSash; + else if (near_sash(rectangle->x + rectangle->width / 2, rectangle->y, x, y)) + return MoveUpperSash; + else if (near_sash(rectangle->x + rectangle->width, rectangle->y, x, y)) + return MoveUpperRightSash; + else if (near_sash(rectangle->x, rectangle->y + rectangle->height / 2, + x, y)) + return MoveLeftSash; + else if (near_sash(rectangle->x + rectangle->width, + rectangle->y + rectangle->height / 2, x, y)) + return MoveRightSash; + else if (near_sash(rectangle->x, rectangle->y + rectangle->height, x, y)) + return MoveLowerLeftSash; + else if (near_sash(rectangle->x + rectangle->width / 2, + rectangle->y + rectangle->height, x, y)) + return MoveLowerSash; + else if (near_sash(rectangle->x + rectangle->width, + rectangle->y + rectangle->height, x, y)) + return MoveLowerRightSash; + return NULL; +} + +static gboolean +rectangle_point_is_on(Object_t *obj, gint x, gint y) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + return x >= rectangle->x && x <= rectangle->x + rectangle->width && + y >= rectangle->y && y <= rectangle->y + rectangle->height; +} + +static void +rectangle_get_dimensions(Object_t *obj, gint *x, gint *y, + gint *width, gint *height) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + *x = rectangle->x; + *y = rectangle->y; + *width = rectangle->width; + *height = rectangle->height; +} + +static void +rectangle_resize(Object_t *obj, gint percentage_x, gint percentage_y) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->x = rectangle->x * percentage_x / 100; + rectangle->y = rectangle->y * percentage_y / 100; + rectangle->width = rectangle->width * percentage_x / 100; + rectangle->height = rectangle->height * percentage_y / 100; +} + +static void +rectangle_move(Object_t *obj, gint dx, gint dy) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + rectangle->x += dx; + rectangle->y += dy; +} + +typedef struct { + Object_t *obj; + GtkWidget *x; + GtkWidget *y; + GtkWidget *width; + GtkWidget *height; + GtkWidget *chain_button; +} RectangleProperties_t; + +static void +x_changed_cb(GtkWidget *widget, gpointer data) +{ + RectangleProperties_t *props = (RectangleProperties_t*) data; + Object_t *obj = props->obj; + gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); + + if (gimp_chain_button_get_active(GIMP_CHAIN_BUTTON(props->chain_button))) + gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->y), x); + + ObjectToRectangle(obj)->x = x; + edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog); +} + +static void +y_changed_cb(GtkWidget *widget, gpointer data) +{ + Object_t *obj = ((RectangleProperties_t*) data)->obj; + gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); + ObjectToRectangle(obj)->y = y; + edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog); +} + +static void +width_changed_cb(GtkWidget *widget, gpointer data) +{ + Object_t *obj = ((RectangleProperties_t*) data)->obj; + gint width = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); + ObjectToRectangle(obj)->width = width; + edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog); +} + +static void +height_changed_cb(GtkWidget *widget, gpointer data) +{ + Object_t *obj = ((RectangleProperties_t*) data)->obj; + gint height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); + ObjectToRectangle(obj)->height = height; + edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog); +} + +static gpointer +rectangle_create_info_widget(GtkWidget *frame) +{ + RectangleProperties_t *props = g_new(RectangleProperties_t, 1); + GtkWidget *table, *label, *chain_button; + gint max_width = get_image_width(); + gint max_height = get_image_height(); + + table = gtk_table_new(4, 4, FALSE); + gtk_container_add(GTK_CONTAINER(frame), table); + + gtk_table_set_row_spacings(GTK_TABLE(table), 6); + gtk_table_set_col_spacings(GTK_TABLE(table), 6); + gtk_widget_show(table); + + label = create_label_in_table(table, 0, 0, _("Upper left _x:")); + props->x = create_spin_button_in_table(table, label, 0, 1, 1, 0, + max_width - 1); + g_signal_connect(props->x, "value-changed", + G_CALLBACK(x_changed_cb), (gpointer) props); + create_label_in_table(table, 0, 3, _("pixels")); + + label = create_label_in_table(table, 1, 0, _("Upper left _y:")); + props->y = create_spin_button_in_table(table, label, 1, 1, 1, 0, + max_height - 1); + g_signal_connect(props->y, "value-changed", + G_CALLBACK(y_changed_cb), (gpointer) props); + create_label_in_table(table, 1, 3, _("pixels")); + + label = create_label_in_table(table, 2, 0, _("_Width:")); + props->width = create_spin_button_in_table(table, label, 2, 1, 1, 1, + max_width); + g_signal_connect(props->width, "value-changed", + G_CALLBACK(width_changed_cb), (gpointer) props); + create_label_in_table(table, 2, 3, _("pixels")); + + label = create_label_in_table(table, 3, 0, _("_Height:")); + props->height = create_spin_button_in_table(table, label, 3, 1, 1, 1, + max_height); + g_signal_connect(props->height, "value-changed", + G_CALLBACK(height_changed_cb), (gpointer) props); + create_label_in_table(table, 3, 3, _("pixels")); + + chain_button = gimp_chain_button_new(GIMP_CHAIN_RIGHT); + props->chain_button = chain_button; + gtk_table_attach_defaults(GTK_TABLE(table), chain_button, 2, 3, 2, 4); + gtk_widget_show(chain_button); + + return props; +} + +static void +rectangle_fill_info_tab(Object_t *obj, gpointer data) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + RectangleProperties_t *props = (RectangleProperties_t*) data; + + props->obj = obj; + gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->x), rectangle->x); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->y), rectangle->y); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->width), rectangle->width); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->height), + rectangle->height); +} + +static void +rectangle_set_initial_focus(Object_t *obj, gpointer data) +{ + RectangleProperties_t *props = (RectangleProperties_t*) data; + gtk_widget_grab_focus(props->x); +} + +static void +rectangle_update(Object_t* obj, gpointer data) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + RectangleProperties_t *props = (RectangleProperties_t*) data; + + rectangle->x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(props->x)); + rectangle->y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(props->y)); + rectangle->width = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(props->width)); + rectangle->height = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(props->height)); +} + +static void +rectangle_write_csim(Object_t *obj, gpointer param, OutputFunc_t output) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + output(param, "\"rect\" coords=\"%d,%d,%d,%d\"", rectangle->x, rectangle->y, + rectangle->x + rectangle->width, rectangle->y + rectangle->height); +} + +static void +rectangle_write_cern(Object_t *obj, gpointer param, OutputFunc_t output) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + output(param, "rect (%d,%d) (%d,%d)", rectangle->x, rectangle->y, + rectangle->x + rectangle->width, rectangle->y + rectangle->height); +} + +static void +rectangle_write_ncsa(Object_t *obj, gpointer param, OutputFunc_t output) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + output(param, "rect %s %d,%d %d,%d", obj->url, + rectangle->x, rectangle->y, + rectangle->x + rectangle->width, rectangle->y + rectangle->height); +} + +static const gchar* +rectangle_get_stock_icon_name(void) +{ + return IMAP_STOCK_RECTANGLE; +} + +static gboolean +rectangle_factory_finish(Object_t *obj, gint x, gint y) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + + rectangle->width = x - rectangle->x; + rectangle->height = y - rectangle->y; + + rectangle_normalize(obj); + + return TRUE; +} + +static Object_t* +rectangle_factory_create_object(gint x, gint y) +{ + return create_rectangle(x, y, 0, 0); +} + +static void +rectangle_factory_set_xy(Object_t *obj, guint state, gint x, gint y) +{ + Rectangle_t *rectangle = ObjectToRectangle(obj); + + rectangle->width = x - rectangle->x; + rectangle->height = y - rectangle->y; + + if (state & GDK_SHIFT_MASK){ + gint width = abs(rectangle->width); + gint height = abs(rectangle->height); + if (width < height) + rectangle->height = (rectangle->height < 0) ? -width : width; + else + rectangle->width = (rectangle->width < 0) ? -height : height; + } + + main_set_dimension(rectangle->width, rectangle->height); +} + +static ObjectFactory_t rectangle_factory = { + NULL, /* Object pointer */ + rectangle_factory_finish, + NULL, /* Cancel func */ + rectangle_factory_create_object, + rectangle_factory_set_xy +}; + +ObjectFactory_t* +get_rectangle_factory(guint state) +{ + return &rectangle_factory; +} |