[gimp/soc-2011-seamless-clone2] Bug 55367 - Rotated view of the canvas (view is rotated, not image contents)
- From: Clayton Walker <claytonw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/soc-2011-seamless-clone2] Bug 55367 - Rotated view of the canvas (view is rotated, not image contents)
- Date: Wed, 8 May 2013 15:15:54 +0000 (UTC)
commit 5f28d25d1155e5334759d57ccd26c69e2492e011
Author: Michael Natterer <mitch gimp org>
Date: Fri Apr 19 16:22:19 2013 +0200
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".
app/display/Makefile.am | 2 +
app/display/gimpcanvasitem.c | 11 ++-
app/display/gimpdisplay.c | 5 +-
app/display/gimpdisplayshell-callbacks.c | 21 ++-
app/display/gimpdisplayshell-draw.c | 45 ++++++-
app/display/gimpdisplayshell-items.c | 38 +++++-
app/display/gimpdisplayshell-rotate.c | 201 ++++++++++++++++++++++++++++
app/display/gimpdisplayshell-rotate.h | 51 +++++++
app/display/gimpdisplayshell-scroll.c | 3 +
app/display/gimpdisplayshell-selection.c | 6 +
app/display/gimpdisplayshell-tool-events.c | 51 ++++++--
app/display/gimpdisplayshell-transform.c | 125 +++++++++++++++++-
app/display/gimpdisplayshell-transform.h | 19 +++
app/display/gimpdisplayshell.c | 20 ++-
app/display/gimpdisplayshell.h | 6 +
15 files changed, 568 insertions(+), 36 deletions(-)
---
diff --git a/app/display/Makefile.am b/app/display/Makefile.am
index de9fc49..3539dc2 100644
--- a/app/display/Makefile.am
+++ b/app/display/Makefile.am
@@ -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 \
diff --git a/app/display/gimpcanvasitem.c b/app/display/gimpcanvasitem.c
index 093eaf3..9e1a260 100644
--- a/app/display/gimpcanvasitem.c
+++ b/app/display/gimpcanvasitem.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;
}
diff --git a/app/display/gimpdisplay.c b/app/display/gimpdisplay.c
index 880b9bd..3e0b746 100644
--- a/app/display/gimpdisplay.c
+++ b/app/display/gimpdisplay.c
@@ -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
diff --git a/app/display/gimpdisplayshell-callbacks.c b/app/display/gimpdisplayshell-callbacks.c
index 3209ba4..5861c0a 100644
--- a/app/display/gimpdisplayshell-callbacks.c
+++ b/app/display/gimpdisplayshell-callbacks.c
@@ -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 */
diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c
index 075b2ec..0e0e032 100644
--- a/app/display/gimpdisplayshell-draw.c
+++ b/app/display/gimpdisplayshell-draw.c
@@ -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;
diff --git a/app/display/gimpdisplayshell-items.c b/app/display/gimpdisplayshell-items.c
index 9cb1261..0e3ef2d 100644
--- a/app/display/gimpdisplayshell-items.c
+++ b/app/display/gimpdisplayshell-items.c
@@ -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);
+ }
}
diff --git a/app/display/gimpdisplayshell-rotate.c b/app/display/gimpdisplayshell-rotate.c
new file mode 100644
index 0000000..d04ce16
--- /dev/null
+++ b/app/display/gimpdisplayshell-rotate.c
@@ -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);
+}
diff --git a/app/display/gimpdisplayshell-rotate.h b/app/display/gimpdisplayshell-rotate.h
new file mode 100644
index 0000000..0c71bab
--- /dev/null
+++ b/app/display/gimpdisplayshell-rotate.h
@@ -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__ */
diff --git a/app/display/gimpdisplayshell-scroll.c b/app/display/gimpdisplayshell-scroll.c
index f7c776d..4fb8bc3 100644
--- a/app/display/gimpdisplayshell-scroll.c
+++ b/app/display/gimpdisplayshell-scroll.c
@@ -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);
diff --git a/app/display/gimpdisplayshell-selection.c b/app/display/gimpdisplayshell-selection.c
index b6e1885..cc48fe8 100644
--- a/app/display/gimpdisplayshell-selection.c
+++ b/app/display/gimpdisplayshell-selection.c
@@ -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);
diff --git a/app/display/gimpdisplayshell-tool-events.c b/app/display/gimpdisplayshell-tool-events.c
index 733c972..089cc40 100644
--- a/app/display/gimpdisplayshell-tool-events.c
+++ b/app/display/gimpdisplayshell-tool-events.c
@@ -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;
diff --git a/app/display/gimpdisplayshell-transform.c b/app/display/gimpdisplayshell-transform.c
index ffe1fd5..11aafdf 100644
--- a/app/display/gimpdisplayshell-transform.c
+++ b/app/display/gimpdisplayshell-transform.c
@@ -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
diff --git a/app/display/gimpdisplayshell-transform.h b/app/display/gimpdisplayshell-transform.h
index 0f8b747..ead1cdb 100644
--- a/app/display/gimpdisplayshell-transform.h
+++ b/app/display/gimpdisplayshell-transform.h
@@ -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,
diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c
index c25c290..3b4f227 100644
--- a/app/display/gimpdisplayshell.c
+++ b/app/display/gimpdisplayshell.c
@@ -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);
}
diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h
index 08ef099..640cfdf 100644
--- a/app/display/gimpdisplayshell.h
+++ b/app/display/gimpdisplayshell.h
@@ -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;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]