[clutter] Add PanAxis mode that automatically pins scroll based on initial movement
- From: Gustavo Noronha Silva <gns src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter] Add PanAxis mode that automatically pins scroll based on initial movement
- Date: Thu, 11 Jun 2015 18:48:15 +0000 (UTC)
commit 0c75e178145c3296f05deefed34be3691b1ffb3b
Author: Gustavo Noronha Silva <gustavo noronha collabora com>
Date: Wed Sep 11 12:33:57 2013 -0300
Add PanAxis mode that automatically pins scroll based on initial movement
This code is inspired by the implementation of the same feature for the
Mx toolkit's MxKineticScrollView. See commit 4d08771.
https://bugzilla.gnome.org/show_bug.cgi?id=707982
clutter/clutter-enums.h | 6 ++-
clutter/clutter-pan-action.c | 120 ++++++++++++++++++++++++++++++------
clutter/clutter-pan-action.h | 5 ++
doc/reference/clutter-sections.txt | 1 +
examples/pan-action.c | 58 ++++++++++++++++-
5 files changed, 167 insertions(+), 23 deletions(-)
---
diff --git a/clutter/clutter-enums.h b/clutter/clutter-enums.h
index 9dd1b66..859579d 100644
--- a/clutter/clutter-enums.h
+++ b/clutter/clutter-enums.h
@@ -1018,6 +1018,8 @@ typedef enum { /*< prefix=CLUTTER_SWIPE_DIRECTION >*/
* @CLUTTER_PAN_AXIS_NONE: No constraint
* @CLUTTER_PAN_X_AXIS: Set a constraint on the X axis
* @CLUTTER_PAN_Y_AXIS: Set a constraint on the Y axis
+ * @CLUTTER_PAN_AXIS_AUTO: Constrain panning automatically based on initial
+ * movement (available since 1.24)
*
* The axis of the constraint that should be applied on the
* panning action
@@ -1028,7 +1030,9 @@ typedef enum { /*< prefix=CLUTTER_PAN >*/
CLUTTER_PAN_AXIS_NONE = 0,
CLUTTER_PAN_X_AXIS,
- CLUTTER_PAN_Y_AXIS
+ CLUTTER_PAN_Y_AXIS,
+
+ CLUTTER_PAN_AXIS_AUTO
} ClutterPanAxis;
diff --git a/clutter/clutter-pan-action.c b/clutter/clutter-pan-action.c
index a1f6124..f2d1e18 100644
--- a/clutter/clutter-pan-action.c
+++ b/clutter/clutter-pan-action.c
@@ -5,7 +5,7 @@
*
* Copyright (C) 2010 Intel Corporation.
* Copyright (C) 2011 Robert Bosch Car Multimedia GmbH.
- * Copyright (C) 2012 Collabora Ltd.
+ * Copyright (C) 2012, 2014 Collabora Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -80,6 +80,14 @@ typedef enum
PAN_STATE_INTERPOLATING
} PanState;
+typedef enum
+{
+ SCROLL_PINNED_UNKNOWN,
+ SCROLL_PINNED_NONE,
+ SCROLL_PINNED_HORIZONTAL,
+ SCROLL_PINNED_VERTICAL
+} PinState;
+
struct _ClutterPanActionPrivate
{
ClutterPanAxis pan_axis;
@@ -102,6 +110,8 @@ struct _ClutterPanActionPrivate
gfloat release_y;
guint should_interpolate : 1;
+
+ PinState pin_state;
};
enum
@@ -135,7 +145,34 @@ emit_pan (ClutterPanAction *self,
ClutterActor *actor,
gboolean is_interpolated)
{
+ ClutterPanActionPrivate *priv = self->priv;
gboolean retval;
+
+ if (priv->pin_state == SCROLL_PINNED_UNKNOWN)
+ {
+ priv->pin_state = SCROLL_PINNED_NONE;
+ if (priv->pan_axis == CLUTTER_PAN_AXIS_AUTO)
+ {
+ gfloat delta_x;
+ gfloat delta_y;
+ gfloat scroll_threshold = G_PI_4/2;
+ gfloat drag_angle;
+
+ clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (self), 0, &delta_x, &delta_y);
+
+ if (delta_x != 0.0f)
+ drag_angle = atanf (delta_y / delta_x);
+ else
+ drag_angle = G_PI_2;
+
+ if ((drag_angle > -scroll_threshold) && (drag_angle < scroll_threshold))
+ priv->pin_state = SCROLL_PINNED_HORIZONTAL;
+ else if ((drag_angle > (G_PI_2 - scroll_threshold)) ||
+ (drag_angle < -(G_PI_2 - scroll_threshold)))
+ priv->pin_state = SCROLL_PINNED_VERTICAL;
+ }
+ }
+
g_signal_emit (self, pan_signals[PAN], 0, actor, is_interpolated, &retval);
}
@@ -207,6 +244,7 @@ gesture_begin (ClutterGestureAction *gesture,
ClutterPanAction *self = CLUTTER_PAN_ACTION (gesture);
ClutterPanActionPrivate *priv = self->priv;
+ priv->pin_state = SCROLL_PINNED_UNKNOWN;
priv->state = PAN_STATE_PANNING;
priv->interpolated_x = priv->interpolated_y = 0.0f;
priv->dx = priv->dy = 0.0f;
@@ -297,25 +335,10 @@ clutter_pan_action_real_pan (ClutterPanAction *self,
ClutterActor *actor,
gboolean is_interpolated)
{
- ClutterPanActionPrivate *priv = self->priv;
gfloat dx, dy;
ClutterMatrix transform;
- clutter_pan_action_get_motion_delta (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_pan_action_get_constrained_motion_delta (self, 0, &dx, &dy);
clutter_actor_get_child_transform (actor, &transform);
cogl_matrix_translate (&transform, dx, dy, 0.0f);
@@ -605,7 +628,7 @@ clutter_pan_action_set_pan_axis (ClutterPanAction *self,
g_return_if_fail (CLUTTER_IS_PAN_ACTION (self));
g_return_if_fail (axis >= CLUTTER_PAN_AXIS_NONE &&
- axis <= CLUTTER_PAN_Y_AXIS);
+ axis <= CLUTTER_PAN_AXIS_AUTO);
priv = self->priv;
@@ -832,6 +855,67 @@ clutter_pan_action_get_interpolated_delta (ClutterPanAction *self,
}
/**
+ * clutter_pan_action_get_constrained_motion_delta:
+ * @self: A #ClutterPanAction
+ * @point: the touch point index, with 0 being the first touch
+ * point received by the action
+ * @delta_x: (out) (optional): return location for the X delta
+ * @delta_y: (out) (optional): return location for the Y delta
+ *
+ * Retrieves the delta, in stage space, dependent on the current state
+ * of the #ClutterPanAction, and respecting the constraint specified by the
+ * #ClutterPanAction:pan-axis property.
+ *
+ * Return value: the distance since last motion event
+ *
+ * Since: 1.24
+ */
+gfloat
+clutter_pan_action_get_constrained_motion_delta (ClutterPanAction *self,
+ guint point,
+ gfloat *out_delta_x,
+ gfloat *out_delta_y)
+{
+ ClutterPanActionPrivate *priv;
+ gfloat delta_x = 0.f, delta_y = 0.f, distance;
+
+ g_return_val_if_fail (CLUTTER_IS_PAN_ACTION (self), 0.0f);
+
+ priv = self->priv;
+
+ distance = clutter_pan_action_get_motion_delta (self, point, &delta_x, &delta_y);
+
+ switch (priv->pan_axis)
+ {
+ case CLUTTER_PAN_AXIS_NONE:
+ break;
+
+ case CLUTTER_PAN_AXIS_AUTO:
+ if (priv->pin_state == SCROLL_PINNED_VERTICAL)
+ delta_x = 0.0f;
+ else if (priv->pin_state == SCROLL_PINNED_HORIZONTAL)
+ delta_y = 0.0f;
+ break;
+
+ case CLUTTER_PAN_X_AXIS:
+ delta_y = 0.0f;
+ break;
+
+ case CLUTTER_PAN_Y_AXIS:
+ delta_x = 0.0f;
+ break;
+ }
+
+ if (out_delta_x)
+ *out_delta_x = delta_x;
+
+ if (out_delta_y)
+ *out_delta_y = delta_y;
+
+ return distance;
+}
+
+/**
* clutter_pan_action_get_motion_delta:
* @self: A #ClutterPanAction
* @point: the touch point index, with 0 being the first touch
diff --git a/clutter/clutter-pan-action.h b/clutter/clutter-pan-action.h
index 8d90b7a..37f0c99 100644
--- a/clutter/clutter-pan-action.h
+++ b/clutter/clutter-pan-action.h
@@ -142,6 +142,11 @@ void clutter_pan_action_get_motion_coords (ClutterPanAction *s
guint point,
gfloat *motion_x,
gfloat *motion_y);
+CLUTTER_AVAILABLE_IN_1_24
+gfloat clutter_pan_action_get_constrained_motion_delta (ClutterPanAction *self,
+ guint point,
+ gfloat *delta_x,
+ gfloat *delta_y);
G_END_DECLS
#endif /* __CLUTTER_PAN_ACTION_H__ */
diff --git a/doc/reference/clutter-sections.txt b/doc/reference/clutter-sections.txt
index 56389db..0f807df 100644
--- a/doc/reference/clutter-sections.txt
+++ b/doc/reference/clutter-sections.txt
@@ -3566,6 +3566,7 @@ clutter_pan_action_get_interpolated_coords
clutter_pan_action_get_interpolated_delta
clutter_pan_action_get_motion_coords
clutter_pan_action_get_motion_delta
+clutter_pan_action_get_constrained_motion_delta
<SUBSECTION Standard>
CLUTTER_IS_PAN_ACTION
CLUTTER_IS_PAN_ACTION_CLASS
diff --git a/examples/pan-action.c b/examples/pan-action.c
index e873305..4e3f73f 100644
--- a/examples/pan-action.c
+++ b/examples/pan-action.c
@@ -83,7 +83,7 @@ create_scroll_actor (ClutterActor *stage)
pan_action = clutter_pan_action_new ();
clutter_pan_action_set_interpolate (CLUTTER_PAN_ACTION (pan_action), TRUE);
g_signal_connect (pan_action, "pan", G_CALLBACK (on_pan), NULL);
- clutter_actor_add_action (scroll, pan_action);
+ clutter_actor_add_action_with_name (scroll, "pan", pan_action);
clutter_actor_set_reactive (scroll, TRUE);
@@ -113,10 +113,45 @@ on_key_press (ClutterActor *stage,
return CLUTTER_EVENT_STOP;
}
+static gboolean
+label_clicked_cb (ClutterText *label, ClutterEvent *event, ClutterActor *scroll)
+{
+ ClutterPanAction *action = CLUTTER_PAN_ACTION (clutter_actor_get_action (scroll, "pan"));
+ const gchar *label_text = clutter_text_get_text (label);
+
+ if (g_str_equal (label_text, "X AXIS"))
+ clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_X_AXIS);
+ else if (g_str_equal (label_text, "Y AXIS"))
+ clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_Y_AXIS);
+ else if (g_str_equal (label_text, "AUTO"))
+ clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_AXIS_AUTO);
+ else
+ clutter_pan_action_set_pan_axis (action, CLUTTER_PAN_AXIS_NONE);
+
+ return TRUE;
+}
+
+static void
+add_label (const gchar *text, ClutterActor *box, ClutterActor *scroll)
+{
+ ClutterActor *label;
+
+ label = clutter_text_new_with_text (NULL, text);
+ clutter_actor_set_reactive (label, TRUE);
+ clutter_actor_set_x_align (label, CLUTTER_ACTOR_ALIGN_START);
+ clutter_actor_set_x_expand (label, TRUE);
+
+ clutter_actor_add_child (box, label);
+
+ g_signal_connect (label, "button-release-event",
+ G_CALLBACK (label_clicked_cb), scroll);
+}
+
int
main (int argc, char *argv[])
{
- ClutterActor *stage, *scroll, *info;
+ ClutterActor *stage, *scroll, *box, *info;
+ ClutterLayoutManager *layout;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
@@ -129,9 +164,24 @@ main (int argc, char *argv[])
scroll = create_scroll_actor (stage);
clutter_actor_add_child (stage, scroll);
+ box = clutter_actor_new ();
+ clutter_actor_add_child (stage, box);
+ clutter_actor_set_position (box, 12, 12);
+
+ layout = clutter_box_layout_new ();
+ clutter_box_layout_set_orientation (CLUTTER_BOX_LAYOUT (layout), CLUTTER_ORIENTATION_VERTICAL);
+ clutter_actor_set_layout_manager (box, layout);
+
info = clutter_text_new_with_text (NULL, "Press <space> to reset the image position.");
- clutter_actor_add_child (stage, info);
- clutter_actor_set_position (info, 12, 12);
+ clutter_actor_add_child (box, info);
+
+ info = clutter_text_new_with_text (NULL, "Click labels below to change AXIS pinning.");
+ clutter_actor_add_child (box, info);
+
+ add_label ("NONE", box, scroll);
+ add_label ("X AXIS", box, scroll);
+ add_label ("Y AXIS", box, scroll);
+ add_label ("AUTO", box, scroll);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
g_signal_connect (stage, "key-press-event", G_CALLBACK (on_key_press), scroll);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]