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 @@
#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,
......@@ -226,6 +230,50 @@ gimp_display_shell_scale_get_image_size (GimpDisplayShell *shell,
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:
* @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) -
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,56 +559,12 @@ 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);
gimp_display_shell_scale_fit_or_fill (shell,
/* fill = */ FALSE);
}
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:
* @shell: the #GimpDisplayShell
......@@ -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,
......
......@@ -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,
......
......@@ -18,6 +18,7 @@
#include "config.h"
#include <stdlib.h>
#include <math.h>
#include <gegl.h>
#include <gtk/gtk.h>
......@@ -159,8 +160,10 @@ gimp_display_shell_scroll_clamp_and_update (GimpDisplayShell *shell)
if (image)
{
gdouble dx, dy;
gdouble dw, dh;
gint bounds_x;
gint bounds_y;
gint bounds_width;
gint bounds_height;
gint min_offset_x;
gint max_offset_x;
gint min_offset_y;
......@@ -170,47 +173,48 @@ gimp_display_shell_scroll_clamp_and_update (GimpDisplayShell *shell)
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,7 +345,10 @@ gimp_display_shell_scroll_center_image (GimpDisplayShell *shell,
gboolean horizontally,
gboolean vertically)
{
GimpImage *image;
gint image_x;
gint image_y;
gint image_width;
gint image_height;
gint center_x;
gint center_y;
gint offset_x = 0;
......@@ -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);
}
......
......@@ -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;
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;
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,
......
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