[gthumb] Added ability to drag multiple files
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] Added ability to drag multiple files
- Date: Sun, 25 Apr 2010 14:45:08 +0000 (UTC)
commit b09b61e61b879239f61e133f898b5568c7f47999
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sun Apr 25 16:39:42 2010 +0200
Added ability to drag multiple files
gthumb/gth-icon-view.c | 246 +++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 233 insertions(+), 13 deletions(-)
---
diff --git a/gthumb/gth-icon-view.c b/gthumb/gth-icon-view.c
index e34a18c..4fbe539 100644
--- a/gthumb/gth-icon-view.c
+++ b/gthumb/gth-icon-view.c
@@ -31,7 +31,23 @@
struct _GthIconViewPrivate {
- int selection_range_start;
+ /* selection */
+
+ int selection_range_start;
+ gboolean selection_pending;
+ int selection_pending_pos;
+
+ /* drag-and-drop */
+
+ gboolean drag_source_enabled;
+ GdkModifierType drag_start_button_mask;
+ GtkTargetList *drag_target_list;
+ GdkDragAction drag_actions;
+
+ gboolean dragging : 1; /* Whether the user is dragging items. */
+ gboolean drag_started : 1; /* Whether the drag has started. */
+ int drag_start_x; /* The position where the drag started. */
+ int drag_start_y;
};
@@ -204,24 +220,30 @@ gth_icon_view_real_set_spacing (GthFileView *self,
static void
-gth_icon_view_enable_drag_source (GthFileView *self,
+gth_icon_view_enable_drag_source (GthFileView *base,
GdkModifierType start_button_mask,
const GtkTargetEntry *targets,
int n_targets,
GdkDragAction actions)
{
- gtk_icon_view_enable_model_drag_source (GTK_ICON_VIEW (self),
- start_button_mask,
- targets,
- n_targets,
- actions);
+ GthIconView *self = GTH_ICON_VIEW (base);
+
+ if (self->priv->drag_target_list != NULL)
+ gtk_target_list_unref (self->priv->drag_target_list);
+
+ self->priv->drag_source_enabled = TRUE;
+ self->priv->drag_start_button_mask = start_button_mask;
+ self->priv->drag_target_list = gtk_target_list_new (targets, n_targets);
+ self->priv->drag_actions = actions;
}
static void
-gth_icon_view_unset_drag_source (GthFileView *self)
+gth_icon_view_unset_drag_source (GthFileView *base)
{
- gtk_icon_view_unset_model_drag_source (GTK_ICON_VIEW (self));
+ GthIconView *self = GTH_ICON_VIEW (base);
+
+ self->priv->drag_source_enabled = FALSE;
}
@@ -464,6 +486,13 @@ gtk_icon_view_add_move_binding (GtkBindingSet *binding_set,
static void
gth_icon_view_finalize (GObject *object)
{
+ GthIconView *self = GTH_ICON_VIEW (object);
+
+ if (self->priv->drag_target_list != NULL) {
+ gtk_target_list_unref (self->priv->drag_target_list);
+ self->priv->drag_target_list = NULL;
+ }
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -471,8 +500,9 @@ gth_icon_view_finalize (GObject *object)
static void
gth_icon_view_class_init (GthIconViewClass *klass)
{
- GObjectClass *object_class;
- GtkBindingSet *binding_set;
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkBindingSet *binding_set;
parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (klass, sizeof (GthIconViewPrivate));
@@ -480,6 +510,9 @@ gth_icon_view_class_init (GthIconViewClass *klass)
object_class = (GObjectClass*) klass;
object_class->finalize = gth_icon_view_finalize;
+ widget_class = (GtkWidgetClass*) klass;
+ widget_class->drag_begin = NULL;
+
binding_set = gtk_binding_set_by_class (klass);
gtk_icon_view_add_move_binding (binding_set, GDK_Right, 0,
@@ -489,15 +522,27 @@ gth_icon_view_class_init (GthIconViewClass *klass)
}
+static void
+stop_dragging (GthIconView *icon_view)
+{
+ if (! icon_view->priv->dragging)
+ return;
+ icon_view->priv->dragging = FALSE;
+ icon_view->priv->drag_started = FALSE;
+}
+
+
static gboolean
icon_view_button_press_event_cb (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
GthIconView *icon_view = user_data;
+ gboolean retval = FALSE;
if (event->button == 1) {
GtkTreePath *path;
+ int pos;
int new_selection_end;
path = gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (icon_view), event->x, event->y);
@@ -508,7 +553,28 @@ icon_view_button_press_event_cb (GtkWidget *widget,
return FALSE;
}
- new_selection_end = gtk_tree_path_get_indices (path)[0];
+ /* This can be the start of a dragging action. */
+
+ if (! (event->state & GDK_CONTROL_MASK)
+ && ! (event->state & GDK_SHIFT_MASK)
+ && icon_view->priv->drag_source_enabled)
+ {
+ icon_view->priv->dragging = TRUE;
+ icon_view->priv->drag_start_x = event->x;
+ icon_view->priv->drag_start_y = event->y;
+ }
+
+ /* Selection */
+
+ pos = gtk_tree_path_get_indices (path)[0];
+
+ if (! (event->state & GDK_CONTROL_MASK) && gth_file_selection_is_selected (GTH_FILE_SELECTION (icon_view), pos)) {
+ icon_view->priv->selection_pending = TRUE;
+ icon_view->priv->selection_pending_pos = pos;
+ retval = TRUE;
+ }
+
+ new_selection_end = pos;
if (event->state & GDK_SHIFT_MASK) {
int selection_start;
int selection_end;
@@ -548,10 +614,152 @@ icon_view_button_press_event_cb (GtkWidget *widget,
gtk_tree_path_free (path);
}
- return TRUE;
+ retval = TRUE;
}
else
icon_view->priv->selection_range_start = new_selection_end;
+
+ return retval;
+ }
+
+ return FALSE;
+}
+
+
+static void
+_gdk_pixbuf_set_transparency (GdkPixbuf *dest,
+ GdkPixbuf *src,
+ int alpha_value)
+{
+ int i, j;
+ int width, height, has_alpha, srcrowstride, destrowstride;
+ guchar *target_pixels;
+ guchar *original_pixels;
+ guchar *pixsrc;
+ guchar *pixdest;
+
+ has_alpha = gdk_pixbuf_get_has_alpha (src);
+ width = gdk_pixbuf_get_width (src);
+ height = gdk_pixbuf_get_height (src);
+ srcrowstride = gdk_pixbuf_get_rowstride (src);
+ destrowstride = gdk_pixbuf_get_rowstride (dest);
+ target_pixels = gdk_pixbuf_get_pixels (dest);
+ original_pixels = gdk_pixbuf_get_pixels (src);
+
+ for (i = 0; i < height; i++) {
+ pixdest = target_pixels + i * destrowstride;
+ pixsrc = original_pixels + i * srcrowstride;
+ for (j = 0; j < width; j++) {
+ *(pixdest++) = *(pixsrc++);
+ *(pixdest++) = *(pixsrc++);
+ *(pixdest++) = *(pixsrc++);
+ if (has_alpha) {
+ *(pixdest++) = (*pixsrc != 0) ? alpha_value : 0;
+ pixsrc++;
+ }
+ }
+ }
+}
+
+
+static gboolean
+icon_view_motion_notify_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GthIconView *icon_view = user_data;
+
+ if (icon_view->priv->dragging) {
+ if (! icon_view->priv->drag_started
+ && gtk_drag_check_threshold (widget,
+ icon_view->priv->drag_start_x,
+ icon_view->priv->drag_start_y,
+ event->x,
+ event->y))
+ {
+ GtkTreePath *path = NULL;
+ GdkDragContext *context;
+ GdkPixmap *dnd_icon;
+ int width;
+ int height;
+ int n_selected;
+
+ path = gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (icon_view),
+ event->x,
+ event->y);
+ if (path == NULL)
+ return FALSE;
+
+ gtk_icon_view_set_cursor (GTK_ICON_VIEW (icon_view), path, NULL, FALSE);
+ icon_view->priv->drag_started = TRUE;
+
+ /**/
+
+ context = gtk_drag_begin (widget,
+ icon_view->priv->drag_target_list,
+ icon_view->priv->drag_actions,
+ 1,
+ (GdkEvent *) event);
+
+ dnd_icon = gtk_icon_view_create_drag_icon (GTK_ICON_VIEW (icon_view), path);
+ gdk_drawable_get_size (dnd_icon, &width, &height);
+
+ n_selected = gth_file_selection_get_n_selected (GTH_FILE_SELECTION (icon_view));
+ if (n_selected >= 1) {
+ const int offset = 3;
+ int n_visible;
+ int border;
+ GdkPixbuf *multi_dnd_icon;
+ int i;
+
+ n_visible = MIN (n_selected, 4);
+ gdk_drawable_get_size (dnd_icon, &width, &height);
+ border = n_visible * offset;
+ multi_dnd_icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width + border, height + border);
+ gdk_pixbuf_fill (multi_dnd_icon, 0x00000000);
+ for (i = n_visible - 1; i >= 0; i--)
+ gdk_pixbuf_get_from_drawable (multi_dnd_icon,
+ dnd_icon,
+ gdk_drawable_get_colormap (dnd_icon),
+ 0, 0,
+ i * offset, i * offset,
+ width, height);
+ _gdk_pixbuf_set_transparency (multi_dnd_icon, multi_dnd_icon, 128);
+ gtk_drag_set_icon_pixbuf (context,
+ multi_dnd_icon,
+ width / 4,
+ height / 4);
+
+ g_object_unref (multi_dnd_icon);
+ }
+
+ g_object_unref (dnd_icon);
+ gtk_tree_path_free (path);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static gboolean
+icon_view_button_release_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GthIconView *icon_view = user_data;
+
+ if (icon_view->priv->dragging) {
+ icon_view->priv->selection_pending = icon_view->priv->selection_pending && ! icon_view->priv->drag_started;
+ stop_dragging (icon_view);
+ }
+
+ if (icon_view->priv->selection_pending) {
+ gth_file_selection_unselect_all (GTH_FILE_SELECTION (icon_view));
+ gth_file_selection_select (GTH_FILE_SELECTION (icon_view), icon_view->priv->selection_pending_pos);
+ icon_view->priv->selection_pending = FALSE;
}
return FALSE;
@@ -581,6 +789,10 @@ gth_icon_view_init (GthIconView *icon_view)
{
icon_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (icon_view, GTH_TYPE_ICON_VIEW, GthIconViewPrivate);
icon_view->priv->selection_range_start = 0;
+ icon_view->priv->drag_source_enabled = FALSE;
+ icon_view->priv->dragging = FALSE;
+ icon_view->priv->drag_started = FALSE;
+ icon_view->priv->drag_target_list = NULL;
gtk_icon_view_set_spacing (GTK_ICON_VIEW (icon_view), IMAGE_TEXT_SPACING);
gth_icon_view_real_set_spacing (GTH_FILE_VIEW (icon_view), DEFAULT_ICON_SPACING);
@@ -592,6 +804,14 @@ gth_icon_view_init (GthIconView *icon_view)
G_CALLBACK (icon_view_button_press_event_cb),
icon_view);
g_signal_connect (icon_view,
+ "motion-notify-event",
+ G_CALLBACK (icon_view_motion_notify_event_cb),
+ icon_view);
+ g_signal_connect (icon_view,
+ "button-release-event",
+ G_CALLBACK (icon_view_button_release_event_cb),
+ icon_view);
+ g_signal_connect (icon_view,
"selection-changed",
G_CALLBACK (icon_view_selection_changed_cb),
icon_view);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]