From c3e172e5469caf21d12a3f4bb1f8c831e7c42888 Mon Sep 17 00:00:00 2001 From: William Jon McCann Date: Thu, 18 Jul 2013 17:35:42 -0400 Subject: [PATCH] Add press and hold support to set zoom scroll mode Triggering zoom scroll mode by Shift click was too much of an easter egg. It also requires using keyboard and mouse together, which is hard to do for many users. Instead, we now trigger zoom scroll mode by click-and-hold (or touch-and-hold). https://bugzilla.gnome.org/show_bug.cgi?id=704703 --- gtk/gtkrange.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c index 64496febad..f99c309cb2 100644 --- a/gtk/gtkrange.c +++ b/gtk/gtkrange.c @@ -36,6 +36,7 @@ #include "gtkmain.h" #include "gtkmarshalers.h" #include "gtkorientableprivate.h" +#include "gtkpressandholdprivate.h" #include "gtkprivate.h" #include "gtkscale.h" #include "gtkscrollbar.h" @@ -62,6 +63,7 @@ #define UPDATE_DELAY 300 /* Delay for queued update */ #define TIMEOUT_INITIAL 500 #define TIMEOUT_REPEAT 50 +#define ZOOM_HOLD_TIME 500 typedef struct _GtkRangeStepTimer GtkRangeStepTimer; @@ -142,6 +144,8 @@ struct _GtkRangePrivate /* Whether we're doing fine adjustment */ guint zoom : 1; + guint zoom_set : 1; + GtkPressAndHold *press_and_hold; /* Fill level */ guint show_fill_level : 1; @@ -1499,6 +1503,8 @@ gtk_range_destroy (GtkWidget *widget) gtk_range_remove_step_timer (range); + g_clear_object (&priv->press_and_hold); + if (priv->adjustment) { g_signal_handlers_disconnect_by_func (priv->adjustment, @@ -2346,6 +2352,33 @@ range_grab_add (GtkRange *range, gtk_widget_queue_draw (GTK_WIDGET (range)); } +static void +update_zoom_state (GtkRange *range, + gboolean enabled) +{ + GtkStyleContext *context; + + context = gtk_widget_get_style_context (GTK_WIDGET (range)); + + if (enabled) + gtk_style_context_add_class (context, "fine-tune"); + else + gtk_style_context_remove_class (context, "fine-tune"); + gtk_widget_queue_draw (GTK_WIDGET (range)); + + range->priv->zoom = enabled; +} + +static void +update_zoom_set (GtkRange *range, + gboolean zoom_set) +{ + if (zoom_set) + g_clear_object (&range->priv->press_and_hold); + + range->priv->zoom_set = zoom_set; +} + static void range_grab_remove (GtkRange *range) { @@ -2368,7 +2401,8 @@ range_grab_remove (GtkRange *range) location != MOUSE_OUTSIDE) gtk_widget_queue_draw (GTK_WIDGET (range)); - priv->zoom = FALSE; + update_zoom_state (range, FALSE); + update_zoom_set (range, FALSE); } static GtkScrollType @@ -2511,6 +2545,16 @@ gtk_range_key_press (GtkWidget *widget, return GTK_WIDGET_CLASS (gtk_range_parent_class)->key_press_event (widget, event); } +static void +hold_action (GtkPressAndHold *pah, + gint x, + gint y, + GtkRange *range) +{ + update_zoom_state (range, TRUE); + update_zoom_set (range, TRUE); +} + static gint gtk_range_button_press (GtkWidget *widget, GdkEventButton *event) @@ -2657,7 +2701,32 @@ gtk_range_button_press (GtkWidget *widget, { /* Shift-click in the slider = fine adjustment */ if (event->state & GDK_SHIFT_MASK) - priv->zoom = TRUE; + { + update_zoom_state (range, TRUE); + update_zoom_set (range, TRUE); + } + else + { + if (!priv->press_and_hold) + { + gint drag_threshold; + + g_object_get (gtk_widget_get_settings (widget), + "gtk-dnd-drag-threshold", &drag_threshold, + NULL); + priv->press_and_hold = gtk_press_and_hold_new (); + + g_object_set (priv->press_and_hold, + "drag-threshold", drag_threshold, + "hold-time", ZOOM_HOLD_TIME, + NULL); + + g_signal_connect (priv->press_and_hold, "hold", + G_CALLBACK (hold_action), range); + } + + gtk_press_and_hold_process_event (priv->press_and_hold, (GdkEvent *)event); + } } if (priv->orientation == GTK_ORIENTATION_VERTICAL) @@ -2803,7 +2872,11 @@ gtk_range_button_release (GtkWidget *widget, priv->grab_button == event->button) { if (priv->grab_location == MOUSE_SLIDER) - update_slider_position (range, priv->mouse_x, priv->mouse_y); + { + update_slider_position (range, priv->mouse_x, priv->mouse_y); + if (priv->press_and_hold) + gtk_press_and_hold_process_event (priv->press_and_hold, (GdkEvent *)event); + } stop_scrolling (range); @@ -2905,7 +2978,12 @@ gtk_range_motion_notify (GtkWidget *widget, gtk_widget_queue_draw (widget); if (priv->grab_location == MOUSE_SLIDER) - update_slider_position (range, event->x, event->y); + { + if (!priv->zoom_set && priv->press_and_hold != NULL) + gtk_press_and_hold_process_event (priv->press_and_hold, (GdkEvent *)event); + + update_slider_position (range, event->x, event->y); + } /* We handled the event if the mouse was in the range_rect */ return priv->mouse_location != MOUSE_OUTSIDE;