summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk/Makefile.am2
-rw-r--r--gtk/gtk.h1
-rw-r--r--gtk/gtkenums.h14
-rw-r--r--gtk/gtkgesturepan.c274
-rw-r--r--gtk/gtkgesturepan.h75
5 files changed, 366 insertions, 0 deletions
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 <gtk/gtkgesturedrag.h>
#include <gtk/gtkgesturelongpress.h>
#include <gtk/gtkgesturemultipress.h>
+#include <gtk/gtkgesturepan.h>
#include <gtk/gtkgesturerotate.h>
#include <gtk/gtkgesturesingle.h>
#include <gtk/gtkgestureswipe.h>
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 <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Carlos Garnacho <carlosg@gnome.org>
+ */
+#include "config.h"
+#include <gtk/gtkgesturepan.h>
+#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 <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Carlos Garnacho <carlosg@gnome.org>
+ */
+#ifndef __GTK_GESTURE_PAN_H__
+#define __GTK_GESTURE_PAN_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkenums.h>
+#include <gtk/gtkgesturedrag.h>
+
+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__ */