[gthumb] added ability to drag an image from the viewer
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] added ability to drag an image from the viewer
- Date: Mon, 22 Apr 2019 10:08:22 +0000 (UTC)
commit 8dd2ee9ab86af929163c5baccab2deeaa218840c
Author: Paolo Bacchilega <paobac src gnome org>
Date: Mon Apr 22 11:50:44 2019 +0200
added ability to drag an image from the viewer
Fixes https://gitlab.gnome.org/GNOME/gthumb/issues/24
extensions/image_viewer/gth-image-viewer-page.c | 69 +++++++++++++
gthumb/cairo-utils.c | 82 ++++++++++++++++
gthumb/cairo-utils.h | 8 ++
gthumb/gth-image-dragger.c | 125 ++++++++++++++++++++----
gthumb/gth-image-dragger.h | 10 +-
gthumb/gth-image-viewer.c | 31 +++++-
6 files changed, 298 insertions(+), 27 deletions(-)
---
diff --git a/extensions/image_viewer/gth-image-viewer-page.c b/extensions/image_viewer/gth-image-viewer-page.c
index b1509d70..bf64b0ec 100644
--- a/extensions/image_viewer/gth-image-viewer-page.c
+++ b/extensions/image_viewer/gth-image-viewer-page.c
@@ -106,6 +106,7 @@ struct _GthImageViewerPagePrivate {
gboolean apply_icc_profile;
GthFileData *next_file_data[N_FORWARD_PRELOADERS];
GthFileData *prev_file_data[N_BACKWARD_PRELOADERS];
+ gulong drag_data_get_event;
};
@@ -1991,6 +1992,8 @@ gth_image_viewer_page_init (GthImageViewerPage *self)
self->priv->next_file_data[i] = NULL;
for (i = 0; i < N_BACKWARD_PRELOADERS; i++)
self->priv->prev_file_data[i] = NULL;
+
+ self->priv->drag_data_get_event = 0;
}
@@ -2096,6 +2099,70 @@ gth_image_viewer_page_reset (GthImageViewerPage *self)
}
+static void
+viewer_drag_data_get_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *data,
+ guint info,
+ guint time,
+ gpointer user_data)
+{
+ GthImageViewerPage *self = user_data;
+ char *uris[2];
+
+ if (self->priv->file_data == NULL)
+ return;
+
+ uris[0] = g_file_get_uri (self->priv->file_data->file);
+ uris[1] = NULL;
+ gtk_selection_data_set_uris (data, (char **) uris);
+
+ g_free (uris[0]);
+}
+
+
+static void
+_gth_image_viewer_page_enable_drag_source (GthImageViewerPage *self,
+ gboolean enable)
+{
+ GthImageViewerTool *dragger;
+ GtkTargetList *source_target_list;
+ GtkTargetEntry *source_targets;
+ int n_source_targets;
+
+ dragger = gth_image_viewer_get_tool (GTH_IMAGE_VIEWER (self->priv->viewer));
+ if (! GTH_IS_IMAGE_DRAGGER (dragger))
+ return;
+
+ if (! enable) {
+ if (self->priv->drag_data_get_event > 0) {
+ g_signal_handler_disconnect (self->priv->viewer, self->priv->drag_data_get_event);
+ self->priv->drag_data_get_event = 0;
+ }
+ gth_image_dragger_disable_drag_source (GTH_IMAGE_DRAGGER (dragger));
+ return;
+ }
+
+ source_target_list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add_uri_targets (source_target_list, 0);
+ gtk_target_list_add_text_targets (source_target_list, 0);
+ source_targets = gtk_target_table_new_from_list (source_target_list, &n_source_targets);
+ gth_image_dragger_enable_drag_source (GTH_IMAGE_DRAGGER (dragger),
+ GDK_BUTTON1_MASK,
+ source_targets,
+ n_source_targets,
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ gtk_target_table_free (source_targets, n_source_targets);
+ gtk_target_list_unref (source_target_list);
+
+ if (self->priv->drag_data_get_event == 0)
+ self->priv->drag_data_get_event = g_signal_connect (self->priv->viewer,
+ "drag-data-get",
+ G_CALLBACK (viewer_drag_data_get_cb),
+ self);
+}
+
+
void
gth_image_viewer_page_reset_viewer_tool (GthImageViewerPage *self)
{
@@ -2112,6 +2179,8 @@ gth_image_viewer_page_reset_viewer_tool (GthImageViewerPage *self)
g_settings_get_enum (self->priv->settings,
PREF_IMAGE_VIEWER_ZOOM_CHANGE));
gth_image_viewer_set_reset_scrollbars (GTH_IMAGE_VIEWER (self->priv->viewer),
g_settings_get_boolean (self->priv->settings,
PREF_IMAGE_VIEWER_RESET_SCROLLBARS));
+
+ _gth_image_viewer_page_enable_drag_source (self, TRUE);
}
diff --git a/gthumb/cairo-utils.c b/gthumb/cairo-utils.c
index babed8b8..77cc75d5 100644
--- a/gthumb/cairo-utils.c
+++ b/gthumb/cairo-utils.c
@@ -23,6 +23,8 @@
#include <math.h>
#include <string.h>
#include "cairo-utils.h"
+#include "cairo-scale.h"
+#include "gth-image-utils.h"
G_DEFINE_BOXED_TYPE (GthCairoSurface,
@@ -1208,3 +1210,83 @@ _cairo_create_checked_pattern (int size)
return pattern;
}
+
+
+void
+_cairo_draw_thumbnail_frame (cairo_t *cr,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ /* the drop shadow */
+
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.33);
+ _cairo_draw_rounded_box (cr,
+ x + 2,
+ y + 2,
+ width - 1,
+ height - 1,
+ 0);
+ cairo_fill (cr);
+
+ /* the outer frame */
+
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ _cairo_draw_rounded_box (cr,
+ x,
+ y,
+ width - 1,
+ height - 1,
+ 0);
+ cairo_fill_preserve (cr);
+
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.55);
+ cairo_stroke (cr);
+}
+
+
+#define DRAG_ICON_BORDER 8
+#define DRAG_ICON_THUMBNAIL_OFFSET 3
+
+
+cairo_surface_t *
+_cairo_create_dnd_icon (cairo_surface_t *image,
+ int icon_size,
+ gboolean multi_dnd)
+{
+ int width, height;
+ cairo_surface_t *thumbnail;
+ cairo_surface_t *icon;
+ cairo_t *cr;
+
+ width = cairo_image_surface_get_width (image);
+ height = cairo_image_surface_get_height (image);
+ scale_keeping_ratio (&width, &height, icon_size, icon_size, FALSE);
+ thumbnail = _cairo_image_surface_scale_fast (image, width, height);
+
+ icon = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ width + DRAG_ICON_BORDER + (multi_dnd ? DRAG_ICON_BORDER : 0),
+ height + DRAG_ICON_BORDER + (multi_dnd ? DRAG_ICON_BORDER : 0));
+ cr = cairo_create (icon);
+
+ if (multi_dnd)
+ _cairo_draw_thumbnail_frame (cr, DRAG_ICON_THUMBNAIL_OFFSET, DRAG_ICON_THUMBNAIL_OFFSET,
width + DRAG_ICON_BORDER - 1, height + DRAG_ICON_BORDER - 1);
+ _cairo_draw_thumbnail_frame (cr, 0, 0, width + DRAG_ICON_BORDER - 1, height + DRAG_ICON_BORDER - 1);
+
+
+ cairo_save (cr);
+ cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+ cairo_set_source_surface (cr, thumbnail, DRAG_ICON_THUMBNAIL_OFFSET, DRAG_ICON_THUMBNAIL_OFFSET);
+ cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
+ cairo_rectangle (cr, DRAG_ICON_THUMBNAIL_OFFSET, DRAG_ICON_THUMBNAIL_OFFSET, width, height);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ cairo_surface_set_device_offset (icon, -width / 2, -height / 2);
+
+ cairo_surface_destroy (thumbnail);
+ cairo_destroy (cr);
+
+ return icon;
+}
diff --git a/gthumb/cairo-utils.h b/gthumb/cairo-utils.h
index 83888114..30be7e6c 100644
--- a/gthumb/cairo-utils.h
+++ b/gthumb/cairo-utils.h
@@ -266,5 +266,13 @@ void _cairo_paint_grid (cairo_t
cairo_rectangle_int_t *rectangle,
GthGridType grid_type);
cairo_pattern_t * _cairo_create_checked_pattern (int size);
+void _cairo_draw_thumbnail_frame (cairo_t *cr,
+ int x,
+ int y,
+ int width,
+ int height);
+cairo_surface_t * _cairo_create_dnd_icon (cairo_surface_t *image,
+ int icon_size,
+ gboolean multi_dnd);
#endif /* CAIRO_UTILS_H */
diff --git a/gthumb/gth-image-dragger.c b/gthumb/gth-image-dragger.c
index 1a117d98..4433a123 100644
--- a/gthumb/gth-image-dragger.c
+++ b/gthumb/gth-image-dragger.c
@@ -32,6 +32,7 @@
#define SIZE_TOO_BIG_FOR_SCALE_BILINEAR (3000 * 3000)
#define MAX_ZOOM_LEVEL_FOR_HIGH_QUALITY 3.0
#define FRAME_BORDER 15
+#define DRAG_ICON_SIZE 128
/* Properties */
@@ -43,11 +44,20 @@ enum {
struct _GthImageDraggerPrivate {
GthImageViewer *viewer;
- gboolean draggable;
+ gboolean scrollable;
gboolean show_frame;
cairo_surface_t *scaled;
double scaled_zoom;
GthTask *scale_task;
+
+ /* drag & drop */
+
+ gboolean dnd_source_enabled;
+ GdkModifierType dnd_start_button_mask;
+ GtkTargetList *dnd_target_list;
+ GdkDragAction dnd_actions;
+ gboolean dnd_started;
+ gboolean dnd_began;
};
@@ -74,6 +84,10 @@ gth_image_dragger_finalize (GObject *object)
_cairo_clear_surface (&self->priv->scaled);
if (self->priv->scale_task != NULL)
gth_task_cancel (self->priv->scale_task);
+ if (self->priv->dnd_target_list != NULL) {
+ gtk_target_list_unref (self->priv->dnd_target_list);
+ self->priv->dnd_target_list = NULL;
+ }
/* Chain up */
G_OBJECT_CLASS (gth_image_dragger_parent_class)->finalize (object);
@@ -157,8 +171,15 @@ gth_image_dragger_init (GthImageDragger *dragger)
dragger->priv->scaled_zoom = 0;
dragger->priv->scale_task = NULL;
dragger->priv->viewer = NULL;
- dragger->priv->draggable = FALSE;
+ dragger->priv->scrollable = FALSE;
dragger->priv->show_frame = FALSE;
+
+ dragger->priv->dnd_source_enabled = FALSE;
+ dragger->priv->dnd_start_button_mask = 0;
+ dragger->priv->dnd_target_list = NULL;
+ dragger->priv->dnd_actions = 0;
+ dragger->priv->dnd_started = FALSE;
+ dragger->priv->dnd_began = FALSE;
}
@@ -235,7 +256,7 @@ gth_image_dragger_size_allocate (GthImageViewerTool *base,
h_upper = gtk_adjustment_get_upper (viewer->hadj);
v_upper = gtk_adjustment_get_upper (viewer->vadj);
- self->priv->draggable = (h_page_size > 0) && (v_page_size > 0) && ((h_upper > h_page_size) ||
(v_upper > v_page_size));
+ self->priv->scrollable = (h_page_size > 0) && (v_page_size > 0) && ((h_upper > h_page_size) ||
(v_upper > v_page_size));
if (gtk_widget_get_realized (GTK_WIDGET (viewer)))
_gth_image_dragger_update_cursor (self);
}
@@ -310,11 +331,10 @@ gth_image_dragger_button_press (GthImageViewerTool *self,
viewer = dragger->priv->viewer;
widget = GTK_WIDGET (viewer);
- if (! dragger->priv->draggable)
- return FALSE;
-
- if (((event->button == 1) || (event->button == 2)) &&
- ! viewer->dragging) {
+ if (dragger->priv->scrollable
+ && ! viewer->dragging
+ && ((event->button == 1) || (event->button == 2)))
+ {
GdkCursor *cursor;
GdkGrabStatus retval;
@@ -340,6 +360,18 @@ gth_image_dragger_button_press (GthImageViewerTool *self,
return TRUE;
}
+ if (dragger->priv->dnd_source_enabled
+ && ! viewer->dragging
+ && (event->button == 1)
+ && (event->type == GDK_BUTTON_PRESS)
+ && ! (event->state & GDK_CONTROL_MASK)
+ && ! (event->state & GDK_SHIFT_MASK))
+ {
+ viewer->pressed = TRUE;
+ viewer->dragging = TRUE;
+ dragger->priv->dnd_began = FALSE;
+ }
+
return FALSE;
}
@@ -351,16 +383,16 @@ gth_image_dragger_button_release (GthImageViewerTool *self,
GthImageDragger *dragger;
GthImageViewer *viewer;
- if ((event->button != 1) && (event->button != 2))
- return FALSE;
-
dragger = (GthImageDragger *) self;
viewer = dragger->priv->viewer;
- if (viewer->dragging)
+ if (dragger->priv->scrollable && viewer->dragging)
gdk_seat_ungrab (gdk_device_get_seat (event->device));
- return TRUE;
+ if (dragger->priv->dnd_source_enabled && viewer->dragging)
+ dragger->priv->dnd_began = FALSE;
+
+ return FALSE;
}
@@ -374,16 +406,46 @@ gth_image_dragger_motion_notify (GthImageViewerTool *self,
dragger = (GthImageDragger *) self;
viewer = dragger->priv->viewer;
- if (! viewer->pressed)
- return FALSE;
+ if (dragger->priv->scrollable && viewer->dragging) {
+ gth_image_viewer_scroll_to (viewer,
+ viewer->drag_x_start - event->x,
+ viewer->drag_y_start - event->y);
+ return TRUE;
+ }
+
+ if (dragger->priv->dnd_source_enabled
+ && viewer->dragging
+ && ! dragger->priv->dnd_began
+ && gtk_drag_check_threshold (GTK_WIDGET (viewer),
+ viewer->drag_x_start,
+ viewer->drag_y_start,
+ event->x,
+ event->y))
+ {
+ GdkDragContext *context;
+ cairo_surface_t *image;
+
+ context = gtk_drag_begin_with_coordinates (GTK_WIDGET (viewer),
+ dragger->priv->dnd_target_list,
+ dragger->priv->dnd_actions,
+ 1,
+ (GdkEvent *) event,
+ viewer->drag_x_start,
+ viewer->drag_y_start);
+
+ image = gth_image_viewer_get_current_image (GTH_IMAGE_VIEWER (viewer));
+ if (image != NULL) {
+ cairo_surface_t *icon = _cairo_create_dnd_icon (image, DRAG_ICON_SIZE, FALSE);
+ gtk_drag_set_icon_surface (context, icon);
+ cairo_surface_destroy (icon);
+ }
- viewer->dragging = TRUE;
+ dragger->priv->dnd_began = TRUE;
- gth_image_viewer_scroll_to (viewer,
- viewer->drag_x_start - event->x,
- viewer->drag_y_start - event->y);
+ return TRUE;
+ }
- return TRUE;
+ return FALSE;
}
@@ -594,3 +656,26 @@ gth_image_dragger_new (gboolean show_frame)
"show-frame", show_frame,
NULL);
}
+
+
+void
+gth_image_dragger_enable_drag_source (GthImageDragger *self,
+ GdkModifierType start_button_mask,
+ const GtkTargetEntry *targets,
+ int n_targets,
+ GdkDragAction actions)
+{
+ if (self->priv->dnd_target_list != NULL)
+ gtk_target_list_unref (self->priv->dnd_target_list);
+
+ self->priv->dnd_source_enabled = TRUE;
+ self->priv->dnd_start_button_mask = start_button_mask;
+ self->priv->dnd_target_list = gtk_target_list_new (targets, n_targets);
+ self->priv->dnd_actions = actions;
+}
+
+void
+gth_image_dragger_disable_drag_source (GthImageDragger *self)
+{
+ self->priv->dnd_source_enabled = FALSE;
+}
diff --git a/gthumb/gth-image-dragger.h b/gthumb/gth-image-dragger.h
index 102d64b4..1effb230 100644
--- a/gthumb/gth-image-dragger.h
+++ b/gthumb/gth-image-dragger.h
@@ -51,8 +51,14 @@ struct _GthImageDraggerClass
GObjectClass __parent_class;
};
-GType gth_image_dragger_get_type (void);
-GthImageViewerTool * gth_image_dragger_new (gboolean show_frame);
+GType gth_image_dragger_get_type (void);
+GthImageViewerTool * gth_image_dragger_new (gboolean show_frame);
+void gth_image_dragger_enable_drag_source (GthImageDragger *self,
+ GdkModifierType start_button_mask,
+ const GtkTargetEntry *targets,
+ int n_targets,
+ GdkDragAction actions);
+void gth_image_dragger_disable_drag_source (GthImageDragger *self);
G_END_DECLS
diff --git a/gthumb/gth-image-viewer.c b/gthumb/gth-image-viewer.c
index 923c3fc9..fc0e022a 100644
--- a/gthumb/gth-image-viewer.c
+++ b/gthumb/gth-image-viewer.c
@@ -863,6 +863,17 @@ gth_image_viewer_button_press (GtkWidget *widget,
return retval;
}
+static void
+_gth_image_viewer_button_release (GthImageViewer *self,
+ GdkEventButton *event)
+{
+ gth_image_viewer_tool_button_release (self->priv->tool, event);
+
+ self->priv->just_focused = FALSE;
+ self->pressed = FALSE;
+ self->dragging = FALSE;
+}
+
static gboolean
gth_image_viewer_button_release (GtkWidget *widget,
@@ -880,11 +891,7 @@ gth_image_viewer_button_release (GtkWidget *widget,
0);
}
- gth_image_viewer_tool_button_release (self->priv->tool, event);
-
- self->priv->just_focused = FALSE;
- self->pressed = FALSE;
- self->dragging = FALSE;
+ _gth_image_viewer_button_release (self, event);
return FALSE;
}
@@ -1010,6 +1017,19 @@ gth_image_viewer_scroll_event (GtkWidget *widget,
}
+static void
+gth_image_viewer_drag_end (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ GthImageViewer *self;
+
+ g_return_if_fail (GTH_IS_IMAGE_VIEWER (widget));
+
+ self = GTH_IMAGE_VIEWER (widget);
+ _gth_image_viewer_button_release (self, NULL);
+}
+
+
static void
scroll_relative (GthImageViewer *self,
int delta_x,
@@ -1355,6 +1375,7 @@ gth_image_viewer_class_init (GthImageViewerClass *class)
widget_class->button_release_event = gth_image_viewer_button_release;
widget_class->motion_notify_event = gth_image_viewer_motion_notify;
widget_class->scroll_event = gth_image_viewer_scroll_event;
+ widget_class->drag_end = gth_image_viewer_drag_end;
class->clicked = NULL;
class->zoom_changed = NULL;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]