gimptransformtool.c 32.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
#include "base/tile-manager.h"
32

Michael Natterer's avatar
Michael Natterer committed
33
#include "core/gimp.h"
34 35 36
#include "core/gimpchannel.h"
#include "core/gimpcontext.h"
#include "core/gimpdrawable.h"
Michael Natterer's avatar
Michael Natterer committed
37
#include "core/gimpdrawable-transform.h"
38 39 40 41
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
#include "core/gimplayer.h"
#include "core/gimpmarshal.h"
Michael Natterer's avatar
Michael Natterer committed
42
#include "core/gimptoolinfo.h"
43

44
#include "gui/info-dialog.h"
45 46

#include "display/gimpdisplay.h"
47
#include "display/gimpdisplay-foreach.h"
Michael Natterer's avatar
Michael Natterer committed
48
#include "display/gimpdisplayshell.h"
Nate Summers's avatar
Nate Summers committed
49

50 51 52
#include "tool_manager.h"
#include "transform_options.h"
#include "gimptransformtool.h"
Michael Natterer's avatar
Michael Natterer committed
53 54 55 56 57
#include "gimpperspectivetool.h"
#include "gimprotatetool.h"
#include "gimpscaletool.h"
#include "gimpsheartool.h"
#include "gimpfliptool.h"
58

Michael Natterer's avatar
Michael Natterer committed
59
#include "floating_sel.h"
Michael Natterer's avatar
Michael Natterer committed
60
#include "gimpprogress.h"
Michael Natterer's avatar
Michael Natterer committed
61 62
#include "undo.h"
#include "path_transform.h"
Nate Summers's avatar
Nate Summers committed
63 64 65

#include "libgimp/gimpintl.h"

66

Michael Natterer's avatar
Michael Natterer committed
67 68
#define HANDLE 10

69

Michael Natterer's avatar
Michael Natterer committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
/*  local function prototypes  */

static void   gimp_transform_tool_init        (GimpTransformTool      *tool);
static void   gimp_transform_tool_class_init  (GimpTransformToolClass *tool);

static void   gimp_transform_tool_finalize         (GObject           *object);

static void   gimp_transform_tool_control          (GimpTool          *tool,
                                                    ToolAction         action,
                                                    GimpDisplay       *gdisp);
static void   gimp_transform_tool_button_press     (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    guint32            time,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
static void   gimp_transform_tool_button_release   (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    guint32            time,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
static void   gimp_transform_tool_motion           (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    guint32            time,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
static void   gimp_transform_tool_cursor_update    (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);

static void   gimp_transform_tool_draw             (GimpDrawTool      *draw_tool);

static TileManager * gimp_transform_tool_transform (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp,
                                                    TransformState     state);
static void   gimp_transform_tool_reset            (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
static void   gimp_transform_tool_bounds           (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
static void   gimp_transform_tool_recalc           (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
static void   gimp_transform_tool_doit             (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
static void   gimp_transform_tool_setup_grid       (GimpTransformTool *tr_tool,
                                                    TransformOptions  *options);
static void   gimp_transform_tool_grid_recalc      (GimpTransformTool *tr_tool);

static void   transform_ok_callback                (GtkWidget         *widget,
                                                    gpointer           data);
static void   transform_reset_callback             (GtkWidget         *widget,
                                                    gpointer           data);
121 122


Nate Summers's avatar
Nate Summers committed
123
/*  variables  */
Michael Natterer's avatar
Michael Natterer committed
124
static TransInfo          old_trans_info;
Nate Summers's avatar
Nate Summers committed
125 126
InfoDialog               *transform_info        = NULL;
static gboolean           transform_info_inited = FALSE;
Nate Summers's avatar
Nate Summers committed
127

128
static GimpDrawToolClass *parent_class = NULL;
129

130 131

GType
Nate Summers's avatar
Nate Summers committed
132 133
gimp_transform_tool_get_type (void)
{
134
  static GType tool_type = 0;
Nate Summers's avatar
Nate Summers committed
135 136 137

  if (! tool_type)
    {
138
      static const GTypeInfo tool_info =
Nate Summers's avatar
Nate Summers committed
139 140
      {
        sizeof (GimpTransformToolClass),
141 142 143 144 145 146 147 148
	(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
149 150
      };

151 152 153
      tool_type = g_type_register_static (GIMP_TYPE_DRAW_TOOL,
					  "GimpTransformTool", 
                                          &tool_info, 0);
Nate Summers's avatar
Nate Summers committed
154 155 156 157 158 159 160 161
    }

  return tool_type;
}

static void
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
{
162
  GObjectClass      *object_class;
Nate Summers's avatar
Nate Summers committed
163 164
  GimpToolClass     *tool_class;
  GimpDrawToolClass *draw_class;
Nate Summers's avatar
Nate Summers committed
165

166 167 168
  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
169

170
  parent_class = g_type_class_peek_parent (klass);
Nate Summers's avatar
Nate Summers committed
171

172
  object_class->finalize     = gimp_transform_tool_finalize;
Nate Summers's avatar
Nate Summers committed
173

174
  tool_class->control        = gimp_transform_tool_control;
Nate Summers's avatar
Nate Summers committed
175 176 177 178
  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
179 180

  draw_class->draw           = gimp_transform_tool_draw;
Nate Summers's avatar
Nate Summers committed
181 182 183
}

static void
Michael Natterer's avatar
Michael Natterer committed
184
gimp_transform_tool_init (GimpTransformTool *transform_tool)
Nate Summers's avatar
Nate Summers committed
185
{
Michael Natterer's avatar
Michael Natterer committed
186
  GimpTool *tool;
187
  gint      i;
Nate Summers's avatar
Nate Summers committed
188

Michael Natterer's avatar
Michael Natterer committed
189 190 191 192
  tool = GIMP_TOOL (transform_tool);

  transform_tool->function = TRANSFORM_CREATING;
  transform_tool->original = NULL;
Nate Summers's avatar
Nate Summers committed
193 194

  for (i = 0; i < TRAN_INFO_SIZE; i++)
Michael Natterer's avatar
Michael Natterer committed
195
    transform_tool->trans_info[i] = 0.0;
Nate Summers's avatar
Nate Summers committed
196

Michael Natterer's avatar
Michael Natterer committed
197
  gimp_matrix3_identity (transform_tool->transform);
Nate Summers's avatar
Nate Summers committed
198

Michael Natterer's avatar
Michael Natterer committed
199 200 201 202 203
  transform_tool->use_grid     = TRUE;
  transform_tool->ngx          = 0;
  transform_tool->ngy          = 0;
  transform_tool->grid_coords  = NULL;
  transform_tool->tgrid_coords = NULL;
204

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

Nate Summers's avatar
Nate Summers committed
208 209
}

210
static void
211
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
212
{
213
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
214

215 216 217
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  if (tr_tool->original)
218 219 220 221
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
222 223

  if (transform_info)
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    {
      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
246 247 248
gimp_transform_tool_control (GimpTool    *tool,
			     ToolAction   action,
			     GimpDisplay *gdisp)
249
{
Michael Natterer's avatar
Michael Natterer committed
250
  GimpTransformTool *transform_tool;
251

Michael Natterer's avatar
Michael Natterer committed
252
  transform_tool = GIMP_TRANSFORM_TOOL (tool);
253

254 255 256 257
  switch (action)
    {
    case PAUSE:
      break;
258

259
    case RESUME:
Michael Natterer's avatar
Michael Natterer committed
260
      gimp_transform_tool_recalc (transform_tool, gdisp);
261
      break;
262

263
    case HALT:
Michael Natterer's avatar
Michael Natterer committed
264
      gimp_transform_tool_reset (transform_tool, gdisp);
265
      break;
266

267 268 269 270
    default:
      break;
    }

Michael Natterer's avatar
Michael Natterer committed
271
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
272 273 274
}

static void
275 276 277 278 279
gimp_transform_tool_button_press (GimpTool        *tool,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
			          GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
280
{
Michael Natterer's avatar
Michael Natterer committed
281
  GimpTransformTool *tr_tool;
282
  GimpDrawTool      *draw_tool;
Michael Natterer's avatar
Michael Natterer committed
283 284
  GimpDisplayShell  *shell;
  GimpDrawable      *drawable;
285 286
  gdouble            dist;
  gdouble            closest_dist;
Michael Natterer's avatar
Michael Natterer committed
287 288
  gint               i;
  gint               off_x, off_y;
Nate Summers's avatar
Nate Summers committed
289

Michael Natterer's avatar
Michael Natterer committed
290
  tr_tool   = GIMP_TRANSFORM_TOOL (tool);
291
  draw_tool = GIMP_DRAW_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
292

Michael Natterer's avatar
Michael Natterer committed
293 294
  shell = GIMP_DISPLAY_SHELL (gdisp->shell);

Nate Summers's avatar
Nate Summers committed
295 296
  drawable = gimp_image_active_drawable (gdisp->gimage);

Michael Natterer's avatar
Michael Natterer committed
297
  if (tr_tool->function == TRANSFORM_CREATING && tool->state == ACTIVE)
Nate Summers's avatar
Nate Summers committed
298 299 300
    {
      /*  Save the current transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
Michael Natterer's avatar
Michael Natterer committed
301
	old_trans_info[i] = tr_tool->trans_info[i];
Nate Summers's avatar
Nate Summers committed
302 303 304 305 306 307
    }

  /*  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
   */
Michael Natterer's avatar
Michael Natterer committed
308
  if (gdisp == tool->gdisp)
Nate Summers's avatar
Nate Summers committed
309 310
    {
      /*  start drawing the bounding box and handles...  */
Michael Natterer's avatar
Michael Natterer committed
311
      gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), shell->canvas->window);
312

313 314
      closest_dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                                   coords->x, coords->y,
Michael Natterer's avatar
Michael Natterer committed
315 316
                                                   tr_tool->tx1, tr_tool->ty1);
      tr_tool->function = TRANSFORM_HANDLE_1;
Nate Summers's avatar
Nate Summers committed
317

318 319
      dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                           coords->x, coords->y,
Michael Natterer's avatar
Michael Natterer committed
320
                                           tr_tool->tx2, tr_tool->ty2);
Nate Summers's avatar
Nate Summers committed
321 322 323
      if (dist < closest_dist)
	{
	  closest_dist = dist;
Michael Natterer's avatar
Michael Natterer committed
324
	  tr_tool->function = TRANSFORM_HANDLE_2;
Nate Summers's avatar
Nate Summers committed
325 326
	}

327 328
      dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                           coords->x, coords->y,
Michael Natterer's avatar
Michael Natterer committed
329
                                           tr_tool->tx3, tr_tool->ty3);
Nate Summers's avatar
Nate Summers committed
330 331 332
      if (dist < closest_dist)
	{
	  closest_dist = dist;
Michael Natterer's avatar
Michael Natterer committed
333
	  tr_tool->function = TRANSFORM_HANDLE_3;
Nate Summers's avatar
Nate Summers committed
334 335
	}

336 337
      dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                           coords->x, coords->y,
Michael Natterer's avatar
Michael Natterer committed
338
                                           tr_tool->tx4, tr_tool->ty4);
Nate Summers's avatar
Nate Summers committed
339 340 341
      if (dist < closest_dist)
	{
	  closest_dist = dist;
Michael Natterer's avatar
Michael Natterer committed
342
	  tr_tool->function = TRANSFORM_HANDLE_4;
Nate Summers's avatar
Nate Summers committed
343 344
	}

345
      if (gimp_draw_tool_on_handle (draw_tool, gdisp,
346
                                    coords->x, coords->y,
347
                                    GIMP_HANDLE_CIRCLE,
Michael Natterer's avatar
Michael Natterer committed
348
                                    tr_tool->tcx, tr_tool->tcy,
349 350 351
                                    HANDLE, HANDLE,
                                    GIMP_HANDLE_CIRCLE,
                                    FALSE))
Nate Summers's avatar
Nate Summers committed
352
	{
Michael Natterer's avatar
Michael Natterer committed
353
	  tr_tool->function = TRANSFORM_HANDLE_CENTER;
Nate Summers's avatar
Nate Summers committed
354 355 356
	}

      /*  Save the current pointer position  */
Michael Natterer's avatar
Michael Natterer committed
357 358
      tr_tool->lastx = tr_tool->startx = coords->x;
      tr_tool->lasty = tr_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
359

Michael Natterer's avatar
Michael Natterer committed
360
      gdk_pointer_grab (shell->canvas->window, FALSE,
Nate Summers's avatar
Nate Summers committed
361 362 363
			GDK_POINTER_MOTION_HINT_MASK |
			GDK_BUTTON1_MOTION_MASK |
			GDK_BUTTON_RELEASE_MASK,
364
			NULL, NULL, time);
Nate Summers's avatar
Nate Summers committed
365 366 367 368 369 370 371 372 373

      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);
374 375 376 377 378

  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)))
379 380
    {
      if (gimage_mask_is_empty (gdisp->gimage) ||
381
	  gimage_mask_value (gdisp->gimage, coords->x, coords->y))
382 383 384 385 386 387 388 389 390 391 392 393 394 395
	{
	  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)
Michael Natterer's avatar
Michael Natterer committed
396
	    gimp_transform_tool_reset (tr_tool, gdisp);
397 398 399 400 401 402

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

Michael Natterer's avatar
Michael Natterer committed
403 404 405 406 407
          gdk_pointer_grab (shell->canvas->window, FALSE,
                            GDK_POINTER_MOTION_HINT_MASK |
                            GDK_BUTTON1_MOTION_MASK |
                            GDK_BUTTON_RELEASE_MASK,
                            NULL, NULL, time);
408 409 410 411 412

	  /*  Find the transform bounds for some tools (like scale,
	   *  perspective) that actually need the bounds for
	   *  initializing
	   */
Michael Natterer's avatar
Michael Natterer committed
413
	  gimp_transform_tool_bounds (tr_tool, gdisp);
414 415

	  /*  Initialize the transform tool */
Michael Natterer's avatar
Michael Natterer committed
416
	  gimp_transform_tool_transform (tr_tool, gdisp, TRANSFORM_INIT);
417

Michael Natterer's avatar
Michael Natterer committed
418
	  if (transform_info && ! transform_info_inited)
419
	    {
420
	      GType tool_type;
421 422

	      tool_type =
Michael Natterer's avatar
Michael Natterer committed
423
		gimp_context_get_tool (gimp_get_user_context (gdisp->gimage->gimp))->tool_type;
424 425

	      gimp_dialog_create_action_area
426
		(GIMP_DIALOG (transform_info->shell),
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445

		 /* 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  */
Michael Natterer's avatar
Michael Natterer committed
446
	  gimp_transform_tool_recalc (tr_tool, gdisp);
447 448

	  /*  recall this function to find which handle we're dragging  */
Michael Natterer's avatar
Michael Natterer committed
449
          gimp_transform_tool_button_press (tool, coords, time, state, gdisp);
450 451
	}
    }
Nate Summers's avatar
Nate Summers committed
452 453
}

454
static void
455 456 457 458 459
gimp_transform_tool_button_release (GimpTool        *tool,
                                    GimpCoords      *coords,
                                    guint32          time,
			            GdkModifierType  state,
			            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
460
{
Michael Natterer's avatar
Michael Natterer committed
461
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
462
  gint               i;
Nate Summers's avatar
Nate Summers committed
463

Michael Natterer's avatar
Michael Natterer committed
464
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
465 466

  /*  if we are creating, there is nothing to be done...exit  */
Michael Natterer's avatar
Michael Natterer committed
467
  if (tr_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
468 469 470
    return;

  /*  release of the pointer grab  */
471
  gdk_pointer_ungrab (time);
Nate Summers's avatar
Nate Summers committed
472 473 474
  gdk_flush ();

  /*  if the 3rd button isn't pressed, transform the selected mask  */
475
  if (! (state & GDK_BUTTON3_MASK))
Nate Summers's avatar
Nate Summers committed
476 477
    {
      /* Shift-clicking is another way to approve the transform  */
478
      if ((state & GDK_SHIFT_MASK) || GIMP_IS_FLIP_TOOL (tool))
Nate Summers's avatar
Nate Summers committed
479
	{
Michael Natterer's avatar
Michael Natterer committed
480
	  gimp_transform_tool_doit (tr_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
481 482 483 484 485
	}
      else
	{
	  /*  Only update the paths preview */
	  path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
486
				       tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
487 488 489 490 491
	}
    }
  else
    {
      /*  stop the current tool drawing process  */
492
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
493 494 495

      /*  Restore the previous transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
Michael Natterer's avatar
Michael Natterer committed
496
	tr_tool->trans_info[i] = old_trans_info[i];
Nate Summers's avatar
Nate Summers committed
497 498

      /*  recalculate the tool's transformation matrix  */
Michael Natterer's avatar
Michael Natterer committed
499
      gimp_transform_tool_recalc (tr_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
500 501

      /*  resume drawing the current tool  */
502
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
503 504 505

      /* Update the paths preview */
      path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
506
				   tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
507 508
    }

Michael Natterer's avatar
Michael Natterer committed
509
  tool->state = INACTIVE;
Nate Summers's avatar
Nate Summers committed
510 511
}

512
static void
513 514 515 516 517
gimp_transform_tool_motion (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
		            GdkModifierType  state,
		            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
518
{
Michael Natterer's avatar
Michael Natterer committed
519
  GimpTransformTool *transform_tool;
Nate Summers's avatar
Nate Summers committed
520

Michael Natterer's avatar
Michael Natterer committed
521
  transform_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
522 523 524 525

  /*  if we are creating or this tool is non-interactive, there is
   *  nothing to be done so exit.
   */
Michael Natterer's avatar
Michael Natterer committed
526
  if (transform_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
527 528
    return;

529
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
530

Michael Natterer's avatar
Michael Natterer committed
531 532 533
  transform_tool->curx  = coords->x;
  transform_tool->cury  = coords->y;
  transform_tool->state = state;
Nate Summers's avatar
Nate Summers committed
534 535

  /*  recalculate the tool's transformation matrix  */
Michael Natterer's avatar
Michael Natterer committed
536
  gimp_transform_tool_transform (transform_tool, gdisp, TRANSFORM_MOTION);
Nate Summers's avatar
Nate Summers committed
537

Michael Natterer's avatar
Michael Natterer committed
538 539
  transform_tool->lastx = transform_tool->curx;
  transform_tool->lasty = transform_tool->cury;
Nate Summers's avatar
Nate Summers committed
540

541
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
542 543
}

544
static void
545 546 547 548
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
			           GdkModifierType  state,
			           GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
549
{
Michael Natterer's avatar
Michael Natterer committed
550 551
  GimpDrawable  *drawable;
  GdkCursorType  ctype = GDK_TOP_LEFT_ARROW;
Nate Summers's avatar
Nate Summers committed
552 553 554

  if ((drawable = gimp_image_active_drawable (gdisp->gimage)))
    {
555 556 557 558
      gint off_x, off_y;

      gimp_drawable_offsets (drawable, &off_x, &off_y);

Nate Summers's avatar
Nate Summers committed
559
      if (GIMP_IS_LAYER (drawable) &&
560
          gimp_layer_get_mask (GIMP_LAYER (drawable)))
Nate Summers's avatar
Nate Summers committed
561 562 563
	{
	  ctype = GIMP_BAD_CURSOR;
	}
564 565 566 567
      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
568 569
	{
	  if (gimage_mask_is_empty (gdisp->gimage) ||
570
	      gimage_mask_value (gdisp->gimage, coords->x, coords->y))
Nate Summers's avatar
Nate Summers committed
571 572 573 574 575 576
	    {
	      ctype = GIMP_MOUSE_CURSOR;
	    }
	}
    }

577
  gimp_display_shell_install_tool_cursor (GIMP_DISPLAY_SHELL (gdisp->shell),
Michael Natterer's avatar
Michael Natterer committed
578 579 580
                                          ctype,
                                          tool->tool_cursor,
                                          GIMP_CURSOR_MODIFIER_NONE);
Nate Summers's avatar
Nate Summers committed
581 582
}

583
static void
584
gimp_transform_tool_draw (GimpDrawTool *draw_tool)
Nate Summers's avatar
Nate Summers committed
585
{
586
  GimpTransformTool *tr_tool;
Michael Natterer's avatar
Michael Natterer committed
587
  TransformOptions  *options;
588 589 590
  gint               i, k, gci;

  tr_tool = GIMP_TRANSFORM_TOOL (draw_tool);
Nate Summers's avatar
Nate Summers committed
591

Michael Natterer's avatar
Michael Natterer committed
592 593
  options = (TransformOptions *) GIMP_TOOL (draw_tool)->tool_info->tool_options;

Nate Summers's avatar
Nate Summers committed
594
  /*  draw the bounding box  */
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
  gimp_draw_tool_draw_line (draw_tool,
                            tr_tool->tx1, tr_tool->ty1,
                            tr_tool->tx2, tr_tool->ty2,
                            FALSE);
  gimp_draw_tool_draw_line (draw_tool,
                            tr_tool->tx2, tr_tool->ty2,
                            tr_tool->tx4, tr_tool->ty4,
                            FALSE);
  gimp_draw_tool_draw_line (draw_tool,
                            tr_tool->tx3, tr_tool->ty3,
                            tr_tool->tx4, tr_tool->ty4,
                            FALSE);
  gimp_draw_tool_draw_line (draw_tool,
                            tr_tool->tx3, tr_tool->ty3,
                            tr_tool->tx1, tr_tool->ty1,
                            FALSE);
Nate Summers's avatar
Nate Summers committed
611 612 613

  /*  Draw the grid */

Nate Summers's avatar
Nate Summers committed
614
  if ((tr_tool->grid_coords != NULL) &&
Nate Summers's avatar
Nate Summers committed
615 616
      (tr_tool->tgrid_coords != NULL) /* FIXME!!! this doesn't belong here &&
      ((tool->type != PERSPECTIVE)  ||
Nate Summers's avatar
Nate Summers committed
617
       ((tr_tool->transform[0][0] >=0.0) &&
Nate Summers's avatar
Nate Summers committed
618
	(tr_tool->transform[1][1] >=0.0)) */ ) 
Nate Summers's avatar
Nate Summers committed
619 620
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
621
      k = tr_tool->ngx + tr_tool->ngy;
622

Nate Summers's avatar
Nate Summers committed
623 624
      for (i = 0; i < k; i++)
	{
625 626 627 628 629 630
          gimp_draw_tool_draw_line (draw_tool,
                                    tr_tool->tgrid_coords[gci],
                                    tr_tool->tgrid_coords[gci + 1],
                                    tr_tool->tgrid_coords[gci + 2],
                                    tr_tool->tgrid_coords[gci + 3],
                                    FALSE);
Nate Summers's avatar
Nate Summers committed
631 632 633 634 635
	  gci += 4;
	}
    }

  /*  draw the tool handles  */
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx1, tr_tool->ty1,
                              HANDLE, HANDLE,
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx2, tr_tool->ty2,
                              HANDLE, HANDLE,
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx3, tr_tool->ty3,
                              HANDLE, HANDLE,
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx4, tr_tool->ty4,
                              HANDLE, HANDLE,
                              GTK_ANCHOR_CENTER,
                              FALSE);
Nate Summers's avatar
Nate Summers committed
660 661

  /*  draw the center  */
662 663 664 665 666 667
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_FILLED_CIRCLE,
                              tr_tool->tcx, tr_tool->tcy,
                              HANDLE, HANDLE,
                              GTK_ANCHOR_CENTER,
                              FALSE);
Nate Summers's avatar
Nate Summers committed
668

Michael Natterer's avatar
Michael Natterer committed
669
  if (options->show_path)
Nate Summers's avatar
Nate Summers committed
670 671 672
    {
      GimpMatrix3 tmp_matrix;

Michael Natterer's avatar
Michael Natterer committed
673
      if (options->direction == GIMP_TRANSFORM_BACKWARD)
Nate Summers's avatar
Nate Summers committed
674
	{
Nate Summers's avatar
Nate Summers committed
675
	  gimp_matrix3_invert (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
676 677 678
	}
      else
	{
Nate Summers's avatar
Nate Summers committed
679
	  gimp_matrix3_duplicate (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
680 681
	}

682 683
      path_transform_draw_current (GIMP_TOOL (draw_tool)->gdisp,
                                   draw_tool, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
684 685 686
    }
}

Michael Natterer's avatar
Michael Natterer committed
687 688 689 690 691 692 693
static TileManager *
gimp_transform_tool_transform (GimpTransformTool   *tool,
                               GimpDisplay         *gdisp,
			       TransformState       state)
{
  g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tool), NULL);

694
  return GIMP_TRANSFORM_TOOL_GET_CLASS (tool)->transform (tool, gdisp, state);
Michael Natterer's avatar
Michael Natterer committed
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
}

static void
gimp_transform_tool_doit (GimpTransformTool  *tr_tool,
		          GimpDisplay        *gdisp)
{
  GimpDisplayShell *shell;
  GimpTool         *tool;
  TileManager      *new_tiles;
  TransformUndo    *tu;
  PathUndo         *pundo;
  gboolean          new_layer;
  gint              i;

  gimp_set_busy (gdisp->gimage->gimp);

  tool = GIMP_TOOL (tr_tool);

  shell = GIMP_DISPLAY_SHELL (gdisp->shell);

  /* undraw the tool before we muck around with the transform matrix */
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool));

  /*  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);

  /* With the old UI, if original is NULL, then this is the
   * first transformation. In the new UI, it is always so, right?
   */
  g_assert (tr_tool->original == NULL);

  /*  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);

  tr_tool->original = gimp_drawable_transform_cut (tool->drawable,
                                                   &new_layer);

  pundo = path_transform_start_undo (gdisp->gimage);

  /*  Send the request for the transformation to the tool...
   */
  new_tiles = gimp_transform_tool_transform (tr_tool, gdisp, TRANSFORM_FINISH);

  gimp_transform_tool_transform (tr_tool, gdisp, TRANSFORM_INIT);

  gimp_transform_tool_recalc (tr_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_drawable_transform_paste (tool->drawable,
                                     new_tiles,
                                     new_layer);

      /*  create and initialize the transform_undo structure  */
      tu = g_new0 (TransformUndo, 1);
      tu->tool_ID   = tool->ID;
      tu->tool_type = G_TYPE_FROM_INSTANCE (tool);

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

      tu->original  = NULL;
      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);

      undo_push_transform (gdisp->gimage, tu);
    }

  /*  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;

  gimp_unset_busy (gdisp->gimage->gimp);

  gdisplays_flush ();

  gimp_transform_tool_reset (tr_tool, gdisp);

  tool->state = INACTIVE;
}

TileManager *
gimp_transform_tool_transform_tiles (GimpTransformTool *transform_tool,
                                     const gchar       *progress_text)
{
  GimpTool         *tool;
  TransformOptions *options;
  GimpProgress     *progress;
  TileManager      *ret;

  g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (transform_tool), NULL);
  g_return_val_if_fail (progress_text != NULL, NULL);

  gtk_widget_set_sensitive (GTK_WIDGET (transform_info->shell), FALSE);

  tool = GIMP_TOOL (transform_tool);

  options = (TransformOptions *) tool->tool_info->tool_options;

  progress = progress_start (tool->gdisp, progress_text, FALSE, NULL, NULL);

  ret = gimp_drawable_transform_tiles_affine (gimp_image_active_drawable (tool->gdisp->gimage),
                                              transform_tool->original,
                                              options->smoothing,
                                              options->clip,
                                              transform_tool->transform,
                                              options->direction,
                                              progress ? progress_update_and_flush :
                                              (GimpProgressFunc) NULL,
                                              progress);

  if (progress)
    progress_end (progress);

  return ret;
}

Nate Summers's avatar
Nate Summers committed
832
void
Nate Summers's avatar
Nate Summers committed
833
gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
834
{
Nate Summers's avatar
Nate Summers committed
835 836 837 838
  GimpTool  *tool;
  gint       i, k;
  gint       gci;

839
  tool = GIMP_TOOL (tr_tool);
Nate Summers's avatar
Nate Summers committed
840 841 842 843 844 845 846 847 848 849 850 851 852

  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
853

854 855 856
  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
857

Nate Summers's avatar
Nate Summers committed
858 859
  if (tr_tool->grid_coords != NULL &&
      tr_tool->tgrid_coords != NULL)
Nate Summers's avatar
Nate Summers committed
860 861
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
862
      k  = (tr_tool->ngx + tr_tool->ngy) * 2;
863

Nate Summers's avatar
Nate Summers committed
864 865
      for (i = 0; i < k; i++)
	{
Nate Summers's avatar
Nate Summers committed
866 867 868 869 870
	  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
871 872 873 874 875 876
	  gci += 2;
	}
    }
}

void
877
gimp_transform_tool_reset (GimpTransformTool *tr_tool,
878
		           GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
879
{
Nate Summers's avatar
Nate Summers committed
880
  GimpTool *tool;
Nate Summers's avatar
Nate Summers committed
881

882
  tool = GIMP_TOOL (tr_tool);
Nate Summers's avatar
Nate Summers committed
883

Nate Summers's avatar
Nate Summers committed
884
  if (tr_tool->original)
885 886 887 888
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
Nate Summers's avatar
Nate Summers committed
889 890

  /*  inactivate the tool  */
Nate Summers's avatar
Nate Summers committed
891
  tr_tool->function = TRANSFORM_CREATING;
892
  gimp_draw_tool_stop (GIMP_DRAW_TOOL (tr_tool));
Nate Summers's avatar
Nate Summers committed
893 894 895 896 897 898 899 900
  info_dialog_popdown (transform_info);

  tool->state    = INACTIVE;
  tool->gdisp    = NULL;
  tool->drawable = NULL;
}

static void
901
gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
902
		            GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
903
{
904 905 906
  TileManager  *tiles;
  GimpDrawable *drawable;
  gint          offset_x, offset_y;
Nate Summers's avatar
Nate Summers committed
907

908 909
  tiles    = tr_tool->original;
  drawable = gimp_image_active_drawable (gdisp->gimage);
Nate Summers's avatar
Nate Summers committed
910 911 912 913 914

  /*  find the boundaries  */
  if (tiles)
    {
      tile_manager_get_offsets (tiles,
Nate Summers's avatar
Nate Summers committed
915 916 917 918
				&tr_tool->x1, &tr_tool->y1);
				
      tr_tool->x2 = tr_tool->x1 + tile_manager_width (tiles);
      tr_tool->y2 = tr_tool->y1 + tile_manager_height (tiles);
Nate Summers's avatar
Nate Summers committed
919 920 921 922 923
    }
  else
    {
      gimp_drawable_offsets (drawable, &offset_x, &offset_y);
      gimp_drawable_mask_bounds (drawable,
Nate Summers's avatar
Nate Summers committed
924 925 926 927 928 929
				 &tr_tool->x1, &tr_tool->y1,
				 &tr_tool->x2, &tr_tool->y2);
      tr_tool->x1 += offset_x;
      tr_tool->y1 += offset_y;
      tr_tool->x2 += offset_x;
      tr_tool->y2 += offset_y;
Nate Summers's avatar
Nate Summers committed
930
    }
Nate Summers's avatar
Nate Summers committed
931 932 933

  tr_tool->cx = (tr_tool->x1 + tr_tool->x2) / 2;
  tr_tool->cy = (tr_tool->y1 + tr_tool->y2) / 2;
Nate Summers's avatar
Nate Summers committed
934

Michael Natterer's avatar
Michael Natterer committed
935 936 937 938 939
  if (tr_tool->use_grid)
    {
      /*  changing the bounds invalidates any grid we may have  */
      gimp_transform_tool_grid_recalc (tr_tool);
    }
Nate Summers's avatar
Nate Summers committed
940 941 942
}

void
Michael Natterer's avatar
Michael Natterer committed
943
gimp_transform_tool_grid_density_changed (GimpTransformTool *transform_tool)
Nate Summers's avatar
Nate Summers committed
944
{
Michael Natterer's avatar
Michael Natterer committed
945
  if (transform_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
946 947
    return;

Michael Natterer's avatar
Michael Natterer committed
948
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (transform_tool));
949

Michael Natterer's avatar
Michael Natterer committed
950 951
  gimp_transform_tool_grid_recalc (transform_tool);
  gimp_transform_tool_transform_bounding_box (transform_tool);
952

Michael Natterer's avatar
Michael Natterer committed
953
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (transform_tool));
Nate Summers's avatar
Nate Summers committed
954 955 956
}

void
Michael Natterer's avatar
Michael Natterer committed
957 958
gimp_transform_tool_show_path_changed (GimpTransformTool *transform_tool,
                                       gint               type /* a truly undescriptive name */)
Nate Summers's avatar
Nate Summers committed
959
{
Michael Natterer's avatar
Michael Natterer committed
960
  if (transform_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
961 962 963
    return;

  if (type)
Michael Natterer's avatar
Michael Natterer committed
964
    gimp_draw_tool_pause (GIMP_DRAW_TOOL (transform_tool));
Nate Summers's avatar
Nate Summers committed
965
  else
Michael Natterer's avatar
Michael Natterer committed
966
    gimp_draw_tool_resume (GIMP_DRAW_TOOL (transform_tool));
Nate Summers's avatar
Nate Summers committed
967 968 969
}

static void
Nate Summers's avatar
Nate Summers committed
970
gimp_transform_tool_grid_recalc (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
971
{
Michael Natterer's avatar
Michael Natterer committed
972 973 974 975
  TransformOptions *options;

  options = (TransformOptions *) GIMP_TOOL (tr_tool)->tool_info->tool_options;

Nate Summers's avatar
Nate Summers committed
976
  if (tr_tool->grid_coords != NULL)
Nate Summers's avatar
Nate Summers committed
977
    {
Nate Summers's avatar
Nate Summers committed
978 979
      g_free (tr_tool->grid_coords);
      tr_tool->grid_coords = NULL;
Nate Summers's avatar
Nate Summers committed
980
    }
981

Nate Summers's avatar
Nate Summers committed
982
  if (tr_tool->tgrid_coords != NULL)
Nate Summers's avatar
Nate Summers committed
983