gimptransformtool.c 35 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

30
#ifdef __GNUC__
31
#warning FIXME #include "gui/gui-types.h"
32
#endif
33
#include "gui/gui-types.h"
Nate Summers's avatar
Nate Summers committed
34

Michael Natterer's avatar
Michael Natterer committed
35
#include "base/tile-manager.h"
36

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

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

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

54
#include "gimptransformtool.h"
55 56
#include "tool_manager.h"
#include "transform_options.h"
57

Michael Natterer's avatar
Michael Natterer committed
58 59
#include "undo.h"
#include "path_transform.h"
Nate Summers's avatar
Nate Summers committed
60 61 62

#include "libgimp/gimpintl.h"

63

Michael Natterer's avatar
Michael Natterer committed
64 65
#define HANDLE 10

66

Michael Natterer's avatar
Michael Natterer committed
67 68 69 70 71 72 73 74
/*  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,
75
                                                    GimpToolAction     action,
Michael Natterer's avatar
Michael Natterer committed
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
                                                    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);
92 93 94 95 96
static void   gimp_transform_tool_modifier_key     (GimpTool          *tool,
                                                    GdkModifierType    key,
                                                    gboolean           press,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
97 98 99 100
static void   gimp_transform_tool_oper_update      (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
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);
127 128


129
static GimpDrawToolClass *parent_class = NULL;
130

131 132

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

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

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

  return tool_type;
}

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

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

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

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

175
  tool_class->control        = gimp_transform_tool_control;
Nate Summers's avatar
Nate Summers committed
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;
179
  tool_class->modifier_key   = gimp_transform_tool_modifier_key;
180
  tool_class->oper_update    = gimp_transform_tool_oper_update;
Nate Summers's avatar
Nate Summers committed
181
  tool_class->cursor_update  = gimp_transform_tool_cursor_update;
Nate Summers's avatar
Nate Summers committed
182 183

  draw_class->draw           = gimp_transform_tool_draw;
Nate Summers's avatar
Nate Summers committed
184 185 186
}

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

Michael Natterer's avatar
Michael Natterer committed
192 193
  tool = GIMP_TOOL (transform_tool);

Michael Natterer's avatar
Michael Natterer committed
194 195 196
  gimp_tool_control_set_scroll_lock (tool->control, TRUE);
  gimp_tool_control_set_preserve    (tool->control, FALSE);

Michael Natterer's avatar
Michael Natterer committed
197 198
  transform_tool->function = TRANSFORM_CREATING;
  transform_tool->original = NULL;
Nate Summers's avatar
Nate Summers committed
199 200

  for (i = 0; i < TRAN_INFO_SIZE; i++)
201 202 203 204
    {
      transform_tool->trans_info[i]     = 0.0;
      transform_tool->old_trans_info[i] = 0.0;
    }
Nate Summers's avatar
Nate Summers committed
205

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

Michael Natterer's avatar
Michael Natterer committed
208
  transform_tool->use_grid     = TRUE;
209
  transform_tool->use_center   = TRUE;
Michael Natterer's avatar
Michael Natterer committed
210 211 212 213
  transform_tool->ngx          = 0;
  transform_tool->ngy          = 0;
  transform_tool->grid_coords  = NULL;
  transform_tool->tgrid_coords = NULL;
214

215 216
  transform_tool->info_dialog  = NULL;

Nate Summers's avatar
Nate Summers committed
217 218
}

219
static void
220
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
221
{
222
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
223

224 225 226
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  if (tr_tool->original)
227 228 229 230
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
231

232
  if (tr_tool->info_dialog)
233
    {
234 235
      info_dialog_free (tr_tool->info_dialog);
      tr_tool->info_dialog = NULL;
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
    }

  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
254 255 256
gimp_transform_tool_control (GimpTool       *tool,
			     GimpToolAction  action,
			     GimpDisplay    *gdisp)
257
{
Michael Natterer's avatar
Michael Natterer committed
258
  GimpTransformTool *transform_tool;
259

Michael Natterer's avatar
Michael Natterer committed
260
  transform_tool = GIMP_TRANSFORM_TOOL (tool);
261

262 263 264 265
  switch (action)
    {
    case PAUSE:
      break;
266

267
    case RESUME:
Michael Natterer's avatar
Michael Natterer committed
268
      gimp_transform_tool_recalc (transform_tool, gdisp);
269
      break;
270

271
    case HALT:
Michael Natterer's avatar
Michael Natterer committed
272
      gimp_transform_tool_reset (transform_tool, gdisp);
273
      return; /* don't upchain */
274
      break;
275

276 277 278 279
    default:
      break;
    }

Michael Natterer's avatar
Michael Natterer committed
280
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
281 282 283
}

static void
284 285 286 287 288
gimp_transform_tool_button_press (GimpTool        *tool,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
			          GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
289
{
Michael Natterer's avatar
Michael Natterer committed
290
  GimpTransformTool *tr_tool;
291
  GimpDrawTool      *draw_tool;
Michael Natterer's avatar
Michael Natterer committed
292 293
  GimpDrawable      *drawable;
  gint               off_x, off_y;
Nate Summers's avatar
Nate Summers committed
294

Michael Natterer's avatar
Michael Natterer committed
295
  tr_tool   = GIMP_TRANSFORM_TOOL (tool);
296
  draw_tool = GIMP_DRAW_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
297 298 299

  drawable = gimp_image_active_drawable (gdisp->gimage);

300 301 302 303 304 305 306 307 308 309 310 311
  if (gdisp != tool->gdisp)
    {
      /*  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);

      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)))
        {
312 313
          if (gimp_image_mask_is_empty (gdisp->gimage) ||
              gimp_image_mask_value (gdisp->gimage, coords->x, coords->y))
314 315 316 317 318 319
            {
              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."));
320
                  gimp_tool_control_halt (tool->control);    /* sets paused_count to 0 -- is this ok? */
321 322 323 324 325 326
                  return;
                }

              /*  If the tool is already active, clear the current state
               *  and reset
               */
327
              if (gimp_tool_control_is_active (tool->control))
328 329 330 331 332 333 334 335 336
                {
                  g_warning ("%s: tool_already ACTIVE", G_GNUC_FUNCTION);

                  gimp_transform_tool_reset (tr_tool, gdisp);
                }

              /*  Set the pointer to the active display  */
              tool->gdisp    = gdisp;
              tool->drawable = drawable;
337
              gimp_tool_control_activate (tool->control);
338 339 340 341 342 343 344 345 346 347 348 349 350 351

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

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

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

              /*  start drawing the bounding box and handles...  */
352
              gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), gdisp);
353 354 355

              /*  find which handle we're dragging  */
              gimp_transform_tool_oper_update (tool, coords, state, gdisp);
356 357

              tr_tool->function = TRANSFORM_CREATING;
358 359 360 361
            }
        }
    }

362 363
  if (tr_tool->function == TRANSFORM_CREATING &&
      gimp_tool_control_is_active (tool->control))
Nate Summers's avatar
Nate Summers committed
364
    {
365 366
      gint i;

Nate Summers's avatar
Nate Summers committed
367 368
      /*  Save the current transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
369
	tr_tool->old_trans_info[i] = tr_tool->trans_info[i];
Nate Summers's avatar
Nate Summers committed
370 371 372 373 374 375
    }

  /*  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
376
  if (gdisp == tool->gdisp)
Nate Summers's avatar
Nate Summers committed
377 378
    {
      /*  Save the current pointer position  */
Michael Natterer's avatar
Michael Natterer committed
379 380
      tr_tool->lastx = tr_tool->startx = coords->x;
      tr_tool->lasty = tr_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
381

382
      gimp_tool_control_activate (tool->control);
383
    }
Nate Summers's avatar
Nate Summers committed
384 385
}

386
static void
387 388 389 390 391
gimp_transform_tool_button_release (GimpTool        *tool,
                                    GimpCoords      *coords,
                                    guint32          time,
			            GdkModifierType  state,
			            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
392
{
Michael Natterer's avatar
Michael Natterer committed
393
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
394
  gint               i;
Nate Summers's avatar
Nate Summers committed
395

Michael Natterer's avatar
Michael Natterer committed
396
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
397 398

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

  /*  if the 3rd button isn't pressed, transform the selected mask  */
403
  if (! (state & GDK_BUTTON3_MASK))
Nate Summers's avatar
Nate Summers committed
404 405
    {
      /* Shift-clicking is another way to approve the transform  */
406
      if ((state & GDK_SHIFT_MASK) || ! tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
407
	{
Michael Natterer's avatar
Michael Natterer committed
408
	  gimp_transform_tool_doit (tr_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
409 410 411 412 413
	}
      else
	{
	  /*  Only update the paths preview */
	  path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
414
				       tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
415 416 417 418
	}
    }
  else
    {
419
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
420 421 422

      /*  Restore the previous transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
423
	tr_tool->trans_info[i] = tr_tool->old_trans_info[i];
Nate Summers's avatar
Nate Summers committed
424 425

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

428
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
429 430 431

      /* Update the paths preview */
      path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
432
				   tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
433 434 435
    }
}

436
static void
437 438 439 440 441
gimp_transform_tool_motion (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
		            GdkModifierType  state,
		            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
442
{
Michael Natterer's avatar
Michael Natterer committed
443
  GimpTransformTool *transform_tool;
Nate Summers's avatar
Nate Summers committed
444

Michael Natterer's avatar
Michael Natterer committed
445
  transform_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
446

447
  /*  if we are creating, there is nothing to be done so exit.  */
Michael Natterer's avatar
Michael Natterer committed
448
  if (transform_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
449 450
    return;

451
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
452

Michael Natterer's avatar
Michael Natterer committed
453 454 455
  transform_tool->curx  = coords->x;
  transform_tool->cury  = coords->y;
  transform_tool->state = state;
Nate Summers's avatar
Nate Summers committed
456 457

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

Michael Natterer's avatar
Michael Natterer committed
460 461
  transform_tool->lastx = transform_tool->curx;
  transform_tool->lasty = transform_tool->cury;
Nate Summers's avatar
Nate Summers committed
462

463
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
464 465
}

466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
static void
gimp_transform_tool_modifier_key (GimpTool        *tool,
                                  GdkModifierType  key,
                                  gboolean         press,
                                  GdkModifierType  state,
                                  GimpDisplay     *gdisp)
{
  TransformOptions *options;

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

  if (key == GDK_CONTROL_MASK && options->constrain_1_w)
    {
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->constrain_1_w),
                                    ! options->constrain_1);
    }
  else if (key == GDK_MOD1_MASK && options->constrain_2_w)
    {
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->constrain_2_w),
                                    ! options->constrain_2);
    }
}

489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
static void
gimp_transform_tool_oper_update (GimpTool        *tool,
                                 GimpCoords      *coords,
                                 GdkModifierType  state,
                                 GimpDisplay     *gdisp)
{
  GimpTransformTool *tr_tool;
  GimpDrawTool      *draw_tool;

  tr_tool   = GIMP_TRANSFORM_TOOL (tool);
  draw_tool = GIMP_DRAW_TOOL (tool);

  if (gdisp == tool->gdisp)
    {
      gdouble closest_dist;
      gdouble dist;

      closest_dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                                   coords->x, coords->y,
                                                   tr_tool->tx1, tr_tool->ty1);
      tr_tool->function = TRANSFORM_HANDLE_1;

      dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                           coords->x, coords->y,
                                           tr_tool->tx2, tr_tool->ty2);
      if (dist < closest_dist)
	{
	  closest_dist = dist;
	  tr_tool->function = TRANSFORM_HANDLE_2;
	}

      dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                           coords->x, coords->y,
                                           tr_tool->tx3, tr_tool->ty3);
      if (dist < closest_dist)
	{
	  closest_dist = dist;
	  tr_tool->function = TRANSFORM_HANDLE_3;
	}

      dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                           coords->x, coords->y,
                                           tr_tool->tx4, tr_tool->ty4);
      if (dist < closest_dist)
	{
	  closest_dist = dist;
	  tr_tool->function = TRANSFORM_HANDLE_4;
	}

      if (gimp_draw_tool_on_handle (draw_tool, gdisp,
                                    coords->x, coords->y,
                                    GIMP_HANDLE_CIRCLE,
                                    tr_tool->tcx, tr_tool->tcy,
                                    HANDLE, HANDLE,
                                    GTK_ANCHOR_CENTER,
                                    FALSE))
	{
	  tr_tool->function = TRANSFORM_HANDLE_CENTER;
	}
    }
}

551
static void
552 553 554 555
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
			           GdkModifierType  state,
			           GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
556
{
557 558 559 560
  GimpTransformTool  *tr_tool;
  GimpDrawable       *drawable;

  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
561

Michael Natterer's avatar
Michael Natterer committed
562
  if (tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
563
    {
Michael Natterer's avatar
Michael Natterer committed
564 565
      GdkCursorType      ctype     = GDK_TOP_LEFT_ARROW;
      GimpCursorModifier cmodifier = GIMP_CURSOR_MODIFIER_NONE;
566

Michael Natterer's avatar
Michael Natterer committed
567 568 569
     if ((drawable = gimp_image_active_drawable (gdisp->gimage)))
        {
          gint off_x, off_y;
570

Michael Natterer's avatar
Michael Natterer committed
571
          gimp_drawable_offsets (drawable, &off_x, &off_y);
Nate Summers's avatar
Nate Summers committed
572

Michael Natterer's avatar
Michael Natterer committed
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
          if (GIMP_IS_LAYER (drawable) &&
              gimp_layer_get_mask (GIMP_LAYER (drawable)))
            {
              ctype = GIMP_BAD_CURSOR;
            }
          else if (coords->x >= off_x &&
                   coords->y >= off_y &&
                   coords->x < (off_x + drawable->width) &&
                   coords->y < (off_y + drawable->height))
            {
              if (gimp_image_mask_is_empty (gdisp->gimage) ||
                  gimp_image_mask_value (gdisp->gimage, coords->x, coords->y))
                {
                  ctype = GIMP_MOUSE_CURSOR;
                }
            }
        }
590

Michael Natterer's avatar
Michael Natterer committed
591 592 593 594 595 596 597 598
      if (tr_tool->use_center && tr_tool->function == TRANSFORM_HANDLE_CENTER)
        {
          cmodifier = GIMP_CURSOR_MODIFIER_MOVE;
        }

      gimp_tool_control_set_cursor          (tool->control, ctype);
      gimp_tool_control_set_cursor_modifier (tool->control, cmodifier);
    }
599 600

  GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, gdisp);
Nate Summers's avatar
Nate Summers committed
601 602
}

603
static void
604
gimp_transform_tool_draw (GimpDrawTool *draw_tool)
Nate Summers's avatar
Nate Summers committed
605
{
606
  GimpTransformTool *tr_tool;
Michael Natterer's avatar
Michael Natterer committed
607
  TransformOptions  *options;
608 609 610
  gint               i, k, gci;

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

612 613 614
  if (! tr_tool->use_grid)
    return;

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

Nate Summers's avatar
Nate Summers committed
617
  /*  draw the bounding box  */
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
  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
634 635 636

  /*  Draw the grid */

637
  if ((tr_tool->grid_coords != NULL) && (tr_tool->tgrid_coords != NULL))
Nate Summers's avatar
Nate Summers committed
638 639
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
640
      k = tr_tool->ngx + tr_tool->ngy;
641

Nate Summers's avatar
Nate Summers committed
642 643
      for (i = 0; i < k; i++)
	{
644 645 646 647 648 649
          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
650 651 652 653 654
	  gci += 4;
	}
    }

  /*  draw the tool handles  */
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
  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
679 680

  /*  draw the center  */
681 682 683 684 685 686 687 688 689
  if (tr_tool->use_center)
    {
      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
690

Michael Natterer's avatar
Michael Natterer committed
691
  if (options->show_path)
Nate Summers's avatar
Nate Summers committed
692 693 694
    {
      GimpMatrix3 tmp_matrix;

Michael Natterer's avatar
Michael Natterer committed
695
      if (options->direction == GIMP_TRANSFORM_BACKWARD)
Nate Summers's avatar
Nate Summers committed
696
	{
Nate Summers's avatar
Nate Summers committed
697
	  gimp_matrix3_invert (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
698 699 700
	}
      else
	{
Nate Summers's avatar
Nate Summers committed
701
	  gimp_matrix3_duplicate (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
702 703
	}

704 705
      path_transform_draw_current (GIMP_TOOL (draw_tool)->gdisp,
                                   draw_tool, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
706 707 708
    }
}

Michael Natterer's avatar
Michael Natterer committed
709 710 711 712 713 714 715
static TileManager *
gimp_transform_tool_transform (GimpTransformTool   *tool,
                               GimpDisplay         *gdisp,
			       TransformState       state)
{
  g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tool), NULL);

716
  return GIMP_TRANSFORM_TOOL_GET_CLASS (tool)->transform (tool, gdisp, state);
Michael Natterer's avatar
Michael Natterer committed
717 718 719 720 721 722
}

static void
gimp_transform_tool_doit (GimpTransformTool  *tr_tool,
		          GimpDisplay        *gdisp)
{
Michael Natterer's avatar
Michael Natterer committed
723 724 725 726
  GimpTool    *tool;
  TileManager *new_tiles;
  GSList      *path_undo;
  gboolean     new_layer;
Michael Natterer's avatar
Michael Natterer committed
727 728 729 730 731 732 733 734 735 736 737

  gimp_set_busy (gdisp->gimage->gimp);

  tool = GIMP_TOOL (tr_tool);

  /* 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
   */
738
  gimp_tool_control_set_preserve (tool->control, TRUE);
Michael Natterer's avatar
Michael Natterer committed
739 740

  /*  Start a transform undo group  */
Michael Natterer's avatar
Michael Natterer committed
741
  undo_push_group_start (gdisp->gimage, TRANSFORM_UNDO_GROUP);
Michael Natterer's avatar
Michael Natterer committed
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756

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

Michael Natterer's avatar
Michael Natterer committed
757
  path_undo = path_transform_start_undo (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781

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

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

Michael Natterer's avatar
Michael Natterer committed
782 783 784 785 786 787
      undo_push_transform (gdisp->gimage,
                           tool->ID,
                           G_TYPE_FROM_INSTANCE (tool),
                           tr_tool->old_trans_info,
                           NULL,
                           path_undo);
Michael Natterer's avatar
Michael Natterer committed
788 789 790 791 792 793 794 795
    }

  /*  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
   */
796
  gimp_tool_control_set_preserve (tool->control, FALSE);
Michael Natterer's avatar
Michael Natterer committed
797 798 799

  gimp_unset_busy (gdisp->gimage->gimp);

800
  gimp_image_flush (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816

  gimp_transform_tool_reset (tr_tool, gdisp);
}

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

817
  if (transform_tool->info_dialog)
818 819
    gtk_widget_set_sensitive (GTK_WIDGET (transform_tool->info_dialog->shell),
                              FALSE);
Michael Natterer's avatar
Michael Natterer committed
820 821 822 823 824

  tool = GIMP_TOOL (transform_tool);

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

Michael Natterer's avatar
Michael Natterer committed
825 826
  progress = gimp_progress_start (tool->gdisp, progress_text, FALSE,
                                  NULL, NULL);
Michael Natterer's avatar
Michael Natterer committed
827 828 829

  ret = gimp_drawable_transform_tiles_affine (gimp_image_active_drawable (tool->gdisp->gimage),
                                              transform_tool->original,
830
                                              options->interpolation,
Michael Natterer's avatar
Michael Natterer committed
831 832 833
                                              options->clip,
                                              transform_tool->transform,
                                              options->direction,
Michael Natterer's avatar
Michael Natterer committed
834 835 836
                                              progress ?
                                              gimp_progress_update_and_flush : 
                                              NULL,
Michael Natterer's avatar
Michael Natterer committed
837 838 839
                                              progress);

  if (progress)
Michael Natterer's avatar
Michael Natterer committed
840
    gimp_progress_end (progress);
Michael Natterer's avatar
Michael Natterer committed
841 842 843 844

  return ret;
}

Nate Summers's avatar
Nate Summers committed
845
void
Nate Summers's avatar
Nate Summers committed
846
gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
847
{
848
  g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
Nate Summers's avatar
Nate Summers committed
849 850 851 852 853 854 855 856 857 858 859 860 861

  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
862

863 864 865
  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
866

867
  if (tr_tool->grid_coords != NULL && tr_tool->tgrid_coords != NULL)
Nate Summers's avatar
Nate Summers committed
868
    {
869 870 871
      gint i, k;
      gint gci;

Nate Summers's avatar
Nate Summers committed
872
      gci = 0;
873
      k   = (tr_tool->ngx + tr_tool->ngy) * 2;
874

Nate Summers's avatar
Nate Summers committed
875 876
      for (i = 0; i < k; i++)
	{
Nate Summers's avatar
Nate Summers committed
877 878 879 880 881
	  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
882 883 884 885 886
	  gci += 2;
	}
    }
}

887
static void
888
gimp_transform_tool_reset (GimpTransformTool *tr_tool,
889
		           GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
890
{
Nate Summers's avatar
Nate Summers committed
891
  GimpTool *tool;
Nate Summers's avatar
Nate Summers committed
892

893
  tool = GIMP_TOOL (tr_tool);
Nate Summers's avatar
Nate Summers committed
894

Nate Summers's avatar
Nate Summers committed
895
  if (tr_tool->original)
896 897 898 899
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
Nate Summers's avatar
Nate Summers committed
900 901

  /*  inactivate the tool  */
Nate Summers's avatar
Nate Summers committed
902
  tr_tool->function = TRANSFORM_CREATING;
903

904
  gimp_draw_tool_stop (GIMP_DRAW_TOOL (tr_tool));
905 906 907

  if (tr_tool->info_dialog)
    info_dialog_popdown (tr_tool->info_dialog);
Nate Summers's avatar
Nate Summers committed
908

909
  gimp_tool_control_halt (tool->control);    /* sets paused_count to 0 -- is this ok? */
Nate Summers's avatar
Nate Summers committed
910 911 912 913 914
  tool->gdisp    = NULL;
  tool->drawable = NULL;
}

static void
915
gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
916
		            GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
917
{
918 919
  TileManager  *tiles;
  GimpDrawable *drawable;
Nate Summers's avatar
Nate Summers committed
920

921 922
  tiles    = tr_tool->original;
  drawable = gimp_image_active_drawable (gdisp->gimage);
Nate Summers's avatar
Nate Summers committed
923 924 925 926 927

  /*  find the boundaries  */
  if (tiles)
    {
      tile_manager_get_offsets (tiles,
Nate Summers's avatar
Nate Summers committed
928 929 930 931
				&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
932 933 934
    }
  else
    {
935 936
      gint offset_x, offset_y;

Nate Summers's avatar
Nate Summers committed
937
      gimp_drawable_offsets (drawable, &offset_x, &offset_y);
938

Nate Summers's avatar
Nate Summers committed
939
      gimp_drawable_mask_bounds (drawable,
Nate Summers's avatar
Nate Summers committed
940 941 942 943 944 945
				 &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
946
    }
Nate Summers's avatar
Nate Summers committed
947

948 949
  tr_tool->cx = (gdouble) (tr_tool->x1 + tr_tool->x2) / 2.0;
  tr_tool->cy = (gdouble) (tr_tool->y1 + tr_tool->y2) / 2.0;
Nate Summers's avatar
Nate Summers committed
950

Michael Natterer's avatar
Michael Natterer committed
951 952 953 954 955
  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
956 957
}

958 959 960 961 962 963 964 965 966 967 968
void
gimp_transform_tool_info_dialog_connect (GimpTransformTool *tr_tool,
                                         const gchar       *ok_button)
{
  g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
  g_return_if_fail (ok_button != NULL);

  if (tr_tool->info_dialog)
    {
      gimp_dialog_create_action_area (GIMP_DIALOG (tr_tool->info_dialog->shell),

969
                                      GIMP_STOCK_RESET, transform_reset_callback,
970 971
                                      tr_tool, NULL, NULL, FALSE, FALSE,

972 973 974
                                      ok_button, transform_ok_callback,
                                      tr_tool, NULL, NULL, TRUE, FALSE,

975 976 977 978
                                      NULL);
    }
}

Nate Summers's avatar
Nate Summers committed
979
void
Michael Natterer's avatar
Michael Natterer committed
980
gimp_transform_tool_grid_density_changed (GimpTransformTool *transform_tool)
Nate Summers's avatar
Nate Summers committed
981
{
Michael Natterer's avatar
Michael Natterer committed
982
  if (transform_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
983 984
    return;

Michael Natterer's avatar
Michael Natterer committed
985
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (transform_tool));
986

Michael Natterer's avatar
Michael Natterer committed
987 988
  gimp_transform_tool_grid_recalc (transform_tool);
  gimp_transform_tool_transform_bounding_box (transform_tool);
989

Michael Natterer's avatar
Michael Natterer committed
990
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (transform_tool));
Nate Summers's avatar
Nate Summers committed
991 992 993
}

void