[gnome-photos] Prepare the zoom-* GActions for touch gestures



commit de6a45480949d2ed66b51b799f814ca325afc150
Author: Debarshi Ray <debarshir gnome org>
Date:   Sat Oct 14 08:59:31 2017 +0200

    Prepare the zoom-* GActions for touch gestures
    
    So far the zooming interface provided by the zoom-in/out GActions was
    based on the notion of incremental steps. Each step represents one
    press/release of an accelerator key or mouse button, or one notch on
    the mouse's scroll wheel. A new zoom value is calculated for each step.
    
    However, touch gestures are different.
    
    Once the touch points start moving, the changing distance between them
    is indicated as a ratio to the initial distance when the gesture was
    initiated. This makes it necessary to keep track of the initial
    distance. A pair of zoom-begin and zoom-end GActions were added for
    this.
    
    With touch, the content needs to stick to the touch points while the
    gesture is active. This means that the ratio of the new and initial
    zoom values should track the ratio of the distance between the touch
    touch points and their initial distance. Moreover, touch events have a
    finer granularity than keyboard accelerators, mouse buttons or the
    scroll wheel. Therefore, changes in zoom levels are not animated when
    reacting to touch.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=783922

 src/photos-application.c  |   12 +++++
 src/photos-preview-view.c |  105 ++++++++++++++++++++++++++++++++++++++++++--
 src/photos-utils.h        |    3 +-
 3 files changed, 114 insertions(+), 6 deletions(-)
---
diff --git a/src/photos-application.c b/src/photos-application.c
index 4957d98..4fe57c6 100644
--- a/src/photos-application.c
+++ b/src/photos-application.c
@@ -111,7 +111,9 @@ struct _PhotosApplication
   GSimpleAction *set_ss_action;
   GSimpleAction *share_action;
   GSimpleAction *sharpen_action;
+  GSimpleAction *zoom_begin_action;
   GSimpleAction *zoom_best_fit_action;
+  GSimpleAction *zoom_end_action;
   GSimpleAction *zoom_in_action;
   GSimpleAction *zoom_out_action;
   GtkWidget *main_window;
@@ -375,6 +377,7 @@ photos_application_actions_update (PhotosApplication *self)
   selection_mode = photos_utils_get_selection_mode ();
 
   g_simple_action_set_enabled (self->zoom_best_fit_action, FALSE);
+  g_simple_action_set_enabled (self->zoom_end_action, FALSE);
   g_simple_action_set_enabled (self->zoom_out_action, FALSE);
 
   enable = (mode == PHOTOS_WINDOW_MODE_EDIT);
@@ -419,6 +422,7 @@ photos_application_actions_update (PhotosApplication *self)
   g_simple_action_set_enabled (self->gear_action, enable);
   g_simple_action_set_enabled (self->set_bg_action, enable);
   g_simple_action_set_enabled (self->set_ss_action, enable);
+  g_simple_action_set_enabled (self->zoom_begin_action, enable);
   g_simple_action_set_enabled (self->zoom_in_action, enable);
 
   enable = ((load_state == PHOTOS_LOAD_STATE_FINISHED && mode == PHOTOS_WINDOW_MODE_PREVIEW)
@@ -2060,9 +2064,15 @@ photos_application_startup (GApplication *application)
   self->sharpen_action = g_simple_action_new ("sharpen-current", G_VARIANT_TYPE_DOUBLE);
   g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (self->sharpen_action));
 
+  self->zoom_begin_action = g_simple_action_new ("zoom-begin", G_VARIANT_TYPE_VARDICT);
+  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (self->zoom_begin_action));
+
   self->zoom_best_fit_action = g_simple_action_new ("zoom-best-fit", NULL);
   g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (self->zoom_best_fit_action));
 
+  self->zoom_end_action = g_simple_action_new ("zoom-end", G_VARIANT_TYPE_VARDICT);
+  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (self->zoom_end_action));
+
   self->zoom_in_action = g_simple_action_new ("zoom-in", G_VARIANT_TYPE_VARDICT);
   g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (self->zoom_in_action));
 
@@ -2182,7 +2192,9 @@ photos_application_dispose (GObject *object)
   g_clear_object (&self->set_ss_action);
   g_clear_object (&self->share_action);
   g_clear_object (&self->sharpen_action);
+  g_clear_object (&self->zoom_begin_action);
   g_clear_object (&self->zoom_best_fit_action);
+  g_clear_object (&self->zoom_end_action);
   g_clear_object (&self->zoom_in_action);
   g_clear_object (&self->zoom_out_action);
   g_clear_object (&self->shr_pnt_mngr);
diff --git a/src/photos-preview-view.c b/src/photos-preview-view.c
index e354854..c8a99e1 100644
--- a/src/photos-preview-view.c
+++ b/src/photos-preview-view.c
@@ -47,7 +47,9 @@
 struct _PhotosPreviewView
 {
   GtkBin parent_instance;
+  GAction *zoom_begin_action;
   GAction *zoom_best_fit_action;
+  GAction *zoom_end_action;
   GAction *zoom_in_action;
   GAction *zoom_out_action;
   GCancellable *cancellable;
@@ -63,6 +65,7 @@ struct _PhotosPreviewView
   gboolean grabbed;
   gdouble event_x_last;
   gdouble event_y_last;
+  gdouble zoom_begin;
   gdouble zoom_best_fit;
 };
 
@@ -76,6 +79,7 @@ enum
 G_DEFINE_TYPE (PhotosPreviewView, photos_preview_view, GTK_TYPE_BIN);
 
 
+static const gdouble ZOOM_BEST_FIT_FACTOR_TOUCH = 0.6;
 static const gdouble ZOOM_FACTOR_1 = 2.8561;
 static const gdouble ZOOM_FACTOR_2 = 1.69;
 static const gdouble ZOOM_FACTOR_3 = 1.3;
@@ -836,6 +840,29 @@ photos_preview_view_window_mode_changed (PhotosPreviewView *self, PhotosWindowMo
 
 
 static void
+photos_preview_view_zoom_begin (PhotosPreviewView *self, GVariant *parameter)
+{
+  GtkWidget *view;
+  GtkWidget *view_container;
+  PhotosZoomEvent event;
+
+  event = photos_utils_get_zoom_event (parameter);
+  g_return_if_fail (event == PHOTOS_ZOOM_EVENT_TOUCH);
+
+  view_container = gtk_stack_get_visible_child (GTK_STACK (self->stack));
+  view = photos_preview_view_get_view_from_view_container (view_container);
+  self->zoom_begin = photos_image_view_get_zoom (PHOTOS_IMAGE_VIEW (view));
+
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_begin_action), FALSE);
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_best_fit_action), TRUE);
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_end_action), TRUE);
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_out_action), TRUE);
+  photos_preview_nav_buttons_set_auto_hide (self->nav_buttons, FALSE);
+  photos_preview_nav_buttons_set_show_navigation (self->nav_buttons, FALSE);
+}
+
+
+static void
 photos_preview_view_zoom_best_fit (PhotosPreviewView *self)
 {
   GtkWidget *view;
@@ -851,6 +878,37 @@ photos_preview_view_zoom_best_fit (PhotosPreviewView *self)
 }
 
 
+static void
+photos_preview_view_zoom_end (PhotosPreviewView *self, GVariant *parameter)
+{
+  GtkWidget *view;
+  GtkWidget *view_container;
+  PhotosZoomEvent event;
+  gdouble zoom;
+
+  event = photos_utils_get_zoom_event (parameter);
+  g_return_if_fail (event == PHOTOS_ZOOM_EVENT_TOUCH);
+
+  view_container = gtk_stack_get_visible_child (GTK_STACK (self->stack));
+  view = photos_preview_view_get_view_from_view_container (view_container);
+  zoom = photos_image_view_get_zoom (PHOTOS_IMAGE_VIEW (view));
+
+  if (zoom < self->zoom_best_fit || photos_utils_equal_double (self->zoom_best_fit, zoom))
+    {
+      photos_image_view_set_best_fit (PHOTOS_IMAGE_VIEW (view), TRUE, TRUE);
+      g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_best_fit_action), FALSE);
+      g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_out_action), FALSE);
+    }
+
+  self->zoom_begin = 0.0;
+
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_begin_action), TRUE);
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_end_action), FALSE);
+  photos_preview_nav_buttons_set_auto_hide (self->nav_buttons, TRUE);
+  photos_preview_nav_buttons_set_show_navigation (self->nav_buttons, TRUE);
+}
+
+
 static gdouble
 photos_preview_view_calculate_zoom_for_non_touch (PhotosPreviewView *self,
                                                   gdouble delta,
@@ -865,6 +923,7 @@ photos_preview_view_calculate_zoom_for_non_touch (PhotosPreviewView *self,
   gdouble zoom_factor_for_delta;
 
   g_return_val_if_fail (event != PHOTOS_ZOOM_EVENT_NONE, 0.0);
+  g_return_val_if_fail (event != PHOTOS_ZOOM_EVENT_TOUCH, 0.0);
   g_return_val_if_fail ((event == PHOTOS_ZOOM_EVENT_KEYBOARD_ACCELERATOR && photos_utils_equal_double 
(delta, 1.0))
                         || (event == PHOTOS_ZOOM_EVENT_MOUSE_CLICK && photos_utils_equal_double (delta, 1.0))
                         || (event == PHOTOS_ZOOM_EVENT_SCROLL && delta >= 0.0),
@@ -887,6 +946,7 @@ photos_preview_view_calculate_zoom_for_non_touch (PhotosPreviewView *self,
       break;
 
     case PHOTOS_ZOOM_EVENT_NONE:
+    case PHOTOS_ZOOM_EVENT_TOUCH:
     default:
       g_assert_not_reached ();
       break;
@@ -910,6 +970,7 @@ photos_preview_view_zoom_in (PhotosPreviewView *self, GVariant *parameter)
   GtkWidget *view;
   GtkWidget *view_container;
   PhotosZoomEvent event;
+  gboolean enable_animation;
   gdouble delta;
   gdouble zoom;
 
@@ -921,16 +982,23 @@ photos_preview_view_zoom_in (PhotosPreviewView *self, GVariant *parameter)
   delta = photos_utils_get_zoom_delta (parameter);
   g_return_if_fail ((event == PHOTOS_ZOOM_EVENT_KEYBOARD_ACCELERATOR && photos_utils_equal_double (delta, 
1.0))
                     || (event == PHOTOS_ZOOM_EVENT_MOUSE_CLICK && photos_utils_equal_double (delta, 1.0))
-                    || (event == PHOTOS_ZOOM_EVENT_SCROLL && delta >= 0.0));
+                    || (event == PHOTOS_ZOOM_EVENT_SCROLL && delta >= 0.0)
+                    || (event == PHOTOS_ZOOM_EVENT_TOUCH && delta >= 0.0 && self->zoom_begin > 0.0));
 
   switch (event)
     {
     case PHOTOS_ZOOM_EVENT_KEYBOARD_ACCELERATOR:
     case PHOTOS_ZOOM_EVENT_MOUSE_CLICK:
     case PHOTOS_ZOOM_EVENT_SCROLL:
+      enable_animation = TRUE;
       zoom = photos_preview_view_calculate_zoom_for_non_touch (self, delta, event, TRUE);
       break;
 
+    case PHOTOS_ZOOM_EVENT_TOUCH:
+      enable_animation = FALSE;
+      zoom = self->zoom_begin * delta;
+      break;
+
     case PHOTOS_ZOOM_EVENT_NONE:
     default:
       g_assert_not_reached ();
@@ -939,7 +1007,7 @@ photos_preview_view_zoom_in (PhotosPreviewView *self, GVariant *parameter)
 
   view_container = gtk_stack_get_visible_child (GTK_STACK (self->stack));
   view = photos_preview_view_get_view_from_view_container (view_container);
-  photos_image_view_set_zoom (PHOTOS_IMAGE_VIEW (view), zoom, TRUE);
+  photos_image_view_set_zoom (PHOTOS_IMAGE_VIEW (view), zoom, enable_animation);
 
   g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_best_fit_action), TRUE);
   g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_out_action), TRUE);
@@ -954,8 +1022,11 @@ photos_preview_view_zoom_out (PhotosPreviewView *self, GVariant *parameter)
   GtkWidget *view;
   GtkWidget *view_container;
   PhotosZoomEvent event;
+  gboolean enable_animation;
   gdouble delta;
   gdouble zoom;
+  gdouble zoom_best_fit;
+  gdouble zoom_best_fit_factor;
 
   g_return_if_fail (self->zoom_best_fit > 0.0);
 
@@ -965,14 +1036,23 @@ photos_preview_view_zoom_out (PhotosPreviewView *self, GVariant *parameter)
   delta = photos_utils_get_zoom_delta (parameter);
   g_return_if_fail ((event == PHOTOS_ZOOM_EVENT_KEYBOARD_ACCELERATOR && photos_utils_equal_double (delta, 
1.0))
                     || (event == PHOTOS_ZOOM_EVENT_MOUSE_CLICK && photos_utils_equal_double (delta, 1.0))
-                    || (event == PHOTOS_ZOOM_EVENT_SCROLL && delta >= 0.0));
+                    || (event == PHOTOS_ZOOM_EVENT_SCROLL && delta >= 0.0)
+                    || (event == PHOTOS_ZOOM_EVENT_TOUCH && delta >= 0.0 && self->zoom_begin > 0.0));
 
   switch (event)
     {
     case PHOTOS_ZOOM_EVENT_KEYBOARD_ACCELERATOR:
     case PHOTOS_ZOOM_EVENT_MOUSE_CLICK:
     case PHOTOS_ZOOM_EVENT_SCROLL:
+      enable_animation = TRUE;
       zoom = photos_preview_view_calculate_zoom_for_non_touch (self, delta, event, FALSE);
+      zoom_best_fit_factor = 1.0;
+      break;
+
+    case PHOTOS_ZOOM_EVENT_TOUCH:
+      enable_animation = FALSE;
+      zoom = self->zoom_begin * delta;
+      zoom_best_fit_factor = ZOOM_BEST_FIT_FACTOR_TOUCH;
       break;
 
     case PHOTOS_ZOOM_EVENT_NONE:
@@ -984,7 +1064,8 @@ photos_preview_view_zoom_out (PhotosPreviewView *self, GVariant *parameter)
   view_container = gtk_stack_get_visible_child (GTK_STACK (self->stack));
   view = photos_preview_view_get_view_from_view_container (view_container);
 
-  if (zoom < self->zoom_best_fit || photos_utils_equal_double (self->zoom_best_fit, zoom))
+  zoom_best_fit = self->zoom_best_fit * zoom_best_fit_factor;
+  if (zoom < zoom_best_fit || photos_utils_equal_double (zoom_best_fit, zoom))
     {
       photos_image_view_set_best_fit (PHOTOS_IMAGE_VIEW (view), TRUE, TRUE);
       g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_best_fit_action), FALSE);
@@ -994,7 +1075,7 @@ photos_preview_view_zoom_out (PhotosPreviewView *self, GVariant *parameter)
     }
   else
     {
-      photos_image_view_set_zoom (PHOTOS_IMAGE_VIEW (view), zoom, TRUE);
+      photos_image_view_set_zoom (PHOTOS_IMAGE_VIEW (view), zoom, enable_animation);
     }
 }
 
@@ -1156,6 +1237,13 @@ photos_preview_view_init (PhotosPreviewView *self)
   action = g_action_map_lookup_action (G_ACTION_MAP (app), "sharpen-current");
   g_signal_connect_object (action, "activate", G_CALLBACK (photos_preview_view_sharpen), self, 
G_CONNECT_SWAPPED);
 
+  self->zoom_begin_action = g_action_map_lookup_action (G_ACTION_MAP (app), "zoom-begin");
+  g_signal_connect_object (self->zoom_begin_action,
+                           "activate",
+                           G_CALLBACK (photos_preview_view_zoom_begin),
+                           self,
+                           G_CONNECT_SWAPPED);
+
   self->zoom_best_fit_action = g_action_map_lookup_action (G_ACTION_MAP (app), "zoom-best-fit");
   g_signal_connect_object (self->zoom_best_fit_action,
                            "activate",
@@ -1163,6 +1251,13 @@ photos_preview_view_init (PhotosPreviewView *self)
                            self,
                            G_CONNECT_SWAPPED);
 
+  self->zoom_end_action = g_action_map_lookup_action (G_ACTION_MAP (app), "zoom-end");
+  g_signal_connect_object (self->zoom_end_action,
+                           "activate",
+                           G_CALLBACK (photos_preview_view_zoom_end),
+                           self,
+                           G_CONNECT_SWAPPED);
+
   self->zoom_in_action = g_action_map_lookup_action (G_ACTION_MAP (app), "zoom-in");
   g_signal_connect_object (self->zoom_in_action,
                            "activate",
diff --git a/src/photos-utils.h b/src/photos-utils.h
index e40ef2a..0956f58 100644
--- a/src/photos-utils.h
+++ b/src/photos-utils.h
@@ -57,7 +57,8 @@ typedef enum
   PHOTOS_ZOOM_EVENT_NONE,
   PHOTOS_ZOOM_EVENT_KEYBOARD_ACCELERATOR,
   PHOTOS_ZOOM_EVENT_MOUSE_CLICK,
-  PHOTOS_ZOOM_EVENT_SCROLL
+  PHOTOS_ZOOM_EVENT_SCROLL,
+  PHOTOS_ZOOM_EVENT_TOUCH
 } PhotosZoomEvent;
 
 GdkPixbuf       *photos_utils_center_pixbuf               (GdkPixbuf *pixbuf, gint size);


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