Пример #1
0
/**
 * clutter_gesture_action_get_velocity:
 * @action: a #ClutterGestureAction
 * @point: the touch point index, with 0 being the first touch
 *   point received by the action
 * @velocity_x: (out) (allow-none): return location for the latest motion
 *   event's X velocity
 * @velocity_y: (out) (allow-none): return location for the latest motion
 *   event's Y velocity
 *
 * Retrieves the velocity, in stage pixels per millisecond, of the
 * latest motion event during the dragging.
 *
 * Since: 1.12
 */
gfloat
clutter_gesture_action_get_velocity (ClutterGestureAction *action,
                                     guint                 point,
                                     gfloat               *velocity_x,
                                     gfloat               *velocity_y)
{
  gfloat d_x, d_y, distance, velocity;
  gint64 d_t;

  g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0);
  g_return_val_if_fail (action->priv->points->len > point, 0);

  distance = clutter_gesture_action_get_motion_delta (action, point,
                                                      &d_x, &d_y);

  d_t = g_array_index (action->priv->points,
                       GesturePoint,
                       point).last_delta_time;

  if (velocity_x)
    *velocity_x = d_t > FLOAT_EPSILON ? d_x / d_t : 0;

  if (velocity_y)
    *velocity_y = d_t > FLOAT_EPSILON ? d_y / d_t : 0;

  velocity = d_t > FLOAT_EPSILON ? distance / d_t : 0;
  return velocity;
}
Пример #2
0
/**
 * 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 ();
    }
}
Пример #3
0
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;
}
Пример #4
0
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);
    }
}