mirror of
https://github.com/brl/mutter.git
synced 2024-11-12 17:27:03 -05:00
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
This commit is contained in:
parent
2105055a34
commit
0c75e17814
@ -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;
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -831,6 +854,67 @@ clutter_pan_action_get_interpolated_delta (ClutterPanAction *self,
|
||||
return sqrt ((priv->dx * priv->dx) + (priv->dy * priv->dy));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -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__ */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user