Commit 720b73ca authored by Ell's avatar Ell

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.
parent e384d533
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include "config.h" #include "config.h"
#include <math.h>
#include <gegl.h> #include <gegl.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
...@@ -65,10 +67,12 @@ static void gimp_display_shell_calculate_scale_x_and_y ...@@ -65,10 +67,12 @@ static void gimp_display_shell_calculate_scale_x_and_y
gdouble *scale_x, gdouble *scale_x,
gdouble *scale_y); gdouble *scale_y);
static void gimp_display_shell_scale_to (GimpDisplayShell *shell, static void gimp_display_shell_scale_to (GimpDisplayShell *shell,
gdouble scale, gdouble scale,
gdouble viewport_x, gdouble viewport_x,
gdouble viewport_y); 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 static gboolean gimp_display_shell_scale_image_starts_to_fit
(GimpDisplayShell *shell, (GimpDisplayShell *shell,
...@@ -226,6 +230,50 @@ gimp_display_shell_scale_get_image_size (GimpDisplayShell *shell, ...@@ -226,6 +230,50 @@ gimp_display_shell_scale_get_image_size (GimpDisplayShell *shell,
w, h); w, h);
} }
/**
* 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: * gimp_display_shell_scale_image_is_within_viewport:
* @shell: * @shell:
...@@ -465,11 +513,8 @@ gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell, ...@@ -465,11 +513,8 @@ gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell,
* center of viewport in screen coords without * center of viewport in screen coords without
* offset * offset
*/ */
offset_x = RINT (factor * (x + width / 2.0) - offset_x = RINT (factor * (x + width / 2.0) - (shell->disp_width / 2));
(shell->disp_width / 2.0)); offset_y = RINT (factor * (y + height / 2.0) - (shell->disp_height / 2));
offset_y = RINT (factor * (y + height / 2.0) -
(shell->disp_height / 2.0));
break; break;
case GIMP_ZOOM_OUT: case GIMP_ZOOM_OUT:
...@@ -482,10 +527,10 @@ gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell, ...@@ -482,10 +527,10 @@ gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell,
* center of rectangle in screen coords without * center of rectangle in screen coords without
* offset * offset
*/ */
offset_x = RINT (factor * (shell->offset_x + shell->disp_width / 2.0) - offset_x = RINT (factor * (shell->offset_x + shell->disp_width / 2) -
((x + width / 2.0) - shell->offset_x)); ((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)); ((y + height / 2.0) - shell->offset_y));
break; break;
...@@ -514,55 +559,11 @@ gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell, ...@@ -514,55 +559,11 @@ gimp_display_shell_scale_to_rectangle (GimpDisplayShell *shell,
void void
gimp_display_shell_scale_fit_in (GimpDisplayShell *shell) 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)); g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
image = gimp_display_get_image (shell->display); gimp_display_shell_scale_fit_or_fill (shell,
/* fill = */ FALSE);
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_fill: * gimp_display_shell_scale_fill:
...@@ -574,54 +575,10 @@ gimp_display_shell_scale_fit_in (GimpDisplayShell *shell) ...@@ -574,54 +575,10 @@ gimp_display_shell_scale_fit_in (GimpDisplayShell *shell)
void void
gimp_display_shell_scale_fill (GimpDisplayShell *shell) 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)); g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
image = gimp_display_get_image (shell->display); gimp_display_shell_scale_fit_or_fill (shell,
/* fill = */ TRUE);
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);
} }
/** /**
...@@ -961,6 +918,59 @@ gimp_display_shell_scale_to (GimpDisplayShell *shell, ...@@ -961,6 +918,59 @@ gimp_display_shell_scale_to (GimpDisplayShell *shell,
gimp_display_shell_resume (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 static gboolean
gimp_display_shell_scale_image_starts_to_fit (GimpDisplayShell *shell, gimp_display_shell_scale_image_starts_to_fit (GimpDisplayShell *shell,
gdouble new_scale, gdouble new_scale,
......
...@@ -29,6 +29,11 @@ void gimp_display_shell_scale_set_dot_for_dot (GimpDisplayShell *shell, ...@@ -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, void gimp_display_shell_scale_get_image_size (GimpDisplayShell *shell,
gint *w, gint *w,
gint *h); 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 gboolean gimp_display_shell_scale_image_is_within_viewport
(GimpDisplayShell *shell, (GimpDisplayShell *shell,
gboolean *horizontally, gboolean *horizontally,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "config.h" #include "config.h"
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
#include <gegl.h> #include <gegl.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
...@@ -159,58 +160,61 @@ gimp_display_shell_scroll_clamp_and_update (GimpDisplayShell *shell) ...@@ -159,58 +160,61 @@ gimp_display_shell_scroll_clamp_and_update (GimpDisplayShell *shell)
if (image) if (image)
{ {
gdouble dx, dy; gint bounds_x;
gdouble dw, dh; gint bounds_y;
gint min_offset_x; gint bounds_width;
gint max_offset_x; gint bounds_height;
gint min_offset_y; gint min_offset_x;
gint max_offset_y; gint max_offset_x;
gint offset_x; gint min_offset_y;
gint offset_y; gint max_offset_y;
gint offset_x;
gint offset_y;
gimp_display_shell_rotate_update_transform (shell); gimp_display_shell_rotate_update_transform (shell);
gimp_display_shell_transform_bounds (shell, gimp_display_shell_scale_get_image_bounds (shell,
0, 0, &bounds_x, &bounds_y,
gimp_image_get_width (image), &bounds_width, &bounds_height);
gimp_image_get_height (image),
&dx, &dy,
&dw, &dh);
/* Convert scrolled (x1, y1, x2, y2) to unscrolled (x, y, width, height). */ if (shell->disp_width < bounds_width)
dw -= dx;
dh -= dy;
dx += shell->offset_x;
dy += shell->offset_y;
if (shell->disp_width < dw)
{ {
min_offset_x = dx - shell->disp_width * OVERPAN_FACTOR; min_offset_x = bounds_x -
max_offset_x = dx + dw - shell->disp_width * (1.0 - OVERPAN_FACTOR); shell->disp_width * OVERPAN_FACTOR;
max_offset_x = bounds_x + bounds_width -
shell->disp_width * (1.0 - OVERPAN_FACTOR);
} }
else else
{ {
gint overpan_amount; 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; min_offset_x = bounds_x -
max_offset_x = dx + dw + overpan_amount - shell->disp_width; 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; min_offset_y = bounds_y
max_offset_y = dy + dh - shell->disp_height * (1.0 - OVERPAN_FACTOR); - shell->disp_height * OVERPAN_FACTOR;
max_offset_y = bounds_y + bounds_height -
shell->disp_height * (1.0 - OVERPAN_FACTOR);
} }
else else
{ {
gint overpan_amount; 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; min_offset_y = bounds_y -
max_offset_y = dy + dh + overpan_amount - shell->disp_height; overpan_amount;
max_offset_y = bounds_y + bounds_height +
overpan_amount - shell->disp_height;
} }
/* Clamp */ /* Clamp */
...@@ -341,11 +345,14 @@ gimp_display_shell_scroll_center_image (GimpDisplayShell *shell, ...@@ -341,11 +345,14 @@ gimp_display_shell_scroll_center_image (GimpDisplayShell *shell,
gboolean horizontally, gboolean horizontally,
gboolean vertically) gboolean vertically)
{ {
GimpImage *image; gint image_x;
gint center_x; gint image_y;
gint center_y; gint image_width;
gint offset_x = 0; gint image_height;
gint offset_y = 0; gint center_x;
gint center_y;
gint offset_x = 0;
gint offset_y = 0;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
...@@ -354,19 +361,30 @@ gimp_display_shell_scroll_center_image (GimpDisplayShell *shell, ...@@ -354,19 +361,30 @@ gimp_display_shell_scroll_center_image (GimpDisplayShell *shell,
(! vertically && ! horizontally)) (! vertically && ! horizontally))
return; 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, if (shell->disp_width > image_width)
gimp_image_get_width (image) / 2, {
gimp_image_get_height (image) / 2, image_x -= (shell->disp_width - image_width) / 2;
&center_x, image_width = shell->disp_width;
&center_y); }
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) if (horizontally)
offset_x = center_x - shell->disp_width / 2; offset_x = center_x - shell->disp_width / 2 - shell->offset_x;
if (vertically) 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); gimp_display_shell_scroll (shell, offset_x, offset_y);
} }
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include "config.h" #include "config.h"
#include <math.h>
#include <gegl.h> #include <gegl.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
...@@ -27,7 +29,6 @@ ...@@ -27,7 +29,6 @@
#include "gimpdisplay.h" #include "gimpdisplay.h"
#include "gimpdisplayshell.h" #include "gimpdisplayshell.h"
#include "gimpdisplayshell-scale.h" #include "gimpdisplayshell-scale.h"
#include "gimpdisplayshell-transform.h"
#include "gimpdisplayshell-scrollbars.h" #include "gimpdisplayshell-scrollbars.h"
...@@ -90,44 +91,29 @@ void ...@@ -90,44 +91,29 @@ void
gimp_display_shell_scrollbars_setup_horizontal (GimpDisplayShell *shell, gimp_display_shell_scrollbars_setup_horizontal (GimpDisplayShell *shell,
gdouble value) gdouble value)
{ {
GimpImage *image; gint bounds_x;
gdouble dx, dy; gint bounds_width;
gdouble dw, dh; gdouble lower;
gdouble lower; gdouble upper;
gdouble upper;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
if (! shell->display) if (! shell->display || ! gimp_display_get_image (shell->display))
return;
image = gimp_display_get_image (shell->display);
if (! image)
return; return;
gimp_display_shell_transform_bounds (shell, gimp_display_shell_scale_get_image_bounds (shell,
0, 0, &bounds_x, NULL,
gimp_image_get_width (image), &bounds_width, NULL);
gimp_image_get_height (image),
&dx, &dy,
&dw, &dh);
/* Convert scrolled (x1, x2) to unscrolled (x, width). */ if (shell->disp_width > bounds_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
{ {
lower = MIN (value, dx - (shell->disp_width - dw) / 2); bounds_x -= (shell->disp_width - bounds_width) / 2;
upper = MAX (value + shell->disp_width, bounds_width = shell->disp_width;
dx + dw + (shell->disp_width - dw) / 2);
} }
lower = MIN (value, bounds_x);
upper = MAX (value + shell->disp_width, bounds_x + bounds_width);
g_object_set (shell->hsbdata, g_object_set (shell->hsbdata,
"lower", lower, "lower", lower,
"upper", upper, "upper", upper,
...@@ -147,44 +133,29 @@ void ...@@ -147,44 +133,29 @@ void
gimp_display_shell_scrollbars_setup_vertical (GimpDisplayShell *shell, gimp_display_shell_scrollbars_setup_vertical (GimpDisplayShell *shell,
gdouble value) gdouble value)
{ {
GimpImage *image; gint bounds_y;
gdouble dx, dy; gint bounds_height;
gdouble dw, dh; gdouble lower;
gdouble lower; gdouble upper;
gdouble upper;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
if (! shell->display) if (! shell->display || ! gimp_display_get_image (shell->display))
return;
image = gimp_display_get_image (shell->display);
if (! image)
return; return;
gimp_display_shell_transform_bounds (shell, gimp_display_shell_scale_get_image_bounds (shell,
0, 0, NULL, &bounds_y,
gimp_image_get_width (image), NULL, &bounds_height);
gimp_image_get_height (image),
&dx, &dy,
&dw, &dh);
/* Convert scrolled (y1, y2) to unscrolled (y, height). */
dh -= dy;
dy += shell->offset_y;
if (shell->disp_height < dh) if (shell->disp_height > bounds_height)
{ {
lower = MIN (value, dy); bounds_y -= (shell->disp_height - bounds_height) / 2;
upper = MAX (value + shell->disp_height, dy + dh); bounds_height = shell->disp_height;
}
else
{
lower = MIN (value, dy - (shell->disp_height - dh) / 2);
upper = MAX (value + shell->disp_height,
dy + dh + (shell->disp_height - dh) / 2);
} }
lower = MIN (value, bounds_y);
upper = MAX (value + shell->disp_height, bounds_y + bounds_height);
g_object_set (shell->vsbdata, g_object_set (shell->vsbdata,
"lower", lower, "lower", lower,
"upper", upper, "upper", upper,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment