Commit 8dd2ee9a authored by Paolo Bacchilega's avatar Paolo Bacchilega

added ability to drag an image from the viewer

Fixes #24
parent f2eab2da
......@@ -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);
}
......
......@@ -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;
}
......@@ -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 */
......@@ -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;
}
......@@ -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
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment