app: improve display scroll/zoom-related behavior in "show all" mode

In "show all" mode, the image is thought to be "infinite"; this
commit improves the overall scrolling/zooming behavior in this mode
according to this assumption.  In cases where a specific image size
is needed (e.g., for the scrollbar bounds, fit-image-in-window,
etc.), the image's full bounding box is used; however, in cases
where a center point is needed (e.g., for the zoomed-out scrollbar
bounds, center-image-in-window), the canvas center, rather than the
bounding-box center, is still used.
This commit is contained in:
Ell
2019-09-04 16:11:54 +03:00
parent 1f76013d1e
commit f0b7d0a2e2
9 changed files with 282 additions and 159 deletions

View File

@ -44,6 +44,8 @@
#include "gimpdisplayshell-expose.h"
#include "gimpdisplayshell-handlers.h"
#include "gimpdisplayshell-icon.h"
#include "gimpdisplayshell-scroll.h"
#include "gimpdisplayshell-scrollbars.h"
#include "gimpdisplayshell-transform.h"
#include "gimpimagewindow.h"
@ -807,6 +809,9 @@ gimp_display_update_bounding_box (GimpDisplay *display)
}
private->bounding_box = bounding_box;
gimp_display_shell_scroll_clamp_and_update (shell);
gimp_display_shell_scrollbars_update (shell);
}
}
else

View File

@ -207,9 +207,18 @@ gimp_display_shell_canvas_size_allocate (GtkWidget *widget,
center_horizontally = sw <= shell->disp_width;
center_vertically = sh <= shell->disp_height;
gimp_display_shell_scroll_center_image (shell,
center_horizontally,
center_vertically);
if (! shell->show_all)
{
gimp_display_shell_scroll_center_image (shell,
center_horizontally,
center_vertically);
}
else
{
gimp_display_shell_scroll_center_content (shell,
center_horizontally,
center_vertically);
}
/* This is basically the best we can do before we get an
* API for storing the image offset at the start of an

View File

@ -841,7 +841,11 @@ gimp_display_shell_size_changed_detailed_handler (GimpImage *image,
shell->offset_x + scaled_previous_origin_x,
shell->offset_y + scaled_previous_origin_y);
gimp_display_shell_scroll_center_image (shell, horizontally, vertically);
if (! shell->show_all)
{
gimp_display_shell_scroll_center_image (shell,
horizontally, vertically);
}
/* The above calls might not lead to a call to
* gimp_display_shell_scroll_clamp_and_update() and

View File

@ -398,7 +398,6 @@ gimp_display_shell_scale_image_is_within_viewport (GimpDisplayShell *shell,
gboolean *horizontally,
gboolean *vertically)
{
gint sw, sh;
gboolean horizontally_dummy, vertically_dummy;
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
@ -406,15 +405,25 @@ gimp_display_shell_scale_image_is_within_viewport (GimpDisplayShell *shell,
if (! horizontally) horizontally = &horizontally_dummy;
if (! vertically) vertically = &vertically_dummy;
gimp_display_shell_scale_get_image_size (shell, &sw, &sh);
if (! shell->show_all)
{
gint sx, sy;
gint sw, sh;
*horizontally = sw <= shell->disp_width &&
shell->offset_x <= 0 &&
shell->offset_x >= sw - shell->disp_width;
gimp_display_shell_scale_get_image_bounding_box (shell,
&sx, &sy, &sw, &sh);
*vertically = sh <= shell->disp_height &&
shell->offset_y <= 0 &&
shell->offset_y >= sh - shell->disp_height;
sx -= shell->offset_x;
sy -= shell->offset_y;
*horizontally = sx >= 0 && sx + sw <= shell->disp_width;
*vertically = sy >= 0 && sy + sh <= shell->disp_height;
}
else
{
*horizontally = FALSE;
*vertically = FALSE;
}
return *vertically && *horizontally;
}
@ -1113,22 +1122,25 @@ 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;
GeglRectangle bounding_box;
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);
bounding_box = gimp_display_shell_get_bounding_box (shell);
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);
bounding_box.x,
bounding_box.y,
bounding_box.x + bounding_box.width,
bounding_box.y + bounding_box.height,
&image_x,
&image_y,
&image_width,
&image_height);
image_width -= image_x;
image_height -= image_y;
@ -1151,7 +1163,7 @@ gimp_display_shell_scale_fit_or_fill (GimpDisplayShell *shell,
zoom_factor * current_scale,
GIMP_ZOOM_FOCUS_BEST_GUESS);
gimp_display_shell_scroll_center_image (shell, TRUE, TRUE);
gimp_display_shell_scroll_center_content (shell, TRUE, TRUE);
}
static gboolean
@ -1168,7 +1180,7 @@ gimp_display_shell_scale_image_starts_to_fit (GimpDisplayShell *shell,
if (! horizontally) horizontally = &horizontally_dummy;
/* The image can only start to fit if we zoom out */
if (new_scale > current_scale)
if (new_scale > current_scale || shell->show_all)
{
*vertically = FALSE;
*horizontally = FALSE;
@ -1229,16 +1241,19 @@ gimp_display_shell_scale_viewport_coord_almost_centered (GimpDisplayShell *shell
gboolean *horizontally,
gboolean *vertically)
{
gboolean local_horizontally;
gboolean local_vertically;
gint center_x = shell->disp_width / 2;
gint center_y = shell->disp_height / 2;
gboolean local_horizontally = FALSE;
gboolean local_vertically = FALSE;
gint center_x = shell->disp_width / 2;
gint center_y = shell->disp_height / 2;
local_horizontally = (x > center_x - ALMOST_CENTERED_THRESHOLD &&
x < center_x + ALMOST_CENTERED_THRESHOLD);
if (! shell->show_all)
{
local_horizontally = (x > center_x - ALMOST_CENTERED_THRESHOLD &&
x < center_x + ALMOST_CENTERED_THRESHOLD);
local_vertically = (y > center_y - ALMOST_CENTERED_THRESHOLD &&
y < center_y + ALMOST_CENTERED_THRESHOLD);
local_vertically = (y > center_y - ALMOST_CENTERED_THRESHOLD &&
y < center_y + ALMOST_CENTERED_THRESHOLD);
}
if (horizontally) *horizontally = local_horizontally;
if (vertically) *vertically = local_vertically;

View File

@ -160,83 +160,98 @@ gimp_display_shell_scroll_clamp_and_update (GimpDisplayShell *shell)
if (image)
{
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_scale_get_image_bounds (shell,
&bounds_x, &bounds_y,
&bounds_width, &bounds_height);
if (shell->disp_width < bounds_width)
if (! shell->show_all)
{
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 -
bounds_width * (1.0 - OVERPAN_FACTOR);
min_offset_x = bounds_x -
overpan_amount;
max_offset_x = bounds_x + bounds_width - shell->disp_width +
overpan_amount;
}
if (shell->disp_height < bounds_height)
{
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 -
bounds_height * (1.0 - OVERPAN_FACTOR);
min_offset_y = bounds_y -
overpan_amount;
max_offset_y = bounds_y + bounds_height +
overpan_amount - shell->disp_height;
}
/* Clamp */
offset_x = CLAMP (shell->offset_x, min_offset_x, max_offset_x);
offset_y = CLAMP (shell->offset_y, min_offset_y, max_offset_y);
if (offset_x != shell->offset_x || offset_y != shell->offset_y)
{
shell->offset_x = offset_x;
shell->offset_y = 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_scale_get_image_bounds (shell,
&bounds_x,
&bounds_y,
&bounds_width,
&bounds_height);
if (shell->disp_width < bounds_width)
{
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 -
bounds_width * (1.0 - OVERPAN_FACTOR);
min_offset_x = bounds_x -
overpan_amount;
max_offset_x = bounds_x + bounds_width - shell->disp_width +
overpan_amount;
}
if (shell->disp_height < bounds_height)
{
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 -
bounds_height * (1.0 - OVERPAN_FACTOR);
min_offset_y = bounds_y -
overpan_amount;
max_offset_y = bounds_y + bounds_height +
overpan_amount - shell->disp_height;
}
/* Clamp */
offset_x = CLAMP (shell->offset_x, min_offset_x, max_offset_x);
offset_y = CLAMP (shell->offset_y, min_offset_y, max_offset_y);
if (offset_x != shell->offset_x || offset_y != shell->offset_y)
{
shell->offset_x = offset_x;
shell->offset_y = offset_y;
gimp_display_shell_rotate_update_transform (shell);
}
/* Set scrollbar stepper sensitiity */
gimp_display_shell_scrollbars_update_steppers (shell,
min_offset_x,
max_offset_x,
min_offset_y,
max_offset_y);
}
else
{
/* Set scrollbar stepper sensitiity */
/* Set scrollbar stepper sensitiity */
gimp_display_shell_scrollbars_update_steppers (shell,
min_offset_x,
max_offset_x,
min_offset_y,
max_offset_y);
gimp_display_shell_scrollbars_update_steppers (shell,
G_MININT,
G_MAXINT,
G_MININT,
G_MAXINT);
}
}
else
{
@ -278,32 +293,35 @@ gimp_display_shell_scroll_unoverscrollify (GimpDisplayShell *shell,
*out_offset_x = in_offset_x;
*out_offset_y = in_offset_y;
gimp_display_shell_scale_get_image_size (shell, &sw, &sh);
if (in_offset_x < 0)
if (! shell->show_all)
{
*out_offset_x = MAX (in_offset_x,
MIN (0, 0 - shell->offset_x));
}
else if (in_offset_x > 0)
{
gint min_offset = sw - shell->disp_width;
gimp_display_shell_scale_get_image_size (shell, &sw, &sh);
*out_offset_x = MIN (in_offset_x,
MAX (0, min_offset - shell->offset_x));
}
if (in_offset_x < 0)
{
*out_offset_x = MAX (in_offset_x,
MIN (0, 0 - shell->offset_x));
}
else if (in_offset_x > 0)
{
gint min_offset = sw - shell->disp_width;
if (in_offset_y < 0)
{
*out_offset_y = MAX (in_offset_y,
MIN (0, 0 - shell->offset_y));
}
else if (in_offset_y > 0)
{
gint min_offset = sh - shell->disp_height;
*out_offset_x = MIN (in_offset_x,
MAX (0, min_offset - shell->offset_x));
}
*out_offset_y = MIN (in_offset_y,
MAX (0, min_offset - shell->offset_y));
if (in_offset_y < 0)
{
*out_offset_y = MAX (in_offset_y,
MIN (0, 0 - shell->offset_y));
}
else if (in_offset_y > 0)
{
gint min_offset = sh - shell->disp_height;
*out_offset_y = MIN (in_offset_y,
MAX (0, min_offset - shell->offset_y));
}
}
}
@ -389,6 +407,65 @@ gimp_display_shell_scroll_center_image (GimpDisplayShell *shell,
gimp_display_shell_scroll (shell, offset_x, offset_y);
}
/**
* gimp_display_shell_scroll_center_image:
* @shell:
* @horizontally:
* @vertically:
*
* Centers the image content in the display shell on the desired axes.
**/
void
gimp_display_shell_scroll_center_content (GimpDisplayShell *shell,
gboolean horizontally,
gboolean vertically)
{
gint content_x;
gint content_y;
gint content_width;
gint content_height;
gint center_x;
gint center_y;
gint offset_x = 0;
gint offset_y = 0;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
if (! shell->display ||
! gimp_display_get_image (shell->display) ||
(! vertically && ! horizontally))
return;
gimp_display_shell_scale_get_image_bounding_box (shell,
&content_x,
&content_y,
&content_width,
&content_height);
if (shell->disp_width > content_width)
{
content_x -= (shell->disp_width - content_width) / 2;
content_width = shell->disp_width;
}
if (shell->disp_height > content_height)
{
content_y -= (shell->disp_height - content_height) / 2;
content_height = shell->disp_height;
}
center_x = content_x + content_width / 2;
center_y = content_y + content_height / 2;
if (horizontally)
offset_x = center_x - shell->disp_width / 2 - shell->offset_x;
if (vertically)
offset_y = center_y - shell->disp_height / 2 - shell->offset_y;
gimp_display_shell_scroll (shell, offset_x, offset_y);
}
/**
* gimp_display_shell_scroll_get_scaled_viewport:
* @shell:

View File

@ -40,6 +40,9 @@ void gimp_display_shell_scroll_center_image_xy (GimpDisplayShell *shell,
void gimp_display_shell_scroll_center_image (GimpDisplayShell *shell,
gboolean horizontally,
gboolean vertically);
void gimp_display_shell_scroll_center_content (GimpDisplayShell *shell,
gboolean horizontally,
gboolean vertically);
void gimp_display_shell_scroll_get_scaled_viewport (GimpDisplayShell *shell,
gint *x,

View File

@ -93,6 +93,10 @@ gimp_display_shell_scrollbars_setup_horizontal (GimpDisplayShell *shell,
{
gint bounds_x;
gint bounds_width;
gint bounding_box_x;
gint bounding_box_width;
gint x1;
gint x2;
gdouble lower;
gdouble upper;
gdouble scale_x;
@ -103,17 +107,21 @@ gimp_display_shell_scrollbars_setup_horizontal (GimpDisplayShell *shell,
return;
gimp_display_shell_scale_get_image_bounds (shell,
&bounds_x, NULL,
&bounds_x, NULL,
&bounds_width, NULL);
if (shell->disp_width > bounds_width)
{
bounds_x -= (shell->disp_width - bounds_width) / 2;
bounds_width = shell->disp_width;
}
gimp_display_shell_scale_get_image_bounding_box (shell,
&bounding_box_x, NULL,
&bounding_box_width, NULL);
lower = MIN (value, bounds_x);
upper = MAX (value + shell->disp_width, bounds_x + bounds_width);
x1 = bounding_box_x;
x2 = bounding_box_x + bounding_box_width;
x1 = MIN (x1, bounds_x + bounds_width / 2 - shell->disp_width / 2);
x2 = MAX (x2, bounds_x + bounds_width / 2 + (shell->disp_width + 1) / 2);
lower = MIN (value, x1);
upper = MAX (value + shell->disp_width, x2);
gimp_display_shell_get_rotated_scale (shell, &scale_x, NULL);
@ -137,6 +145,10 @@ gimp_display_shell_scrollbars_setup_vertical (GimpDisplayShell *shell,
{
gint bounds_y;
gint bounds_height;
gint bounding_box_y;
gint bounding_box_height;
gint y1;
gint y2;
gdouble lower;
gdouble upper;
gdouble scale_y;
@ -150,14 +162,18 @@ gimp_display_shell_scrollbars_setup_vertical (GimpDisplayShell *shell,
NULL, &bounds_y,
NULL, &bounds_height);
if (shell->disp_height > bounds_height)
{
bounds_y -= (shell->disp_height - bounds_height) / 2;
bounds_height = shell->disp_height;
}
gimp_display_shell_scale_get_image_bounding_box (shell,
NULL, &bounding_box_y,
NULL, &bounding_box_height);
lower = MIN (value, bounds_y);
upper = MAX (value + shell->disp_height, bounds_y + bounds_height);
y1 = bounding_box_y;
y2 = bounding_box_y + bounding_box_height;
y1 = MIN (y1, bounds_y + bounds_height / 2 - shell->disp_height / 2);
y2 = MAX (y2, bounds_y + bounds_height / 2 + (shell->disp_height + 1) / 2);
lower = MIN (value, y1);
upper = MAX (value + shell->disp_height, y2);
gimp_display_shell_get_rotated_scale (shell, NULL, &scale_y);

View File

@ -75,6 +75,7 @@
#include "gimpdisplayshell-rulers.h"
#include "gimpdisplayshell-scale.h"
#include "gimpdisplayshell-scroll.h"
#include "gimpdisplayshell-scrollbars.h"
#include "gimpdisplayshell-selection.h"
#include "gimpdisplayshell-title.h"
#include "gimpdisplayshell-tool-events.h"
@ -1848,6 +1849,9 @@ gimp_display_shell_set_show_all (GimpDisplayShell *shell,
gimp_display_update_bounding_box (shell->display);
gimp_display_shell_scroll_clamp_and_update (shell);
gimp_display_shell_scrollbars_update (shell);
gimp_display_shell_set_priority_viewport (shell);
gimp_display_shell_expose_full (shell);

View File

@ -1465,15 +1465,13 @@ gimp_image_window_shrink_wrap (GimpImageWindow *window,
gboolean grow_only)
{
GimpDisplayShell *active_shell;
GimpImage *image;
GtkWidget *widget;
GtkAllocation allocation;
GdkScreen *screen;
GdkRectangle rect;
gint monitor;
gint disp_width, disp_height;
gdouble x, y;
gdouble width, height;
gint width, height;
gint max_auto_width, max_auto_height;
gint border_width, border_height;
gboolean resize = FALSE;
@ -1490,8 +1488,6 @@ gimp_image_window_shrink_wrap (GimpImageWindow *window,
if (!active_shell)
return;
image = gimp_display_get_image (active_shell->display);
widget = GTK_WIDGET (window);
screen = gtk_widget_get_screen (widget);
@ -1501,15 +1497,9 @@ gimp_image_window_shrink_wrap (GimpImageWindow *window,
gtk_widget_get_window (widget));
gdk_screen_get_monitor_workarea (screen, monitor, &rect);
gimp_display_shell_transform_bounds (active_shell,
0, 0,
gimp_image_get_width (image),
gimp_image_get_height (image),
&x, &y,
&width, &height);
width = ceil (width - x);
height = ceil (height - y);
gimp_display_shell_scale_get_image_bounding_box (active_shell,
NULL, NULL,
&width, &height);
disp_width = active_shell->disp_width;
disp_height = active_shell->disp_height;
@ -1612,7 +1602,7 @@ gimp_image_window_shrink_wrap (GimpImageWindow *window,
* GimpDisplayShell::configure_event().
*/
/* FIXME multiple shells */
gimp_display_shell_scroll_center_image (active_shell, TRUE, TRUE);
gimp_display_shell_scroll_center_content (active_shell, TRUE, TRUE);
}
static GtkWidget *