Files
gimp/plug-ins/imagemap/imap_preview.c
Alx Sa f9df980585 plug-ins: Convert custom ImageMap icons to vectors
Adds SVG versions of ImageMap custom
icons and conditionally uses them if
have_vector_icons is enabled. If not, we
fall back to the original PNG icons.
Since ImageMap mixes custom and
stock icons, this keeps the icon size
consistent across the UI.

Per Denis Rangelov, tooltips for the
coordinates and area displays as well
as the shortcut menu were added.

Also, removes a reference to IMAP_ARROW
which no longer applies since that icon
was removed in favor of using the stock
cursor icon.
2024-08-02 00:01:55 +00:00

399 lines
12 KiB
C

/*
* This is a plug-in for GIMP.
*
* Generates clickable image maps.
*
* Copyright (C) 1998-2005 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 <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "imap_commands.h"
#include "imap_grid.h"
#include "imap_main.h"
#include "imap_menu.h"
#include "imap_preview.h"
#include "libgimp/stdplugins-intl.h"
#define PREVIEW_MASK (GDK_EXPOSURE_MASK | \
GDK_POINTER_MOTION_MASK | \
GDK_BUTTON_PRESS_MASK | \
GDK_BUTTON_RELEASE_MASK | \
GDK_BUTTON_MOTION_MASK | \
GDK_KEY_PRESS_MASK | \
GDK_KEY_RELEASE_MASK | \
GDK_ENTER_NOTIFY_MASK | \
GDK_LEAVE_NOTIFY_MASK)
#define PREVIEW_WIDTH 600
#define PREVIEW_HEIGHT 400
/*======================================================================
Preview Rendering Util routine
=======================================================================*/
#define CHECKWIDTH 4
#define LIGHTCHECK 192
#define DARKCHECK 128
#ifndef OPAQUE
#define OPAQUE 255
#endif
static Object_t *_tmp_obj;
static Preview_t*
preview_user_data(GtkWidget *preview)
{
return (Preview_t*) g_object_get_data (G_OBJECT (preview), "preview");
}
gint
preview_get_width(GtkWidget *preview)
{
return preview_user_data(preview)->width;
}
gint
preview_get_height(GtkWidget *preview)
{
return preview_user_data(preview)->height;
}
static void
render_background(Preview_t *preview_base)
{
GtkWidget *preview = preview_base->preview;
gimp_preview_area_fill (GIMP_PREVIEW_AREA (preview),
0, 0, G_MAXINT, G_MAXINT,
255, 255, 255);
}
static void
render_rgb_image (Preview_t *preview_base,
GimpDrawable *drawable)
{
GeglBuffer *buffer;
guchar *dest_buffer;
gint dwidth, dheight, pwidth, pheight;
GtkWidget *preview = preview_base->preview;
dwidth = gimp_drawable_get_width (drawable);
dheight = gimp_drawable_get_height (drawable);
pwidth = preview_base->widget_width;
pheight = preview_base->widget_height;
dest_buffer = g_new (guchar, pwidth * pheight * 4);
buffer = gimp_drawable_get_buffer (drawable);
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, pwidth, pheight),
MIN ((gdouble) pwidth / (gdouble) dwidth,
(gdouble) pheight / (gdouble) dheight),
babl_format ("R'G'B'A u8"), dest_buffer,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
g_object_unref (buffer);
gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
0, 0, pwidth, pheight,
GIMP_RGBA_IMAGE,
dest_buffer,
pwidth * 4);
g_free (dest_buffer);
}
static void
render_preview (Preview_t *preview_base,
GimpDrawable *drawable)
{
render_background (preview_base);
render_rgb_image (preview_base, drawable);
}
static gboolean
arrow_cb (GtkWidget *widget,
GdkEventButton *event,
gpointer data)
{
if (event->button == 1)
do_main_popup_menu (event, data);
return TRUE;
}
static gboolean
preview_draw (GtkWidget *widget,
cairo_t *cr)
{
gint width = preview_get_width (widget);
gint height = preview_get_height (widget);
cairo_set_line_width (cr, 1.);
draw_grid (cr, width, height);
draw_shapes (cr);
if (_tmp_obj)
{
/* this is a bit of a hack */
gdouble dash = 4.;
_tmp_obj->selected |= 4;
cairo_set_source_rgb (cr, 1., 0., 1.);
cairo_set_dash (cr, &dash, 1, dash);
object_draw (_tmp_obj, cr);
}
return FALSE;
}
void
preview_set_tmp_obj (Object_t *obj)
{
_tmp_obj = obj;
}
void
preview_unset_tmp_obj (Object_t *obj)
{
if (_tmp_obj == obj) _tmp_obj = NULL;
}
void
preview_zoom (Preview_t *preview,
gfloat zoom_factor)
{
preview->widget_width = ceil (preview->width * zoom_factor);
preview->widget_height = ceil (preview->height * zoom_factor);
gtk_widget_set_size_request (preview->preview, preview->widget_width,
preview->widget_height);
gtk_widget_queue_resize (preview->window);
render_preview (preview, preview->drawable);
preview_redraw ();
}
GdkCursorType
preview_set_cursor(Preview_t *preview, GdkCursorType cursor_type)
{
GdkCursorType prev_cursor = preview->cursor;
GdkDisplay *display = gtk_widget_get_display (preview->window);
GdkCursor *cursor = gdk_cursor_new_for_display (display,
cursor_type);
gdk_window_set_cursor(gtk_widget_get_window (preview->window), cursor);
g_object_unref (cursor);
preview->cursor = cursor_type;
return prev_cursor;
}
static const GtkTargetEntry target_table[] =
{
{"STRING", 0, 1 },
{"text/plain", 0, 2 }
};
static void
handle_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
GtkSelectionData *data, guint info, guint time)
{
gboolean success = FALSE;
if (gtk_selection_data_get_length (data) >= 0 &&
gtk_selection_data_get_format (data) == 8)
{
ObjectList_t *list = get_shapes();
Object_t *obj;
x = get_real_coord(x);
y = get_real_coord(y);
obj = object_list_find(list, x, y);
if (obj && !obj->locked)
{
command_list_add(edit_object_command_new(obj));
object_set_url(obj, (const gchar *) gtk_selection_data_get_data (data));
object_emit_update_signal(obj);
success = TRUE;
}
}
gtk_drag_finish(context, success, FALSE, time);
}
static void
preview_size_allocate (GtkWidget *widget,
GtkAllocation *allocation,
gpointer preview_void)
{
Preview_t *preview = preview_void;
render_preview (preview, preview->drawable);
}
static void
scroll_adj_changed (GtkAdjustment *adj,
GimpRuler *ruler)
{
gimp_ruler_set_range (ruler,
gtk_adjustment_get_value (adj),
gtk_adjustment_get_value (adj) +
gtk_adjustment_get_page_size (adj),
gtk_adjustment_get_upper (adj));
}
Preview_t *
make_preview (GimpDrawable *drawable,
gpointer imap)
{
Preview_t *data = g_new (Preview_t, 1);
GtkAdjustment *hadj;
GtkAdjustment *vadj;
GtkWidget *preview;
GtkWidget *window;
GtkWidget *viewport;
GtkWidget *button, *arrow;
GtkWidget *ruler;
GtkWidget *grid;
GtkWidget *scrollbar;
gint width, height;
data->drawable = drawable;
data->preview = preview = gimp_preview_area_new ();
g_object_set_data (G_OBJECT (preview), "preview", data);
gtk_widget_set_events (GTK_WIDGET (preview), PREVIEW_MASK);
g_signal_connect_after (preview, "draw",
G_CALLBACK (preview_draw),
data);
g_signal_connect (preview, "size-allocate",
G_CALLBACK (preview_size_allocate),
data);
/* Handle drop of links in preview widget */
gtk_drag_dest_set (preview, GTK_DEST_DEFAULT_ALL, target_table,
2, GDK_ACTION_COPY);
g_signal_connect (preview, "drag-data-received",
G_CALLBACK (handle_drop),
NULL);
data->widget_width = data->width = gimp_drawable_get_width (drawable);
data->widget_height = data->height = gimp_drawable_get_height (drawable);
gtk_widget_set_size_request (preview, data->widget_width,
data->widget_height);
/* The main grid */
data->window = grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 1);
gtk_grid_set_column_spacing (GTK_GRID (grid), 1);
/* Create button with arrow */
button = gtk_button_new ();
gtk_widget_set_can_focus (button, FALSE);
gtk_widget_set_tooltip_text (button, _("Shortcut Menu"));
gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);
// GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_set_events (button,
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
gtk_widget_show (button);
g_signal_connect (button, "button-press-event",
G_CALLBACK (arrow_cb),
imap);
arrow = gtk_image_new_from_icon_name (GIMP_ICON_GO_NEXT,
GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), arrow);
gtk_widget_show (arrow);
/* Create horizontal ruler */
data->hruler = ruler = gimp_ruler_new (GTK_ORIENTATION_HORIZONTAL);
g_signal_connect_swapped (preview, "motion-notify-event",
G_CALLBACK (GTK_WIDGET_GET_CLASS (ruler)->motion_notify_event),
ruler);
gtk_widget_set_hexpand (ruler, TRUE);
gtk_grid_attach (GTK_GRID (grid), ruler, 1, 0, 1, 1);
gtk_widget_show (ruler);
/* Create vertical ruler */
data->vruler = ruler = gimp_ruler_new (GTK_ORIENTATION_VERTICAL);
g_signal_connect_swapped (preview, "motion-notify-event",
G_CALLBACK (GTK_WIDGET_GET_CLASS (ruler)->motion_notify_event),
ruler);
gtk_widget_set_vexpand (ruler, TRUE);
gtk_grid_attach (GTK_GRID (grid), ruler, 0, 1, 1, 1);
gtk_widget_show (ruler);
window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window),
GTK_POLICY_EXTERNAL, GTK_POLICY_EXTERNAL);
width = (data->width > PREVIEW_WIDTH) ? PREVIEW_WIDTH : data->width;
height = (data->height > PREVIEW_HEIGHT) ? PREVIEW_HEIGHT : data->height;
gtk_widget_set_size_request (window, width, height);
gtk_grid_attach (GTK_GRID (grid), window, 1, 1, 1, 1);
gtk_widget_show (window);
viewport = gtk_viewport_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), viewport);
gtk_widget_show (viewport);
hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (window));
g_signal_connect (hadj, "changed",
G_CALLBACK (scroll_adj_changed),
data->hruler);
g_signal_connect (hadj, "value-changed",
G_CALLBACK (scroll_adj_changed),
data->hruler);
vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (window));
g_signal_connect (vadj, "changed",
G_CALLBACK (scroll_adj_changed),
data->vruler);
g_signal_connect (vadj, "value-changed",
G_CALLBACK (scroll_adj_changed),
data->vruler);
gtk_container_add (GTK_CONTAINER (viewport), preview);
scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, hadj);
gtk_grid_attach (GTK_GRID (grid), scrollbar, 1, 2, 1, 1);
// GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
gtk_widget_show (scrollbar);
scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, vadj);
gtk_grid_attach (GTK_GRID (grid), scrollbar, 2, 1, 1, 1);
// GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
gtk_widget_show (scrollbar);
gtk_widget_show (preview);
render_preview (data, drawable);
gtk_widget_show (grid);
return data;
}