/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
* Copyright (C) 2011 Robert Bosch Car Multimedia GmbH.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Author:
* Tomeu Vizoso
*
* Based on ClutterDragAction, written by:
* Emmanuele Bassi
*/
/**
* SECTION:clutter-swipe-action
* @Title: ClutterSwipeAction
* @Short_Description: Action for swipe gestures
*
* #ClutterSwipeAction is a sub-class of #ClutterGestureAction that implements
* the logic for recognizing swipe gestures.
*
* Since: 1.8
*/
#include "clutter-build-config.h"
#include "clutter-swipe-action.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-gesture-action-private.h"
#include "clutter-marshal.h"
#include "clutter-private.h"
struct _ClutterSwipeActionPrivate
{
ClutterSwipeDirection h_direction;
ClutterSwipeDirection v_direction;
float distance_x, distance_y;
};
enum
{
SWEPT,
SWIPE,
LAST_SIGNAL
};
static guint swipe_signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE_WITH_PRIVATE (ClutterSwipeAction, clutter_swipe_action, CLUTTER_TYPE_GESTURE_ACTION)
static gboolean
gesture_begin (ClutterGestureAction *action,
ClutterActor *actor)
{
ClutterSwipeActionPrivate *priv = CLUTTER_SWIPE_ACTION (action)->priv;
/* reset the state at the beginning of a new gesture */
priv->h_direction = 0;
priv->v_direction = 0;
g_object_get (action,
"threshold-trigger-distance-x", &priv->distance_x,
"threshold-trigger-distance-y", &priv->distance_y,
NULL);
return TRUE;
}
static gboolean
gesture_progress (ClutterGestureAction *action,
ClutterActor *actor)
{
ClutterSwipeActionPrivate *priv = CLUTTER_SWIPE_ACTION (action)->priv;
gfloat press_x, press_y;
gfloat motion_x, motion_y;
gfloat delta_x, delta_y;
ClutterSwipeDirection h_direction = 0, v_direction = 0;
clutter_gesture_action_get_press_coords (action,
0,
&press_x,
&press_y);
clutter_gesture_action_get_motion_coords (action,
0,
&motion_x,
&motion_y);
delta_x = press_x - motion_x;
delta_y = press_y - motion_y;
if (delta_x >= priv->distance_x)
h_direction = CLUTTER_SWIPE_DIRECTION_RIGHT;
else if (delta_x < -priv->distance_x)
h_direction = CLUTTER_SWIPE_DIRECTION_LEFT;
if (delta_y >= priv->distance_y)
v_direction = CLUTTER_SWIPE_DIRECTION_DOWN;
else if (delta_y < -priv->distance_y)
v_direction = CLUTTER_SWIPE_DIRECTION_UP;
/* cancel gesture on direction reversal */
if (priv->h_direction == 0)
priv->h_direction = h_direction;
if (priv->v_direction == 0)
priv->v_direction = v_direction;
if (priv->h_direction != h_direction)
return FALSE;
if (priv->v_direction != v_direction)
return FALSE;
return TRUE;
}
static void
gesture_end (ClutterGestureAction *action,
ClutterActor *actor)
{
ClutterSwipeActionPrivate *priv = CLUTTER_SWIPE_ACTION (action)->priv;
gfloat press_x, press_y;
gfloat release_x, release_y;
ClutterSwipeDirection direction = 0;
gboolean can_emit_swipe;
const ClutterEvent *last_event;
clutter_gesture_action_get_press_coords (action,
0,
&press_x, &press_y);
/* Check the last event instead of get_release_coords(), this
* might not be the sequence that finished on multi-finger swipes.
*/
last_event = clutter_gesture_action_get_last_event (action, 0);
clutter_event_get_coords (last_event, &release_x, &release_y);
if (release_x - press_x > priv->distance_x)
direction |= CLUTTER_SWIPE_DIRECTION_RIGHT;
else if (press_x - release_x > priv->distance_x)
direction |= CLUTTER_SWIPE_DIRECTION_LEFT;
if (release_y - press_y > priv->distance_y)
direction |= CLUTTER_SWIPE_DIRECTION_DOWN;
else if (press_y - release_y > priv->distance_y)
direction |= CLUTTER_SWIPE_DIRECTION_UP;
/* XXX:2.0 remove */
g_signal_emit (action, swipe_signals[SWIPE], 0, actor, direction,
&can_emit_swipe);
if (can_emit_swipe)
g_signal_emit (action, swipe_signals[SWEPT], 0, actor, direction);
}
/* XXX:2.0 remove */
static gboolean
clutter_swipe_action_real_swipe (ClutterSwipeAction *action,
ClutterActor *actor,
ClutterSwipeDirection direction)
{
return TRUE;
}
static void
clutter_swipe_action_constructed (GObject *object)
{
clutter_gesture_action_set_threshold_trigger_edge (CLUTTER_GESTURE_ACTION (object),
CLUTTER_GESTURE_TRIGGER_EDGE_AFTER);
}
static void
clutter_swipe_action_class_init (ClutterSwipeActionClass *klass)
{
ClutterGestureActionClass *gesture_class =
CLUTTER_GESTURE_ACTION_CLASS (klass);
GObjectClass *object_class =
G_OBJECT_CLASS (klass);
object_class->constructed = clutter_swipe_action_constructed;
gesture_class->gesture_begin = gesture_begin;
gesture_class->gesture_progress = gesture_progress;
gesture_class->gesture_end = gesture_end;
/* XXX:2.0 remove */
klass->swipe = clutter_swipe_action_real_swipe;
/**
* ClutterSwipeAction::swept:
* @action: the #ClutterSwipeAction that emitted the signal
* @actor: the #ClutterActor attached to the @action
* @direction: the main direction of the swipe gesture
*
* The ::swept signal is emitted when a swipe gesture is recognized on the
* attached actor.
*
* Deprecated: 1.14: Use the ::swipe signal instead.
*
* Since: 1.8
*/
swipe_signals[SWEPT] =
g_signal_new (I_("swept"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST |
G_SIGNAL_DEPRECATED,
G_STRUCT_OFFSET (ClutterSwipeActionClass, swept),
NULL, NULL,
_clutter_marshal_VOID__OBJECT_FLAGS,
G_TYPE_NONE, 2,
CLUTTER_TYPE_ACTOR,
CLUTTER_TYPE_SWIPE_DIRECTION);
/**
* ClutterSwipeAction::swipe:
* @action: the #ClutterSwipeAction that emitted the signal
* @actor: the #ClutterActor attached to the @action
* @direction: the main direction of the swipe gesture
*
* The ::swipe signal is emitted when a swipe gesture is recognized on the
* attached actor.
*
* Return value: %TRUE if the swipe should continue, and %FALSE if
* the swipe should be cancelled.
*
* Since: 1.14
*/
swipe_signals[SWIPE] =
g_signal_new (I_("swipe"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterSwipeActionClass, swipe),
_clutter_boolean_continue_accumulator, NULL,
_clutter_marshal_BOOLEAN__OBJECT_FLAGS,
G_TYPE_BOOLEAN, 2,
CLUTTER_TYPE_ACTOR,
CLUTTER_TYPE_SWIPE_DIRECTION);
}
static void
clutter_swipe_action_init (ClutterSwipeAction *self)
{
self->priv = clutter_swipe_action_get_instance_private (self);
}
/**
* clutter_swipe_action_new:
*
* Creates a new #ClutterSwipeAction instance
*
* Return value: the newly created #ClutterSwipeAction
*
* Since: 1.8
*/
ClutterAction *
clutter_swipe_action_new (void)
{
return g_object_new (CLUTTER_TYPE_SWIPE_ACTION, NULL);
}