[gimp] app: fix a few canvas scroll/scale rounding inconsistencies



commit 720b73ca868c380c35c81e6d63b93bbaad18d308
Author: Ell <ell_se yahoo com>
Date:   Sun Jul 24 13:01:12 2016 +0000

    app: fix a few canvas scroll/scale rounding inconsistencies
    
    Apply rounding more consistently across some of the scroll/scale
    functions, to avoid annoying one-pixel-off scrollbar size/position
    issues.

 app/display/gimpdisplayshell-scale.c      |  214 +++++++++++++++--------------
 app/display/gimpdisplayshell-scale.h      |    5 +
 app/display/gimpdisplayshell-scroll.c     |  108 +++++++++------
 app/display/gimpdisplayshell-scrollbars.c |   89 ++++--------
 4 files changed, 210 insertions(+), 206 deletions(-)
---
diff --git a/app/display/gimpdisplayshell-scale.c b/app/display/gimpdisplayshell-scale.c
index 42c1ccb..3ca4ce1 100644
--- a/app/display/gimpdisplayshell-scale.c
+++ b/app/display/gimpdisplayshell-scale.c
@@ -17,6 +17,8 @@
 
 #include "config.h"
 
+#include <math.h>
+
 #include <gegl.h>
 #include <gtk/gtk.h>
 
@@ -65,10 +67,12 @@ static void      gimp_display_shell_calculate_scale_x_and_y
                                                           gdouble          *scale_x,
                                                           gdouble          *scale_y);
 
-  static void    gimp_display_shell_scale_to             (GimpDisplayShell *shell,
+static void      gimp_display_shell_scale_to             (GimpDisplayShell *shell,
                                                           gdouble           scale,
                                                           gdouble           viewport_x,
                                                           gdouble           viewport_y);
+static void      gimp_display_shell_scale_fit_or_fill    (GimpDisplayShell *shell,
+                                                          gboolean          fill);
 
 static gboolean  gimp_display_shell_scale_image_starts_to_fit
                                                          (GimpDisplayShell *shell,
@@ -227,6 +231,50 @@ gimp_display_shell_scale_get_image_size (GimpDisplayShell *shell,
 }
 
 /**
+ * gimp_display_shell_scale_get_image_bounds:
+ * @shell:
+ * @x:
+ * @y:
+ * @w:
+ * @h:
+ *
+ * Gets the screen-space boudning box of the image, after it has
+ * been transformed (i.e., scaled, rotated, and scrolled).
+ **/
+void
+gimp_display_shell_scale_get_image_bounds (GimpDisplayShell *shell,
+                                           gint             *x,
+                                           gint             *y,
+                                           gint             *w,
+                                           gint             *h)
+{
+  GimpImage *image;
+  gdouble    x1, y1;
+  gdouble    x2, y2;
+
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+
+  image = gimp_display_get_image (shell->display);
+
+  gimp_display_shell_transform_bounds (shell,
+                                       0, 0,
+                                       gimp_image_get_width (image),
+                                       gimp_image_get_height (image),
+                                       &x1, &y1,
+                                       &x2, &y2);
+
+  x1 = ceil (x1);
+  y1 = ceil (y1);
+  x2 = floor (x2);
+  y2 = floor (y2);
+
+  if (x) *x = x1 + shell->offset_x;
+  if (y) *y = y1 + shell->offset_y;
+  if (w) *w = x2 - x1;
+  if (h) *h = y2 - y1;
+}
+
+/**
  * gimp_display_shell_scale_image_is_within_viewport:
  * @shell:
  *
@@ -465,11 +513,8 @@ gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell,
        *               center of viewport in screen coords without
        *               offset
        */
-      offset_x = RINT (factor * (x + width / 2.0) -
-                       (shell->disp_width / 2.0));
-
-      offset_y = RINT (factor * (y + height / 2.0) -
-                       (shell->disp_height / 2.0));
+      offset_x = RINT (factor * (x + width  / 2.0) - (shell->disp_width  / 2));
+      offset_y = RINT (factor * (y + height / 2.0) - (shell->disp_height / 2));
       break;
 
     case GIMP_ZOOM_OUT:
@@ -482,10 +527,10 @@ gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell,
        *               center of rectangle in screen coords without
        *               offset
        */
-      offset_x = RINT (factor * (shell->offset_x + shell->disp_width / 2.0) -
-                       ((x + width / 2.0) - shell->offset_x));
+      offset_x = RINT (factor * (shell->offset_x + shell->disp_width  / 2) -
+                       ((x + width  / 2.0) - shell->offset_x));
 
-      offset_y = RINT (factor * (shell->offset_y + shell->disp_height / 2.0) -
+      offset_y = RINT (factor * (shell->offset_y + shell->disp_height / 2) -
                        ((y + height / 2.0) - shell->offset_y));
       break;
 
@@ -514,55 +559,11 @@ gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell,
 void
 gimp_display_shell_scale_fit_in (GimpDisplayShell *shell)
 {
-  GimpImage *image;
-  gdouble    image_x;
-  gdouble    image_y;
-  gdouble    image_width;
-  gdouble    image_height;
-  gdouble    zoom_factor;
-
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
-  image = gimp_display_get_image (shell->display);
-
-  gimp_display_shell_transform_bounds (shell,
-                                       0, 0,
-                                       gimp_image_get_width  (image),
-                                       gimp_image_get_height  (image),
-                                       &image_x, &image_y,
-                                       &image_width, &image_height);
-
-  gimp_display_shell_unzoom_xy_f (shell,
-                                  image_x, image_y,
-                                  &image_x, &image_y);
-  gimp_display_shell_unzoom_xy_f (shell,
-                                  image_width, image_height,
-                                  &image_width, &image_height);
-
-  image_width  -= image_x;
-  image_height -= image_y;
-
-  if (! shell->dot_for_dot)
-    {
-      gdouble xres;
-      gdouble yres;
-
-      gimp_image_get_resolution (image, &xres, &yres);
-
-      image_width  = RINT (image_width  * shell->monitor_xres / xres);
-      image_height = RINT (image_height * shell->monitor_yres / yres);
-    }
-
-  zoom_factor = MIN (shell->disp_width  / image_width,
-                     shell->disp_height / image_height);
-
-  gimp_display_shell_scale (shell,
-                            GIMP_ZOOM_TO,
-                            zoom_factor,
-                            GIMP_ZOOM_FOCUS_BEST_GUESS);
-
-  gimp_display_shell_scroll_center_image (shell, TRUE, TRUE);
-}
+  gimp_display_shell_scale_fit_or_fill (shell,
+                                        /* fill = */ FALSE);
+ }
 
 /**
  * gimp_display_shell_scale_fill:
@@ -574,54 +575,10 @@ gimp_display_shell_scale_fit_in (GimpDisplayShell *shell)
 void
 gimp_display_shell_scale_fill (GimpDisplayShell *shell)
 {
-  GimpImage *image;
-  gdouble    image_x;
-  gdouble    image_y;
-  gdouble    image_width;
-  gdouble    image_height;
-  gdouble    zoom_factor;
-
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
-  image = gimp_display_get_image (shell->display);
-
-  gimp_display_shell_transform_bounds (shell,
-                                       0, 0,
-                                       gimp_image_get_width  (image),
-                                       gimp_image_get_height  (image),
-                                       &image_x, &image_y,
-                                       &image_width, &image_height);
-
-  gimp_display_shell_unzoom_xy_f (shell,
-                                  image_x, image_y,
-                                  &image_x, &image_y);
-  gimp_display_shell_unzoom_xy_f (shell,
-                                  image_width, image_height,
-                                  &image_width, &image_height);
-
-  image_width  -= image_x;
-  image_height -= image_y;
-
-  if (! shell->dot_for_dot)
-    {
-      gdouble xres;
-      gdouble yres;
-
-      gimp_image_get_resolution (image, &xres, &yres);
-
-      image_width  = RINT (image_width  * shell->monitor_xres / xres);
-      image_height = RINT (image_height * shell->monitor_yres / yres);
-    }
-
-  zoom_factor = MAX (shell->disp_width  / image_width,
-                     shell->disp_height / image_height);
-
-  gimp_display_shell_scale (shell,
-                            GIMP_ZOOM_TO,
-                            zoom_factor,
-                            GIMP_ZOOM_FOCUS_BEST_GUESS);
-
-  gimp_display_shell_scroll_center_image (shell, TRUE, TRUE);
+  gimp_display_shell_scale_fit_or_fill (shell,
+                                        /* fill = */ TRUE);
 }
 
 /**
@@ -961,6 +918,59 @@ gimp_display_shell_scale_to (GimpDisplayShell *shell,
   gimp_display_shell_resume (shell);
 }
 
+/**
+ * gimp_display_shell_scale_fit_or_fill:
+ * @shell: the #GimpDisplayShell
+ * @fill:  whether to scale the image to fill the viewport,
+ *         or fit inside the viewport
+ *
+ * A common implementation for gimp_display_shell_scale_{fit_in,fill}().
+ **/
+static void
+gimp_display_shell_scale_fit_or_fill (GimpDisplayShell *shell,
+                                      gboolean          fill)
+{
+  GimpImage *image;
+  gdouble    image_x;
+  gdouble    image_y;
+  gdouble    image_width;
+  gdouble    image_height;
+  gdouble    current_scale;
+  gdouble    zoom_factor;
+
+  image = gimp_display_get_image (shell->display);
+
+  gimp_display_shell_transform_bounds (shell,
+                                       0, 0,
+                                       gimp_image_get_width  (image),
+                                       gimp_image_get_height (image),
+                                       &image_x, &image_y,
+                                       &image_width, &image_height);
+
+  image_width  -= image_x;
+  image_height -= image_y;
+
+  current_scale = gimp_zoom_model_get_factor (shell->zoom);
+
+  if (fill)
+    {
+      zoom_factor = MAX (shell->disp_width  / image_width,
+                         shell->disp_height / image_height);
+    }
+  else
+    {
+      zoom_factor = MIN (shell->disp_width  / image_width,
+                         shell->disp_height / image_height);
+    }
+
+  gimp_display_shell_scale (shell,
+                            GIMP_ZOOM_TO,
+                            zoom_factor * current_scale,
+                            GIMP_ZOOM_FOCUS_BEST_GUESS);
+
+  gimp_display_shell_scroll_center_image (shell, TRUE, TRUE);
+}
+
 static gboolean
 gimp_display_shell_scale_image_starts_to_fit (GimpDisplayShell *shell,
                                               gdouble           new_scale,
diff --git a/app/display/gimpdisplayshell-scale.h b/app/display/gimpdisplayshell-scale.h
index 033a78d..4e55f26 100644
--- a/app/display/gimpdisplayshell-scale.h
+++ b/app/display/gimpdisplayshell-scale.h
@@ -29,6 +29,11 @@ void     gimp_display_shell_scale_set_dot_for_dot    (GimpDisplayShell *shell,
 void     gimp_display_shell_scale_get_image_size     (GimpDisplayShell *shell,
                                                       gint             *w,
                                                       gint             *h);
+void     gimp_display_shell_scale_get_image_bounds   (GimpDisplayShell *shell,
+                                                      gint             *x,
+                                                      gint             *y,
+                                                      gint             *w,
+                                                      gint             *h);
 gboolean gimp_display_shell_scale_image_is_within_viewport
                                                      (GimpDisplayShell *shell,
                                                       gboolean         *horizontally,
diff --git a/app/display/gimpdisplayshell-scroll.c b/app/display/gimpdisplayshell-scroll.c
index 089d738..75c81fb 100644
--- a/app/display/gimpdisplayshell-scroll.c
+++ b/app/display/gimpdisplayshell-scroll.c
@@ -18,6 +18,7 @@
 #include "config.h"
 
 #include <stdlib.h>
+#include <math.h>
 
 #include <gegl.h>
 #include <gtk/gtk.h>
@@ -159,58 +160,61 @@ gimp_display_shell_scroll_clamp_and_update (GimpDisplayShell *shell)
 
   if (image)
     {
-      gdouble dx, dy;
-      gdouble dw, dh;
-      gint    min_offset_x;
-      gint    max_offset_x;
-      gint    min_offset_y;
-      gint    max_offset_y;
-      gint    offset_x;
-      gint    offset_y;
+      gint bounds_x;
+      gint bounds_y;
+      gint bounds_width;
+      gint bounds_height;
+      gint min_offset_x;
+      gint max_offset_x;
+      gint min_offset_y;
+      gint max_offset_y;
+      gint offset_x;
+      gint offset_y;
 
       gimp_display_shell_rotate_update_transform (shell);
 
-      gimp_display_shell_transform_bounds (shell,
-                                           0, 0,
-                                           gimp_image_get_width (image),
-                                           gimp_image_get_height (image),
-                                           &dx, &dy,
-                                           &dw, &dh);
+      gimp_display_shell_scale_get_image_bounds (shell,
+                                                 &bounds_x, &bounds_y,
+                                                 &bounds_width, &bounds_height);
 
-      /* Convert scrolled (x1, y1, x2, y2) to unscrolled (x, y, width, height). */
-      dw -= dx;
-      dh -= dy;
-      dx += shell->offset_x;
-      dy += shell->offset_y;
-
-      if (shell->disp_width < dw)
+      if (shell->disp_width < bounds_width)
         {
-          min_offset_x = dx      - shell->disp_width * OVERPAN_FACTOR;
-          max_offset_x = dx + dw - shell->disp_width * (1.0 - OVERPAN_FACTOR);
+          min_offset_x = bounds_x -
+                         shell->disp_width * OVERPAN_FACTOR;
+          max_offset_x = bounds_x + bounds_width -
+                         shell->disp_width * (1.0 - OVERPAN_FACTOR);
         }
       else
         {
           gint overpan_amount;
 
-          overpan_amount = shell->disp_width - dw * (1.0 - OVERPAN_FACTOR);
+          overpan_amount = shell->disp_width -
+                           bounds_width * (1.0 - OVERPAN_FACTOR);
 
-          min_offset_x = dx      - overpan_amount;
-          max_offset_x = dx + dw + overpan_amount - shell->disp_width;
+          min_offset_x = bounds_x -
+                         overpan_amount;
+          max_offset_x = bounds_x + bounds_width - shell->disp_width +
+                         overpan_amount;
         }
 
-      if (shell->disp_height < dh)
+      if (shell->disp_height < bounds_height)
         {
-          min_offset_y = dy      - shell->disp_height * OVERPAN_FACTOR;
-          max_offset_y = dy + dh - shell->disp_height * (1.0 - OVERPAN_FACTOR);
+          min_offset_y = bounds_y
+                         - shell->disp_height * OVERPAN_FACTOR;
+          max_offset_y = bounds_y + bounds_height -
+                         shell->disp_height * (1.0 - OVERPAN_FACTOR);
         }
       else
         {
           gint overpan_amount;
 
-          overpan_amount = shell->disp_height - dh * (1.0 - OVERPAN_FACTOR);
+          overpan_amount = shell->disp_height -
+                           bounds_height * (1.0 - OVERPAN_FACTOR);
 
-          min_offset_y = dy      - overpan_amount;
-          max_offset_y = dy + dh + overpan_amount - shell->disp_height;
+          min_offset_y = bounds_y -
+                         overpan_amount;
+          max_offset_y = bounds_y + bounds_height +
+                         overpan_amount - shell->disp_height;
         }
 
       /* Clamp */
@@ -341,11 +345,14 @@ gimp_display_shell_scroll_center_image (GimpDisplayShell *shell,
                                         gboolean          horizontally,
                                         gboolean          vertically)
 {
-  GimpImage *image;
-  gint       center_x;
-  gint       center_y;
-  gint       offset_x = 0;
-  gint       offset_y = 0;
+  gint image_x;
+  gint image_y;
+  gint image_width;
+  gint image_height;
+  gint center_x;
+  gint center_y;
+  gint offset_x = 0;
+  gint offset_y = 0;
 
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
@@ -354,19 +361,30 @@ gimp_display_shell_scroll_center_image (GimpDisplayShell *shell,
       (! vertically && ! horizontally))
     return;
 
-  image = gimp_display_get_image (shell->display);
+  gimp_display_shell_scale_get_image_bounds (shell,
+                                             &image_x, &image_y,
+                                             &image_width, &image_height);
 
-  gimp_display_shell_transform_xy (shell,
-                                   gimp_image_get_width  (image) / 2,
-                                   gimp_image_get_height (image) / 2,
-                                   &center_x,
-                                   &center_y);
+  if (shell->disp_width > image_width)
+    {
+      image_x     -= (shell->disp_width - image_width) / 2;
+      image_width  = shell->disp_width;
+    }
+
+  if (shell->disp_height > image_height)
+    {
+      image_y      -= (shell->disp_height - image_height) / 2;
+      image_height  = shell->disp_height;
+    }
+
+  center_x = image_x + image_width  / 2;
+  center_y = image_y + image_height / 2;
 
   if (horizontally)
-    offset_x = center_x - shell->disp_width / 2;
+    offset_x = center_x - shell->disp_width / 2 - shell->offset_x;
 
   if (vertically)
-    offset_y = center_y - shell->disp_height / 2;
+    offset_y = center_y - shell->disp_height / 2 - shell->offset_y;
 
   gimp_display_shell_scroll (shell, offset_x, offset_y);
 }
diff --git a/app/display/gimpdisplayshell-scrollbars.c b/app/display/gimpdisplayshell-scrollbars.c
index fd61d81..34c461b 100644
--- a/app/display/gimpdisplayshell-scrollbars.c
+++ b/app/display/gimpdisplayshell-scrollbars.c
@@ -17,6 +17,8 @@
 
 #include "config.h"
 
+#include <math.h>
+
 #include <gegl.h>
 #include <gtk/gtk.h>
 
@@ -27,7 +29,6 @@
 #include "gimpdisplay.h"
 #include "gimpdisplayshell.h"
 #include "gimpdisplayshell-scale.h"
-#include "gimpdisplayshell-transform.h"
 #include "gimpdisplayshell-scrollbars.h"
 
 
@@ -90,44 +91,29 @@ void
 gimp_display_shell_scrollbars_setup_horizontal (GimpDisplayShell *shell,
                                                 gdouble           value)
 {
-  GimpImage *image;
-  gdouble    dx, dy;
-  gdouble    dw, dh;
-  gdouble    lower;
-  gdouble    upper;
+  gint    bounds_x;
+  gint    bounds_width;
+  gdouble lower;
+  gdouble upper;
 
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
-  if (! shell->display)
-    return;
-
-  image = gimp_display_get_image (shell->display);
-  if (! image)
+  if (! shell->display || ! gimp_display_get_image (shell->display))
     return;
 
-  gimp_display_shell_transform_bounds (shell,
-                                       0, 0,
-                                       gimp_image_get_width (image),
-                                       gimp_image_get_height (image),
-                                       &dx, &dy,
-                                       &dw, &dh);
+  gimp_display_shell_scale_get_image_bounds (shell,
+                                             &bounds_x, NULL,
+                                             &bounds_width, NULL);
 
-  /* Convert scrolled (x1, x2) to unscrolled (x, width). */
-  dw -= dx;
-  dx += shell->offset_x;
-
-  if (shell->disp_width < dw)
-    {
-      lower = MIN (value, dx);
-      upper = MAX (value + shell->disp_width, dx + dw);
-    }
-  else
+  if (shell->disp_width > bounds_width)
     {
-      lower = MIN (value, dx - (shell->disp_width - dw) / 2);
-      upper = MAX (value + shell->disp_width,
-                   dx + dw + (shell->disp_width - dw) / 2);
+      bounds_x     -= (shell->disp_width - bounds_width) / 2;
+      bounds_width  = shell->disp_width;
     }
 
+  lower = MIN (value, bounds_x);
+  upper = MAX (value + shell->disp_width, bounds_x + bounds_width);
+
   g_object_set (shell->hsbdata,
                 "lower",          lower,
                 "upper",          upper,
@@ -147,44 +133,29 @@ void
 gimp_display_shell_scrollbars_setup_vertical (GimpDisplayShell *shell,
                                               gdouble           value)
 {
-  GimpImage *image;
-  gdouble    dx, dy;
-  gdouble    dw, dh;
-  gdouble    lower;
-  gdouble    upper;
+  gint    bounds_y;
+  gint    bounds_height;
+  gdouble lower;
+  gdouble upper;
 
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
-  if (! shell->display)
-    return;
-
-  image = gimp_display_get_image (shell->display);
-  if (! image)
+  if (! shell->display || ! gimp_display_get_image (shell->display))
     return;
 
-  gimp_display_shell_transform_bounds (shell,
-                                       0, 0,
-                                       gimp_image_get_width (image),
-                                       gimp_image_get_height (image),
-                                       &dx, &dy,
-                                       &dw, &dh);
-
-  /* Convert scrolled (y1, y2) to unscrolled (y, height). */
-  dh -= dy;
-  dy += shell->offset_y;
+  gimp_display_shell_scale_get_image_bounds (shell,
+                                             NULL, &bounds_y,
+                                             NULL, &bounds_height);
 
-  if (shell->disp_height < dh)
+  if (shell->disp_height > bounds_height)
     {
-      lower = MIN (value, dy);
-      upper = MAX (value + shell->disp_height, dy + dh);
-    }
-  else
-    {
-      lower = MIN (value, dy - (shell->disp_height - dh) / 2);
-      upper = MAX (value + shell->disp_height,
-                   dy + dh + (shell->disp_height - dh) / 2);
+      bounds_y      -= (shell->disp_height - bounds_height) / 2;
+      bounds_height  = shell->disp_height;
     }
 
+  lower = MIN (value, bounds_y);
+  upper = MAX (value + shell->disp_height, bounds_y + bounds_height);
+
   g_object_set (shell->vsbdata,
                 "lower",          lower,
                 "upper",          upper,


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