mirror of https://github.com/GNOME/gimp.git
Bug 55367 - Rotated view of the canvas (view is rotated, not image contents)
First version of display rotation, inspired by gimp-painter. The rotation always happens around the image's center. The only "UI" for rotating is currently shift+middle-drag and shift+space-drag. Control constrains the angle to 15 degrees and is currently the only way to go back to "no rotation".
This commit is contained in:
parent
f45e7c26be
commit
b3a9a6a3e3
|
@ -113,6 +113,8 @@ libappdisplay_a_sources = \
|
|||
gimpdisplayshell-progress.h \
|
||||
gimpdisplayshell-render.c \
|
||||
gimpdisplayshell-render.h \
|
||||
gimpdisplayshell-rotate.c \
|
||||
gimpdisplayshell-rotate.h \
|
||||
gimpdisplayshell-scale.c \
|
||||
gimpdisplayshell-scale.h \
|
||||
gimpdisplayshell-scale-dialog.c \
|
||||
|
|
|
@ -629,12 +629,18 @@ gimp_canvas_item_transform_xy (GimpCanvasItem *item,
|
|||
gint *ty)
|
||||
{
|
||||
GimpCanvasItemPrivate *private;
|
||||
gint64 nx;
|
||||
gint64 ny;
|
||||
|
||||
g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
|
||||
|
||||
private = GET_PRIVATE (item);
|
||||
|
||||
gimp_display_shell_transform_xy (private->shell, x, y, tx, ty);
|
||||
nx = x * private->shell->scale_x - private->shell->offset_x;
|
||||
ny = y * private->shell->scale_y - private->shell->offset_y;
|
||||
|
||||
*tx = CLAMP (nx, G_MININT, G_MAXINT);
|
||||
*ty = CLAMP (ny, G_MININT, G_MAXINT);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -650,7 +656,8 @@ gimp_canvas_item_transform_xy_f (GimpCanvasItem *item,
|
|||
|
||||
private = GET_PRIVATE (item);
|
||||
|
||||
gimp_display_shell_transform_xy_f (private->shell, x, y, tx, ty);
|
||||
*tx = SCALEX (private->shell, x) - private->shell->offset_x;
|
||||
*ty = SCALEY (private->shell, y) - private->shell->offset_y;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -886,8 +886,9 @@ gimp_display_paint_area (GimpDisplay *display,
|
|||
h = (y2 - y1);
|
||||
|
||||
/* display the area */
|
||||
gimp_display_shell_transform_xy_f (shell, x, y, &x1_f, &y1_f);
|
||||
gimp_display_shell_transform_xy_f (shell, x + w, y + h, &x2_f, &y2_f);
|
||||
gimp_display_shell_transform_bounds (shell,
|
||||
x, y, x + w, y + h,
|
||||
&x1_f, &y1_f, &x2_f, &y2_f);
|
||||
|
||||
/* make sure to expose a superset of the transformed sub-pixel expose
|
||||
* area, not a subset. bug #126942. --mitch
|
||||
|
|
|
@ -454,7 +454,8 @@ static void
|
|||
gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell,
|
||||
cairo_t *cr)
|
||||
{
|
||||
cairo_rectangle_int_t image_rect;
|
||||
cairo_rectangle_list_t *clip_rectangles;
|
||||
cairo_rectangle_int_t image_rect;
|
||||
|
||||
image_rect.x = - shell->offset_x;
|
||||
image_rect.y = - shell->offset_y;
|
||||
|
@ -469,6 +470,9 @@ gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell,
|
|||
|
||||
cairo_save (cr);
|
||||
|
||||
if (shell->rotate_transform)
|
||||
cairo_transform (cr, shell->rotate_transform);
|
||||
|
||||
cairo_rectangle (cr,
|
||||
image_rect.x,
|
||||
image_rect.y,
|
||||
|
@ -489,6 +493,10 @@ gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell,
|
|||
*/
|
||||
|
||||
cairo_save (cr);
|
||||
clip_rectangles = cairo_copy_clip_rectangle_list (cr);
|
||||
|
||||
if (shell->rotate_transform)
|
||||
cairo_transform (cr, shell->rotate_transform);
|
||||
|
||||
cairo_rectangle (cr,
|
||||
image_rect.x,
|
||||
|
@ -499,15 +507,12 @@ gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell,
|
|||
|
||||
if (gdk_cairo_get_clip_rectangle (cr, NULL))
|
||||
{
|
||||
cairo_rectangle_list_t *clip_rectangles;
|
||||
gint i;
|
||||
gint i;
|
||||
|
||||
cairo_save (cr);
|
||||
gimp_display_shell_draw_checkerboard (shell, cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
clip_rectangles = cairo_copy_clip_rectangle_list (cr);
|
||||
|
||||
for (i = 0; i < clip_rectangles->num_rectangles; i++)
|
||||
{
|
||||
cairo_rectangle_t rect = clip_rectangles->rectangles[i];
|
||||
|
@ -518,10 +523,9 @@ gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell,
|
|||
ceil (rect.width),
|
||||
ceil (rect.height));
|
||||
}
|
||||
|
||||
cairo_rectangle_list_destroy (clip_rectangles);
|
||||
}
|
||||
|
||||
cairo_rectangle_list_destroy (clip_rectangles);
|
||||
cairo_restore (cr);
|
||||
|
||||
|
||||
|
@ -529,6 +533,9 @@ gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell,
|
|||
*/
|
||||
|
||||
/* draw canvas items */
|
||||
if (shell->rotate_transform)
|
||||
cairo_transform (cr, shell->rotate_transform);
|
||||
|
||||
gimp_canvas_item_draw (shell->canvas_item, cr);
|
||||
|
||||
/* restart (and recalculate) the selection boundaries */
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "display-types.h"
|
||||
|
||||
#include "core/gimp-cairo.h"
|
||||
#include "core/gimp-utils.h"
|
||||
|
||||
#include "gimpcanvas.h"
|
||||
#include "gimpcanvas-style.h"
|
||||
|
@ -36,6 +37,8 @@
|
|||
#include "gimpdisplayshell.h"
|
||||
#include "gimpdisplayshell-draw.h"
|
||||
#include "gimpdisplayshell-render.h"
|
||||
#include "gimpdisplayshell-rotate.h"
|
||||
#include "gimpdisplayshell-scale.h"
|
||||
#include "gimpdisplayxfer.h"
|
||||
|
||||
|
||||
|
@ -132,22 +135,54 @@ gimp_display_shell_draw_image (GimpDisplayShell *shell,
|
|||
gint w,
|
||||
gint h)
|
||||
{
|
||||
gint x2, y2;
|
||||
gint x1, y1, x2, y2;
|
||||
gint i, j;
|
||||
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (gimp_display_get_image (shell->display));
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
x2 = x + w;
|
||||
y2 = y + h;
|
||||
if (shell->rotate_untransform)
|
||||
{
|
||||
gdouble tx1, ty1;
|
||||
gdouble tx2, ty2;
|
||||
gint image_width;
|
||||
gint image_height;
|
||||
|
||||
gimp_display_shell_rotate_untransform_bounds (shell,
|
||||
x, y, x + w, y + h,
|
||||
&tx1, &ty1, &tx2, &ty2);
|
||||
|
||||
x1 = floor (tx1 - 0.5);
|
||||
y1 = floor (ty1 - 0.5);
|
||||
x2 = ceil (tx2 + 0.5);
|
||||
y2 = ceil (ty2 + 0.5);
|
||||
|
||||
gimp_display_shell_scale_get_image_size (shell,
|
||||
&image_width, &image_height);
|
||||
|
||||
x1 = CLAMP (x1, -shell->offset_x, -shell->offset_x + image_width);
|
||||
y1 = CLAMP (y1, -shell->offset_y, -shell->offset_y + image_height);
|
||||
x2 = CLAMP (x2, -shell->offset_x, -shell->offset_x + image_width);
|
||||
y2 = CLAMP (y2, -shell->offset_y, -shell->offset_y + image_height);
|
||||
|
||||
if (!(x2 > x1) || !(y2 > y1))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
x2 = x + w;
|
||||
y2 = y + h;
|
||||
}
|
||||
|
||||
/* display the image in RENDER_BUF_WIDTH x RENDER_BUF_HEIGHT
|
||||
* sized chunks
|
||||
*/
|
||||
for (i = y; i < y2; i += GIMP_DISPLAY_RENDER_BUF_HEIGHT)
|
||||
for (i = y1; i < y2; i += GIMP_DISPLAY_RENDER_BUF_HEIGHT)
|
||||
{
|
||||
for (j = x; j < x2; j += GIMP_DISPLAY_RENDER_BUF_WIDTH)
|
||||
for (j = x1; j < x2; j += GIMP_DISPLAY_RENDER_BUF_WIDTH)
|
||||
{
|
||||
gint dx, dy;
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <libgimpmath/gimpmath.h>
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "gimpcanvascursor.h"
|
||||
|
@ -32,6 +34,7 @@
|
|||
#include "gimpdisplayshell.h"
|
||||
#include "gimpdisplayshell-expose.h"
|
||||
#include "gimpdisplayshell-items.h"
|
||||
#include "gimpdisplayshell-rotate.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
@ -190,5 +193,38 @@ gimp_display_shell_item_update (GimpCanvasItem *item,
|
|||
cairo_region_t *region,
|
||||
GimpDisplayShell *shell)
|
||||
{
|
||||
gimp_display_shell_expose_region (shell, region);
|
||||
if (shell->rotate_transform)
|
||||
{
|
||||
gint n_rects;
|
||||
gint i;
|
||||
|
||||
n_rects = cairo_region_num_rectangles (region);
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
gdouble tx1, ty1;
|
||||
gdouble tx2, ty2;
|
||||
gint x1, y1, x2, y2;
|
||||
|
||||
cairo_region_get_rectangle (region, i, &rect);
|
||||
|
||||
gimp_display_shell_rotate_transform_bounds (shell,
|
||||
rect.x, rect.y,
|
||||
rect.x + rect.width,
|
||||
rect.y + rect.height,
|
||||
&tx1, &ty1, &tx2, &ty2);
|
||||
|
||||
x1 = floor (tx1 - 0.5);
|
||||
y1 = floor (ty1 - 0.5);
|
||||
x2 = ceil (tx2 + 0.5);
|
||||
y2 = ceil (ty2 + 0.5);
|
||||
|
||||
gimp_display_shell_expose_area (shell, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_display_shell_expose_region (shell, region);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libgimpmath/gimpmath.h"
|
||||
|
||||
#include "display-types.h"
|
||||
|
||||
#include "core/gimp-utils.h"
|
||||
|
||||
#include "gimpdisplay.h"
|
||||
#include "gimpdisplayshell.h"
|
||||
#include "gimpdisplayshell-expose.h"
|
||||
#include "gimpdisplayshell-rotate.h"
|
||||
#include "gimpdisplayshell-scale.h"
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
g_free (shell->rotate_transform);
|
||||
g_free (shell->rotate_untransform);
|
||||
|
||||
if (shell->rotate_angle != 0.0 && gimp_display_get_image (shell->display))
|
||||
{
|
||||
gint image_width, image_height;
|
||||
gdouble cx, cy;
|
||||
|
||||
shell->rotate_transform = g_new (cairo_matrix_t, 1);
|
||||
shell->rotate_untransform = g_new (cairo_matrix_t, 1);
|
||||
|
||||
gimp_display_shell_scale_get_image_size (shell,
|
||||
&image_width, &image_height);
|
||||
|
||||
cx = -shell->offset_x + image_width / 2;
|
||||
cy = -shell->offset_y + image_height / 2;
|
||||
|
||||
cairo_matrix_init_translate (shell->rotate_transform, cx, cy);
|
||||
cairo_matrix_rotate (shell->rotate_transform,
|
||||
shell->rotate_angle / 180.0 * G_PI);
|
||||
cairo_matrix_translate (shell->rotate_transform, -cx, -cy);
|
||||
|
||||
*shell->rotate_untransform = *shell->rotate_transform;
|
||||
cairo_matrix_invert (shell->rotate_untransform);
|
||||
}
|
||||
else
|
||||
{
|
||||
shell->rotate_transform = NULL;
|
||||
shell->rotate_untransform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_display_shell_rotate_transform_bounds (GimpDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
gdouble *nx1,
|
||||
gdouble *ny1,
|
||||
gdouble *nx2,
|
||||
gdouble *ny2)
|
||||
{
|
||||
gdouble tx1, ty1;
|
||||
gdouble tx2, ty2;
|
||||
gdouble tx3, ty3;
|
||||
gdouble tx4, ty4;
|
||||
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
tx1 = x1;
|
||||
ty1 = y1;
|
||||
tx2 = x1;
|
||||
ty2 = y2;
|
||||
tx3 = x2;
|
||||
ty3 = y1;
|
||||
tx4 = x2;
|
||||
ty4 = y2;
|
||||
|
||||
cairo_matrix_transform_point (shell->rotate_transform, &tx1, &ty1);
|
||||
cairo_matrix_transform_point (shell->rotate_transform, &tx2, &ty2);
|
||||
cairo_matrix_transform_point (shell->rotate_transform, &tx3, &ty3);
|
||||
cairo_matrix_transform_point (shell->rotate_transform, &tx4, &ty4);
|
||||
|
||||
*nx1 = MIN4 (tx1, tx2, tx3, tx4);
|
||||
*ny1 = MIN4 (ty1, ty2, ty3, ty4);
|
||||
*nx2 = MAX4 (tx1, tx2, tx3, tx4);
|
||||
*ny2 = MAX4 (ty1, ty2, ty3, ty4);
|
||||
}
|
||||
|
||||
void
|
||||
gimp_display_shell_rotate_untransform_bounds (GimpDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
gdouble *nx1,
|
||||
gdouble *ny1,
|
||||
gdouble *nx2,
|
||||
gdouble *ny2)
|
||||
{
|
||||
gdouble tx1, ty1;
|
||||
gdouble tx2, ty2;
|
||||
gdouble tx3, ty3;
|
||||
gdouble tx4, ty4;
|
||||
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
tx1 = x1;
|
||||
ty1 = y1;
|
||||
tx2 = x1;
|
||||
ty2 = y2;
|
||||
tx3 = x2;
|
||||
ty3 = y1;
|
||||
tx4 = x2;
|
||||
ty4 = y2;
|
||||
|
||||
cairo_matrix_transform_point (shell->rotate_untransform, &tx1, &ty1);
|
||||
cairo_matrix_transform_point (shell->rotate_untransform, &tx2, &ty2);
|
||||
cairo_matrix_transform_point (shell->rotate_untransform, &tx3, &ty3);
|
||||
cairo_matrix_transform_point (shell->rotate_untransform, &tx4, &ty4);
|
||||
|
||||
*nx1 = MIN4 (tx1, tx2, tx3, tx4);
|
||||
*ny1 = MIN4 (ty1, ty2, ty3, ty4);
|
||||
*nx2 = MAX4 (tx1, tx2, tx3, tx4);
|
||||
*ny2 = MAX4 (ty1, ty2, ty3, ty4);
|
||||
}
|
||||
|
||||
void
|
||||
gimp_display_shell_rotate_drag (GimpDisplayShell *shell,
|
||||
gdouble last_x,
|
||||
gdouble last_y,
|
||||
gdouble cur_x,
|
||||
gdouble cur_y,
|
||||
gboolean constrain)
|
||||
{
|
||||
gint image_width, image_height;
|
||||
gdouble px, py;
|
||||
gdouble x1, y1, x2, y2;
|
||||
gdouble angle1, angle2, angle;
|
||||
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
gimp_display_shell_scale_get_image_size (shell,
|
||||
&image_width, &image_height);
|
||||
|
||||
px = -shell->offset_x + image_width / 2;
|
||||
py = -shell->offset_y + image_height / 2;
|
||||
|
||||
x1 = cur_x - px;
|
||||
x2 = last_x - px;
|
||||
y1 = py - cur_y;
|
||||
y2 = py - last_y;
|
||||
|
||||
/* find the first angle */
|
||||
angle1 = atan2 (y1, x1);
|
||||
|
||||
/* find the angle */
|
||||
angle2 = atan2 (y2, x2);
|
||||
|
||||
angle = angle2 - angle1;
|
||||
|
||||
if (angle > G_PI || angle < -G_PI)
|
||||
angle = angle2 - ((angle1 < 0) ? 2.0 * G_PI + angle1 : angle1 - 2.0 * G_PI);
|
||||
|
||||
shell->rotate_drag_angle += (angle * 180.0 / G_PI);
|
||||
|
||||
if (constrain)
|
||||
{
|
||||
shell->rotate_angle = (gint) (((gint) shell->rotate_drag_angle / 15) * 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
shell->rotate_angle = shell->rotate_drag_angle;
|
||||
}
|
||||
|
||||
gimp_display_shell_rotate_update_transform (shell);
|
||||
gimp_display_shell_expose_full (shell);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_DISPLAY_SHELL_ROTATE_H__
|
||||
#define __GIMP_DISPLAY_SHELL_ROTATE_H__
|
||||
|
||||
|
||||
void gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell);
|
||||
|
||||
void gimp_display_shell_rotate_transform_bounds (GimpDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
gdouble *nx1,
|
||||
gdouble *ny1,
|
||||
gdouble *nx2,
|
||||
gdouble *ny2);
|
||||
void gimp_display_shell_rotate_untransform_bounds (GimpDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
gdouble *nx1,
|
||||
gdouble *ny1,
|
||||
gdouble *nx2,
|
||||
gdouble *ny2);
|
||||
|
||||
void gimp_display_shell_rotate_drag (GimpDisplayShell *shell,
|
||||
gdouble last_x,
|
||||
gdouble last_y,
|
||||
gdouble cur_x,
|
||||
gdouble cur_y,
|
||||
gboolean constrain);
|
||||
|
||||
|
||||
#endif /* __GIMP_DISPLAY_SHELL_ROTATE_H__ */
|
|
@ -36,6 +36,7 @@
|
|||
#include "gimpdisplay-foreach.h"
|
||||
#include "gimpdisplayshell.h"
|
||||
#include "gimpdisplayshell-expose.h"
|
||||
#include "gimpdisplayshell-rotate.h"
|
||||
#include "gimpdisplayshell-scale.h"
|
||||
#include "gimpdisplayshell-scroll.h"
|
||||
|
||||
|
@ -119,6 +120,8 @@ gimp_display_shell_scroll (GimpDisplayShell *shell,
|
|||
shell->offset_x += x_offset;
|
||||
shell->offset_y += y_offset;
|
||||
|
||||
gimp_display_shell_rotate_update_transform (shell);
|
||||
|
||||
gimp_overlay_box_scroll (GIMP_OVERLAY_BOX (shell->canvas),
|
||||
-x_offset, -y_offset);
|
||||
|
||||
|
|
|
@ -292,6 +292,9 @@ selection_render_mask (Selection *selection)
|
|||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
|
||||
if (selection->shell->rotate_transform)
|
||||
cairo_transform (cr, selection->shell->rotate_transform);
|
||||
|
||||
gimp_cairo_add_segments (cr,
|
||||
selection->segs_in,
|
||||
selection->n_segs_in);
|
||||
|
@ -438,6 +441,9 @@ selection_start_timeout (Selection *selection)
|
|||
|
||||
cr = gdk_cairo_create (gtk_widget_get_window (selection->shell->canvas));
|
||||
|
||||
if (selection->shell->rotate_transform)
|
||||
cairo_transform (cr, selection->shell->rotate_transform);
|
||||
|
||||
gimp_display_shell_draw_selection_out (selection->shell, cr,
|
||||
selection->segs_out,
|
||||
selection->n_segs_out);
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "gimpdisplayshell-cursor.h"
|
||||
#include "gimpdisplayshell-grab.h"
|
||||
#include "gimpdisplayshell-layer-select.h"
|
||||
#include "gimpdisplayshell-rotate.h"
|
||||
#include "gimpdisplayshell-scale.h"
|
||||
#include "gimpdisplayshell-scroll.h"
|
||||
#include "gimpdisplayshell-tool-events.h"
|
||||
|
@ -79,6 +80,7 @@ static void gimp_display_shell_check_device_cursor (GimpDisplayShell
|
|||
|
||||
static void gimp_display_shell_start_scrolling (GimpDisplayShell *shell,
|
||||
const GdkEvent *event,
|
||||
GdkModifierType state,
|
||||
gint x,
|
||||
gint y);
|
||||
static void gimp_display_shell_stop_scrolling (GimpDisplayShell *shell,
|
||||
|
@ -561,7 +563,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
|
|||
}
|
||||
else if (bevent->button == 2)
|
||||
{
|
||||
gimp_display_shell_start_scrolling (shell, NULL,
|
||||
gimp_display_shell_start_scrolling (shell, NULL, state,
|
||||
bevent->x, bevent->y);
|
||||
}
|
||||
|
||||
|
@ -841,9 +843,24 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
|
|||
? ((GdkEventMotion *) compressed_motion)->y
|
||||
: mevent->y);
|
||||
|
||||
gimp_display_shell_scroll (shell,
|
||||
shell->scroll_last_x - x,
|
||||
shell->scroll_last_y - y);
|
||||
if (shell->rotating)
|
||||
{
|
||||
gboolean constrain = (state & GDK_CONTROL_MASK) ? TRUE : FALSE;
|
||||
|
||||
gimp_display_shell_rotate_drag (shell,
|
||||
shell->scroll_last_x,
|
||||
shell->scroll_last_y,
|
||||
x,
|
||||
y,
|
||||
constrain);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_display_shell_scroll (shell,
|
||||
shell->scroll_last_x - x,
|
||||
shell->scroll_last_y - y);
|
||||
|
||||
}
|
||||
|
||||
shell->scroll_last_x = x;
|
||||
shell->scroll_last_y = y;
|
||||
|
@ -1406,6 +1423,7 @@ gimp_display_shell_check_device_cursor (GimpDisplayShell *shell)
|
|||
static void
|
||||
gimp_display_shell_start_scrolling (GimpDisplayShell *shell,
|
||||
const GdkEvent *event,
|
||||
GdkModifierType state,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
|
@ -1413,11 +1431,16 @@ gimp_display_shell_start_scrolling (GimpDisplayShell *shell,
|
|||
|
||||
gimp_display_shell_pointer_grab (shell, event, GDK_POINTER_MOTION_MASK);
|
||||
|
||||
shell->scrolling = TRUE;
|
||||
shell->scroll_last_x = x;
|
||||
shell->scroll_last_y = y;
|
||||
shell->scrolling = TRUE;
|
||||
shell->scroll_last_x = x;
|
||||
shell->scroll_last_y = y;
|
||||
shell->rotating = (state & GDK_SHIFT_MASK) ? TRUE : FALSE;
|
||||
shell->rotate_drag_angle = shell->rotate_angle;
|
||||
|
||||
gimp_display_shell_set_override_cursor (shell, GDK_FLEUR);
|
||||
if (shell->rotating)
|
||||
gimp_display_shell_set_override_cursor (shell, GDK_EXCHANGE);
|
||||
else
|
||||
gimp_display_shell_set_override_cursor (shell, GDK_FLEUR);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1428,9 +1451,11 @@ gimp_display_shell_stop_scrolling (GimpDisplayShell *shell,
|
|||
|
||||
gimp_display_shell_unset_override_cursor (shell);
|
||||
|
||||
shell->scrolling = FALSE;
|
||||
shell->scroll_last_x = 0;
|
||||
shell->scroll_last_y = 0;
|
||||
shell->scrolling = FALSE;
|
||||
shell->scroll_last_x = 0;
|
||||
shell->scroll_last_y = 0;
|
||||
shell->rotating = FALSE;
|
||||
shell->rotate_drag_angle = 0.0;
|
||||
|
||||
gimp_display_shell_pointer_ungrab (shell, event);
|
||||
}
|
||||
|
@ -1457,6 +1482,7 @@ gimp_display_shell_space_pressed (GimpDisplayShell *shell,
|
|||
GimpDeviceManager *manager;
|
||||
GimpDeviceInfo *current_device;
|
||||
GimpCoords coords;
|
||||
GdkModifierType state = 0;
|
||||
|
||||
manager = gimp_devices_get_manager (gimp);
|
||||
current_device = gimp_device_manager_get_current_device (manager);
|
||||
|
@ -1464,8 +1490,9 @@ gimp_display_shell_space_pressed (GimpDisplayShell *shell,
|
|||
gimp_device_info_get_device_coords (current_device,
|
||||
gtk_widget_get_window (shell->canvas),
|
||||
&coords);
|
||||
gdk_event_get_state (event, &state);
|
||||
|
||||
gimp_display_shell_start_scrolling (shell, event,
|
||||
gimp_display_shell_start_scrolling (shell, event, state,
|
||||
coords.x, coords.y);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "core/gimpboundary.h"
|
||||
#include "core/gimpdrawable.h"
|
||||
#include "core/gimpimage.h"
|
||||
#include "core/gimp-utils.h"
|
||||
|
||||
#include "gimpdisplay.h"
|
||||
#include "gimpdisplayshell.h"
|
||||
|
@ -59,6 +60,11 @@ gimp_display_shell_transform_coords (const GimpDisplayShell *shell,
|
|||
|
||||
display_coords->x -= shell->offset_x;
|
||||
display_coords->y -= shell->offset_y;
|
||||
|
||||
if (shell->rotate_transform)
|
||||
cairo_matrix_transform_point (shell->rotate_transform,
|
||||
&display_coords->x,
|
||||
&display_coords->y);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,8 +87,13 @@ gimp_display_shell_untransform_coords (const GimpDisplayShell *shell,
|
|||
|
||||
*image_coords = *display_coords;
|
||||
|
||||
image_coords->x = display_coords->x + shell->offset_x;
|
||||
image_coords->y = display_coords->y + shell->offset_y;
|
||||
if (shell->rotate_untransform)
|
||||
cairo_matrix_transform_point (shell->rotate_untransform,
|
||||
&image_coords->x,
|
||||
&image_coords->y);
|
||||
|
||||
image_coords->x += shell->offset_x;
|
||||
image_coords->y += shell->offset_y;
|
||||
|
||||
image_coords->x /= shell->scale_x;
|
||||
image_coords->y /= shell->scale_y;
|
||||
|
@ -115,6 +126,17 @@ gimp_display_shell_transform_xy (const GimpDisplayShell *shell,
|
|||
tx = x * shell->scale_x - shell->offset_x;
|
||||
ty = y * shell->scale_y - shell->offset_y;
|
||||
|
||||
if (shell->rotate_transform)
|
||||
{
|
||||
gdouble fx = tx;
|
||||
gdouble fy = ty;
|
||||
|
||||
cairo_matrix_transform_point (shell->rotate_transform, &fy, &fy);
|
||||
|
||||
tx = fx;
|
||||
ty = fy;
|
||||
}
|
||||
|
||||
/* The projected coordinates might overflow a gint in the case of big
|
||||
images at high zoom levels, so we clamp them here to avoid problems. */
|
||||
*nx = CLAMP (tx, G_MININT, G_MAXINT);
|
||||
|
@ -150,6 +172,17 @@ gimp_display_shell_untransform_xy (const GimpDisplayShell *shell,
|
|||
g_return_if_fail (nx != NULL);
|
||||
g_return_if_fail (ny != NULL);
|
||||
|
||||
if (shell->rotate_untransform)
|
||||
{
|
||||
gdouble fx = x;
|
||||
gdouble fy = y;
|
||||
|
||||
cairo_matrix_transform_point (shell->rotate_untransform, &fy, &fy);
|
||||
|
||||
x = fx;
|
||||
y = fy;
|
||||
}
|
||||
|
||||
if (round)
|
||||
{
|
||||
tx = SIGNED_ROUND (((gint64) x + shell->offset_x) / shell->scale_x);
|
||||
|
@ -189,6 +222,9 @@ gimp_display_shell_transform_xy_f (const GimpDisplayShell *shell,
|
|||
|
||||
*nx = SCALEX (shell, x) - shell->offset_x;
|
||||
*ny = SCALEY (shell, y) - shell->offset_y;
|
||||
|
||||
if (shell->rotate_transform)
|
||||
cairo_matrix_transform_point (shell->rotate_transform, nx, ny);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,10 +250,95 @@ gimp_display_shell_untransform_xy_f (const GimpDisplayShell *shell,
|
|||
g_return_if_fail (nx != NULL);
|
||||
g_return_if_fail (ny != NULL);
|
||||
|
||||
if (shell->rotate_untransform)
|
||||
cairo_matrix_transform_point (shell->rotate_untransform, &x, &y);
|
||||
|
||||
*nx = (x + shell->offset_x) / shell->scale_x;
|
||||
*ny = (y + shell->offset_y) / shell->scale_y;
|
||||
}
|
||||
|
||||
void
|
||||
gimp_display_shell_transform_bounds (const GimpDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
gdouble *nx1,
|
||||
gdouble *ny1,
|
||||
gdouble *nx2,
|
||||
gdouble *ny2)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (nx1 != NULL);
|
||||
g_return_if_fail (ny1 != NULL);
|
||||
g_return_if_fail (nx2 != NULL);
|
||||
g_return_if_fail (ny2 != NULL);
|
||||
|
||||
if (shell->rotate_transform)
|
||||
{
|
||||
gdouble tx1, ty1;
|
||||
gdouble tx2, ty2;
|
||||
gdouble tx3, ty3;
|
||||
gdouble tx4, ty4;
|
||||
|
||||
gimp_display_shell_transform_xy_f (shell, x1, y1, &tx1, &ty1);
|
||||
gimp_display_shell_transform_xy_f (shell, x1, y2, &tx2, &ty2);
|
||||
gimp_display_shell_transform_xy_f (shell, x2, y1, &tx3, &ty3);
|
||||
gimp_display_shell_transform_xy_f (shell, x2, y2, &tx4, &ty4);
|
||||
|
||||
*nx1 = MIN4 (tx1, tx2, tx3, tx4);
|
||||
*ny1 = MIN4 (ty1, ty2, ty3, ty4);
|
||||
*nx2 = MAX4 (tx1, tx2, tx3, tx4);
|
||||
*ny2 = MAX4 (ty1, ty2, ty3, ty4);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_display_shell_transform_xy_f (shell, x1, y1, nx1, ny1);
|
||||
gimp_display_shell_transform_xy_f (shell, x2, y2, nx2, ny2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_display_shell_untransform_bounds (const GimpDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
gdouble *nx1,
|
||||
gdouble *ny1,
|
||||
gdouble *nx2,
|
||||
gdouble *ny2)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
g_return_if_fail (nx1 != NULL);
|
||||
g_return_if_fail (ny1 != NULL);
|
||||
g_return_if_fail (nx2 != NULL);
|
||||
g_return_if_fail (ny2 != NULL);
|
||||
|
||||
if (shell->rotate_untransform)
|
||||
{
|
||||
gdouble tx1, ty1;
|
||||
gdouble tx2, ty2;
|
||||
gdouble tx3, ty3;
|
||||
gdouble tx4, ty4;
|
||||
|
||||
gimp_display_shell_untransform_xy_f (shell, x1, y1, &tx1, &ty1);
|
||||
gimp_display_shell_untransform_xy_f (shell, x1, y2, &tx2, &ty2);
|
||||
gimp_display_shell_untransform_xy_f (shell, x2, y1, &tx3, &ty3);
|
||||
gimp_display_shell_untransform_xy_f (shell, x2, y2, &tx4, &ty4);
|
||||
|
||||
*nx1 = MIN4 (tx1, tx2, tx3, tx4);
|
||||
*ny1 = MIN4 (ty1, ty2, ty3, ty4);
|
||||
*nx2 = MAX4 (tx1, tx2, tx3, tx4);
|
||||
*ny2 = MAX4 (ty1, ty2, ty3, ty4);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_display_shell_untransform_xy_f (shell, x1, y1, nx1, ny1);
|
||||
gimp_display_shell_untransform_xy_f (shell, x2, y2, nx2, ny2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_display_shell_transform_segments:
|
||||
* @shell: a #GimpDisplayShell
|
||||
|
|
|
@ -49,6 +49,25 @@ void gimp_display_shell_untransform_xy_f (const GimpDisplayShell *shell,
|
|||
gdouble *nx,
|
||||
gdouble *ny);
|
||||
|
||||
void gimp_display_shell_transform_bounds (const GimpDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
gdouble *nx1,
|
||||
gdouble *ny1,
|
||||
gdouble *nx2,
|
||||
gdouble *ny2);
|
||||
void gimp_display_shell_untransform_bounds (const GimpDisplayShell *shell,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
gdouble *nx1,
|
||||
gdouble *ny1,
|
||||
gdouble *nx2,
|
||||
gdouble *ny2);
|
||||
|
||||
void gimp_display_shell_transform_segments (const GimpDisplayShell *shell,
|
||||
const GimpBoundSeg *src_segs,
|
||||
GimpSegment *dest_segs,
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "config/gimpdisplayoptions.h"
|
||||
|
||||
#include "core/gimp.h"
|
||||
#include "core/gimp-utils.h"
|
||||
#include "core/gimpchannel.h"
|
||||
#include "core/gimpcontext.h"
|
||||
#include "core/gimpimage.h"
|
||||
|
@ -67,6 +68,7 @@
|
|||
#include "gimpdisplayshell-items.h"
|
||||
#include "gimpdisplayshell-progress.h"
|
||||
#include "gimpdisplayshell-render.h"
|
||||
#include "gimpdisplayshell-rotate.h"
|
||||
#include "gimpdisplayshell-scale.h"
|
||||
#include "gimpdisplayshell-scroll.h"
|
||||
#include "gimpdisplayshell-selection.h"
|
||||
|
@ -1423,6 +1425,8 @@ gimp_display_shell_scaled (GimpDisplayShell *shell)
|
|||
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
gimp_display_shell_rotate_update_transform (shell);
|
||||
|
||||
for (list = shell->children; list; list = g_list_next (list))
|
||||
{
|
||||
GtkWidget *child = list->data;
|
||||
|
@ -1444,6 +1448,8 @@ gimp_display_shell_scrolled (GimpDisplayShell *shell)
|
|||
|
||||
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
|
||||
|
||||
gimp_display_shell_rotate_update_transform (shell);
|
||||
|
||||
for (list = shell->children; list; list = g_list_next (list))
|
||||
{
|
||||
GtkWidget *child = list->data;
|
||||
|
@ -1585,6 +1591,8 @@ gimp_display_shell_mask_bounds (GimpDisplayShell *shell,
|
|||
GimpLayer *layer;
|
||||
gdouble x1_f, y1_f;
|
||||
gdouble x2_f, y2_f;
|
||||
gdouble x3_f, y3_f;
|
||||
gdouble x4_f, y4_f;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
|
||||
g_return_val_if_fail (x1 != NULL, FALSE);
|
||||
|
@ -1625,13 +1633,15 @@ gimp_display_shell_mask_bounds (GimpDisplayShell *shell,
|
|||
}
|
||||
|
||||
gimp_display_shell_transform_xy_f (shell, *x1, *y1, &x1_f, &y1_f);
|
||||
gimp_display_shell_transform_xy_f (shell, *x2, *y2, &x2_f, &y2_f);
|
||||
gimp_display_shell_transform_xy_f (shell, *x1, *y2, &x2_f, &y2_f);
|
||||
gimp_display_shell_transform_xy_f (shell, *x2, *y1, &x3_f, &y3_f);
|
||||
gimp_display_shell_transform_xy_f (shell, *x2, *y2, &x4_f, &y4_f);
|
||||
|
||||
/* Make sure the extents are within bounds */
|
||||
*x1 = CLAMP (floor (x1_f), 0, shell->disp_width);
|
||||
*y1 = CLAMP (floor (y1_f), 0, shell->disp_height);
|
||||
*x2 = CLAMP (ceil (x2_f), 0, shell->disp_width);
|
||||
*y2 = CLAMP (ceil (y2_f), 0, shell->disp_height);
|
||||
*x1 = CLAMP (floor (MIN4 (x1_f, x2_f, x3_f, x4_f)), 0, shell->disp_width);
|
||||
*y1 = CLAMP (floor (MIN4 (y1_f, y2_f, y3_f, y4_f)), 0, shell->disp_height);
|
||||
*x2 = CLAMP (ceil (MAX4 (x1_f, x2_f, x3_f, x4_f)), 0, shell->disp_width);
|
||||
*y2 = CLAMP (ceil (MAX4 (y1_f, y2_f, y3_f, y4_f)), 0, shell->disp_height);
|
||||
|
||||
return ((*x2 - *x1) > 0) && ((*y2 - *y1) > 0);
|
||||
}
|
||||
|
|
|
@ -70,6 +70,10 @@ struct _GimpDisplayShell
|
|||
gdouble scale_x; /* horizontal scale factor */
|
||||
gdouble scale_y; /* vertical scale factor */
|
||||
|
||||
gdouble rotate_angle;
|
||||
cairo_matrix_t *rotate_transform;
|
||||
cairo_matrix_t *rotate_untransform;
|
||||
|
||||
gdouble monitor_xres;
|
||||
gdouble monitor_yres;
|
||||
gboolean dot_for_dot; /* ignore monitor resolution */
|
||||
|
@ -176,6 +180,8 @@ struct _GimpDisplayShell
|
|||
gboolean scrolling;
|
||||
gint scroll_last_x;
|
||||
gint scroll_last_y;
|
||||
gboolean rotating;
|
||||
gdouble rotate_drag_angle;
|
||||
gpointer scroll_info;
|
||||
|
||||
GimpDrawable *mask;
|
||||
|
|
Loading…
Reference in New Issue