[gnome-flashback] desktop: add rubberband selection
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] desktop: add rubberband selection
- Date: Tue, 12 Nov 2019 19:16:05 +0000 (UTC)
commit bc607082f2293b3df44b0416fee278723b38676b
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Tue Nov 12 15:42:07 2019 +0200
desktop: add rubberband selection
gnome-flashback/libdesktop/gf-icon-view.c | 267 +++++++++++++++++++++++++--
gnome-flashback/libdesktop/gf-monitor-view.c | 30 +++
gnome-flashback/libdesktop/gf-monitor-view.h | 3 +
3 files changed, 289 insertions(+), 11 deletions(-)
---
diff --git a/gnome-flashback/libdesktop/gf-icon-view.c b/gnome-flashback/libdesktop/gf-icon-view.c
index 28d9f3b..f9f8444 100644
--- a/gnome-flashback/libdesktop/gf-icon-view.c
+++ b/gnome-flashback/libdesktop/gf-icon-view.c
@@ -34,24 +34,29 @@ typedef struct
struct _GfIconView
{
- GtkEventBox parent;
+ GtkEventBox parent;
- GtkGesture *multi_press;
+ GtkGesture *multi_press;
+ GtkGesture *drag;
- GFile *desktop;
- GFileMonitor *monitor;
+ GFile *desktop;
+ GFileMonitor *monitor;
- GSettings *settings;
+ GSettings *settings;
- GtkWidget *fixed;
+ GtkWidget *fixed;
- GCancellable *cancellable;
+ GCancellable *cancellable;
- GList *icons;
+ GList *icons;
- guint add_icons_id;
+ guint add_icons_id;
- GList *selected_icons;
+ GList *selected_icons;
+
+ GtkStyleContext *rubberband_style;
+ GdkRectangle rubberband_rect;
+ GList *rubberband_icons;
};
G_DEFINE_TYPE (GfIconView, gf_icon_view, GTK_TYPE_EVENT_BOX)
@@ -206,6 +211,7 @@ file_deleted (GfIconView *self,
info->icon);
self->selected_icons = g_list_remove (self->selected_icons, l->data);
+ self->rubberband_icons = g_list_remove (self->rubberband_icons, l->data);
self->icons = g_list_remove_link (self->icons, l);
g_list_free_full (l, gf_icon_info_free);
@@ -456,12 +462,27 @@ multi_press_pressed_cb (GtkGestureMultiPress *gesture,
if (button == GDK_BUTTON_PRIMARY)
{
- unselect_icons (self);
+ GdkModifierType state;
+ gboolean control_pressed;
+ gboolean shift_pressed;
+
+ gdk_event_get_state (event, &state);
+
+ control_pressed = (state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK;
+ shift_pressed = (state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK;
+
+ if (!control_pressed && !shift_pressed)
+ {
+ g_clear_pointer (&self->rubberband_icons, g_list_free);
+ unselect_icons (self);
+ }
}
else if (button == GDK_BUTTON_SECONDARY)
{
GtkWidget *popup_menu;
+ unselect_icons (self);
+
popup_menu = create_popup_menu (self);
g_object_ref_sink (popup_menu);
@@ -470,6 +491,154 @@ multi_press_pressed_cb (GtkGestureMultiPress *gesture,
}
}
+static void
+drag_begin_cb (GtkGestureDrag *gesture,
+ gdouble start_x,
+ gdouble start_y,
+ GfIconView *self)
+{
+ self->rubberband_rect = (GdkRectangle) { 0 };
+
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+static void
+drag_end_cb (GtkGestureDrag *gesture,
+ gdouble offset_x,
+ gdouble offset_y,
+ GfIconView *self)
+{
+
+ g_clear_pointer (&self->rubberband_icons, g_list_free);
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+static void
+drag_update_cb (GtkGestureDrag *gesture,
+ gdouble offset_x,
+ gdouble offset_y,
+ GfIconView *self)
+{
+ double start_x;
+ double start_y;
+ GdkRectangle old_rect;
+
+ gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (self->drag),
+ &start_x, &start_y);
+
+ old_rect = self->rubberband_rect;
+ self->rubberband_rect = (GdkRectangle) {
+ .x = start_x,
+ .y = start_y,
+ .width = ABS (offset_x),
+ .height = ABS (offset_y)
+ };
+
+ if (offset_x < 0)
+ self->rubberband_rect.x += offset_x;
+
+ if (offset_y < 0)
+ self->rubberband_rect.y += offset_y;
+
+ if ((self->rubberband_rect.x > old_rect.x ||
+ self->rubberband_rect.y > old_rect.y ||
+ self->rubberband_rect.width < old_rect.width ||
+ self->rubberband_rect.height < old_rect.height) &&
+ self->rubberband_icons != NULL)
+ {
+ GList *rubberband_icons;
+ GList *l;
+
+ rubberband_icons = g_list_copy (self->rubberband_icons);
+
+ for (l = rubberband_icons; l != NULL; l = l->next)
+ {
+ GfIcon *icon;
+ GtkAllocation allocation;
+
+ icon = l->data;
+
+ gtk_widget_get_allocation (GTK_WIDGET (icon), &allocation);
+
+ if (!gdk_rectangle_intersect (&self->rubberband_rect,
+ &allocation,
+ NULL))
+ {
+ if (gf_icon_get_selected (icon))
+ gf_icon_set_selected (icon, FALSE, GF_ICON_SELECTED_REMOVE);
+ else
+ gf_icon_set_selected (icon, TRUE, GF_ICON_SELECTED_ADD);
+
+ self->rubberband_icons = g_list_remove (self->rubberband_icons,
+ icon);
+ }
+ }
+
+ g_list_free (rubberband_icons);
+ }
+
+ if (self->rubberband_rect.x < old_rect.x ||
+ self->rubberband_rect.y < old_rect.y ||
+ self->rubberband_rect.width > old_rect.width ||
+ self->rubberband_rect.height > old_rect.height)
+ {
+ GList *rubberband_icons;
+ GList *monitor_views;
+ GList *l;
+
+ rubberband_icons = NULL;
+ monitor_views = get_monitor_views (self);
+
+ for (l = monitor_views; l != NULL; l = l->next)
+ {
+ GfMonitorView *monitor_view;
+ GtkAllocation allocation;
+ GdkRectangle rect;
+
+ monitor_view = l->data;
+
+ gtk_widget_get_allocation (GTK_WIDGET (monitor_view), &allocation);
+
+ if (gdk_rectangle_intersect (&self->rubberband_rect,
+ &allocation,
+ &rect))
+ {
+ GList *icons;
+
+ icons = gf_monitor_view_get_icons (monitor_view, &rect);
+ rubberband_icons = g_list_concat (rubberband_icons, icons);
+ }
+ }
+
+ g_list_free (monitor_views);
+
+ if (rubberband_icons != NULL)
+ {
+ for (l = rubberband_icons; l != NULL; l = l->next)
+ {
+ GfIcon *icon;
+
+ icon = l->data;
+
+ if (g_list_find (self->rubberband_icons, icon) != NULL)
+ continue;
+
+ self->rubberband_icons = g_list_prepend (self->rubberband_icons,
+ icon);
+
+ if (gf_icon_get_selected (icon))
+ gf_icon_set_selected (icon, FALSE, GF_ICON_SELECTED_REMOVE);
+ else
+ gf_icon_set_selected (icon, TRUE, GF_ICON_SELECTED_ADD);
+ }
+
+ g_list_free (rubberband_icons);
+ }
+ }
+
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
static void
view_foreach_cb (GtkWidget *widget,
gpointer user_data)
@@ -725,6 +894,8 @@ gf_icon_view_dispose (GObject *object)
self = GF_ICON_VIEW (object);
g_clear_object (&self->multi_press);
+ g_clear_object (&self->drag);
+
g_clear_object (&self->desktop);
g_clear_object (&self->monitor);
g_clear_object (&self->settings);
@@ -740,6 +911,9 @@ gf_icon_view_dispose (GObject *object)
g_clear_pointer (&self->selected_icons, g_list_free);
+ g_clear_object (&self->rubberband_style);
+ g_clear_pointer (&self->rubberband_icons, g_list_free);
+
G_OBJECT_CLASS (gf_icon_view_parent_class)->dispose (object);
}
@@ -759,15 +933,73 @@ gf_icon_view_finalize (GObject *object)
G_OBJECT_CLASS (gf_icon_view_parent_class)->finalize (object);
}
+static void
+ensure_rubberband_style (GfIconView *self)
+{
+ GtkWidgetPath *path;
+
+ if (self->rubberband_style != NULL)
+ return;
+
+ self->rubberband_style = gtk_style_context_new ();
+
+ path = gtk_widget_path_new ();
+
+ gtk_widget_path_append_type (path, G_TYPE_NONE);
+ gtk_widget_path_iter_set_object_name (path, -1, "rubberband");
+ gtk_widget_path_iter_add_class (path, -1, GTK_STYLE_CLASS_RUBBERBAND);
+
+ gtk_style_context_set_path (self->rubberband_style, path);
+ gtk_widget_path_unref (path);
+}
+
+static gboolean
+gf_icon_view_draw (GtkWidget *widget,
+ cairo_t *cr)
+{
+ GfIconView *self;
+
+ self = GF_ICON_VIEW (widget);
+
+ GTK_WIDGET_CLASS (gf_icon_view_parent_class)->draw (widget, cr);
+
+ if (!gtk_gesture_is_recognized (GTK_GESTURE (self->drag)))
+ return TRUE;
+
+ ensure_rubberband_style (self);
+
+ cairo_save (cr);
+
+ gtk_render_background (self->rubberband_style, cr,
+ self->rubberband_rect.x,
+ self->rubberband_rect.y,
+ self->rubberband_rect.width,
+ self->rubberband_rect.height);
+
+ gtk_render_frame (self->rubberband_style, cr,
+ self->rubberband_rect.x,
+ self->rubberband_rect.y,
+ self->rubberband_rect.width,
+ self->rubberband_rect.height);
+
+ cairo_restore (cr);
+
+ return TRUE;
+}
+
static void
gf_icon_view_class_init (GfIconViewClass *self_class)
{
GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
object_class = G_OBJECT_CLASS (self_class);
+ widget_class = GTK_WIDGET_CLASS (self_class);
object_class->dispose = gf_icon_view_dispose;
object_class->finalize = gf_icon_view_finalize;
+
+ widget_class->draw = gf_icon_view_draw;
}
static void
@@ -780,6 +1012,7 @@ gf_icon_view_init (GfIconView *self)
int i;
self->multi_press = gtk_gesture_multi_press_new (GTK_WIDGET (self));
+ self->drag = gtk_gesture_drag_new (GTK_WIDGET (self));
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (self->multi_press), 0);
@@ -787,6 +1020,18 @@ gf_icon_view_init (GfIconView *self)
G_CALLBACK (multi_press_pressed_cb),
self);
+ g_signal_connect (self->drag, "drag-begin",
+ G_CALLBACK (drag_begin_cb),
+ self);
+
+ g_signal_connect (self->drag, "drag-end",
+ G_CALLBACK (drag_end_cb),
+ self);
+
+ g_signal_connect (self->drag, "drag-update",
+ G_CALLBACK (drag_update_cb),
+ self);
+
desktop_dir = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
self->desktop = g_file_new_for_path (desktop_dir);
diff --git a/gnome-flashback/libdesktop/gf-monitor-view.c b/gnome-flashback/libdesktop/gf-monitor-view.c
index 9ec1b10..f2d8513 100644
--- a/gnome-flashback/libdesktop/gf-monitor-view.c
+++ b/gnome-flashback/libdesktop/gf-monitor-view.c
@@ -722,3 +722,33 @@ gf_monitor_view_remove_icon (GfMonitorView *self,
gtk_container_remove (GTK_CONTAINER (self), icon);
gtk_widget_hide (icon);
}
+
+GList *
+gf_monitor_view_get_icons (GfMonitorView *self,
+ GdkRectangle *rect)
+{
+ GList *icons;
+ GList *children;
+ GList *l;
+
+ icons = NULL;
+
+ children = gtk_container_get_children (GTK_CONTAINER (self));
+
+ for (l = children; l != NULL; l = l->next)
+ {
+ GtkWidget *icon;
+ GtkAllocation allocation;
+
+ icon = l->data;
+
+ gtk_widget_get_allocation (icon, &allocation);
+
+ if (gdk_rectangle_intersect (&allocation, rect, NULL))
+ icons = g_list_prepend (icons, icon);
+ }
+
+ g_list_free (children);
+
+ return icons;
+}
diff --git a/gnome-flashback/libdesktop/gf-monitor-view.h b/gnome-flashback/libdesktop/gf-monitor-view.h
index 8a021ff..f52b654 100644
--- a/gnome-flashback/libdesktop/gf-monitor-view.h
+++ b/gnome-flashback/libdesktop/gf-monitor-view.h
@@ -42,6 +42,9 @@ gboolean gf_monitor_view_add_icon (GfMonitorView *self,
void gf_monitor_view_remove_icon (GfMonitorView *self,
GtkWidget *icon);
+GList *gf_monitor_view_get_icons (GfMonitorView *self,
+ GdkRectangle *rect);
+
G_END_DECLS
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]