[gnome-photos/wip/rishi/gesture-zoom: 6/12] image-view, preview-view: Re-work the zoom animation implementation



commit 9730cc14b49ed914c2a3450e093e5f32a61c6322
Author: Debarshi Ray <debarshir gnome org>
Date:   Mon Oct 16 09:08:31 2017 +0200

    image-view, preview-view: Re-work the zoom animation implementation
    
    The best-fit animation was being initiated from inside the
    size-allocated handler. It makes it hard for the ImageView user to
    explicitly disable or tweak the animation, if need be. Secondly, when
    best-fit was enabled or the GeglNode was (un)set, the zoom would be
    reset to 0.0, an invalid value, and left to be recalculated on the
    next size-allocated invocation. Same for zoom-visible in the latter
    case. Ideally, they should have been immediately set to the best-fit
    value and never be invalid.
    
    Instead, the best-fit animation is now initiated from
    photos_image_view_set_best_fit, similar to photos_image_view_set_zoom.
    The zoom is immediately set to the best-fit value when best-fit is
    enabled or the node is (un)set. The zoom-visible is also similarly set
    for the latter case. The value 1.0, not 0.0, is used when the
    ImageView doesn't have a valid GtkAllocation or GeglBuffer extent. The
    best-fit and zoom animations are automatically disabled when that
    happens because there is no worthwhile initial state to animate from.
    
    Always having a valid zoom value makes it possible to detect if the
    widget was resized in the middle of a best-fit animation. This is done
    by comparing the intended best-fit zoom value inside the size-allocated
    handler with the existing one and restarting the animation if they are
    not the same.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=783922

 src/photos-image-view.c   |  150 ++++++++++++++++++++++++++++++++++-----------
 src/photos-preview-view.c |    2 +-
 2 files changed, 114 insertions(+), 38 deletions(-)
---
diff --git a/src/photos-image-view.c b/src/photos-image-view.c
index 4333c65..6dadbee 100644
--- a/src/photos-image-view.c
+++ b/src/photos-image-view.c
@@ -49,7 +49,6 @@ struct _PhotosImageView
   cairo_region_t *bbox_region;
   cairo_region_t *region;
   gboolean best_fit;
-  gboolean queued_best_fit_animation;
   gdouble height;
   gdouble width;
   gdouble x;
@@ -122,6 +121,62 @@ photos_image_view_has_allocation_and_extent (PhotosImageView *self)
 
 
 static void
+photos_image_view_calculate_best_fit_zoom (PhotosImageView *self, gdouble *out_zoom, gdouble 
*out_zoom_scaled)
+{
+  GeglRectangle bbox;
+  GtkAllocation allocation;
+  gdouble zoom;
+  gdouble zoom_scaled = 1.0;
+  gint scale_factor;
+  gint viewport_height_real;
+  gint viewport_width_real;
+
+  if (!photos_image_view_has_allocation_and_extent (self))
+    goto out;
+
+  gtk_widget_get_allocation (GTK_WIDGET (self), &allocation);
+  bbox = *gegl_buffer_get_extent (self->buffer);
+
+  scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
+  viewport_height_real = allocation.height * scale_factor;
+  viewport_width_real = allocation.width * scale_factor;
+
+  if (bbox.height > viewport_height_real || bbox.width > viewport_width_real)
+    {
+      gdouble height_ratio = bbox.height / (gdouble) viewport_height_real;
+      gdouble width_ratio = bbox.width / (gdouble) viewport_width_real;
+      gdouble max_ratio =  MAX (height_ratio, width_ratio);
+
+      zoom_scaled = 1.0 / max_ratio;
+    }
+
+ out:
+  zoom = zoom_scaled / (gdouble) scale_factor;
+
+  if (out_zoom != NULL)
+    *out_zoom = zoom;
+
+  if (out_zoom_scaled != NULL)
+    *out_zoom_scaled = zoom_scaled;
+}
+
+
+static gboolean
+photos_image_view_needs_zoom_animation (PhotosImageView *self)
+{
+  gboolean ret_val = FALSE;
+
+  if (!photos_image_view_has_allocation_and_extent (self))
+    goto out;
+
+  ret_val = TRUE;
+
+ out:
+  return ret_val;
+}
+
+
+static void
 photos_image_view_notify_zoom (GObject *object, GParamSpec *pspec, gpointer user_data)
 {
   PhotosImageView *self = PHOTOS_IMAGE_VIEW (user_data);
@@ -145,6 +200,7 @@ photos_image_view_start_zoom_animation (PhotosImageView *self)
   GdkFrameClock *frame_clock;
   PhotosImageViewHelper *helper;
 
+  g_return_if_fail (photos_image_view_needs_zoom_animation (self));
   g_return_if_fail (self->zoom > 0.0);
   g_return_if_fail (self->zoom_animation == NULL);
   g_return_if_fail (self->zoom_visible > 0.0);
@@ -327,6 +383,30 @@ photos_image_view_update (PhotosImageView *self)
   if (!photos_image_view_has_allocation_and_extent (self))
     goto out;
 
+  if (self->best_fit)
+    {
+      gdouble zoom;
+      gdouble zoom_scaled;
+
+      photos_image_view_calculate_best_fit_zoom (self, &zoom, &zoom_scaled);
+
+      if (!photos_utils_equal_double (self->zoom, zoom))
+        {
+          self->zoom = zoom;
+          g_object_notify (G_OBJECT (self), "zoom");
+
+          if (self->zoom_animation != NULL)
+            {
+              egg_animation_stop (self->zoom_animation);
+              photos_image_view_start_zoom_animation (self);
+              goto out;
+            }
+
+          self->zoom_visible = self->zoom;
+          self->zoom_visible_scaled = zoom_scaled;
+        }
+    }
+
   gtk_widget_get_allocation (GTK_WIDGET (self), &allocation);
   bbox = *gegl_buffer_get_extent (self->buffer);
   scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
@@ -336,33 +416,10 @@ photos_image_view_update (PhotosImageView *self)
 
   if (self->best_fit && self->zoom_animation == NULL)
     {
-      gdouble zoom_scaled = 1.0;
-
-      if (bbox.height > viewport_height_real || bbox.width > viewport_width_real)
-        {
-          gdouble height_ratio = bbox.height / (gdouble) viewport_height_real;
-          gdouble width_ratio = bbox.width / (gdouble) viewport_width_real;
-          gdouble max_ratio =  MAX (height_ratio, width_ratio);
-
-          zoom_scaled = 1.0 / max_ratio;
-        }
-
-      self->zoom = zoom_scaled / (gdouble) scale_factor;
-      g_object_notify (G_OBJECT (self), "zoom");
-
-      if (self->zoom_visible > 0.0 && self->queued_best_fit_animation)
-        {
-          photos_image_view_start_zoom_animation (self);
-          goto out;
-        }
-
-      bbox_zoomed.width = (gint) (zoom_scaled * bbox.width + 0.5);
-      bbox_zoomed.height = (gint) (zoom_scaled * bbox.height + 0.5);
-      bbox_zoomed.x = (gint) (zoom_scaled * bbox.x + 0.5);
-      bbox_zoomed.y = (gint) (zoom_scaled * bbox.y + 0.5);
-
-      self->zoom_visible = self->zoom;
-      self->zoom_visible_scaled = zoom_scaled;
+      bbox_zoomed.width = (gint) (self->zoom_visible_scaled * bbox.width + 0.5);
+      bbox_zoomed.height = (gint) (self->zoom_visible_scaled * bbox.height + 0.5);
+      bbox_zoomed.x = (gint) (self->zoom_visible_scaled * bbox.x + 0.5);
+      bbox_zoomed.y = (gint) (self->zoom_visible_scaled * bbox.y + 0.5);
 
       self->x_scaled = (bbox_zoomed.width - viewport_width_real) / 2.0;
       self->y_scaled = (bbox_zoomed.height - viewport_height_real) / 2.0;
@@ -575,8 +632,6 @@ photos_image_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
   scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
   self->allocation_scaled_old.height = allocation->height * scale_factor;
   self->allocation_scaled_old.width = allocation->width * scale_factor;
-
-  self->queued_best_fit_animation = FALSE;
 }
 
 
@@ -834,6 +889,9 @@ photos_image_view_init (PhotosImageView *self)
   gtk_style_context_add_class (context, "content-view");
 
   self->best_fit = TRUE;
+  self->zoom = 1.0;
+  self->zoom_visible = 1.0;
+  self->zoom_visible_scaled = 1.0;
 }
 
 
@@ -998,12 +1056,24 @@ photos_image_view_set_best_fit (PhotosImageView *self, gboolean best_fit)
 
   if (self->best_fit)
     {
+      gdouble zoom_scaled;
+
       if (self->zoom_animation != NULL)
         egg_animation_stop (self->zoom_animation);
 
-      self->zoom = 0.0;
-      self->queued_best_fit_animation = TRUE;
-      gtk_widget_queue_resize (GTK_WIDGET (self));
+      photos_image_view_calculate_best_fit_zoom (self, &self->zoom, &zoom_scaled);
+
+      if (photos_image_view_needs_zoom_animation (self))
+        {
+          photos_image_view_start_zoom_animation (self);
+        }
+      else
+        {
+          self->zoom_visible = self->zoom;
+          self->zoom_visible_scaled = zoom_scaled;
+          gtk_widget_queue_resize (GTK_WIDGET (self));
+        }
+
       g_object_notify (G_OBJECT (self), "zoom");
     }
 
@@ -1014,6 +1084,8 @@ photos_image_view_set_best_fit (PhotosImageView *self, gboolean best_fit)
 void
 photos_image_view_set_node (PhotosImageView *self, GeglNode *node)
 {
+  gdouble zoom_scaled;
+
   g_return_if_fail (PHOTOS_IS_IMAGE_VIEW (self));
   g_return_if_fail (node == NULL || GEGL_IS_NODE (node));
 
@@ -1038,9 +1110,9 @@ photos_image_view_set_node (PhotosImageView *self, GeglNode *node)
   self->x_scaled = 0.0;
   self->y = 0.0;
   self->y_scaled = 0.0;
-  self->zoom = 0.0;
-  self->zoom_visible = 0.0;
-  self->zoom_visible_scaled = 0.0;
+  self->zoom = 1.0;
+  self->zoom_visible = 1.0;
+  self->zoom_visible_scaled = 1.0;
   g_clear_object (&self->buffer);
   g_clear_object (&self->node);
   g_clear_pointer (&self->bbox_region, (GDestroyNotify) cairo_region_destroy);
@@ -1061,6 +1133,10 @@ photos_image_view_set_node (PhotosImageView *self, GeglNode *node)
                                G_CONNECT_SWAPPED);
     }
 
+  photos_image_view_calculate_best_fit_zoom (self, &self->zoom, &zoom_scaled);
+  self->zoom_visible = self->zoom;
+  self->zoom_visible_scaled = zoom_scaled;
+
   gtk_widget_queue_resize (GTK_WIDGET (self));
 
   g_object_notify (G_OBJECT (self), "best-fit");
@@ -1084,7 +1160,7 @@ photos_image_view_set_zoom (PhotosImageView *self, gdouble zoom)
   self->best_fit = FALSE;
   self->zoom = zoom;
 
-  if (self->zoom_visible > 0.0)
+  if (photos_image_view_needs_zoom_animation (self))
     {
       photos_image_view_start_zoom_animation (self);
     }
diff --git a/src/photos-preview-view.c b/src/photos-preview-view.c
index 15bc98a..7a8619c 100644
--- a/src/photos-preview-view.c
+++ b/src/photos-preview-view.c
@@ -325,7 +325,7 @@ photos_preview_view_update_zoom_best_fit (PhotosPreviewView *self, PhotosImageVi
   g_return_if_fail (view == PHOTOS_IMAGE_VIEW (current_view));
 
   zoom = photos_image_view_get_zoom (view);
-  if (!photos_image_view_get_best_fit (view) || zoom == 0.0)
+  if (!photos_image_view_get_best_fit (view))
     return;
 
   self->zoom_best_fit = zoom;


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