gimptransformtool.c 47.6 KB
Newer Older
Nate Summers's avatar
Nate Summers committed
1
/* The GIMP -- an image manipulation program
Nate Summers's avatar
Nate Summers committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 * Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
 *
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <stdlib.h>

#include <gtk/gtk.h>

#include "libgimpmath/gimpmath.h"
#include "libgimpwidgets/gimpwidgets.h"

Michael Natterer's avatar
Michael Natterer committed
28
#include "tools-types.h"
29
#include "gui/gui-types.h"
Nate Summers's avatar
Nate Summers committed
30

Michael Natterer's avatar
Michael Natterer committed
31 32 33 34 35 36
#include "base/base-config.h"
#include "base/pixel-region.h"
#include "base/pixel-surround.h"
#include "base/tile-manager.h"
#include "base/tile.h"

37 38
#include "paint-funcs/paint-funcs.h"

Michael Natterer's avatar
Michael Natterer committed
39
#include "core/gimp.h"
40 41 42 43 44 45 46
#include "core/gimpchannel.h"
#include "core/gimpcontext.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
#include "core/gimplayer.h"
#include "core/gimpmarshal.h"
Michael Natterer's avatar
Michael Natterer committed
47
#include "core/gimptoolinfo.h"
48

49
#include "gui/info-dialog.h"
50 51

#include "display/gimpdisplay.h"
52
#include "display/gimpdisplay-foreach.h"
Michael Natterer's avatar
Michael Natterer committed
53
#include "display/gimpdisplayshell.h"
Nate Summers's avatar
Nate Summers committed
54

55 56 57 58
#include "tool_manager.h"
#include "tool_options.h"
#include "transform_options.h"
#include "gimptransformtool.h"
Michael Natterer's avatar
Michael Natterer committed
59 60 61 62 63
#include "gimpperspectivetool.h"
#include "gimprotatetool.h"
#include "gimpscaletool.h"
#include "gimpsheartool.h"
#include "gimpfliptool.h"
64

Michael Natterer's avatar
Michael Natterer committed
65 66 67 68
#include "app_procs.h"
#include "floating_sel.h"
#include "undo.h"
#include "path_transform.h"
Nate Summers's avatar
Nate Summers committed
69 70 71

#include "libgimp/gimpintl.h"

72

Nate Summers's avatar
Nate Summers committed
73 74 75 76
enum
{
  TRANSFORM,
  LAST_SIGNAL
Nate Summers's avatar
Nate Summers committed
77
};
Nate Summers's avatar
Nate Summers committed
78 79 80 81 82 83 84

#define BILINEAR(jk,j1k,jk1,j1k1,dx,dy) \
                ((1-dy) * (jk + dx * (j1k - jk)) + \
		    dy  * (jk1 + dx * (j1k1 - jk1)))

/* access interleaved pixels */
#define CUBIC_ROW(dx, row, step) \
Nate Summers's avatar
Nate Summers committed
85
  gimp_transform_tool_cubic(dx, (row)[0], (row)[step], (row)[step+step], (row)[step+step+step])
Nate Summers's avatar
Nate Summers committed
86
#define CUBIC_SCALED_ROW(dx, row, step, i) \
Nate Summers's avatar
Nate Summers committed
87
  gimp_transform_tool_cubic(dx, (row)[0] * (row)[i], \
Nate Summers's avatar
Nate Summers committed
88 89 90 91 92 93 94 95
            (row)[step] * (row)[step + i], \
            (row)[step+step]* (row)[step+step + i], \
            (row)[step+step+step] * (row)[step+step+step + i])

#define REF_TILE(i,x,y) \
     tile[i] = tile_manager_get_tile (float_tiles, x, y, TRUE, FALSE); \
     src[i] = tile_data_pointer (tile[i], (x) % TILE_WIDTH, (y) % TILE_HEIGHT);

96

Nate Summers's avatar
Nate Summers committed
97
/*  forward function declarations  */
Nate Summers's avatar
Nate Summers committed
98
static void      gimp_transform_tool_bounds    (GimpTransformTool      *tool,
99
                                                GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
100
static void      gimp_transform_tool_recalc    (GimpTransformTool      *tool,
101
					        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
102
static void      gimp_transform_tool_doit      (GimpTransformTool      *tool,
103
					        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
104 105 106 107 108 109 110 111 112
static gdouble   gimp_transform_tool_cubic     (gdouble                 dx,
					        gint                    jm1,
					        gint                    j,
					        gint                    jp1,
					        gint                    jp2);
static void    gimp_transform_tool_setup_grid  (GimpTransformTool      *tool);
static void    gimp_transform_tool_grid_recalc (GimpTransformTool      *gimp_transform_tool);
static void    gimp_transform_tool_init        (GimpTransformTool      *tool);
static void    gimp_transform_tool_class_init  (GimpTransformToolClass *tool);
Nate Summers's avatar
Nate Summers committed
113

114
static void    gimp_transform_tool_finalize    (GObject                *object);
115 116

static void   gimp_transform_tool_button_press (GimpTool               *tool,
117 118 119
                                                GimpCoords             *coords,
                                                guint32                 time,
                                                GdkModifierType         state,
120
			                        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
121
			          
122
static void gimp_transform_tool_button_release (GimpTool               *tool,
123 124 125
                                                GimpCoords             *coords,
                                                guint32                 time,
			                        GdkModifierType         state,
126
			                        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
127
			                        
128
static void    gimp_transform_tool_motion      (GimpTool               *tool,
129 130 131
                                                GimpCoords             *coords,
                                                guint32                 time,
		                                GdkModifierType         state,
132
		                                GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
133
		                                
134
static void  gimp_transform_tool_cursor_update (GimpTool               *tool,
135 136
                                                GimpCoords             *coords,
	                 		        GdkModifierType         state,
137
			                        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
138
			                        
139
static void    gimp_transform_tool_control     (GimpTool               *tool,
Nate Summers's avatar
Nate Summers committed
140
			                        ToolAction              action,
141
			                        GimpDisplay            *gdisp);
142 143 144 145

static void    gimp_transform_tool_draw        (GimpDrawTool           *draw_tool);


Nate Summers's avatar
Nate Summers committed
146
/*  variables  */
Nate Summers's avatar
Nate Summers committed
147 148 149
static TranInfo           old_trans_info;
InfoDialog               *transform_info        = NULL;
static gboolean           transform_info_inited = FALSE;
Nate Summers's avatar
Nate Summers committed
150

151
static GimpDrawToolClass *parent_class = NULL;
152

153 154 155 156
static guint   gimp_transform_tool_signals[LAST_SIGNAL] = { 0 };


GType
Nate Summers's avatar
Nate Summers committed
157 158
gimp_transform_tool_get_type (void)
{
159
  static GType tool_type = 0;
Nate Summers's avatar
Nate Summers committed
160 161 162

  if (! tool_type)
    {
163
      static const GTypeInfo tool_info =
Nate Summers's avatar
Nate Summers committed
164 165
      {
        sizeof (GimpTransformToolClass),
166 167 168 169 170 171 172 173
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gimp_transform_tool_class_init,
	NULL,           /* class_finalize */
	NULL,           /* class_data     */
	sizeof (GimpTransformTool),
	0,              /* n_preallocs    */
	(GInstanceInitFunc) gimp_transform_tool_init,
Nate Summers's avatar
Nate Summers committed
174 175
      };

176 177 178
      tool_type = g_type_register_static (GIMP_TYPE_DRAW_TOOL,
					  "GimpTransformTool", 
                                          &tool_info, 0);
Nate Summers's avatar
Nate Summers committed
179 180 181 182 183 184 185 186
    }

  return tool_type;
}

static void
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
{
187
  GObjectClass      *object_class;
Nate Summers's avatar
Nate Summers committed
188 189
  GimpToolClass     *tool_class;
  GimpDrawToolClass *draw_class;
Nate Summers's avatar
Nate Summers committed
190

191 192 193
  object_class = G_OBJECT_CLASS (klass);
  tool_class   = GIMP_TOOL_CLASS (klass);
  draw_class   = GIMP_DRAW_TOOL_CLASS (klass);
Nate Summers's avatar
Nate Summers committed
194

195
  parent_class = g_type_class_peek_parent (klass);
Nate Summers's avatar
Nate Summers committed
196 197

  gimp_transform_tool_signals[TRANSFORM] =
198 199 200 201 202 203 204 205 206
    g_signal_new ("transform",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GimpTransformToolClass, transform),
		  NULL, NULL,
		  gimp_cclosure_marshal_POINTER__POINTER_INT,
		  G_TYPE_POINTER, 2,
		  G_TYPE_POINTER,
		  G_TYPE_INT);
Nate Summers's avatar
Nate Summers committed
207

208
  object_class->finalize     = gimp_transform_tool_finalize;
Nate Summers's avatar
Nate Summers committed
209

210
  tool_class->control        = gimp_transform_tool_control;
Nate Summers's avatar
Nate Summers committed
211 212 213 214
  tool_class->button_press   = gimp_transform_tool_button_press;
  tool_class->button_release = gimp_transform_tool_button_release;
  tool_class->motion         = gimp_transform_tool_motion;
  tool_class->cursor_update  = gimp_transform_tool_cursor_update;
Nate Summers's avatar
Nate Summers committed
215 216

  draw_class->draw           = gimp_transform_tool_draw;
Nate Summers's avatar
Nate Summers committed
217 218 219
}

static void
Nate Summers's avatar
Nate Summers committed
220
gimp_transform_tool_init (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
221
{
222 223
  GimpTool *tool = GIMP_TOOL (tr_tool);
  gint      i;
Nate Summers's avatar
Nate Summers committed
224 225 226 227 228 229 230 231 232

  tr_tool->function = TRANSFORM_CREATING;
  tr_tool->original = NULL;

  for (i = 0; i < TRAN_INFO_SIZE; i++)
    tr_tool->trans_info[i] = 0;

  tr_tool->grid_coords = tr_tool->tgrid_coords = NULL;

233 234 235
  /* FIXME */
  tr_tool->interactive = TRUE;

Nate Summers's avatar
Nate Summers committed
236 237
  tool->scroll_lock = TRUE;   /*  Disallow scrolling  */
  tool->preserve    = FALSE;  /*  Don't preserve on drawable change  */
238

Nate Summers's avatar
Nate Summers committed
239 240
}

Nate Summers's avatar
Nate Summers committed
241 242
TileManager *
gimp_transform_tool_transform (GimpTransformTool   *tool,
243
                               GimpDisplay         *gdisp,
Nate Summers's avatar
Nate Summers committed
244 245 246 247 248 249 250
			       TransformState       state)
{
  TileManager *retval;

  g_return_val_if_fail (tool, NULL);
  g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tool), NULL);

251 252
  g_signal_emit (G_OBJECT (tool), gimp_transform_tool_signals[TRANSFORM], 0,
                 gdisp, state, &retval);
Nate Summers's avatar
Nate Summers committed
253 254 255 256

  return retval;
}

Nate Summers's avatar
Nate Summers committed
257 258 259 260
static void
transform_ok_callback (GtkWidget *widget,
		       gpointer   data)
{
Nate Summers's avatar
Nate Summers committed
261
  GimpTool *tool;
Nate Summers's avatar
Nate Summers committed
262

Nate Summers's avatar
Nate Summers committed
263 264
  tool = GIMP_TOOL(data);
  gimp_transform_tool_doit (GIMP_TRANSFORM_TOOL(tool), tool->gdisp);
Nate Summers's avatar
Nate Summers committed
265 266 267 268 269 270 271 272 273 274
}

static void
transform_reset_callback (GtkWidget *widget,
			  gpointer   data)
{
  GimpTransformTool   *tool;
  GimpDrawTool        *dr_tool;
  gint                 i;

275 276
  tool    = GIMP_TRANSFORM_TOOL (data);
  dr_tool = GIMP_DRAW_TOOL (data);
Nate Summers's avatar
Nate Summers committed
277 278

  /*  stop the current tool drawing process  */
Nate Summers's avatar
Nate Summers committed
279
  gimp_draw_tool_pause (dr_tool);
Nate Summers's avatar
Nate Summers committed
280 281 282 283 284 285

  /*  Restore the previous transformation info  */
  for (i = 0; i < TRAN_INFO_SIZE; i++)
    tool->trans_info [i] = old_trans_info [i];

  /*  recalculate the tool's transformation matrix  */
Nate Summers's avatar
Nate Summers committed
286
  gimp_transform_tool_recalc (tool, GIMP_TOOL(tool)->gdisp);
Nate Summers's avatar
Nate Summers committed
287 288

  /*  resume drawing the current tool  */
Nate Summers's avatar
Nate Summers committed
289
  gimp_draw_tool_resume (dr_tool);
Nate Summers's avatar
Nate Summers committed
290 291
}

292
static void
293
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
294
{
295
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
296

297 298 299
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  if (tr_tool->original)
300 301 302 303
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
304 305

  if (transform_info)
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    {
      info_dialog_free (transform_info);
      transform_info        = NULL;
      transform_info_inited = FALSE;
    }

  if (tr_tool->grid_coords)
    {
      g_free (tr_tool->grid_coords);
      tr_tool->grid_coords = NULL;
    }

  if (tr_tool->tgrid_coords)
    {
      g_free (tr_tool->tgrid_coords);
      tr_tool->tgrid_coords = NULL;
    }

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
328 329 330
gimp_transform_tool_control (GimpTool    *tool,
			     ToolAction   action,
			     GimpDisplay *gdisp)
331 332 333 334 335 336
{
  GimpDrawTool      *dr_tool;
  GimpTransformTool *tr_tool;

  dr_tool = GIMP_DRAW_TOOL (tool);
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
337

338 339 340 341
  switch (action)
    {
    case PAUSE:
      break;
342

343 344 345
    case RESUME:
      gimp_transform_tool_recalc (tr_tool, gdisp);
      break;
346

347 348 349
    case HALT:
      gimp_transform_tool_reset (tr_tool, gdisp);
      break;
350

351 352 353 354 355 356
    default:
      break;
    }

  if (GIMP_TOOL_CLASS (parent_class)->control)
    GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
357 358 359
}

static void
360 361 362 363 364
gimp_transform_tool_button_press (GimpTool        *tool,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
			          GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
365
{
Michael Natterer's avatar
Michael Natterer committed
366 367 368 369 370 371 372
  GimpTransformTool *gt_tool;
  GimpDisplayShell  *shell;
  GimpDrawable      *drawable;
  gint               dist;
  gint               closest_dist;
  gint               i;
  gint               off_x, off_y;
Nate Summers's avatar
Nate Summers committed
373

374
  gt_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
375

Michael Natterer's avatar
Michael Natterer committed
376 377
  shell = GIMP_DISPLAY_SHELL (gdisp->shell);

Nate Summers's avatar
Nate Summers committed
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
  drawable = gimp_image_active_drawable (gdisp->gimage);

  if (gt_tool->function == TRANSFORM_CREATING && tool->state == ACTIVE)
    {
      /*  Save the current transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
	old_trans_info [i] = gt_tool->trans_info [i];
    }

  /*  if we have already displayed the bounding box and handles,
   *  check to make sure that the display which currently owns the
   *  tool is the one which just received the button pressed event
   */
  if ((gdisp == tool->gdisp) && gt_tool->interactive)
    {
      /*  start drawing the bounding box and handles...  */
Michael Natterer's avatar
Michael Natterer committed
394
      gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), shell->canvas->window);
395

396
      closest_dist = SQR (coords->x - gt_tool->tx1) + SQR (coords->y - gt_tool->ty1);
Nate Summers's avatar
Nate Summers committed
397 398
      gt_tool->function = TRANSFORM_HANDLE_1;

399
      dist = SQR (coords->x - gt_tool->tx2) + SQR (coords->y - gt_tool->ty2);
Nate Summers's avatar
Nate Summers committed
400 401 402 403 404 405
      if (dist < closest_dist)
	{
	  closest_dist = dist;
	  gt_tool->function = TRANSFORM_HANDLE_2;
	}

406
      dist = SQR (coords->x - gt_tool->tx3) + SQR (coords->y - gt_tool->ty3);
Nate Summers's avatar
Nate Summers committed
407 408 409 410 411 412
      if (dist < closest_dist)
	{
	  closest_dist = dist;
	  gt_tool->function = TRANSFORM_HANDLE_3;
	}

413
      dist = SQR (coords->x - gt_tool->tx4) + SQR (coords->y - gt_tool->ty4);
Nate Summers's avatar
Nate Summers committed
414 415 416 417 418 419
      if (dist < closest_dist)
	{
	  closest_dist = dist;
	  gt_tool->function = TRANSFORM_HANDLE_4;
	}

420 421
      if ((SQR (coords->x - gt_tool->tcx) +
	   SQR (coords->y - gt_tool->tcy)) <= 100)
Nate Summers's avatar
Nate Summers committed
422 423 424 425 426
	{
	  gt_tool->function = TRANSFORM_HANDLE_CENTER;
	}

      /*  Save the current pointer position  */
427 428
      gt_tool->lastx = gt_tool->startx = coords->x;
      gt_tool->lasty = gt_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
429

Michael Natterer's avatar
Michael Natterer committed
430
      gdk_pointer_grab (shell->canvas->window, FALSE,
Nate Summers's avatar
Nate Summers committed
431 432 433
			GDK_POINTER_MOTION_HINT_MASK |
			GDK_BUTTON1_MOTION_MASK |
			GDK_BUTTON_RELEASE_MASK,
434
			NULL, NULL, time);
Nate Summers's avatar
Nate Summers committed
435 436 437 438 439 440 441 442 443 444

      tool->state = ACTIVE;
      return;
    }


  /*  Initialisation stuff: if the cursor is clicked inside the current
   *  selection, show the bounding box and handles...
   */
  gimp_drawable_offsets (drawable, &off_x, &off_y);
445 446 447 448 449

  if (coords->x >= off_x &&
      coords->y >= off_y &&
      coords->x < (off_x + gimp_drawable_width (drawable)) &&
      coords->y < (off_y + gimp_drawable_height (drawable)))
450 451
    {
      if (gimage_mask_is_empty (gdisp->gimage) ||
452
	  gimage_mask_value (gdisp->gimage, coords->x, coords->y))
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
	{
	  if (GIMP_IS_LAYER (drawable) &&
	      gimp_layer_get_mask (GIMP_LAYER (drawable)))
	    {
	      g_message (_("Transformations do not work on\n"
			   "layers that contain layer masks."));
	      tool->state = INACTIVE;
	      return;
	    }

	  /*  If the tool is already active, clear the current state
	   *  and reset
	   */
	  if (tool->state == ACTIVE)
	    gimp_transform_tool_reset (gt_tool, gdisp);

	  /*  Set the pointer to the active display  */
	  tool->gdisp    = gdisp;
	  tool->drawable = drawable;
	  tool->state    = ACTIVE;

	  /*  Grab the pointer if we're in non-interactive mode  */
475
	  if (! gt_tool->interactive)
Michael Natterer's avatar
Michael Natterer committed
476 477 478 479
	    gdk_pointer_grab (shell->canvas->window, FALSE,
			      GDK_POINTER_MOTION_HINT_MASK |
                              GDK_BUTTON1_MOTION_MASK |
                              GDK_BUTTON_RELEASE_MASK,
480
			      NULL, NULL, time);
481 482 483 484 485 486 487 488 489 490 491 492

	  /*  Find the transform bounds for some tools (like scale,
	   *  perspective) that actually need the bounds for
	   *  initializing
	   */
	  gimp_transform_tool_bounds (gt_tool, gdisp);

	  /*  Initialize the transform tool */
	  gimp_transform_tool_transform (gt_tool, gdisp, TRANSFORM_INIT);

	  if (transform_info && !transform_info_inited)
	    {
493
	      GType tool_type;
494 495

	      tool_type =
Michael Natterer's avatar
Michael Natterer committed
496
		gimp_context_get_tool (gimp_get_user_context (gdisp->gimage->gimp))->tool_type;
497 498

	      gimp_dialog_create_action_area
499
		(GIMP_DIALOG (transform_info->shell),
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522

		 /* FIXME: this does not belong here */
		 (tool_type == GIMP_TYPE_ROTATE_TOOL)      ? _("Rotate")    :
		 (tool_type == GIMP_TYPE_SCALE_TOOL)       ? _("Scale")     :
		 (tool_type == GIMP_TYPE_SHEAR_TOOL)       ? _("Shear")     :
		 (tool_type == GIMP_TYPE_PERSPECTIVE_TOOL) ? _("Transform") :
		 "EEK",
		 transform_ok_callback,
		 tool, NULL, NULL, TRUE, FALSE,

		 _("Reset"), transform_reset_callback,
		 tool, NULL, NULL, FALSE, FALSE,

		 NULL);

	      transform_info_inited = TRUE;
	    }

	  /*  Recalculate the transform tool  */
	  gimp_transform_tool_recalc (gt_tool, gdisp);

	  /*  recall this function to find which handle we're dragging  */
	  if (gt_tool->interactive)
523
	    gimp_transform_tool_button_press (tool, coords, time, state, gdisp);
524 525
	}
    }
Nate Summers's avatar
Nate Summers committed
526 527
}

528
static void
529 530 531 532 533
gimp_transform_tool_button_release (GimpTool        *tool,
                                    GimpCoords      *coords,
                                    guint32          time,
			            GdkModifierType  state,
			            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
534
{
Nate Summers's avatar
Nate Summers committed
535 536
  GimpTransformTool *gt_tool;
  gint               i;
Nate Summers's avatar
Nate Summers committed
537

538
  gt_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
539 540

  /*  if we are creating, there is nothing to be done...exit  */
541
  if (gt_tool->function == TRANSFORM_CREATING && gt_tool->interactive)
Nate Summers's avatar
Nate Summers committed
542 543 544
    return;

  /*  release of the pointer grab  */
545
  gdk_pointer_ungrab (time);
Nate Summers's avatar
Nate Summers committed
546 547 548
  gdk_flush ();

  /*  if the 3rd button isn't pressed, transform the selected mask  */
549
  if (! (state & GDK_BUTTON3_MASK))
Nate Summers's avatar
Nate Summers committed
550 551
    {
      /* Shift-clicking is another way to approve the transform  */
552
      if ((state & GDK_SHIFT_MASK) || GIMP_IS_FLIP_TOOL (tool))
Nate Summers's avatar
Nate Summers committed
553
	{
Nate Summers's avatar
Nate Summers committed
554
	  gimp_transform_tool_doit (gt_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
555 556 557 558 559 560 561 562 563 564 565
	}
      else
	{
	  /*  Only update the paths preview */
	  path_transform_current_path (gdisp->gimage,
				       gt_tool->transform, TRUE);
	}
    }
  else
    {
      /*  stop the current tool drawing process  */
566
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
567 568 569 570 571 572 573 574 575

      /*  Restore the previous transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
	gt_tool->trans_info [i] = old_trans_info [i];

      /*  recalculate the tool's transformation matrix  */
      gimp_transform_tool_recalc (gt_tool, gdisp);

      /*  resume drawing the current tool  */
576
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
577 578 579 580 581 582 583

      /* Update the paths preview */
      path_transform_current_path (gdisp->gimage,
				   gt_tool->transform, TRUE);
    }

  /*  if this tool is non-interactive, make it inactive after use  */
584
  if (! gt_tool->interactive)
Nate Summers's avatar
Nate Summers committed
585 586 587
    tool->state = INACTIVE;
}

588
static void
Nate Summers's avatar
Nate Summers committed
589
gimp_transform_tool_doit (GimpTransformTool  *gt_tool,
590
		          GimpDisplay        *gdisp)
Nate Summers's avatar
Nate Summers committed
591
{
Michael Natterer's avatar
Michael Natterer committed
592 593 594 595 596 597
  GimpDisplayShell *shell;
  GimpTool         *tool;
  TileManager      *new_tiles;
  TransformUndo    *tu;
  PathUndo         *pundo;
  gboolean          new_layer;
598
  gint              i;
Nate Summers's avatar
Nate Summers committed
599

600
  gimp_set_busy (gdisp->gimage->gimp);
Nate Summers's avatar
Nate Summers committed
601

602
  tool = GIMP_TOOL (gt_tool);
Nate Summers's avatar
Nate Summers committed
603

Michael Natterer's avatar
Michael Natterer committed
604 605
  shell = GIMP_DISPLAY_SHELL (gdisp->shell);

Nate Summers's avatar
Nate Summers committed
606
  /* undraw the tool before we muck around with the transform matrix */
607
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (gt_tool));
Nate Summers's avatar
Nate Summers committed
608 609 610 611 612 613 614 615 616

  /*  We're going to dirty this image, but we want to keep the tool
   *  around
   */
  tool->preserve = TRUE;

  /*  Start a transform undo group  */
  undo_push_group_start (gdisp->gimage, TRANSFORM_CORE_UNDO);

617 618 619
  /* With the old UI, if original is NULL, then this is the
   * first transformation. In the new UI, it is always so, right?
   */
Nate Summers's avatar
Nate Summers committed
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
  g_assert (gt_tool->original == NULL);

  /* If we're in interactive mode, we need to copy the current
   *  selection to the transform tool's private selection pointer, so
   *  that the original source can be repeatedly modified.
   */
  tool->drawable = gimp_image_active_drawable (gdisp->gimage);

  gt_tool->original = gimp_transform_tool_cut (gdisp->gimage,
					       tool->drawable,
					       &new_layer);

  pundo = path_transform_start_undo (gdisp->gimage);

  /*  Send the request for the transformation to the tool...
   */
Nate Summers's avatar
Nate Summers committed
636
  new_tiles = gimp_transform_tool_transform (gt_tool, gdisp,
637
					     TRANSFORM_FINISH);
Nate Summers's avatar
Nate Summers committed
638

Nate Summers's avatar
Nate Summers committed
639
  gimp_transform_tool_transform (gt_tool, gdisp, TRANSFORM_INIT);
Nate Summers's avatar
Nate Summers committed
640 641 642 643 644 645 646 647 648 649

  gimp_transform_tool_recalc (gt_tool, gdisp);

  if (new_tiles)
    {
      /*  paste the new transformed image to the gimage...also implement
       *  undo...
       */
      /*  FIXME: we should check if the drawable is still valid  */
      gimp_transform_tool_paste (gdisp->gimage, tool->drawable,
650
				 new_tiles, new_layer);
Nate Summers's avatar
Nate Summers committed
651 652

      /*  create and initialize the transform_undo structure  */
653 654
      tu = g_new0 (TransformUndo, 1);
      tu->tool_ID   = tool->ID;
655
      tu->tool_type = G_TYPE_FROM_INSTANCE (tool);
Nate Summers's avatar
Nate Summers committed
656

Nate Summers's avatar
Nate Summers committed
657 658
      for (i = 0; i < TRAN_INFO_SIZE; i++)
	tu->trans_info[i] = old_trans_info[i];
659 660

      tu->original  = NULL;
Nate Summers's avatar
Nate Summers committed
661 662 663 664 665 666 667
      tu->path_undo = pundo;

      /*  Make a note of the new current drawable (since we may have
       *  a floating selection, etc now.
       */
      tool->drawable = gimp_image_active_drawable (gdisp->gimage);

668
      undo_push_transform (gdisp->gimage, tu);
Nate Summers's avatar
Nate Summers committed
669 670 671 672 673 674 675 676 677 678
    }

  /*  push the undo group end  */
  undo_push_group_end (gdisp->gimage);

  /*  We're done dirtying the image, and would like to be restarted
   *  if the image gets dirty while the tool exists
   */
  tool->preserve = FALSE;

679 680 681 682
#ifdef __GNUC__
#warning FIXME: investigate why display update was done here
#endif
#if 0
Nate Summers's avatar
Nate Summers committed
683 684 685
  /*  Flush the gdisplays  */
  if (gdisp->disp_xoffset || gdisp->disp_yoffset)
    {
686 687 688 689
      gint x, y;

      x = shell->disp_width;
      y = shell->disp_height;
690

Nate Summers's avatar
Nate Summers committed
691 692
      if (gdisp->disp_yoffset)
	{
Michael Natterer's avatar
Michael Natterer committed
693 694 695 696 697 698 699
	  gimp_display_shell_add_expose_area (shell,
                                              0, 0,
                                              gdisp->disp_width,
                                              gdisp->disp_yoffset);
	  gimp_display_shell_add_expose_area (shell,
                                              0, gdisp->disp_yoffset + y,
                                              gdisp->disp_width, gdisp->disp_height);
Nate Summers's avatar
Nate Summers committed
700
	}
Michael Natterer's avatar
Michael Natterer committed
701

Nate Summers's avatar
Nate Summers committed
702 703
      if (gdisp->disp_xoffset)
	{
Michael Natterer's avatar
Michael Natterer committed
704 705 706 707 708 709
	  gimp_display_shell_add_expose_area (shell,
                                              0, 0,
                                              gdisp->disp_xoffset, gdisp->disp_height);
	  gimp_display_shell_add_expose_area (shell,
                                              gdisp->disp_xoffset + x, 0,
                                              gdisp->disp_width, gdisp->disp_height);
Nate Summers's avatar
Nate Summers committed
710 711
	}
    }
712
#endif
Nate Summers's avatar
Nate Summers committed
713

714
  gimp_unset_busy (gdisp->gimage->gimp);
Nate Summers's avatar
Nate Summers committed
715 716 717

  gdisplays_flush ();

718
  gimp_transform_tool_reset (gt_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
719 720

  /*  if this tool is non-interactive, make it inactive after use  */
Nate Summers's avatar
Nate Summers committed
721
  if (!gt_tool->interactive)
Nate Summers's avatar
Nate Summers committed
722 723 724
    tool->state = INACTIVE;
}

725
static void
726 727 728 729 730
gimp_transform_tool_motion (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
		            GdkModifierType  state,
		            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
731
{
Nate Summers's avatar
Nate Summers committed
732
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
733

734
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
735 736 737 738

  /*  if we are creating or this tool is non-interactive, there is
   *  nothing to be done so exit.
   */
739
  if (tr_tool->function == TRANSFORM_CREATING || ! tr_tool->interactive)
Nate Summers's avatar
Nate Summers committed
740 741
    return;

742
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
743

744 745 746
  tr_tool->curx  = coords->x;
  tr_tool->cury  = coords->y;
  tr_tool->state = state;
Nate Summers's avatar
Nate Summers committed
747 748

  /*  recalculate the tool's transformation matrix  */
Nate Summers's avatar
Nate Summers committed
749
  gimp_transform_tool_transform (tr_tool, gdisp, TRANSFORM_MOTION);
Nate Summers's avatar
Nate Summers committed
750

Nate Summers's avatar
Nate Summers committed
751 752
  tr_tool->lastx = tr_tool->curx;
  tr_tool->lasty = tr_tool->cury;
Nate Summers's avatar
Nate Summers committed
753

754
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
755 756
}

757
static void
758 759 760 761
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
			           GdkModifierType  state,
			           GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
762
{
763 764 765
  GimpTransformTool *tr_tool;
  GimpDrawable      *drawable;
  GdkCursorType      ctype = GDK_TOP_LEFT_ARROW;
Nate Summers's avatar
Nate Summers committed
766

767
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
768 769 770

  if ((drawable = gimp_image_active_drawable (gdisp->gimage)))
    {
771 772 773 774
      gint off_x, off_y;

      gimp_drawable_offsets (drawable, &off_x, &off_y);

Nate Summers's avatar
Nate Summers committed
775
      if (GIMP_IS_LAYER (drawable) &&
776
          gimp_layer_get_mask (GIMP_LAYER (drawable)))
Nate Summers's avatar
Nate Summers committed
777 778 779
	{
	  ctype = GIMP_BAD_CURSOR;
	}
780 781 782 783
      else if (coords->x >= off_x &&
	       coords->y >= off_y &&
	       coords->x < (off_x + drawable->width) &&
	       coords->y < (off_y + drawable->height))
Nate Summers's avatar
Nate Summers committed
784 785
	{
	  if (gimage_mask_is_empty (gdisp->gimage) ||
786
	      gimage_mask_value (gdisp->gimage, coords->x, coords->y))
Nate Summers's avatar
Nate Summers committed
787 788 789 790 791 792
	    {
	      ctype = GIMP_MOUSE_CURSOR;
	    }
	}
    }

793
  gimp_display_shell_install_tool_cursor (GIMP_DISPLAY_SHELL (gdisp->shell),
Michael Natterer's avatar
Michael Natterer committed
794 795 796
                                          ctype,
                                          tool->tool_cursor,
                                          GIMP_CURSOR_MODIFIER_NONE);
Nate Summers's avatar
Nate Summers committed
797 798
}

799
static void
Nate Summers's avatar
Nate Summers committed
800
gimp_transform_tool_draw (GimpDrawTool *dr_tool)
Nate Summers's avatar
Nate Summers committed
801
{
802
  GimpDisplay        *gdisp;
Nate Summers's avatar
Nate Summers committed
803 804 805 806 807 808 809
  GimpTransformTool  *tr_tool;
  GimpTool           *tool;
  gint                x1, y1, x2, y2, x3, y3, x4, y4;
  gint                srw, srh;
  gint                i, k, gci;
  gint                xa, ya, xb, yb;

810 811
  tr_tool = GIMP_TRANSFORM_TOOL (dr_tool);
  tool    = GIMP_TOOL (dr_tool);
Nate Summers's avatar
Nate Summers committed
812

813
  gdisp   = tool->gdisp;
Nate Summers's avatar
Nate Summers committed
814 815 816 817 818 819 820 821 822 823 824 825 826 827

  gdisplay_transform_coords (gdisp, tr_tool->tx1, tr_tool->ty1,
			     &tr_tool->sx1, &tr_tool->sy1, FALSE);
  gdisplay_transform_coords (gdisp, tr_tool->tx2, tr_tool->ty2,
			     &tr_tool->sx2, &tr_tool->sy2, FALSE);
  gdisplay_transform_coords (gdisp, tr_tool->tx3, tr_tool->ty3,
			     &tr_tool->sx3, &tr_tool->sy3, FALSE);
  gdisplay_transform_coords (gdisp, tr_tool->tx4, tr_tool->ty4,
			     &tr_tool->sx4, &tr_tool->sy4, FALSE);

  x1 = tr_tool->sx1;  y1 = tr_tool->sy1;
  x2 = tr_tool->sx2;  y2 = tr_tool->sy2;
  x3 = tr_tool->sx3;  y3 = tr_tool->sy3;
  x4 = tr_tool->sx4;  y4 = tr_tool->sy4;
Nate Summers's avatar
Nate Summers committed
828 829 830 831 832 833

  /*  find the handles' width and height  */
  srw = 10;
  srh = 10;

  /*  draw the bounding box  */
Nate Summers's avatar
Nate Summers committed
834
  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
835
		 x1, y1, x2, y2);
Nate Summers's avatar
Nate Summers committed
836
  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
837
		 x2, y2, x4, y4);
Nate Summers's avatar
Nate Summers committed
838
  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
839
		 x3, y3, x4, y4);
Nate Summers's avatar
Nate Summers committed
840
  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
841 842 843 844
		 x3, y3, x1, y1);

  /*  Draw the grid */

Nate Summers's avatar
Nate Summers committed
845
  if ((tr_tool->grid_coords != NULL) &&
Nate Summers's avatar
Nate Summers committed
846 847
      (tr_tool->tgrid_coords != NULL) /* FIXME!!! this doesn't belong here &&
      ((tool->type != PERSPECTIVE)  ||
Nate Summers's avatar
Nate Summers committed
848
       ((tr_tool->transform[0][0] >=0.0) &&
Nate Summers's avatar
Nate Summers committed
849
	(tr_tool->transform[1][1] >=0.0)) */ ) 
Nate Summers's avatar
Nate Summers committed
850 851
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
852
      k = tr_tool->ngx + tr_tool->ngy;
853

Nate Summers's avatar
Nate Summers committed
854 855
      for (i = 0; i < k; i++)
	{
Nate Summers's avatar
Nate Summers committed
856 857
	  gdisplay_transform_coords (gdisp, tr_tool->tgrid_coords[gci],
				     tr_tool->tgrid_coords[gci+1],
Nate Summers's avatar
Nate Summers committed
858
				     &xa, &ya, FALSE);
Nate Summers's avatar
Nate Summers committed
859 860
	  gdisplay_transform_coords (gdisp, tr_tool->tgrid_coords[gci+2],
				     tr_tool->tgrid_coords[gci+3],
Nate Summers's avatar
Nate Summers committed
861 862
				     &xb, &yb, FALSE);

Nate Summers's avatar
Nate Summers committed
863
	  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
864 865 866 867 868 869
			 xa, ya, xb, yb);
	  gci += 4;
	}
    }

  /*  draw the tool handles  */
Nate Summers's avatar
Nate Summers committed
870
  gdk_draw_rectangle (dr_tool->win, dr_tool->gc, 0,
Nate Summers's avatar
Nate Summers committed
871
		      x1 - (srw >> 1), y1 - (srh >> 1), srw, srh);
Nate Summers's avatar
Nate Summers committed
872
  gdk_draw_rectangle (dr_tool->win, dr_tool->gc, 0,
Nate Summers's avatar
Nate Summers committed
873
		      x2 - (srw >> 1), y2 - (srh >> 1), srw, srh);
Nate Summers's avatar
Nate Summers committed
874
  gdk_draw_rectangle (dr_tool->win, dr_tool->gc, 0,
Nate Summers's avatar
Nate Summers committed
875
		      x3 - (srw >> 1), y3 - (srh >> 1), srw, srh);
Nate Summers's avatar
Nate Summers committed
876
  gdk_draw_rectangle (dr_tool->win, dr_tool->gc, 0,
Nate Summers's avatar
Nate Summers committed
877 878 879
		      x4 - (srw >> 1), y4 - (srh >> 1), srw, srh);

  /*  draw the center  */
880 881 882
  gdisplay_transform_coords (gdisp,
			     tr_tool->tcx, tr_tool->tcy,
			     &tr_tool->scx, &tr_tool->scy, FALSE);
Nate Summers's avatar
Nate Summers committed
883

884 885 886 887 888 889
  gdk_draw_arc (dr_tool->win,
		dr_tool->gc,
		1,
		tr_tool->scx - (srw >> 1),
		tr_tool->scy - (srh >> 1),
		srw, srh, 0, 23040);
Nate Summers's avatar
Nate Summers committed
890

891
  if (gimp_transform_tool_showpath ())
Nate Summers's avatar
Nate Summers committed
892 893 894
    {
      GimpMatrix3 tmp_matrix;

895
      if (gimp_transform_tool_direction () == TRANSFORM_CORRECTIVE)
Nate Summers's avatar
Nate Summers committed
896
	{
Nate Summers's avatar
Nate Summers committed
897
	  gimp_matrix3_invert (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
898 899 900
	}
      else
	{
Nate Summers's avatar
Nate Summers committed
901
	  gimp_matrix3_duplicate (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
902 903
	}

Nate Summers's avatar
Nate Summers committed
904
      path_transform_draw_current (gdisp, dr_tool, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
905 906 907 908
    }
}

void
Nate Summers's avatar
Nate Summers committed
909
gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
910
{
Nate Summers's avatar
Nate Summers committed
911 912 913 914
  GimpTool  *tool;
  gint       i, k;
  gint       gci;

915
  tool = GIMP_TOOL (tr_tool);
Nate Summers's avatar
Nate Summers committed
916 917 918 919 920 921 922 923 924 925 926 927 928

  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->x1, tr_tool->y1,
				&tr_tool->tx1, &tr_tool->ty1);
  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->x2, tr_tool->y1,
				&tr_tool->tx2, &tr_tool->ty2);
  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->x1, tr_tool->y2,
				&tr_tool->tx3, &tr_tool->ty3);
  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->x2, tr_tool->y2,
				&tr_tool->tx4, &tr_tool->ty4);
Nate Summers's avatar
Nate Summers committed
929

930 931 932
  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->cx, tr_tool->cy,
				&tr_tool->tcx, &tr_tool->tcy);
Nate Summers's avatar
Nate Summers committed
933

Nate Summers's avatar
Nate Summers committed
934 935
  if (tr_tool->grid_coords != NULL &&
      tr_tool->tgrid_coords != NULL)
Nate Summers's avatar
Nate Summers committed
936 937
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
938
      k  = (tr_tool->ngx + tr_tool->ngy) * 2;
939

Nate Summers's avatar
Nate Summers committed
940 941
      for (i = 0; i < k; i++)
	{
Nate Summers's avatar
Nate Summers committed
942 943 944 945 946
	  gimp_matrix3_transform_point (tr_tool->transform,
					tr_tool->grid_coords[gci],
					tr_tool->grid_coords[gci+1],
					&(tr_tool->tgrid_coords[gci]),
					&(tr_tool->tgrid_coords[gci+1]));
Nate Summers's avatar
Nate Summers committed
947 948 949 950 951 952
	  gci += 2;
	}
    }
}

void
953
gimp_transform_tool_reset (GimpTransformTool *tr_tool,
954
		           GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
955
{
Nate Summers's avatar
Nate Summers committed
956
  GimpTool *tool;
Nate Summers's avatar
Nate Summers committed
957

958
  tool = GIMP_TOOL (tr_tool);