summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2014-05-05 20:17:43 +0200
committerCarlos Garnacho <carlosg@gnome.org>2014-08-13 13:37:25 +0200
commitbce2efce8dfbcd4baaf255331b4722c8dcba297d (patch)
treeef27c05462750035c393703905983358fbc79a2d
parent32f09f732470987f0ad4201ed92dfd3a528e13be (diff)
downloadeog-bce2efce8dfbcd4baaf255331b4722c8dcba297d.tar.gz
EogScrollView: add image rotation gesture/signal
A ::rotation-changed signal has been added to EogScrollView, that reports angle changes happening from within the view in 90 degree steps. A GtkGestureRotate has been hooked to the widget so two-finger touchscreen interaction does rotate the image. In order to avoid unintended angle changes when the delta is too close to a switch point, there is a "grey area" threshold that makes it harder to switch forth and back again. This gesture has been added to the same group than the GtkGestureZoom, as both are meant to share sequences and state.
-rw-r--r--src/eog-scroll-view.c133
-rw-r--r--src/eog-scroll-view.h1
2 files changed, 134 insertions, 0 deletions
diff --git a/src/eog-scroll-view.c b/src/eog-scroll-view.c
index 45ae0d1e..cf9e2114 100644
--- a/src/eog-scroll-view.c
+++ b/src/eog-scroll-view.c
@@ -55,6 +55,7 @@ typedef enum {
/* Signal IDs */
enum {
SIGNAL_ZOOM_CHANGED,
+ SIGNAL_ROTATION_CHANGED,
SIGNAL_LAST
};
static gint view_signals [SIGNAL_LAST];
@@ -65,6 +66,14 @@ typedef enum {
EOG_SCROLL_VIEW_CURSOR_DRAG
} EogScrollViewCursor;
+typedef enum {
+ EOG_ROTATION_0,
+ EOG_ROTATION_90,
+ EOG_ROTATION_180,
+ EOG_ROTATION_270,
+ N_EOG_ROTATIONS
+} EogRotationState;
+
/* Drag 'n Drop */
static GtkTargetEntry target_table[] = {
{ "text/uri-list", 0, 0},
@@ -162,7 +171,9 @@ struct _EogScrollViewPrivate {
cairo_surface_t *background_surface;
GtkGesture *zoom_gesture;
+ GtkGesture *rotate_gesture;
gdouble initial_zoom;
+ EogRotationState rotate_state;
};
static void scroll_by (EogScrollView *view, int xofs, int yofs);
@@ -1968,6 +1979,105 @@ zoom_gesture_end_cb (GtkGestureZoom *gesture,
eog_scroll_view_set_cursor (view, EOG_SCROLL_VIEW_CURSOR_NORMAL);
}
+static void
+rotate_gesture_begin_cb (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ EogScrollView *view)
+{
+ EogScrollViewPrivate *priv;
+
+ priv = view->priv;
+ priv->rotate_state = EOG_TRANSFORM_NONE;
+}
+
+static gboolean
+scroll_view_check_angle (gdouble angle,
+ gdouble min,
+ gdouble max,
+ gdouble threshold)
+{
+ if (min < max) {
+ return (angle > min - threshold &&
+ angle < max + threshold);
+ } else {
+ return (angle < max + threshold ||
+ angle > min - threshold);
+ }
+}
+
+static EogRotationState
+scroll_view_get_rotate_state (EogScrollView *view,
+ gdouble delta)
+{
+ EogScrollViewPrivate *priv;
+
+ priv = view->priv;
+
+#define THRESHOLD (G_PI / 16)
+ switch (priv->rotate_state) {
+ case EOG_ROTATION_0:
+ if (scroll_view_check_angle (delta, G_PI * 7 / 4,
+ G_PI / 4, THRESHOLD))
+ return priv->rotate_state;
+ break;
+ case EOG_ROTATION_90:
+ if (scroll_view_check_angle (delta, G_PI / 4,
+ G_PI * 3 / 4, THRESHOLD))
+ return priv->rotate_state;
+ break;
+ case EOG_ROTATION_180:
+ if (scroll_view_check_angle (delta, G_PI * 3 / 4,
+ G_PI * 5 / 4, THRESHOLD))
+ return priv->rotate_state;
+ break;
+ case EOG_ROTATION_270:
+ if (scroll_view_check_angle (delta, G_PI * 5 / 4,
+ G_PI * 7 / 4, THRESHOLD))
+ return priv->rotate_state;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+#undef THRESHOLD
+
+ if (scroll_view_check_angle (delta, G_PI / 4, G_PI * 3 / 4, 0))
+ return EOG_ROTATION_90;
+ else if (scroll_view_check_angle (delta, G_PI * 3 / 4, G_PI * 5 / 4, 0))
+ return EOG_ROTATION_180;
+ else if (scroll_view_check_angle (delta, G_PI * 5 / 4, G_PI * 7 / 4, 0))
+ return EOG_ROTATION_270;
+
+ return EOG_ROTATION_0;
+}
+
+static void
+rotate_gesture_angle_changed_cb (GtkGestureRotate *rotate,
+ gdouble angle,
+ gdouble delta,
+ EogScrollView *view)
+{
+ EogRotationState rotate_state;
+ EogScrollViewPrivate *priv;
+ gint angle_diffs [N_EOG_ROTATIONS][N_EOG_ROTATIONS] = {
+ { 0, 90, 180, 270 },
+ { 270, 0, 90, 180 },
+ { 180, 270, 0, 90 },
+ { 90, 180, 270, 0 }
+ };
+ gint rotate_angle;
+
+ priv = view->priv;
+ rotate_state = scroll_view_get_rotate_state (view, delta);
+
+ if (priv->rotate_state == rotate_state)
+ return;
+
+ rotate_angle = angle_diffs[priv->rotate_state][rotate_state];
+ g_signal_emit (view, view_signals [SIGNAL_ROTATION_CHANGED], 0, (gdouble) rotate_angle);
+ priv->rotate_state = rotate_state;
+}
+
/*==================================
image loading callbacks
@@ -2632,6 +2742,15 @@ eog_scroll_view_init (EogScrollView *view)
G_CALLBACK (zoom_gesture_end_cb), view);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (priv->zoom_gesture),
GTK_PHASE_CAPTURE);
+
+ priv->rotate_gesture = gtk_gesture_rotate_new (GTK_WIDGET (view));
+ gtk_gesture_group (priv->rotate_gesture, priv->zoom_gesture);
+ g_signal_connect (priv->rotate_gesture, "angle-changed",
+ G_CALLBACK (rotate_gesture_angle_changed_cb), view);
+ g_signal_connect (priv->rotate_gesture, "begin",
+ G_CALLBACK (rotate_gesture_begin_cb), view);
+ gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (priv->rotate_gesture),
+ GTK_PHASE_CAPTURE);
}
static void
@@ -2679,6 +2798,11 @@ eog_scroll_view_dispose (GObject *object)
priv->zoom_gesture = NULL;
}
+ if (priv->rotate_gesture) {
+ g_object_unref (priv->rotate_gesture);
+ priv->rotate_gesture = NULL;
+ }
+
G_OBJECT_CLASS (eog_scroll_view_parent_class)->dispose (object);
}
@@ -2909,6 +3033,15 @@ eog_scroll_view_class_init (EogScrollViewClass *klass)
g_cclosure_marshal_VOID__DOUBLE,
G_TYPE_NONE, 1,
G_TYPE_DOUBLE);
+ view_signals [SIGNAL_ROTATION_CHANGED] =
+ g_signal_new ("rotation-changed",
+ EOG_TYPE_SCROLL_VIEW,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EogScrollViewClass, rotation_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
+ G_TYPE_NONE, 1,
+ G_TYPE_DOUBLE);
widget_class->size_allocate = eog_scroll_view_size_allocate;
widget_class->style_set = eog_scroll_view_style_set;
diff --git a/src/eog-scroll-view.h b/src/eog-scroll-view.h
index bf3171ca..f0c8d43d 100644
--- a/src/eog-scroll-view.h
+++ b/src/eog-scroll-view.h
@@ -27,6 +27,7 @@ struct _EogScrollViewClass {
GtkGridClass parent_class;
void (* zoom_changed) (EogScrollView *view, double zoom);
+ void (* rotation_changed) (EogScrollView *view, double degrees);
};
/**