diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 765df15be0..a91bb1055d 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -284,6 +284,7 @@ gtk_public_h_sources = \ gtkgesturedrag.h \ gtkgesturelongpress.h \ gtkgesturemultipress.h \ + gtkgesturepan.h \ gtkgesturerotate.h \ gtkgesturesingle.h \ gtkgestureswipe.h \ @@ -785,6 +786,7 @@ gtk_base_c_sources = \ gtkgesturedrag.c \ gtkgesturelongpress.c \ gtkgesturemultipress.c \ + gtkgesturepan.c \ gtkgesturerotate.c \ gtkgesturesingle.c \ gtkgestureswipe.c \ diff --git a/gtk/gtk.h b/gtk/gtk.h index 219ca81188..eabc028be2 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -110,6 +110,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index 1653746912..77983d2ad6 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -1063,4 +1063,18 @@ typedef enum GTK_EVENT_SEQUENCE_DENIED } GtkEventSequenceState; +typedef enum +{ + GTK_PAN_DIRECTION_LEFT, + GTK_PAN_DIRECTION_RIGHT, + GTK_PAN_DIRECTION_UP, + GTK_PAN_DIRECTION_DOWN +} GtkPanDirection; + +typedef enum +{ + GTK_PAN_ORIENTATION_VERTICAL, + GTK_PAN_ORIENTATION_HORIZONTAL +} GtkPanOrientation; + #endif /* __GTK_ENUMS_H__ */ diff --git a/gtk/gtkgesturepan.c b/gtk/gtkgesturepan.c new file mode 100644 index 0000000000..5f4eb3d249 --- /dev/null +++ b/gtk/gtkgesturepan.c @@ -0,0 +1,274 @@ +/* GTK - The GIMP Toolkit + * 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 . + * + * Author(s): Carlos Garnacho + */ +#include "config.h" +#include +#include "gtktypebuiltins.h" +#include "gtkprivate.h" +#include "gtkintl.h" + +typedef struct _GtkGesturePanPrivate GtkGesturePanPrivate; + +struct _GtkGesturePanPrivate +{ + guint orientation : 2; + guint panning : 1; +}; + +enum { + PROP_ORIENTATION = 1 +}; + +enum { + PAN, + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0 }; + +G_DEFINE_TYPE (GtkGesturePan, gtk_gesture_pan, GTK_TYPE_GESTURE_DRAG) + +static void +gtk_gesture_pan_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkGesturePanPrivate *priv; + + priv = gtk_gesture_pan_get_instance_private (GTK_GESTURE_PAN (object)); + + switch (prop_id) + { + case PROP_ORIENTATION: + g_value_set_enum (value, priv->orientation); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtk_gesture_pan_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + case PROP_ORIENTATION: + gtk_gesture_pan_set_orientation (GTK_GESTURE_PAN (object), + g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +direction_from_offset (gdouble offset_x, + gdouble offset_y, + GtkPanOrientation orientation, + GtkPanDirection *direction) +{ + if (orientation == GTK_PAN_ORIENTATION_HORIZONTAL) + { + if (offset_x > 0) + *direction = GTK_PAN_DIRECTION_RIGHT; + else + *direction = GTK_PAN_DIRECTION_LEFT; + } + else if (orientation == GTK_PAN_ORIENTATION_VERTICAL) + { + if (offset_y > 0) + *direction = GTK_PAN_DIRECTION_DOWN; + else + *direction = GTK_PAN_DIRECTION_UP; + } + else + g_assert_not_reached (); +} + +static gboolean +guess_direction (GtkGesturePan *gesture, + gdouble offset_x, + gdouble offset_y, + GtkPanDirection *direction) +{ + gdouble abs_x, abs_y; + + abs_x = ABS (offset_x); + abs_y = ABS (offset_y); + +#define FACTOR 3 + if (abs_x > abs_y * FACTOR) + direction_from_offset (offset_x, offset_y, + GTK_PAN_ORIENTATION_HORIZONTAL, direction); + else if (abs_y > abs_x * FACTOR) + direction_from_offset (offset_x, offset_y, + GTK_PAN_ORIENTATION_VERTICAL, direction); + else + return FALSE; + + return TRUE; +#undef FACTOR +} + +static gboolean +check_orientation_matches (GtkGesturePan *gesture, + GtkPanDirection direction) +{ + GtkGesturePanPrivate *priv = gtk_gesture_pan_get_instance_private (gesture); + + if (priv->orientation == 0) + return FALSE; + + return (((direction == GTK_PAN_DIRECTION_LEFT || + direction == GTK_PAN_DIRECTION_RIGHT) && + priv->orientation == GTK_PAN_ORIENTATION_HORIZONTAL) || + ((direction == GTK_PAN_DIRECTION_UP || + direction == GTK_PAN_DIRECTION_DOWN) && + priv->orientation == GTK_PAN_ORIENTATION_VERTICAL)); +} + +static void +gtk_gesture_pan_drag_update (GtkGestureDrag *gesture, + gdouble offset_x, + gdouble offset_y) +{ + GtkGesturePanPrivate *priv; + GtkPanDirection direction; + GtkGesturePan *pan; + gdouble offset; + + pan = GTK_GESTURE_PAN (gesture); + priv = gtk_gesture_pan_get_instance_private (pan); + + if (!priv->panning) + { + if (!guess_direction (pan, offset_x, offset_y, &direction)) + return; + + if (!check_orientation_matches (pan, direction)) + { + gtk_gesture_set_state (GTK_GESTURE (gesture), + GTK_EVENT_SEQUENCE_DENIED); + return; + } + + priv->panning = TRUE; + } + else + direction_from_offset (offset_x, offset_y, priv->orientation, &direction); + + offset = (priv->orientation == GTK_PAN_ORIENTATION_VERTICAL) ? + ABS (offset_y) : ABS (offset_x); + g_signal_emit (gesture, signals[PAN], 0, direction, offset); +} + +static void +gtk_gesture_pan_drag_end (GtkGestureDrag *gesture, + gdouble offset_x, + gdouble offset_y) +{ + GtkGesturePanPrivate *priv; + + priv = gtk_gesture_pan_get_instance_private (GTK_GESTURE_PAN (gesture)); + priv->panning = FALSE; +} + +static void +gtk_gesture_pan_class_init (GtkGesturePanClass *klass) +{ + GtkGestureDragClass *drag_gesture_class = GTK_GESTURE_DRAG_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gtk_gesture_pan_get_property; + object_class->set_property = gtk_gesture_pan_set_property; + + drag_gesture_class->drag_update = gtk_gesture_pan_drag_update; + drag_gesture_class->drag_end = gtk_gesture_pan_drag_end; + + g_object_class_install_property (object_class, + PROP_ORIENTATION, + g_param_spec_enum ("orientation", + P_("Orientation"), + P_("Allowed orientations"), + GTK_TYPE_PAN_ORIENTATION, + GTK_PAN_ORIENTATION_HORIZONTAL, + GTK_PARAM_READWRITE)); + signals[PAN] = + g_signal_new ("pan", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkGesturePanClass, pan), + NULL, NULL, NULL, + G_TYPE_NONE, 1, GTK_TYPE_PAN_DIRECTION); +} + +static void +gtk_gesture_pan_init (GtkGesturePan *gesture) +{ + GtkGesturePanPrivate *priv; + + priv = gtk_gesture_pan_get_instance_private (gesture); + priv->orientation = GTK_PAN_ORIENTATION_HORIZONTAL; +} + +GtkGesture * +gtk_gesture_pan_new (GtkWidget *widget, + GtkPanOrientation orientation) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + + return g_object_new (GTK_TYPE_GESTURE_PAN, + "widget", widget, + "orientation", orientation, + NULL); +} + +GtkPanOrientation +gtk_gesture_pan_get_orientation (GtkGesturePan *gesture) +{ + GtkGesturePanPrivate *priv; + + g_return_val_if_fail (GTK_IS_GESTURE_PAN (gesture), 0); + + priv = gtk_gesture_pan_get_instance_private (gesture); + + return priv->orientation; +} + +void +gtk_gesture_pan_set_orientation (GtkGesturePan *gesture, + GtkPanOrientation orientation) +{ + GtkGesturePanPrivate *priv; + + g_return_if_fail (GTK_IS_GESTURE_PAN (gesture)); + g_return_if_fail (orientation == GTK_PAN_ORIENTATION_HORIZONTAL || + orientation == GTK_PAN_ORIENTATION_VERTICAL); + + priv = gtk_gesture_pan_get_instance_private (gesture); + + if (priv->orientation == orientation) + return; + + priv->orientation = orientation; + g_object_notify (G_OBJECT (gesture), "orientation"); +} diff --git a/gtk/gtkgesturepan.h b/gtk/gtkgesturepan.h new file mode 100644 index 0000000000..fdbde4e250 --- /dev/null +++ b/gtk/gtkgesturepan.h @@ -0,0 +1,75 @@ +/* GTK - The GIMP Toolkit + * 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 . + * + * Author(s): Carlos Garnacho + */ +#ifndef __GTK_GESTURE_PAN_H__ +#define __GTK_GESTURE_PAN_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_GESTURE_PAN (gtk_gesture_pan_get_type ()) +#define GTK_GESTURE_PAN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE_PAN, GtkGesturePan)) +#define GTK_GESTURE_PAN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE_PAN, GtkGesturePanClass)) +#define GTK_IS_GESTURE_PAN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE_PAN)) +#define GTK_IS_GESTURE_PAN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE_PAN)) +#define GTK_GESTURE_PAN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE_PAN, GtkGesturePanClass)) + +typedef struct _GtkGesturePan GtkGesturePan; +typedef struct _GtkGesturePanClass GtkGesturePanClass; + +struct _GtkGesturePan +{ + GtkGestureDrag parent_instance; +}; + +struct _GtkGesturePanClass +{ + GtkGestureDragClass parent_class; + + void (* pan) (GtkGesturePan *gesture, + GtkPanDirection direction, + gdouble offset); + + /*< private >*/ + gpointer padding[10]; +}; + +GDK_AVAILABLE_IN_3_14 +GType gtk_gesture_pan_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_3_14 +GtkGesture * gtk_gesture_pan_new (GtkWidget *widget, + GtkPanOrientation orientation); + +GDK_AVAILABLE_IN_3_14 +GtkPanOrientation gtk_gesture_pan_get_orientation (GtkGesturePan *gesture); + +GDK_AVAILABLE_IN_3_14 +void gtk_gesture_pan_set_orientation (GtkGesturePan *gesture, + GtkPanOrientation orientation); + + +G_END_DECLS + +#endif /* __GTK_GESTURE_PAN_H__ */