[egg-list-box/flow-box-enhancements] Add autoscrolling
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [egg-list-box/flow-box-enhancements] Add autoscrolling
- Date: Sun, 29 Sep 2013 07:37:41 +0000 (UTC)
commit 8674191416e02c12c30e74fd84283a83e697a0ce
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Sep 29 03:36:25 2013 -0400
Add autoscrolling
When the pointer leaves the widget during a rubberband selection,
we scroll to enlarge the selection.
egg-flow-box.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 178 insertions(+), 0 deletions(-)
---
diff --git a/egg-flow-box.c b/egg-flow-box.c
index 92590e2..397a38c 100644
--- a/egg-flow-box.c
+++ b/egg-flow-box.c
@@ -124,6 +124,9 @@ _egg_marshal_VOID__ENUM_INT (GClosure * closure,
#define DEFAULT_MAX_CHILDREN_PER_LINE 7
#define RUBBERBAND_START_DISTANCE 32
+#define AUTOSCROLL_FAST_DISTANCE 32
+#define AUTOSCROLL_FACTOR 20
+#define AUTOSCROLL_FACTOR_FAST 10
enum {
CHILD_ACTIVATED,
@@ -198,6 +201,10 @@ struct _EggFlowBoxPrivate {
EggFlowBoxChild *rubberband_last;
gint button_down_x;
gint button_down_y;
+ GdkDevice *rubberband_device;
+
+ GtkScrollType autoscroll_mode;
+ guint autoscroll_id;
};
typedef struct _EggFlowBoxChildPrivate EggFlowBoxChildPrivate;
@@ -2611,6 +2618,161 @@ egg_flow_box_leave_notify_event (GtkWidget *widget,
return FALSE;
}
+static void
+remove_autoscroll (EggFlowBox *box)
+{
+ EggFlowBoxPrivate *priv = BOX_PRIV (box);
+
+ if (priv->autoscroll_id)
+ {
+ gtk_widget_remove_tick_callback (GTK_WIDGET (box), priv->autoscroll_id);
+ priv->autoscroll_id = 0;
+ }
+
+ priv->autoscroll_mode = GTK_SCROLL_NONE;
+}
+
+static gboolean
+autoscroll_cb (GtkWidget *widget,
+ GdkFrameClock *frame_clock,
+ gpointer data)
+{
+ EggFlowBox *box = EGG_FLOW_BOX (data);
+ EggFlowBoxPrivate *priv = BOX_PRIV (box);
+ GtkAdjustment *adjustment;
+ gdouble factor;
+ gdouble increment;
+ gdouble value;
+ gboolean handled;
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ adjustment = priv->vadjustment;
+ else
+ adjustment = priv->hadjustment;
+
+ switch (priv->autoscroll_mode)
+ {
+ case GTK_SCROLL_STEP_FORWARD:
+ factor = AUTOSCROLL_FACTOR;
+ break;
+ case GTK_SCROLL_STEP_BACKWARD:
+ factor = - AUTOSCROLL_FACTOR;
+ break;
+ case GTK_SCROLL_PAGE_FORWARD:
+ factor = AUTOSCROLL_FACTOR_FAST;
+ break;
+ case GTK_SCROLL_PAGE_BACKWARD:
+ factor = - AUTOSCROLL_FACTOR_FAST;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ increment = gtk_adjustment_get_step_increment (adjustment) / factor;
+
+ value = gtk_adjustment_get_value (adjustment);
+ value += increment;
+ gtk_adjustment_set_value (adjustment, value);
+
+ if (priv->rubberband_select)
+ {
+ gint x, y;
+ EggFlowBoxChild *child;
+
+ gdk_window_get_device_position (gtk_widget_get_window (widget),
+ priv->rubberband_device,
+ &x, &y, NULL);
+
+ child = egg_flow_box_find_child_at_pos (box, x, y);
+
+ egg_flow_box_update_prelight (box, child);
+ egg_flow_box_update_active (box, child);
+
+ if (child != NULL)
+ priv->rubberband_last = child;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+add_autoscroll (EggFlowBox *box)
+{
+ EggFlowBoxPrivate *priv = BOX_PRIV (box);
+
+ if (priv->autoscroll_id != 0 ||
+ priv->autoscroll_mode == GTK_SCROLL_NONE)
+ return;
+
+ priv->autoscroll_id = gtk_widget_add_tick_callback (GTK_WIDGET (box),
+ (GtkTickCallback)autoscroll_cb,
+ box,
+ NULL);
+}
+
+static gboolean
+get_view_rect (EggFlowBox *box,
+ GdkRectangle *rect)
+{
+ EggFlowBoxPrivate *priv = BOX_PRIV (box);
+ GtkWidget *parent;
+ GdkWindow *view;
+
+ parent = gtk_widget_get_parent (GTK_WIDGET (box));
+ if (GTK_IS_VIEWPORT (parent))
+ {
+ view = gtk_viewport_get_view_window (GTK_VIEWPORT (parent));
+ rect->x = gtk_adjustment_get_value (priv->hadjustment);
+ rect->y = gtk_adjustment_get_value (priv->vadjustment);
+ rect->width = gdk_window_get_width (view);
+ rect->height = gdk_window_get_height (view);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+update_autoscroll_mode (EggFlowBox *box,
+ gint x,
+ gint y)
+{
+ EggFlowBoxPrivate *priv = BOX_PRIV (box);
+ GtkScrollType mode = GTK_SCROLL_NONE;
+ GdkRectangle rect;
+ gint size, pos;
+
+ if (priv->rubberband_select && get_view_rect (box, &rect))
+ {
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ size = rect.width;
+ pos = x - rect.x;
+ }
+ else
+ {
+ size = rect.height;
+ pos = y - rect.y;
+ }
+
+ if (pos < 0 - AUTOSCROLL_FAST_DISTANCE)
+ mode = GTK_SCROLL_PAGE_BACKWARD;
+ else if (pos > size + AUTOSCROLL_FAST_DISTANCE)
+ mode = GTK_SCROLL_PAGE_FORWARD;
+ else if (pos < 0)
+ mode = GTK_SCROLL_STEP_BACKWARD;
+ else if (pos > size)
+ mode = GTK_SCROLL_STEP_FORWARD;
+ }
+
+ if (mode != priv->autoscroll_mode)
+ {
+ remove_autoscroll (box);
+ priv->autoscroll_mode = mode;
+ add_autoscroll (box);
+ }
+}
+
static gboolean
egg_flow_box_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event)
@@ -2660,6 +2822,8 @@ egg_flow_box_motion_notify_event (GtkWidget *widget,
priv->rubberband_first = child;
if (child != NULL)
priv->rubberband_last = child;
+
+ update_autoscroll_mode (box, event->x, event->y);
}
}
@@ -2698,6 +2862,7 @@ egg_flow_box_button_press_event (GtkWidget *widget,
priv->rubberband_last = NULL;
priv->button_down_x = event->x;
priv->button_down_y = event->y;
+ priv->rubberband_device = gdk_event_get_device ((GdkEvent*)event);
}
}
@@ -2927,6 +3092,7 @@ egg_flow_box_button_release_event (GtkWidget *widget,
gtk_widget_queue_draw (GTK_WIDGET (box));
}
+ remove_autoscroll (box);
priv->track_motion = FALSE;
if (priv->rubberband_select)
{
@@ -2934,6 +3100,7 @@ egg_flow_box_button_release_event (GtkWidget *widget,
priv->rubberband_first = NULL;
priv->rubberband_last = NULL;
priv->rubberband_select = FALSE;
+ priv->rubberband_device = NULL;
}
return FALSE;
@@ -3669,6 +3836,16 @@ egg_flow_box_realize (GtkWidget *widget)
}
static void
+egg_flow_box_unmap (GtkWidget *widget)
+{
+ EggFlowBox *box = EGG_FLOW_BOX (widget);
+
+ remove_autoscroll (box);
+
+ GTK_WIDGET_CLASS (egg_flow_box_parent_class)->unmap (widget);
+}
+
+static void
egg_flow_box_finalize (GObject *obj)
{
EggFlowBoxPrivate *priv = BOX_PRIV (obj);
@@ -3708,6 +3885,7 @@ egg_flow_box_class_init (EggFlowBoxClass *class)
widget_class->motion_notify_event = egg_flow_box_motion_notify_event;
widget_class->size_allocate = egg_flow_box_size_allocate;
widget_class->realize = egg_flow_box_realize;
+ widget_class->unmap = egg_flow_box_unmap;
widget_class->focus = egg_flow_box_focus;
widget_class->draw = egg_flow_box_draw;
widget_class->button_press_event = egg_flow_box_button_press_event;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]