diff options
author | Emanuele Aina <emanuele.aina@collabora.com> | 2012-08-25 16:23:23 +0200 |
---|---|---|
committer | Gustavo Noronha Silva <gns@gnome.org> | 2012-08-28 10:11:16 -0300 |
commit | 9ca06d2895154eb2c985b85df186db3ade1a5e1e (patch) | |
tree | ab2e048558b9a1e585d29987bd84606f1680c390 /clutter/clutter-pan-action.c | |
parent | 436ebb2716b24743b3873aa7b330073c48793b86 (diff) | |
download | clutter-9ca06d2895154eb2c985b85df186db3ade1a5e1e.tar.gz |
pan-action: add PanAction, to handle panning in scrollable actors
PanAction is a GestureAction-subclass that implements the panning
concept for scrollable actors, with the ability to emit interpolated
signals to emulate the kinetic inertia of the panning. PanAction provides:
• pan signal, notifying users of the panning gesture status;
• pan-stopped signal, emitted at the end of the interpolated phase
of the panning gesture, if enabled;
• pan-axis property, to allow constraining the dragging to a specific
axis;
• interpolated property, to enable or disable the inertial behaviour;
• deceleration property, to customize the rate at which the momentum
of the panning will be slowed down;
• acceleration-factor property, applied to the inertial momentum when
starting the interpolated sequence.
An interactive test is also provided.
https://bugzilla.gnome.org/show_bug.cgi?id=681648
Diffstat (limited to 'clutter/clutter-pan-action.c')
-rw-r--r-- | clutter/clutter-pan-action.c | 814 |
1 files changed, 814 insertions, 0 deletions
diff --git a/clutter/clutter-pan-action.c b/clutter/clutter-pan-action.c new file mode 100644 index 000000000..30e860eba --- /dev/null +++ b/clutter/clutter-pan-action.c @@ -0,0 +1,814 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * Copyright (C) 2011 Robert Bosch Car Multimedia GmbH. + * Copyright (C) 2012 Collabora Ltd. + * + * 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 <http://www.gnu.org/licenses/>. + * + * Author: + * Emanuele Aina <emanuele.aina@collabora.com> + * + * Based on ClutterDragAction, ClutterSwipeAction, and MxKineticScrollView, + * written by: + * Emmanuele Bassi <ebassi@linux.intel.com> + * Tomeu Vizoso <tomeu.vizoso@collabora.co.uk> + * Chris Lord <chris@linux.intel.com> + */ + +/** + * SECTION:clutter-pan-action + * @Title: ClutterPanAction + * @Short_Description: Action for pan gestures + * + * #ClutterPanAction is a sub-class of #ClutterGestureAction that implements + * the logic for recognizing pan gestures. + * + * The simplest usage of #ClutterPanAction consists in adding it to + * a #ClutterActor with a child and setting it as reactive; for instance, + * the following code: + * + * |[ + * clutter_actor_add_action (actor, clutter_pan_action_new ()); + * clutter_actor_set_reactive (actor, TRUE); + * ]| + * + * will automatically result in the actor children to be moved + * when dragging. + * + * Since: 1.12 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-pan-action.h" + +#include "clutter-debug.h" +#include "clutter-enum-types.h" +#include "clutter-marshal.h" +#include "clutter-private.h" +#include <math.h> + +#define FLOAT_EPSILON (1e-15) + +static const gfloat min_velocity = 0.1f; // measured in px/ms +static const gfloat reference_fps = 60.0f; // the fps assumed for the deceleration rate +static const gfloat default_deceleration_rate = 0.95f; +static const gfloat default_acceleration_factor = 1.0f; + +typedef enum +{ + PAN_STATE_INACTIVE, + PAN_STATE_PANNING, + PAN_STATE_INTERPOLATING +} PanState; + +struct _ClutterPanActionPrivate +{ + ClutterPanAxis pan_axis; + + PanState state; + + /* Variables for storing acceleration information */ + ClutterTimeline *deceleration_timeline; + gfloat target_x; + gfloat target_y; + gfloat dx; + gfloat dy; + gdouble deceleration_rate; + gdouble acceleration_factor; + + /* Inertial motion tracking */ + gfloat interpolated_x; + gfloat interpolated_y; + gfloat release_x; + gfloat release_y; + + guint should_interpolate : 1; +}; + +enum +{ + PROP_0, + + PROP_PAN_AXIS, + PROP_INTERPOLATE, + PROP_DECELERATION, + PROP_ACCELERATION_FACTOR, + + PROP_LAST +}; + +static GParamSpec *pan_props[PROP_LAST] = { NULL, }; + +enum +{ + PAN, + PAN_STOPPED, + + LAST_SIGNAL +}; + +static guint pan_signals[LAST_SIGNAL] = { 0, }; + +G_DEFINE_TYPE (ClutterPanAction, clutter_pan_action, + CLUTTER_TYPE_GESTURE_ACTION); + +static void +emit_pan (ClutterPanAction *self, + ClutterActor *actor, + gboolean is_interpolated) +{ + gboolean retval; + g_signal_emit (self, pan_signals[PAN], 0, actor, is_interpolated, &retval); +} + +static void +emit_pan_stopped (ClutterPanAction *self, + ClutterActor *actor) +{ + ClutterPanActionPrivate *priv = self->priv; + + g_signal_emit (self, pan_signals[PAN_STOPPED], 0, actor); + priv->state = PAN_STATE_INACTIVE; +} + +static void +on_deceleration_stopped (ClutterTimeline *timeline, + gboolean is_finished, + ClutterPanAction *self) +{ + ClutterPanActionPrivate *priv = self->priv; + ClutterActor *actor; + + g_object_unref (timeline); + priv->deceleration_timeline = NULL; + + actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self)); + emit_pan_stopped (self, actor); +} + +static void +on_deceleration_new_frame (ClutterTimeline *timeline, + gint elapsed_time, + ClutterPanAction *self) +{ + ClutterPanActionPrivate *priv = self->priv; + ClutterActor *actor; + gdouble progress; + gfloat interpolated_x, interpolated_y; + + progress = clutter_timeline_get_progress (timeline); + + interpolated_x = priv->target_x * progress; + interpolated_y = priv->target_y * progress; + priv->dx = interpolated_x - priv->interpolated_x; + priv->dy = interpolated_y - priv->interpolated_y; + priv->interpolated_x = interpolated_x; + priv->interpolated_y = interpolated_y; + + actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self)); + emit_pan (self, actor, TRUE); +} + +static gboolean +gesture_begin (ClutterGestureAction *gesture, + ClutterActor *actor) +{ + ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture); + ClutterPanActionPrivate *priv = self->priv; + + if (priv->state == PAN_STATE_INTERPOLATING && priv->deceleration_timeline) + clutter_timeline_stop (priv->deceleration_timeline); + + priv->state = PAN_STATE_PANNING; + priv->interpolated_x = priv->interpolated_y = 0.0f; + priv->dx = priv->dy = 0.0f; + + return TRUE; +} + +static gboolean +gesture_progress (ClutterGestureAction *gesture, + ClutterActor *actor) +{ + ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture); + + emit_pan (self, actor, FALSE); + + return TRUE; +} + +static void +gesture_cancel (ClutterGestureAction *gesture, + ClutterActor *actor) +{ + ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture); + ClutterPanActionPrivate *priv = self->priv; + + priv->state = PAN_STATE_INACTIVE; +} + +static void +gesture_end (ClutterGestureAction *gesture, + ClutterActor *actor) +{ + ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture); + ClutterPanActionPrivate *priv = self->priv; + gfloat velocity, velocity_x, velocity_y; + gfloat delta_x, delta_y; + gfloat tau; + gint duration; + + clutter_gesture_action_get_release_coords (CLUTTER_GESTURE_ACTION (self), 0, &priv->release_x, &priv->release_y); + + if (!priv->should_interpolate) + { + priv->state = PAN_STATE_INACTIVE; + return; + } + + priv->state = PAN_STATE_INTERPOLATING; + + clutter_gesture_action_get_motion_delta (gesture, 0, &delta_x, &delta_y); + velocity = clutter_gesture_action_get_velocity (gesture, 0, &velocity_x, &velocity_y); + + /* Exponential timing constant v(t) = v(0) * exp(-t/tau) + * tau = 1000ms / (frame_per_second * - ln(decay_per_frame)) + * with frame_per_second = 60 and decay_per_frame = 0.95, tau ~= 325ms + * see http://ariya.ofilabs.com/2011/10/flick-list-with-its-momentum-scrolling-and-deceleration.html */ + tau = 1000.0f / (reference_fps * - logf (priv->deceleration_rate)); + + /* See where the decreasing velocity reaches $min_velocity px/ms + * v(t) = v(0) * exp(-t/tau) = min_velocity + * t = - tau * ln( min_velocity / |v(0)|) */ + duration = - tau * logf (min_velocity / (ABS (velocity) * priv->acceleration_factor)); + + /* Target point: x(t) = v(0) * tau * [1 - exp(-t/tau)] */ + priv->target_x = velocity_x * priv->acceleration_factor * tau * (1 - exp ((float)-duration / tau)); + priv->target_y = velocity_y * priv->acceleration_factor * tau * (1 - exp ((float)-duration / tau)); + + if (ABS (velocity) * priv->acceleration_factor > min_velocity && duration > FLOAT_EPSILON) + { + priv->interpolated_x = priv->interpolated_y = 0.0f; + priv->deceleration_timeline = clutter_timeline_new (duration); + clutter_timeline_set_progress_mode (priv->deceleration_timeline, CLUTTER_EASE_OUT_EXPO); + + g_signal_connect (priv->deceleration_timeline, "new_frame", + G_CALLBACK (on_deceleration_new_frame), self); + g_signal_connect (priv->deceleration_timeline, "stopped", + G_CALLBACK (on_deceleration_stopped), self); + clutter_timeline_start (priv->deceleration_timeline); + } + else + { + emit_pan_stopped (self, actor); + } +} + +static gboolean +clutter_pan_action_real_pan (ClutterPanAction *self, + ClutterActor *actor, + gboolean is_interpolated) +{ + ClutterPanActionPrivate *priv = self->priv; + gfloat dx, dy; + ClutterMatrix transform; + + if (is_interpolated) + clutter_pan_action_get_interpolated_delta (self, &dx, &dy); + else + clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (self), 0, &dx, &dy); + + switch (priv->pan_axis) + { + case CLUTTER_PAN_AXIS_NONE: + break; + + case CLUTTER_PAN_X_AXIS: + dy = 0.0f; + break; + + case CLUTTER_PAN_Y_AXIS: + dx = 0.0f; + break; + } + + clutter_actor_get_child_transform (actor, &transform); + cogl_matrix_translate (&transform, dx, dy, 0.0f); + clutter_actor_set_child_transform (actor, &transform); + return TRUE; +} + +static void +clutter_pan_action_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ClutterPanAction *self = CLUTTER_PAN_ACTION (gobject); + + switch (prop_id) + { + case PROP_PAN_AXIS: + clutter_pan_action_set_pan_axis (self, g_value_get_enum (value)); + break; + + case PROP_INTERPOLATE : + clutter_pan_action_set_interpolate (self, g_value_get_boolean (value)); + break; + + case PROP_DECELERATION : + clutter_pan_action_set_deceleration (self, g_value_get_double (value)); + break; + + case PROP_ACCELERATION_FACTOR : + clutter_pan_action_set_acceleration_factor (self, g_value_get_double (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + } +} + +static void +clutter_pan_action_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ClutterPanAction *self = CLUTTER_PAN_ACTION (gobject); + ClutterPanActionPrivate *priv = self->priv; + + switch (prop_id) + { + case PROP_PAN_AXIS: + g_value_set_enum (value, priv->pan_axis); + break; + + case PROP_INTERPOLATE : + g_value_set_boolean (value, priv->should_interpolate); + break; + + case PROP_DECELERATION : + g_value_set_double (value, priv->deceleration_rate); + break; + + case PROP_ACCELERATION_FACTOR : + g_value_set_double (value, priv->acceleration_factor); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + } +} + +static void +clutter_pan_action_dispose (GObject *gobject) +{ + ClutterPanActionPrivate *priv = CLUTTER_PAN_ACTION (gobject)->priv; + + g_clear_object (&priv->deceleration_timeline); + + G_OBJECT_CLASS (clutter_pan_action_parent_class)->dispose (gobject); +} + +static void +clutter_pan_action_set_actor (ClutterActorMeta *meta, + ClutterActor *actor) +{ + ClutterPanAction *self = CLUTTER_PAN_ACTION (meta); + ClutterPanActionPrivate *priv = self->priv; + ClutterActor *old_actor; + + old_actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self)); + if (old_actor != actor) + { + /* make sure we reset the state */ + if (priv->state == PAN_STATE_INTERPOLATING) + g_clear_object (&priv->deceleration_timeline); + } + + CLUTTER_ACTOR_META_CLASS (clutter_pan_action_parent_class)->set_actor (meta, actor); +} + + +static void +clutter_pan_action_class_init (ClutterPanActionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); + ClutterGestureActionClass *gesture_class = + CLUTTER_GESTURE_ACTION_CLASS (klass); + + g_type_class_add_private (klass, sizeof (ClutterPanActionPrivate)); + + klass->pan = clutter_pan_action_real_pan; + + gesture_class->gesture_begin = gesture_begin; + gesture_class->gesture_progress = gesture_progress; + gesture_class->gesture_cancel = gesture_cancel; + gesture_class->gesture_end = gesture_end; + + meta_class->set_actor = clutter_pan_action_set_actor; + + /** + * ClutterPanAction:pan-axis: + * + * Constraints the panning action to the specified axis + * + * Since: 1.12 + */ + pan_props[PROP_PAN_AXIS] = + g_param_spec_enum ("pan-axis", + P_("Pan Axis"), + P_("Constraints the panning to an axis"), + CLUTTER_TYPE_PAN_AXIS, + CLUTTER_PAN_AXIS_NONE, + CLUTTER_PARAM_READWRITE); + + /** + * ClutterPanAction:interpolate: + * + * Whether interpolated events emission is enabled. + * + * Since: 1.12 + */ + pan_props[PROP_INTERPOLATE] = + g_param_spec_boolean ("interpolate", + P_("Interpolate"), + P_("Whether interpolated events emission is enabled."), + FALSE, + CLUTTER_PARAM_READWRITE); + + /** + * ClutterPanAction:deceleration: + * + * The rate at which the interpolated panning will decelerate in + * + * #ClutterPanAction will emit interpolated ::pan events with decreasing + * scroll deltas, using the rate specified by this property. + * + * Since: 1.12 + */ + pan_props[PROP_DECELERATION] = + g_param_spec_double ("deceleration", + P_("Deceleration"), + P_("Rate at which the interpolated panning will decelerate in"), + FLOAT_EPSILON, 1.0, default_deceleration_rate, + CLUTTER_PARAM_READWRITE); + + /** + * ClutterPanAction:acceleration-factor: + * + * The initial acceleration factor + * + * The kinetic momentum measured at the time of releasing the pointer will + * be multiplied by the factor specified by this property before being used + * to generate interpolated ::pan events. + * + * Since: 1.12 + */ + pan_props[PROP_ACCELERATION_FACTOR] = + g_param_spec_double ("acceleration-factor", + P_("Initial acceleration factor"), + P_("Factor applied to the momentum when starting the interpolated phase"), + 1.0, G_MAXDOUBLE, default_acceleration_factor, + CLUTTER_PARAM_READWRITE); + + gobject_class->set_property = clutter_pan_action_set_property; + gobject_class->get_property = clutter_pan_action_get_property; + gobject_class->dispose = clutter_pan_action_dispose; + g_object_class_install_properties (gobject_class, + PROP_LAST, + pan_props); + + /** + * ClutterPanAction:pan: + * @action: the #ClutterPanAction that emitted the signal + * @actor: the #ClutterActor attached to the @action + * @is_interpolated: if the event is the result of interpolating + * the motion velocity at the end of the drag + * + * The ::pan signal is emitted to keep track of the motion during + * a pan gesture. @is_interpolated is set to %TRUE during the + * interpolation phase of the pan, after the drag has ended and + * the :interpolate property was set to %TRUE. + * + * Return value: TRUE if the pan action has been handled by one of + * the listener or %FALSE to continue the emission. + * + * Since: 1.12 + */ + pan_signals[PAN] = + g_signal_new (I_("pan"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClutterPanActionClass, pan), + _clutter_boolean_continue_accumulator, NULL, + _clutter_marshal_BOOLEAN__OBJECT_BOOLEAN, + G_TYPE_BOOLEAN, 2, + CLUTTER_TYPE_ACTOR, + G_TYPE_BOOLEAN); + + /** + * ClutterPanAction:pan-stopped: + * @action: the #ClutterPanAction that emitted the signal + * @actor: the #ClutterActor attached to the @action + * + * The ::pan-stopped signal is emitted at the end of the interpolation + * phase of the pan action, only when :interpolate is set to %TRUE. + * + * Since: 1.12 + */ + pan_signals[PAN_STOPPED] = + g_signal_new (I_("pan-stopped"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClutterPanActionClass, pan_stopped), + NULL, NULL, + _clutter_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CLUTTER_TYPE_ACTOR); +} + +static void +clutter_pan_action_init (ClutterPanAction *self) +{ + ClutterPanActionPrivate *priv = self->priv = + G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_PAN_ACTION, + ClutterPanActionPrivate); + priv->deceleration_rate = default_deceleration_rate; + priv->acceleration_factor = default_acceleration_factor; + priv->state = PAN_STATE_INACTIVE; +} + +/** + * clutter_pan_action_new: + * + * Creates a new #ClutterPanAction instance + * + * Return value: the newly created #ClutterPanAction + * + * Since: 1.12 + */ +ClutterAction * +clutter_pan_action_new (void) +{ + return g_object_new (CLUTTER_TYPE_PAN_ACTION, NULL); +} + +/** + * clutter_pan_action_set_pan_axis: + * @self: a #ClutterPanAction + * @axis: the axis to constraint the panning to + * + * Restricts the panning action to a specific axis + * + * Since: 1.12 + */ +void +clutter_pan_action_set_pan_axis (ClutterPanAction *self, + ClutterPanAxis axis) +{ + ClutterPanActionPrivate *priv; + + g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); + g_return_if_fail (axis >= CLUTTER_PAN_AXIS_NONE && + axis <= CLUTTER_PAN_Y_AXIS); + + priv = self->priv; + + if (priv->pan_axis == axis) + return; + + priv->pan_axis = axis; + + g_object_notify_by_pspec (G_OBJECT (self), pan_props[PROP_PAN_AXIS]); +} + +/** + * clutter_pan_action_get_pan_axis: + * @self: a #ClutterPanAction + * + * Retrieves the axis constraint set by clutter_pan_action_set_pan_axis() + * + * Return value: the axis constraint + * + * Since: 1.12 + */ +ClutterPanAxis +clutter_pan_action_get_pan_axis (ClutterPanAction *self) +{ + g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), + CLUTTER_PAN_AXIS_NONE); + + return self->priv->pan_axis; +} + +/** + * clutter_pan_action_set_interpolate: + * @self: a #ClutterPanAction + * @should_interpolate: whether to enable interpolated pan events + * + * Sets whether the action should emit interpolated ::pan events + * after the drag has ended, to emulate the gesture kinetic inertia. + * + * Since: 1.12 + */ +void +clutter_pan_action_set_interpolate (ClutterPanAction *self, + gboolean should_interpolate) +{ + ClutterPanActionPrivate *priv; + + g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); + + priv = self->priv; + + should_interpolate = !!should_interpolate; + + if (priv->should_interpolate == should_interpolate) + return; + + priv->should_interpolate = should_interpolate; + + g_object_notify_by_pspec (G_OBJECT (self), pan_props[PROP_INTERPOLATE]); +} + +/** + * clutter_pan_action_get_interpolate: + * @self: a #ClutterPanAction + * + * Checks if the action should emit ::pan events even after releasing + * the pointer during a panning gesture, to emulate some kind of + * kinetic inertia. + * + * Return value: %TRUE if interpolated events emission is active. + * + * Since: 1.12 + */ +gboolean +clutter_pan_action_get_interpolate (ClutterPanAction *self) +{ + g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), + FALSE); + + return self->priv->should_interpolate; +} + +/** + * clutter_pan_action_set_deceleration: + * @self: A #ClutterPanAction + * @rate: The deceleration rate + * + * Sets the deceleration rate of the interpolated ::pan events generated + * after a pan gesture. This is approximately the value that the momentum + * at the time of releasing the pointer is divided by every 60th of a second. + * + * Since: 1.12 + */ +void +clutter_pan_action_set_deceleration (ClutterPanAction *self, + gdouble rate) +{ + g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); + g_return_if_fail (rate <= 1.0); + g_return_if_fail (rate > 0.0); + + self->priv->deceleration_rate = rate; + g_object_notify_by_pspec (G_OBJECT (self), pan_props[PROP_DECELERATION]); +} + +/** + * clutter_pan_action_get_deceleration: + * @self: A #ClutterPanAction + * + * Retrieves the deceleration rate of interpolated ::pan events. + * + * Return value: The deceleration rate of the interpolated events. + * + * Since: 1.12 + */ +gdouble +clutter_pan_action_get_deceleration (ClutterPanAction *self) +{ + g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), 0.95); + return self->priv->deceleration_rate; +} + +/** + * clutter_pan_action_set_acceleration_factor: + * @self: A #ClutterPanAction + * @factor: The acceleration factor + * + * Factor applied to the momentum velocity at the time of releasing the + * pointer when generating interpolated ::pan events. + * + * Since: 1.12 + */ +void +clutter_pan_action_set_acceleration_factor (ClutterPanAction *self, + gdouble factor) +{ + g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); + g_return_if_fail (factor >= 0.0); + + self->priv->acceleration_factor = factor; + g_object_notify_by_pspec (G_OBJECT (self), pan_props[PROP_ACCELERATION_FACTOR]); +} + +/** + * clutter_pan_action_get_acceleration_factor: + * @self: A #ClutterPanAction + * + * Retrieves the initial acceleration factor for interpolated ::pan events. + * + * Return value: The initial acceleration factor for interpolated events. + * + * Since: 1.12 + */ +gdouble +clutter_pan_action_get_acceleration_factor (ClutterPanAction *self) +{ + g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), 1.0); + return self->priv->acceleration_factor; +} + +/** + * clutter_pan_action_get_interpolated_coords: + * @self: A #ClutterPanAction + * @interpolated_x: (out) (allow-none): return location for the latest + * interpolated event's X coordinate + * @interpolated_y: (out) (allow-none): return location for the latest + * interpolated event's Y coordinate + * + * Retrieves the coordinates, in stage space, of the latest interpolated + * event, analogous to clutter_gesture_action_get_motion_coords(). + * + * Since: 1.12 + */ +void +clutter_pan_action_get_interpolated_coords (ClutterPanAction *self, + gfloat *interpolated_x, + gfloat *interpolated_y) +{ + ClutterPanActionPrivate *priv; + + g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); + + priv = self->priv; + + if (interpolated_x) + *interpolated_x = priv->release_x + priv->interpolated_x; + + if (interpolated_y) + *interpolated_y = priv->release_y + priv->interpolated_y; +} + +/** + * clutter_pan_action_get_interpolated_delta: + * @self: A #ClutterPanAction + * @delta_x: (out) (allow-none): return location for the X delta since + * the latest interpolated event + * @delta_y: (out) (allow-none): return location for the Y delta since + * the latest interpolated event + * + * Retrieves the delta, in stage space, since the latest interpolated + * event, analogous to clutter_gesture_action_get_motion_delta(). + * + * Since: 1.12 + */ +void +clutter_pan_action_get_interpolated_delta (ClutterPanAction *self, + gfloat *delta_x, + gfloat *delta_y) +{ + ClutterPanActionPrivate *priv; + + g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); + + priv = self->priv; + + if (delta_x) + *delta_x = priv->dx; + + if (delta_y) + *delta_y = priv->dy; +} |