event-controler: Add UI feedback for long-press
style and colors of the progress feedback are subject to change Signed-off-by: Carlos Garnacho <carlos@lanedo.com> Acked-by: Simon Schampijer <simon@laptop.org>
This commit is contained in:
parent
63ff76b95f
commit
a2b77a2166
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#define DEFAULT_THRESHOLD 32
|
#define DEFAULT_THRESHOLD 32
|
||||||
#define DEFAULT_TIMEOUT 800
|
#define DEFAULT_TIMEOUT 800
|
||||||
|
#define ANIM_WINDOW_WIDTH 100
|
||||||
|
#define ARC_LINE_WIDTH 10
|
||||||
|
|
||||||
typedef struct _SugarLongPressControllerPriv SugarLongPressControllerPriv;
|
typedef struct _SugarLongPressControllerPriv SugarLongPressControllerPriv;
|
||||||
|
|
||||||
@ -36,8 +38,13 @@ struct _SugarLongPressControllerPriv
|
|||||||
{
|
{
|
||||||
GdkDevice *device;
|
GdkDevice *device;
|
||||||
GdkEventSequence *sequence;
|
GdkEventSequence *sequence;
|
||||||
|
GtkWidget *anim_window;
|
||||||
|
gint64 start_time;
|
||||||
gint x;
|
gint x;
|
||||||
gint y;
|
gint y;
|
||||||
|
gint root_x;
|
||||||
|
gint root_y;
|
||||||
|
guint anim_id;
|
||||||
guint timeout_id;
|
guint timeout_id;
|
||||||
guint threshold;
|
guint threshold;
|
||||||
guint timeout;
|
guint timeout;
|
||||||
@ -60,6 +67,7 @@ sugar_long_press_controller_init (SugarLongPressController *controller)
|
|||||||
priv->threshold = DEFAULT_THRESHOLD;
|
priv->threshold = DEFAULT_THRESHOLD;
|
||||||
priv->timeout = DEFAULT_TIMEOUT;
|
priv->timeout = DEFAULT_TIMEOUT;
|
||||||
priv->x = priv->y = -1;
|
priv->x = priv->y = -1;
|
||||||
|
priv->root_x = priv->root_y = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -75,6 +83,7 @@ _sugar_long_press_controller_unset_device (SugarLongPressController *controller)
|
|||||||
|
|
||||||
priv->sequence = NULL;
|
priv->sequence = NULL;
|
||||||
priv->x = priv->y = -1;
|
priv->x = priv->y = -1;
|
||||||
|
priv->root_x = priv->root_y = -1;
|
||||||
priv->cancelled = priv->triggered = FALSE;
|
priv->cancelled = priv->triggered = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +92,16 @@ _sugar_long_press_controller_cancel (SugarLongPressController *controller)
|
|||||||
{
|
{
|
||||||
SugarLongPressControllerPriv *priv = controller->_priv;
|
SugarLongPressControllerPriv *priv = controller->_priv;
|
||||||
|
|
||||||
|
if (priv->anim_id)
|
||||||
|
{
|
||||||
|
g_source_remove (priv->anim_id);
|
||||||
|
priv->anim_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->anim_window &&
|
||||||
|
gtk_widget_get_visible (priv->anim_window))
|
||||||
|
gtk_widget_hide (priv->anim_window);
|
||||||
|
|
||||||
if (priv->timeout_id)
|
if (priv->timeout_id)
|
||||||
{
|
{
|
||||||
g_source_remove (priv->timeout_id);
|
g_source_remove (priv->timeout_id);
|
||||||
@ -151,6 +170,139 @@ sugar_long_press_controller_finalize (GObject *object)
|
|||||||
G_OBJECT_CLASS (sugar_long_press_controller_parent_class)->finalize (object);
|
G_OBJECT_CLASS (sugar_long_press_controller_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_stroke_progress_notification (cairo_t *cr,
|
||||||
|
gdouble progress)
|
||||||
|
{
|
||||||
|
cairo_set_line_width (cr, ARC_LINE_WIDTH);
|
||||||
|
cairo_arc (cr,
|
||||||
|
ANIM_WINDOW_WIDTH / 2,
|
||||||
|
ANIM_WINDOW_WIDTH / 2,
|
||||||
|
ANIM_WINDOW_WIDTH / 2 - ARC_LINE_WIDTH / 2,
|
||||||
|
- G_PI_2, (2 * G_PI * progress) - G_PI_2);
|
||||||
|
cairo_stroke (cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_sugar_long_press_anim_draw (GtkWidget *widget,
|
||||||
|
cairo_t *cr,
|
||||||
|
SugarLongPressController *controller)
|
||||||
|
{
|
||||||
|
SugarLongPressControllerPriv *priv = controller->_priv;
|
||||||
|
gdouble progress;
|
||||||
|
gint64 diff_msec;
|
||||||
|
|
||||||
|
diff_msec = (g_get_monotonic_time () - priv->start_time) / 1000;
|
||||||
|
progress = (gdouble) diff_msec / priv->timeout;
|
||||||
|
|
||||||
|
cairo_save (cr);
|
||||||
|
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||||
|
cairo_set_source_rgba (cr, 0, 0, 0, 0);
|
||||||
|
cairo_paint (cr);
|
||||||
|
cairo_restore (cr);
|
||||||
|
|
||||||
|
_stroke_progress_notification (cr, progress);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sugar_long_press_controller_update_shape (GtkWidget *widget,
|
||||||
|
SugarLongPressController *controller)
|
||||||
|
{
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
cairo_region_t *region;
|
||||||
|
cairo_t *cr;
|
||||||
|
|
||||||
|
surface = cairo_image_surface_create (CAIRO_FORMAT_A1,
|
||||||
|
ANIM_WINDOW_WIDTH,
|
||||||
|
ANIM_WINDOW_WIDTH);
|
||||||
|
cr = cairo_create (surface);
|
||||||
|
_stroke_progress_notification (cr, 1.0);
|
||||||
|
cairo_destroy (cr);
|
||||||
|
|
||||||
|
region = gdk_cairo_region_create_from_surface (surface);
|
||||||
|
cairo_surface_destroy (surface);
|
||||||
|
|
||||||
|
gtk_widget_shape_combine_region (widget, region);
|
||||||
|
cairo_region_destroy (region);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_sugar_long_press_anim_timeout (gpointer user_data)
|
||||||
|
{
|
||||||
|
SugarLongPressController *controller = user_data;
|
||||||
|
SugarLongPressControllerPriv *priv = controller->_priv;
|
||||||
|
GtkWidget *widget;
|
||||||
|
|
||||||
|
g_object_get (controller, "widget", &widget, NULL);
|
||||||
|
|
||||||
|
if (!widget)
|
||||||
|
{
|
||||||
|
priv->anim_id = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->anim_window &&
|
||||||
|
gtk_widget_get_screen (widget) !=
|
||||||
|
gtk_widget_get_screen (priv->anim_window))
|
||||||
|
{
|
||||||
|
gtk_widget_destroy (priv->anim_window);
|
||||||
|
priv->anim_window = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!priv->anim_window)
|
||||||
|
{
|
||||||
|
GdkScreen *screen;
|
||||||
|
GdkVisual *rgba_visual;
|
||||||
|
|
||||||
|
priv->anim_window = gtk_window_new (GTK_WINDOW_POPUP);
|
||||||
|
gtk_widget_set_app_paintable (priv->anim_window, TRUE);
|
||||||
|
gtk_widget_input_shape_combine_region (priv->anim_window, NULL);
|
||||||
|
gtk_window_set_type_hint (GTK_WINDOW (priv->anim_window),
|
||||||
|
GDK_WINDOW_TYPE_HINT_UTILITY);
|
||||||
|
|
||||||
|
screen = gtk_widget_get_screen (widget);
|
||||||
|
rgba_visual = gdk_screen_get_rgba_visual (screen);
|
||||||
|
|
||||||
|
gtk_window_set_screen (GTK_WINDOW (priv->anim_window), screen);
|
||||||
|
|
||||||
|
if (rgba_visual)
|
||||||
|
{
|
||||||
|
GdkRGBA bg = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
gtk_widget_set_visual (priv->anim_window, rgba_visual);
|
||||||
|
gtk_widget_override_background_color (priv->anim_window, 0, &bg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_sugar_long_press_controller_update_shape (priv->anim_window,
|
||||||
|
controller);
|
||||||
|
g_signal_connect (priv->anim_window, "draw",
|
||||||
|
G_CALLBACK (_sugar_long_press_anim_draw),
|
||||||
|
controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gtk_widget_get_visible (priv->anim_window))
|
||||||
|
{
|
||||||
|
gtk_window_move (GTK_WINDOW (priv->anim_window),
|
||||||
|
priv->root_x - (ANIM_WINDOW_WIDTH / 2),
|
||||||
|
priv->root_y - (ANIM_WINDOW_WIDTH / 2));
|
||||||
|
gtk_window_resize (GTK_WINDOW (priv->anim_window),
|
||||||
|
ANIM_WINDOW_WIDTH, ANIM_WINDOW_WIDTH);
|
||||||
|
gtk_widget_show (priv->anim_window);
|
||||||
|
|
||||||
|
priv->anim_id =
|
||||||
|
gdk_threads_add_timeout (20, _sugar_long_press_anim_timeout,
|
||||||
|
controller);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_widget_queue_draw (priv->anim_window);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_sugar_long_press_controller_timeout (gpointer user_data)
|
_sugar_long_press_controller_timeout (gpointer user_data)
|
||||||
{
|
{
|
||||||
@ -232,10 +384,17 @@ sugar_long_press_controller_handle_event (SugarEventController *controller,
|
|||||||
{
|
{
|
||||||
case GDK_TOUCH_BEGIN:
|
case GDK_TOUCH_BEGIN:
|
||||||
priv->device = g_object_ref (device);
|
priv->device = g_object_ref (device);
|
||||||
|
priv->start_time = g_get_monotonic_time ();
|
||||||
priv->x = event->touch.x;
|
priv->x = event->touch.x;
|
||||||
priv->y = event->touch.y;
|
priv->y = event->touch.y;
|
||||||
|
priv->root_x = event->touch.x_root;
|
||||||
|
priv->root_y = event->touch.y_root;
|
||||||
priv->sequence = sequence;
|
priv->sequence = sequence;
|
||||||
|
|
||||||
|
priv->anim_id =
|
||||||
|
gdk_threads_add_timeout (100,
|
||||||
|
_sugar_long_press_anim_timeout,
|
||||||
|
controller);
|
||||||
priv->timeout_id =
|
priv->timeout_id =
|
||||||
gdk_threads_add_timeout (priv->timeout,
|
gdk_threads_add_timeout (priv->timeout,
|
||||||
_sugar_long_press_controller_timeout,
|
_sugar_long_press_controller_timeout,
|
||||||
|
Loading…
Reference in New Issue
Block a user