[eog/gestures: 2/4] EogScrollView: add image rotation gesture



commit 6682d82afe2051d8a313595404abada5e2d292f6
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon May 5 20:17:43 2014 +0200

    EogScrollView: add image rotation gesture
    
    GtkGestureRotate is used to determine angle changes, which are then
    used to rotate the image in 90 degree steps. 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.

 src/eog-image.c       |    1 +
 src/eog-scroll-view.c |  125 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+), 0 deletions(-)
---
diff --git a/src/eog-image.c b/src/eog-image.c
index b11c8cb..86f216a 100644
--- a/src/eog-image.c
+++ b/src/eog-image.c
@@ -445,6 +445,7 @@ eog_image_real_transform (EogImage     *img,
 
                priv->width = gdk_pixbuf_get_width (transformed);
                priv->height = gdk_pixbuf_get_height (transformed);
+               eog_image_modified (img);
 
                modified = TRUE;
        }
diff --git a/src/eog-scroll-view.c b/src/eog-scroll-view.c
index 0593817..74611df 100644
--- a/src/eog-scroll-view.c
+++ b/src/eog-scroll-view.c
@@ -65,6 +65,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 +170,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);
@@ -1970,6 +1980,107 @@ 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];
+       eog_image_transform (priv->image,
+                            eog_transform_rotate_new (rotate_angle),
+                            NULL);
+       priv->rotate_state = rotate_state;
+}
+
 /*==================================
 
    image loading callbacks
@@ -2633,6 +2744,14 @@ eog_scroll_view_init (EogScrollView *view)
        g_signal_connect (priv->zoom_gesture, "cancel",
                          G_CALLBACK (zoom_gesture_end_cb), view);
        gtk_gesture_attach (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_gesture_attach (priv->rotate_gesture, GTK_PHASE_CAPTURE);
 }
 
 static void
@@ -2681,6 +2800,12 @@ eog_scroll_view_dispose (GObject *object)
                priv->zoom_gesture = NULL;
        }
 
+       if (priv->rotate_gesture) {
+               gtk_gesture_detach (priv->rotate_gesture);
+               g_object_unref (priv->rotate_gesture);
+               priv->rotate_gesture = NULL;
+       }
+
        G_OBJECT_CLASS (eog_scroll_view_parent_class)->dispose (object);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]