From e2264c04849722954d0f8422a49c8558d6ea8753 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Fri, 22 Jun 2012 02:38:21 +0100 Subject: [PATCH] Add rotate action Allow rotation of an actor using 2 points (touch or pointers) events. Also refactor the accumulators from various actions. https://bugzilla.gnome.org/show_bug.cgi?id=678587 --- clutter/Makefile.am | 2 + clutter/clutter-drag-action.c | 16 +- clutter/clutter-gesture-action.c | 18 +- clutter/clutter-main.c | 14 ++ clutter/clutter-private.h | 9 + clutter/clutter-rotate-action.c | 239 +++++++++++++++++++++ clutter/clutter-rotate-action.h | 100 +++++++++ clutter/clutter.h | 3 +- clutter/clutter.symbols | 2 + doc/reference/clutter/clutter-sections.txt | 17 ++ 10 files changed, 388 insertions(+), 32 deletions(-) create mode 100644 clutter/clutter-rotate-action.c create mode 100644 clutter/clutter-rotate-action.h diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 4bb641efd..abb021f6c 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -105,6 +105,7 @@ source_h = \ $(srcdir)/clutter-path-constraint.h \ $(srcdir)/clutter-path.h \ $(srcdir)/clutter-property-transition.h \ + $(srcdir)/clutter-rotate-action.h \ $(srcdir)/clutter-script.h \ $(srcdir)/clutter-scriptable.h \ $(srcdir)/clutter-scroll-actor.h \ @@ -183,6 +184,7 @@ source_c = \ $(srcdir)/clutter-path-constraint.c \ $(srcdir)/clutter-path.c \ $(srcdir)/clutter-property-transition.c \ + $(srcdir)/clutter-rotate-action.c \ $(srcdir)/clutter-script.c \ $(srcdir)/clutter-script-parser.c \ $(srcdir)/clutter-scriptable.c \ diff --git a/clutter/clutter-drag-action.c b/clutter/clutter-drag-action.c index cdb7952f9..1cd6c1e33 100644 --- a/clutter/clutter-drag-action.c +++ b/clutter/clutter-drag-action.c @@ -640,20 +640,6 @@ clutter_drag_action_dispose (GObject *gobject) G_OBJECT_CLASS (clutter_drag_action_parent_class)->dispose (gobject); } -static gboolean -drag_progress_accum (GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, - gpointer user_data) -{ - gboolean continue_emission; - - continue_emission = g_value_get_boolean (handler_return); - g_value_set_boolean (return_accu, continue_emission); - - return continue_emission; -} - static void clutter_drag_action_class_init (ClutterDragActionClass *klass) { @@ -829,7 +815,7 @@ clutter_drag_action_class_init (ClutterDragActionClass *klass) CLUTTER_TYPE_DRAG_ACTION, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterDragActionClass, drag_progress), - drag_progress_accum, NULL, + _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT_FLOAT_FLOAT, G_TYPE_BOOLEAN, 3, CLUTTER_TYPE_ACTOR, diff --git a/clutter/clutter-gesture-action.c b/clutter/clutter-gesture-action.c index f75919b57..a3b7db83f 100644 --- a/clutter/clutter-gesture-action.c +++ b/clutter/clutter-gesture-action.c @@ -167,20 +167,6 @@ gesture_unregister_point (ClutterGestureAction *action, gint position) g_array_remove_index (priv->points, position); } -static gboolean -signal_accumulator (GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, - gpointer user_data) -{ - gboolean continue_emission; - - continue_emission = g_value_get_boolean (handler_return); - g_value_set_boolean (return_accu, continue_emission); - - return continue_emission; -} - static void cancel_gesture (ClutterGestureAction *action) { @@ -418,7 +404,7 @@ clutter_gesture_action_class_init (ClutterGestureActionClass *klass) G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_begin), - signal_accumulator, NULL, + _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_ACTOR); @@ -441,7 +427,7 @@ clutter_gesture_action_class_init (ClutterGestureActionClass *klass) G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterGestureActionClass, gesture_progress), - signal_accumulator, NULL, + _clutter_boolean_continue_accumulator, NULL, _clutter_marshal_BOOLEAN__OBJECT, G_TYPE_BOOLEAN, 1, CLUTTER_TYPE_ACTOR); diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 8d546e7f4..14c92f825 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -2139,6 +2139,20 @@ _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint, return continue_emission; } +gboolean +_clutter_boolean_continue_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy) +{ + gboolean continue_emission; + + continue_emission = g_value_get_boolean (handler_return); + g_value_set_boolean (return_accu, continue_emission); + + return continue_emission; +} + static void event_click_count_generate (ClutterEvent *event) { diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 8fd30b0df..f855727d7 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -237,6 +237,15 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint, const GValue *handler_return, gpointer dummy); +/* use this function as the accumulator if you have a signal with + * a G_TYPE_BOOLEAN return value; this will stop the emission as + * soon as one handler returns FALSE + */ +gboolean _clutter_boolean_continue_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy); + void _clutter_run_repaint_functions (ClutterRepaintFlags flags); void _clutter_constraint_update_allocation (ClutterConstraint *constraint, diff --git a/clutter/clutter-rotate-action.c b/clutter/clutter-rotate-action.c new file mode 100644 index 000000000..d2fb9a34b --- /dev/null +++ b/clutter/clutter-rotate-action.c @@ -0,0 +1,239 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2012 Intel Corporation. + * + * 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 . + * + * Author: + * Lionel Landwerlin + */ + +/** + * SECTION:clutter-rotate-action + * @Title: ClutterRotateAction + * @Short_Description: Action to rotate an actor + * + * #ClutterRotateAction is a sub-class of #ClutterGestureAction that implements + * the logic for recognizing rotate gestures. + * + * Since: 1.12 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "clutter-rotate-action.h" + +#include "clutter-debug.h" +#include "clutter-enum-types.h" +#include "clutter-marshal.h" +#include "clutter-private.h" + +struct _ClutterRotateActionPrivate +{ + gfloat initial_vector[2]; + gdouble initial_vector_norm; + gdouble initial_rotation; +}; + +enum +{ + ROTATE, + + LAST_SIGNAL +}; + +static guint rotate_signals[LAST_SIGNAL] = { 0, }; + +G_DEFINE_TYPE (ClutterRotateAction, clutter_rotate_action, + CLUTTER_TYPE_GESTURE_ACTION); + +static gboolean +clutter_rotate_action_real_rotate (ClutterRotateAction *action, + ClutterActor *actor, + gdouble angle) +{ + clutter_actor_set_rotation_angle (actor, + CLUTTER_Z_AXIS, + action->priv->initial_rotation + angle); + + return TRUE; +} + +static gboolean +clutter_rotate_action_gesture_begin (ClutterGestureAction *action, + ClutterActor *actor) +{ + ClutterRotateActionPrivate *priv = CLUTTER_ROTATE_ACTION (action)->priv; + gfloat p1[2], p2[2]; + + /* capture initial vector */ + clutter_gesture_action_get_motion_coords (action, 0, &p1[0], &p1[1]); + clutter_gesture_action_get_motion_coords (action, 1, &p2[0], &p2[1]); + + priv->initial_vector[0] = p2[0] - p1[0]; + priv->initial_vector[1] = p2[1] - p1[1]; + + priv->initial_vector_norm = + sqrt (priv->initial_vector[0] * priv->initial_vector[0] + + priv->initial_vector[1] * priv->initial_vector[1]); + + priv->initial_rotation = clutter_actor_get_rotation_angle (actor, CLUTTER_Z_AXIS); + + return TRUE; +} + +static gboolean +clutter_rotate_action_gesture_progress (ClutterGestureAction *action, + ClutterActor *actor) +{ + ClutterRotateActionPrivate *priv = CLUTTER_ROTATE_ACTION (action)->priv; + gfloat p1[2], p2[2]; + gfloat vector[2]; + gboolean retval; + + /* capture current vector */ + clutter_gesture_action_get_motion_coords (action, 0, &p1[0], &p1[1]); + clutter_gesture_action_get_motion_coords (action, 1, &p2[0], &p2[1]); + + vector[0] = p2[0] - p1[0]; + vector[1] = p2[1] - p1[1]; + + if ((vector[0] == priv->initial_vector[0]) && + (vector[1] == priv->initial_vector[1])) + { + g_signal_emit (action, rotate_signals[ROTATE], 0, + actor, (gdouble) 0.0, + &retval); + } + else + { + gfloat mult[2]; + gfloat norm; + gdouble angle; + + /* Computes angle between the 2 initial touch points and the + current position of the 2 touch points. */ + norm = sqrt (vector[0] * vector[0] + vector[1] * vector[1]); + norm = (priv->initial_vector[0] * vector[0] + + priv->initial_vector[1] * vector[1]) / (priv->initial_vector_norm * norm); + + if ((norm >= -1.0) && (norm <= 1.0)) + angle = acos (norm); + else + angle = 0; + + /* The angle given is comprise between 0 and 180 degrees, we + need some logic on top to get a value between 0 and 360. */ + mult[0] = priv->initial_vector[0] * vector[1] - + priv->initial_vector[1] * vector[0]; + mult[1] = priv->initial_vector[1] * vector[0] - + priv->initial_vector[0] * vector[1]; + + if (mult[0] < 0) + angle = -angle; + + /* Convert radians to degrees */ + angle = angle * 180.0 / M_PI; + + g_signal_emit (action, rotate_signals[ROTATE], 0, + actor, angle, + &retval); + } + + return TRUE; +} + +static void +clutter_rotate_action_gesture_cancel (ClutterGestureAction *action, + ClutterActor *actor) +{ + gboolean retval; + + g_signal_emit (action, rotate_signals[ROTATE], 0, + actor, (gdouble) 0.0, + &retval); +} + +static void +clutter_rotate_action_class_init (ClutterRotateActionClass *klass) +{ + ClutterGestureActionClass *gesture_class = + CLUTTER_GESTURE_ACTION_CLASS (klass); + + g_type_class_add_private (klass, sizeof (ClutterRotateActionPrivate)); + + klass->rotate = clutter_rotate_action_real_rotate; + + gesture_class->gesture_begin = clutter_rotate_action_gesture_begin; + gesture_class->gesture_progress = clutter_rotate_action_gesture_progress; + gesture_class->gesture_cancel = clutter_rotate_action_gesture_cancel; + + /** + * ClutterRotateAction::rotate: + * @action: the #ClutterRotateAction that emitted the signal + * @actor: the #ClutterActor attached to the @action + * @angle: the difference of angle of rotation between the initial + * rotation and the current rotation + * + * The ::rotate signal is emitted when a rotate gesture is + * recognized on the attached actor and when the gesture is + * cancelled (in this case with an angle value of 0). + * + * Return value: %TRUE if the rotation should continue, and %FALSE if + * the rotation should be cancelled. + * + * Since: 1.12 + */ + rotate_signals[ROTATE] = + g_signal_new (I_("rotate"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClutterRotateActionClass, rotate), + _clutter_boolean_handled_accumulator, NULL, + _clutter_marshal_VOID__OBJECT_DOUBLE, + G_TYPE_BOOLEAN, 2, + CLUTTER_TYPE_ACTOR, + G_TYPE_DOUBLE); +} + +static void +clutter_rotate_action_init (ClutterRotateAction *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_ROTATE_ACTION, + ClutterRotateActionPrivate); + + clutter_gesture_action_set_n_touch_points (CLUTTER_GESTURE_ACTION (self), 2); +} + +/** + * clutter_rotate_action_new: + * + * Creates a new #ClutterRotateAction instance + * + * Return value: the newly created #ClutterRotateAction + * + * Since: 1.12 + */ +ClutterAction * +clutter_rotate_action_new (void) +{ + return g_object_new (CLUTTER_TYPE_ROTATE_ACTION, NULL); +} diff --git a/clutter/clutter-rotate-action.h b/clutter/clutter-rotate-action.h new file mode 100644 index 000000000..4b0ee54d9 --- /dev/null +++ b/clutter/clutter-rotate-action.h @@ -0,0 +1,100 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2012 Intel Corporation. + * + * 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 . + * + * Author: + * Lionel Landwerlin + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_ROTATE_ACTION_H__ +#define __CLUTTER_ROTATE_ACTION_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_ROTATE_ACTION (clutter_rotate_action_get_type ()) +#define CLUTTER_ROTATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ROTATE_ACTION, ClutterRotateAction)) +#define CLUTTER_IS_ROTATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ROTATE_ACTION)) +#define CLUTTER_ROTATE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ROTATE_ACTION, ClutterRotateActionClass)) +#define CLUTTER_IS_ROTATE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ROTATE_ACTION)) +#define CLUTTER_ROTATE_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ROTATE_ACTION, ClutterRotateActionClass)) + +typedef struct _ClutterRotateAction ClutterRotateAction; +typedef struct _ClutterRotateActionPrivate ClutterRotateActionPrivate; +typedef struct _ClutterRotateActionClass ClutterRotateActionClass; + +/** + * ClutterRotateAction: + * + * The ClutterRotateAction structure contains + * only private data and should be accessed using the provided API + * + * Since: 1.12 + */ +struct _ClutterRotateAction +{ + /*< private >*/ + ClutterGestureAction parent_instance; + + ClutterRotateActionPrivate *priv; +}; + +/** + * ClutterRotateActionClass: + * @swept: class handler for the #ClutterRotateAction::rotate signal + * + * The ClutterRotateActionClass structure contains + * only private data. + * + * Since: 1.12 + */ +struct _ClutterRotateActionClass +{ + /*< private >*/ + ClutterGestureActionClass parent_class; + + /*< public >*/ + gboolean (* rotate) (ClutterRotateAction *action, + ClutterActor *actor, + gdouble angle); + + /*< private >*/ + void (* _clutter_rotate_action1) (void); + void (* _clutter_rotate_action2) (void); + void (* _clutter_rotate_action3) (void); + void (* _clutter_rotate_action4) (void); + void (* _clutter_rotate_action5) (void); + void (* _clutter_rotate_action6) (void); + void (* _clutter_rotate_action7) (void); +}; + +CLUTTER_AVAILABLE_IN_1_12 +GType clutter_rotate_action_get_type (void) G_GNUC_CONST; + +CLUTTER_AVAILABLE_IN_1_12 +ClutterAction *clutter_rotate_action_new (void); + +G_END_DECLS + +#endif /* __CLUTTER_ROTATE_ACTION_H__ */ diff --git a/clutter/clutter.h b/clutter/clutter.h index 821a58bdf..991bde3a3 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -72,7 +72,7 @@ #include "clutter-input-device.h" #include "clutter-interval.h" #include "clutter-keyframe-transition.h" -#include "clutter-keysyms.h" +#include "clutter-keysyms.h" #include "clutter-layout-manager.h" #include "clutter-layout-meta.h" #include "clutter-list-model.h" @@ -86,6 +86,7 @@ #include "clutter-path-constraint.h" #include "clutter-path.h" #include "clutter-property-transition.h" +#include "clutter-rotate-action.h" #include "clutter-scriptable.h" #include "clutter-script.h" #include "clutter-scroll-actor.h" diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols index d4ae77cf2..88419c057 100644 --- a/clutter/clutter.symbols +++ b/clutter/clutter.symbols @@ -1091,6 +1091,8 @@ clutter_rectangle_set_color clutter_redraw clutter_repaint_flags_get_type clutter_request_mode_get_type +clutter_rotate_action_get_type +clutter_rotate_action_new clutter_rotate_axis_get_type clutter_rotate_direction_get_type clutter_scaling_filter_get_type diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index eb2ca5781..1a40b77bf 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -2978,6 +2978,23 @@ ClutterDropActionPrivate clutter_drop_action_get_type +
+clutter-rotate-action +ClutterRotateAction +ClutterRotateActionClass +clutter_rotate_action_new + +CLUTTER_ROTATE_ACTION +CLUTTER_ROTATE_ACTION_CLASS +CLUTTER_IS_ROTATE_ACTION +CLUTTER_IS_ROTATE_ACTION_CLASS +CLUTTER_ROTATE_ACTION_GET_CLASS +CLUTTER_TYPE_ROTATE_ACTION + +ClutterRotateActionPrivate +clutter_rotate_action_get_type +
+
clutter-transition ClutterTransition