[gnome-photos/wip/rishi/zoom: 11/11] image-view: Animated zoom



commit e05c5022b318b7b5a92b1f72508006c957299707
Author: Debarshi Ray <debarshir gnome org>
Date:   Fri Jun 2 19:52:59 2017 +0200

    image-view: Animated zoom

 src/photos-image-view.c |  142 +++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 124 insertions(+), 18 deletions(-)
---
diff --git a/src/photos-image-view.c b/src/photos-image-view.c
index 8b99af3..7552823 100644
--- a/src/photos-image-view.c
+++ b/src/photos-image-view.c
@@ -25,9 +25,11 @@
 #include <cairo-gobject.h>
 #include <glib.h>
 
+#include "egg-animation.h"
 #include "photos-debug.h"
 #include "photos-gegl.h"
 #include "photos-image-view.h"
+#include "photos-image-view-animator.h"
 #include "photos-marshalers.h"
 #include "photos-utils.h"
 
@@ -35,6 +37,7 @@
 struct _PhotosImageView
 {
   GtkDrawingArea parent_instance;
+  EggAnimation *zoom_animation;
   GeglBuffer *buffer;
   GeglNode *node;
   GeglRectangle bbox_zoomed_old;
@@ -46,6 +49,7 @@ struct _PhotosImageView
   cairo_region_t *bbox_region;
   cairo_region_t *region;
   gboolean best_fit;
+  gboolean queued_resize_for_animation;
   gdouble height;
   gdouble width;
   gdouble x;
@@ -53,7 +57,8 @@ struct _PhotosImageView
   gdouble y;
   gdouble y_scaled;
   gdouble zoom;
-  gdouble zoom_scaled;
+  gdouble zoom_visible;
+  gdouble zoom_visible_scaled;
 };
 
 enum
@@ -88,6 +93,26 @@ static void photos_image_view_computed (PhotosImageView *self, GeglRectangle *re
 
 
 static void
+photos_image_view_notify_zoom (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+  PhotosImageView *self = PHOTOS_IMAGE_VIEW (user_data);
+  PhotosImageViewAnimator *animator = PHOTOS_IMAGE_VIEW_ANIMATOR (object);
+  gint scale_factor;
+
+  g_return_if_fail (EGG_IS_ANIMATION (self->zoom_animation));
+
+  self->zoom_visible = photos_image_view_animator_get_zoom (animator);
+  g_message ("notify_zoom: %f", self->zoom_visible);
+
+  scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
+  self->zoom_visible_scaled = self->zoom_visible * scale_factor;
+
+  self->queued_resize_for_animation = TRUE;
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+
+static void
 photos_image_view_update_buffer (PhotosImageView *self)
 {
   const Babl *format;
@@ -256,7 +281,7 @@ photos_image_view_update (PhotosImageView *self)
   viewport_height_real = allocation.height * scale_factor;
   viewport_width_real = allocation.width * scale_factor;
 
-  if (self->best_fit)
+  if (self->best_fit && self->zoom_animation == NULL)
     {
       gdouble zoom_scaled = 1.0;
 
@@ -274,8 +299,39 @@ photos_image_view_update (PhotosImageView *self)
       bbox_zoomed.x = (gint) (zoom_scaled * bbox.x + 0.5);
       bbox_zoomed.y = (gint) (zoom_scaled * bbox.y + 0.5);
 
-      self->zoom_scaled = zoom_scaled;
-      self->zoom = self->zoom_scaled / (gdouble) scale_factor;
+      self->zoom = zoom_scaled / (gdouble) scale_factor;
+
+      if (self->zoom_visible > 0.0 && self->queued_resize_for_animation)
+        {
+          GdkFrameClock *frame_clock;
+          PhotosImageViewAnimator *animator;
+
+          animator = photos_image_view_animator_new ();
+          photos_image_view_animator_set_zoom (animator, self->zoom_visible);
+          g_signal_connect (animator, "notify::zoom", G_CALLBACK (photos_image_view_notify_zoom), self);
+
+          frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (self));
+
+          self->zoom_animation = egg_object_animate_full (g_object_ref (animator),
+                                                          EGG_ANIMATION_EASE_OUT_CUBIC,
+                                                          250,
+                                                          frame_clock,
+                                                          g_object_unref,
+                                                          animator,
+                                                          "zoom",
+                                                          self->zoom,
+                                                          NULL);
+          g_message ("best-fit animation: %f -> %f", self->zoom_visible, self->zoom);
+          g_object_add_weak_pointer (G_OBJECT (self->zoom_animation), (gpointer *) &self->zoom_animation);
+
+          g_object_unref (animator);
+        }
+      else
+        {
+          self->zoom_visible = self->zoom;
+          self->zoom_visible_scaled = zoom_scaled;
+          g_message ("best-fit: %f -> %f", self->zoom_visible, self->zoom);
+        }
 
       self->x_scaled = (bbox_zoomed.width - viewport_width_real) / 2.0;
       self->y_scaled = (bbox_zoomed.height - viewport_height_real) / 2.0;
@@ -286,10 +342,10 @@ photos_image_view_update (PhotosImageView *self)
     {
       gdouble ratio_old;
 
-      bbox_zoomed.width = (gint) (self->zoom_scaled * bbox.width + 0.5);
-      bbox_zoomed.height = (gint) (self->zoom_scaled * bbox.height + 0.5);
-      bbox_zoomed.x = (gint) (self->zoom_scaled * bbox.x + 0.5);
-      bbox_zoomed.y = (gint) (self->zoom_scaled * bbox.y + 0.5);
+      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);
 
       if (bbox_zoomed.width > viewport_width_real)
         {
@@ -403,8 +459,8 @@ photos_image_view_draw_node (PhotosImageView *self, cairo_t *cr, GdkRectangle *r
   gint64 start;
 
   g_return_if_fail (GEGL_IS_BUFFER (self->buffer));
-  g_return_if_fail (self->zoom > 0.0);
-  g_return_if_fail (self->zoom_scaled > 0.0);
+  g_return_if_fail (self->zoom_visible > 0.0);
+  g_return_if_fail (self->zoom_visible_scaled > 0.0);
 
   scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
 
@@ -423,7 +479,7 @@ photos_image_view_draw_node (PhotosImageView *self, cairo_t *cr, GdkRectangle *r
   stride = bpp * roi.width;
   gegl_buffer_get (self->buffer,
                    &roi,
-                   self->zoom_scaled,
+                   self->zoom_visible_scaled,
                    format,
                    buf,
                    stride,
@@ -485,11 +541,16 @@ photos_image_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
 
   GTK_WIDGET_CLASS (photos_image_view_parent_class)->size_allocate (widget, allocation);
 
+  if (!self->queued_resize_for_animation && self->zoom_animation != NULL)
+    egg_animation_stop (self->zoom_animation);
+
   photos_image_view_update (self);
 
   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_resize_for_animation = FALSE;
 }
 
 
@@ -576,6 +637,12 @@ photos_image_view_dispose (GObject *object)
 {
   PhotosImageView *self = PHOTOS_IMAGE_VIEW (object);
 
+  if (self->zoom_animation != NULL)
+    {
+      egg_animation_stop (self->zoom_animation);
+      g_assert_null (self->zoom_animation);
+    }
+
   g_clear_object (&self->buffer);
   g_clear_object (&self->node);
   g_clear_object (&self->hadjustment);
@@ -905,8 +972,11 @@ photos_image_view_set_best_fit (PhotosImageView *self, gboolean best_fit)
 
   if (self->best_fit)
     {
+      if (self->zoom_animation != NULL)
+        egg_animation_stop (self->zoom_animation);
+
       self->zoom = 0.0;
-      self->zoom_scaled = 0.0;
+      self->queued_resize_for_animation = TRUE;
       gtk_widget_queue_resize (GTK_WIDGET (self));
       g_object_notify (G_OBJECT (self), "zoom");
     }
@@ -940,7 +1010,8 @@ photos_image_view_set_node (PhotosImageView *self, GeglNode *node)
   self->y = 0.0;
   self->y_scaled = 0.0;
   self->zoom = 0.0;
-  self->zoom_scaled = 0.0;
+  self->zoom_visible = 0.0;
+  self->zoom_visible_scaled = 0.0;
   g_clear_object (&self->buffer);
   g_clear_object (&self->node);
   g_clear_pointer (&self->bbox_region, (GDestroyNotify) cairo_region_destroy);
@@ -972,20 +1043,55 @@ photos_image_view_set_node (PhotosImageView *self, GeglNode *node)
 void
 photos_image_view_set_zoom (PhotosImageView *self, gdouble zoom)
 {
-  gint scale_factor;
-
   g_return_if_fail (PHOTOS_IS_IMAGE_VIEW (self));
 
   if (photos_utils_equal_double (self->zoom, zoom))
     return;
 
+  if (self->zoom_animation != NULL)
+    egg_animation_stop (self->zoom_animation);
+
   self->best_fit = FALSE;
   self->zoom = zoom;
 
-  scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
-  self->zoom_scaled = self->zoom * scale_factor;
+  if (self->zoom_visible > 0.0)
+    {
+      GdkFrameClock *frame_clock;
+      PhotosImageViewAnimator *animator;
+
+      animator = photos_image_view_animator_new ();
+      photos_image_view_animator_set_zoom (animator, self->zoom_visible);
+      g_signal_connect (animator, "notify::zoom", G_CALLBACK (photos_image_view_notify_zoom), self);
+
+      frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (self));
+
+      self->zoom_animation = egg_object_animate_full (g_object_ref (animator),
+                                                      EGG_ANIMATION_EASE_OUT_CUBIC,
+                                                      250,
+                                                      frame_clock,
+                                                      g_object_unref,
+                                                      animator,
+                                                      "zoom",
+                                                      self->zoom,
+                                                      NULL);
+      g_object_add_weak_pointer (G_OBJECT (self->zoom_animation), (gpointer *) &self->zoom_animation);
+      g_message ("zoom animation: %f -> %f", self->zoom_visible, self->zoom);
+
+      g_object_unref (animator);
+    }
+  else
+    {
+      gint scale_factor;
 
-  gtk_widget_queue_resize (GTK_WIDGET (self));
+      self->zoom_visible = self->zoom;
+
+      scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
+      self->zoom_visible_scaled = self->zoom_visible * scale_factor;
+
+      gtk_widget_queue_resize (GTK_WIDGET (self));
+
+      g_message ("zoom: %f -> %f", self->zoom_visible, self->zoom);
+    }
 
   g_object_notify (G_OBJECT (self), "best-fit");
   g_object_notify (G_OBJECT (self), "zoom");


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