diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2013-01-17 21:06:06 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2014-05-23 19:54:21 +0200 |
commit | 2495b518c1bf889e93cd90e53640117d8f7bc1fd (patch) | |
tree | 26e86c1d9b671c0bd6e78885f03f3ff57ba6f021 /gtk/gtkgesturerotate.c | |
parent | 8733e2a918c9ce244fb00bc28623436ec98c23ca (diff) | |
download | gtk+-2495b518c1bf889e93cd90e53640117d8f7bc1fd.tar.gz |
Add GtkGestureRotate
This gesture implementation recognizes rotations when fed with
events from two different GdkEventSequences
Diffstat (limited to 'gtk/gtkgesturerotate.c')
-rw-r--r-- | gtk/gtkgesturerotate.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/gtk/gtkgesturerotate.c b/gtk/gtkgesturerotate.c new file mode 100644 index 0000000000..74edda487f --- /dev/null +++ b/gtk/gtkgesturerotate.c @@ -0,0 +1,206 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2012, One Laptop Per Child. + * Copyright (C) 2014, Red Hat, Inc. + * + * 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 <http://www.gnu.org/licenses/>. + * + * Author(s): Carlos Garnacho <carlosg@gnome.org> + */ +#include "config.h" +#include <math.h> +#include <gtk/gtkgesturerotate.h> +#include "gtkmarshalers.h" + +typedef struct _GtkGestureRotatePrivate GtkGestureRotatePrivate; + +enum { + ANGLE_CHANGED, + LAST_SIGNAL +}; + +struct _GtkGestureRotatePrivate +{ + gdouble initial_angle; +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureRotate, gtk_gesture_rotate, GTK_TYPE_GESTURE) + +static void +gtk_gesture_rotate_init (GtkGestureRotate *gesture) +{ +} + +static GObject * +gtk_gesture_rotate_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object; + + object = G_OBJECT_CLASS (gtk_gesture_rotate_parent_class)->constructor (type, + n_construct_properties, + construct_properties); + g_object_set (object, "n-points", 2, NULL); + + return object; +} + +static gboolean +_gtk_gesture_rotate_get_angle (GtkGestureRotate *rotate, + gdouble *angle) +{ + gdouble x1, y1, x2, y2; + GtkGesture *gesture; + gdouble dx, dy; + GList *sequences; + + gesture = GTK_GESTURE (rotate); + + if (!gtk_gesture_is_recognized (gesture)) + return FALSE; + + sequences = gtk_gesture_get_sequences (gesture); + g_assert (sequences && sequences->next); + + gtk_gesture_get_point (gesture, sequences->data, &x1, &y1); + gtk_gesture_get_point (gesture, sequences->next->data, &x2, &y2); + g_list_free (sequences); + + dx = x1 - x2; + dy = y1 - y2; + + *angle = atan2 (dx, dy); + + /* Invert angle */ + *angle = (2 * G_PI) - *angle; + + /* And constraint it to 0°-360° */ + *angle = fmod (*angle, 2 * G_PI); + + return TRUE; +} + +static gboolean +_gtk_gesture_rotate_check_emit (GtkGestureRotate *gesture) +{ + GtkGestureRotatePrivate *priv; + gdouble angle; + + if (!_gtk_gesture_rotate_get_angle (gesture, &angle)) + return FALSE; + + priv = gtk_gesture_rotate_get_instance_private (gesture); + + g_signal_emit (gesture, signals[ANGLE_CHANGED], 0, + angle, angle - priv->initial_angle); + return TRUE; +} + +static void +gtk_gesture_rotate_begin (GtkGesture *gesture, + GdkEventSequence *sequence) +{ + GtkGestureRotate *rotate = GTK_GESTURE_ROTATE (gesture); + GtkGestureRotatePrivate *priv; + + priv = gtk_gesture_rotate_get_instance_private (rotate); + _gtk_gesture_rotate_get_angle (rotate, &priv->initial_angle); +} + +static void +gtk_gesture_rotate_update (GtkGesture *gesture, + GdkEventSequence *sequence) +{ + _gtk_gesture_rotate_check_emit (GTK_GESTURE_ROTATE (gesture)); +} + +static void +gtk_gesture_rotate_class_init (GtkGestureRotateClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass); + + object_class->constructor = gtk_gesture_rotate_constructor; + + gesture_class->begin = gtk_gesture_rotate_begin; + gesture_class->update = gtk_gesture_rotate_update; + + /** + * GtkGestureRotate::angle-changed: + * @gesture: the object on which the signal is emitted + * @angle: Current angle in radians + * @angle_delta: Difference with the starting angle in radians + */ + signals[ANGLE_CHANGED] = + g_signal_new ("angle-changed", + GTK_TYPE_GESTURE_ROTATE, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkGestureRotateClass, angle_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE); +} + +/** + * gtk_gesture_rotate_new: + * @widget: a #GtkWidget + * + * Returns a newly created #GtkGesture that recognizes 2-touch + * rotation gestures. + * + * Returns: a newly created #GtkGestureRotate + * + * Since: 3.14 + **/ +GtkGesture * +gtk_gesture_rotate_new (GtkWidget *widget) +{ + return g_object_new (GTK_TYPE_GESTURE_ROTATE, + "widget", widget, + NULL); +} + +/** + * gtk_gesture_rotate_get_angle_delta: + * @gesture: a #GtkGestureRotate + * @delta: (out) (transfer none): angle delta + * + * If @gesture is active, this function returns %TRUE and fills + * in @delta with the angle difference in radians since the + * gesture was first recognized. + * + * Returns: %TRUE if @controller is recognizing a rotate gesture + * + * Since: 3.14 + **/ +gboolean +gtk_gesture_rotate_get_angle_delta (GtkGestureRotate *gesture, + gdouble *delta) +{ + GtkGestureRotatePrivate *priv; + gdouble angle; + + g_return_val_if_fail (GTK_IS_GESTURE_ROTATE (gesture), FALSE); + + if (!_gtk_gesture_rotate_get_angle (gesture, &angle)) + return FALSE; + + priv = gtk_gesture_rotate_get_instance_private (gesture); + + if (delta) + *delta = angle - priv->initial_angle; + + return TRUE; +} |