static gboolean on_pan (ClutterPanAction *action, ClutterActor *scroll, gboolean is_interpolated, gpointer *user_data) { gfloat delta_x, delta_y; const ClutterEvent *event = NULL; if (is_interpolated) clutter_pan_action_get_interpolated_delta (action, &delta_x, &delta_y); else { clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (action), 0, &delta_x, &delta_y); event = clutter_gesture_action_get_last_event (CLUTTER_GESTURE_ACTION (action), 0); } g_print ("[%s] panning dx:%.2f dy:%.2f\n", event == NULL ? "INTERPOLATED" : event->type == CLUTTER_MOTION ? "MOTION" : event->type == CLUTTER_TOUCH_UPDATE ? "TOUCH UPDATE" : "?", delta_x, delta_y); return TRUE; }
static void clutter_gesture_action_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { ClutterGestureAction *self = CLUTTER_GESTURE_ACTION (gobject); switch (prop_id) { case PROP_N_TOUCH_POINTS: clutter_gesture_action_set_n_touch_points (self, g_value_get_int (value)); break; case PROP_THRESHOLD_TRIGGER_EDGE: clutter_gesture_action_set_threshold_trigger_edge (self, g_value_get_enum (value)); break; case PROP_THRESHOLD_TRIGGER_DISTANCE_X: clutter_gesture_action_set_threshold_trigger_distance (self, g_value_get_float (value), self->priv->distance_y); break; case PROP_THRESHOLD_TRIGGER_DISTANCE_Y: clutter_gesture_action_set_threshold_trigger_distance (self, self->priv->distance_x, g_value_get_float (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } }
/** * clutter_pan_action_get_motion_coords: * @self: A #ClutterPanAction * @point: the touch point index, with 0 being the first touch * point received by the action * @motion_x: (out) (allow-none): return location for the X coordinate * @motion_y: (out) (allow-none): return location for the Y coordinate * * Retrieves the coordinates, in stage space, dependent on the current state * of the #ClutterPanAction. If it is inactive, both fields will be * set to 0. If it is panning by user action, the values will be equivalent * to those returned by clutter_gesture_action_get_motion_coords(). * If it is interpolating with some form of kinetic scrolling, the values * will be equivalent to those returned by * clutter_pan_action_get_interpolated_coords(). This is a convenience * method designed to be used in replacement "pan" signal handlers. */ void clutter_pan_action_get_motion_coords (ClutterPanAction *self, guint point, gfloat *motion_x, gfloat *motion_y) { ClutterPanActionPrivate *priv; g_return_if_fail (CLUTTER_IS_PAN_ACTION (self)); priv = self->priv; switch (priv->state) { case PAN_STATE_INACTIVE: if (motion_x) *motion_x = 0; if (motion_y) *motion_y = 0; break; case PAN_STATE_PANNING: clutter_gesture_action_get_motion_coords (CLUTTER_GESTURE_ACTION (self), point, motion_x, motion_y); break; case PAN_STATE_INTERPOLATING: clutter_pan_action_get_interpolated_coords (self, motion_x, motion_y); break; default: g_assert_not_reached (); } }
/** * clutter_pan_action_get_motion_delta: * @self: A #ClutterPanAction * @point: the touch point index, with 0 being the first touch * point received by the action * @delta_x: (out) (allow-none): return location for the X delta * @delta_y: (out) (allow-none): return location for the Y delta * * Retrieves the delta, in stage space, dependent on the current state * of the #ClutterPanAction. If it is inactive, both fields will be * set to 0. If it is panning by user action, the values will be equivalent * to those returned by clutter_gesture_action_get_motion_delta(). * If it is interpolating with some form of kinetic scrolling, the values * will be equivalent to those returned by * clutter_pan_action_get_interpolated_delta(). This is a convenience * method designed to be used in replacement "pan" signal handlers. */ gfloat clutter_pan_action_get_motion_delta (ClutterPanAction *self, guint point, gfloat *delta_x, gfloat *delta_y) { ClutterPanActionPrivate *priv; g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), 0.0f); priv = self->priv; switch (priv->state) { case PAN_STATE_INACTIVE: if (delta_x) *delta_x = 0; if (delta_y) *delta_y = 0; return 0; case PAN_STATE_PANNING: return clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (self), point, delta_x, delta_y); case PAN_STATE_INTERPOLATING: return clutter_pan_action_get_interpolated_delta (self, delta_x, delta_y); default: g_assert_not_reached (); } }
static void clutter_gesture_action_finalize (GObject *gobject) { ClutterGestureActionPrivate *priv = CLUTTER_GESTURE_ACTION (gobject)->priv; g_array_unref (priv->points); G_OBJECT_CLASS (clutter_gesture_action_parent_class)->finalize (gobject); }
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 void clutter_zoom_action_init (ClutterZoomAction *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_ZOOM_ACTION, ClutterZoomActionPrivate); self->priv->zoom_axis = CLUTTER_ZOOM_BOTH; clutter_gesture_action_set_n_touch_points (CLUTTER_GESTURE_ACTION (self), 2); }
static void clutter_gesture_action_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { ClutterGestureAction *self = CLUTTER_GESTURE_ACTION (gobject); switch (prop_id) { case PROP_N_TOUCH_POINTS: g_value_set_int (value, self->priv->requested_nb_points); break; case PROP_THRESHOLD_TRIGGER_EDGE: g_value_set_enum (value, self->priv->edge); break; case PROP_THRESHOLD_TRIGGER_DISTANCE_X: if (self->priv->distance_x > 0.0) g_value_set_float (value, self->priv->distance_x); else g_value_set_float (value, gesture_get_default_threshold ()); break; case PROP_THRESHOLD_TRIGGER_DISTANCE_Y: if (self->priv->distance_y > 0.0) g_value_set_float (value, self->priv->distance_y); else g_value_set_float (value, gesture_get_default_threshold ()); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } }
static void clutter_gesture_action_set_actor (ClutterActorMeta *meta, ClutterActor *actor) { ClutterGestureActionPrivate *priv = CLUTTER_GESTURE_ACTION (meta)->priv; ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (clutter_gesture_action_parent_class); if (priv->actor_capture_id != 0) { ClutterActor *old_actor = clutter_actor_meta_get_actor (meta); if (old_actor != NULL) g_signal_handler_disconnect (old_actor, priv->actor_capture_id); priv->actor_capture_id = 0; } if (priv->stage_capture_id != 0) { if (priv->stage != NULL) g_signal_handler_disconnect (priv->stage, priv->stage_capture_id); priv->stage_capture_id = 0; priv->stage = NULL; } if (actor != NULL) { priv->actor_capture_id = g_signal_connect (actor, "captured-event", G_CALLBACK (actor_captured_event_cb), meta); } meta_class->set_actor (meta, actor); }
static void clutter_tap_action_init (ClutterTapAction *self) { _clutter_gesture_action_set_threshold_trigger_edge (CLUTTER_GESTURE_ACTION (self), CLUTTER_GESTURE_TRIGGER_EDGE_BEFORE); }