393 lines
12 KiB
C
393 lines
12 KiB
C
|
/*
|
||
|
* This is a plug-in for PIKA.
|
||
|
*
|
||
|
* 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 <libpika/pika.h>
|
||
|
#include <libpika/pikaui.h>
|
||
|
|
||
|
#include "imap_commands.h"
|
||
|
#include "imap_grid.h"
|
||
|
#include "imap_main.h"
|
||
|
#include "imap_menu.h"
|
||
|
#include "imap_preview.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_SIZE 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;
|
||
|
|
||
|
pika_preview_area_fill (PIKA_PREVIEW_AREA (preview),
|
||
|
0, 0, G_MAXINT, G_MAXINT,
|
||
|
255, 255, 255);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
render_rgb_image (Preview_t *preview_base,
|
||
|
PikaDrawable *drawable)
|
||
|
{
|
||
|
GeglBuffer *buffer;
|
||
|
guchar *dest_buffer;
|
||
|
gint dwidth, dheight, pwidth, pheight;
|
||
|
GtkWidget *preview = preview_base->preview;
|
||
|
|
||
|
dwidth = pika_drawable_get_width (drawable);
|
||
|
dheight = pika_drawable_get_height (drawable);
|
||
|
pwidth = preview_base->widget_width;
|
||
|
pheight = preview_base->widget_height;
|
||
|
|
||
|
dest_buffer = g_new (guchar, pwidth * pheight * 4);
|
||
|
|
||
|
buffer = pika_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);
|
||
|
|
||
|
pika_preview_area_draw (PIKA_PREVIEW_AREA (preview),
|
||
|
0, 0, pwidth, pheight,
|
||
|
PIKA_RGBA_IMAGE,
|
||
|
dest_buffer,
|
||
|
pwidth * 4);
|
||
|
|
||
|
g_free (dest_buffer);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
render_preview (Preview_t *preview_base,
|
||
|
PikaDrawable *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, gint zoom_factor)
|
||
|
{
|
||
|
preview->widget_width = preview->width * zoom_factor;
|
||
|
preview->widget_height = 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,
|
||
|
PikaRuler *ruler)
|
||
|
{
|
||
|
pika_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 (PikaDrawable *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 = pika_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 = pika_drawable_get_width (drawable);
|
||
|
data->widget_height = data->height = pika_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_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 (PIKA_ICON_GO_NEXT,
|
||
|
GTK_ICON_SIZE_BUTTON);
|
||
|
gtk_container_add (GTK_CONTAINER (button), arrow);
|
||
|
gtk_widget_show (arrow);
|
||
|
|
||
|
/* Create horizontal ruler */
|
||
|
data->hruler = ruler = pika_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 = pika_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_NEVER, GTK_POLICY_NEVER);
|
||
|
width = (data->width > 600) ? 600 : data->width;
|
||
|
height = (data->height > 400) ? 400 : 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;
|
||
|
}
|