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

Michael Natterer's avatar
Michael Natterer committed
48 49
#include "widgets/gimpviewabledialog.h"

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

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

56
#include "gimptransformtool.h"
57 58
#include "tool_manager.h"
#include "transform_options.h"
59

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

#include "libgimp/gimpintl.h"

65

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

68

Michael Natterer's avatar
Michael Natterer committed
69 70 71 72 73 74 75 76
/*  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,
77
                                                    GimpToolAction     action,
Michael Natterer's avatar
Michael Natterer committed
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
                                                    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);
94 95 96 97 98
static void   gimp_transform_tool_modifier_key     (GimpTool          *tool,
                                                    GdkModifierType    key,
                                                    gboolean           press,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
99 100 101 102
static void   gimp_transform_tool_oper_update      (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
103 104 105 106 107 108 109
static void   gimp_transform_tool_cursor_update    (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);

static void   gimp_transform_tool_draw             (GimpDrawTool      *draw_tool);

Michael Natterer's avatar
Michael Natterer committed
110
static void   gimp_transform_tool_reset            (GimpTransformTool *tr_tool);
Michael Natterer's avatar
Michael Natterer committed
111 112
static void   gimp_transform_tool_bounds           (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
113 114 115
static void   gimp_transform_tool_dialog           (GimpTransformTool *tr_tool);
static void   gimp_transform_tool_prepare          (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
116 117 118 119 120 121 122 123 124
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_reset_callback             (GtkWidget         *widget,
Michael Natterer's avatar
Michael Natterer committed
125 126 127 128 129
                                                    GimpTransformTool *tr_tool);
static void   transform_cancel_callback            (GtkWidget         *widget,
                                                    GimpTransformTool *tr_tool);
static void   transform_ok_callback                (GtkWidget         *widget,
                                                    GimpTransformTool *tr_tool);
130 131


132
static GimpDrawToolClass *parent_class = NULL;
133

134 135

GType
Nate Summers's avatar
Nate Summers committed
136 137
gimp_transform_tool_get_type (void)
{
138
  static GType tool_type = 0;
Nate Summers's avatar
Nate Summers committed
139 140 141

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

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

  return tool_type;
}

static void
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
{
166
  GObjectClass      *object_class;
Nate Summers's avatar
Nate Summers committed
167 168
  GimpToolClass     *tool_class;
  GimpDrawToolClass *draw_class;
Nate Summers's avatar
Nate Summers committed
169

170 171 172
  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
173

174
  parent_class = g_type_class_peek_parent (klass);
Nate Summers's avatar
Nate Summers committed
175

176
  object_class->finalize     = gimp_transform_tool_finalize;
Nate Summers's avatar
Nate Summers committed
177

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

  draw_class->draw           = gimp_transform_tool_draw;
Michael Natterer's avatar
Michael Natterer committed
187 188 189 190 191 192

  klass->dialog              = NULL;
  klass->prepare             = NULL;
  klass->motion              = NULL;
  klass->recalc              = NULL;
  klass->transform           = NULL;
Nate Summers's avatar
Nate Summers committed
193 194 195
}

static void
Michael Natterer's avatar
Michael Natterer committed
196
gimp_transform_tool_init (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
197
{
Michael Natterer's avatar
Michael Natterer committed
198
  GimpTool *tool;
199
  gint      i;
Nate Summers's avatar
Nate Summers committed
200

Michael Natterer's avatar
Michael Natterer committed
201
  tool = GIMP_TOOL (tr_tool);
Michael Natterer's avatar
Michael Natterer committed
202

Michael Natterer's avatar
Michael Natterer committed
203 204 205
  gimp_tool_control_set_scroll_lock (tool->control, TRUE);
  gimp_tool_control_set_preserve    (tool->control, FALSE);

Michael Natterer's avatar
Michael Natterer committed
206 207
  tr_tool->function = TRANSFORM_CREATING;
  tr_tool->original = NULL;
Nate Summers's avatar
Nate Summers committed
208 209

  for (i = 0; i < TRAN_INFO_SIZE; i++)
210
    {
Michael Natterer's avatar
Michael Natterer committed
211 212
      tr_tool->trans_info[i]     = 0.0;
      tr_tool->old_trans_info[i] = 0.0;
213
    }
Nate Summers's avatar
Nate Summers committed
214

Michael Natterer's avatar
Michael Natterer committed
215
  gimp_matrix3_identity (tr_tool->transform);
216

Michael Natterer's avatar
Michael Natterer committed
217 218 219 220 221 222
  tr_tool->use_grid     = TRUE;
  tr_tool->use_center   = TRUE;
  tr_tool->ngx          = 0;
  tr_tool->ngy          = 0;
  tr_tool->grid_coords  = NULL;
  tr_tool->tgrid_coords = NULL;
223

Michael Natterer's avatar
Michael Natterer committed
224
  tr_tool->info_dialog  = NULL;
Nate Summers's avatar
Nate Summers committed
225 226
}

227
static void
228
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
229
{
230
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
231

232 233 234
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  if (tr_tool->original)
235 236 237 238
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
239

240
  if (tr_tool->info_dialog)
241
    {
242 243
      info_dialog_free (tr_tool->info_dialog);
      tr_tool->info_dialog = NULL;
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
    }

  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
262 263 264
gimp_transform_tool_control (GimpTool       *tool,
			     GimpToolAction  action,
			     GimpDisplay    *gdisp)
265
{
Michael Natterer's avatar
Michael Natterer committed
266
  GimpTransformTool *tr_tool;
267

Michael Natterer's avatar
Michael Natterer committed
268
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
269

270 271 272 273
  switch (action)
    {
    case PAUSE:
      break;
274

275
    case RESUME:
Michael Natterer's avatar
Michael Natterer committed
276
      gimp_transform_tool_recalc (tr_tool, gdisp);
277
      break;
278

279
    case HALT:
Michael Natterer's avatar
Michael Natterer committed
280
      gimp_transform_tool_reset (tr_tool);
281
      return; /* don't upchain */
282
      break;
283

284 285 286 287
    default:
      break;
    }

Michael Natterer's avatar
Michael Natterer committed
288
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
289 290 291
}

static void
292 293 294 295 296
gimp_transform_tool_button_press (GimpTool        *tool,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
			          GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
297
{
Michael Natterer's avatar
Michael Natterer committed
298
  GimpTransformTool *tr_tool;
299
  GimpDrawTool      *draw_tool;
Michael Natterer's avatar
Michael Natterer committed
300 301
  GimpDrawable      *drawable;
  gint               off_x, off_y;
Nate Summers's avatar
Nate Summers committed
302

Michael Natterer's avatar
Michael Natterer committed
303
  tr_tool   = GIMP_TRANSFORM_TOOL (tool);
304
  draw_tool = GIMP_DRAW_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
305 306 307

  drawable = gimp_image_active_drawable (gdisp->gimage);

308 309 310 311 312 313 314 315 316
  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 &&
Michael Natterer's avatar
Michael Natterer committed
317 318 319 320 321
          coords->x < (off_x + gimp_drawable_width (drawable))  &&
          coords->y < (off_y + gimp_drawable_height (drawable)) &&

          (gimp_image_mask_is_empty (gdisp->gimage) ||
           gimp_image_mask_value (gdisp->gimage, coords->x, coords->y)))
322
        {
Michael Natterer's avatar
Michael Natterer committed
323 324
          if (GIMP_IS_LAYER (drawable) &&
              gimp_layer_get_mask (GIMP_LAYER (drawable)))
325
            {
Michael Natterer's avatar
Michael Natterer committed
326 327 328 329 330
              g_message (_("Transformations do not work on\n"
                           "layers that contain layer masks."));
              gimp_tool_control_halt (tool->control);    /* sets paused_count to 0 -- is this ok? */
              return;
            }
331

Michael Natterer's avatar
Michael Natterer committed
332 333 334 335 336 337
          /*  If the tool is already active, clear the current state
           *  and reset
           */
          if (gimp_tool_control_is_active (tool->control))
            {
              g_warning ("%s: tool_already ACTIVE", G_GNUC_FUNCTION);
338

Michael Natterer's avatar
Michael Natterer committed
339 340
              gimp_transform_tool_reset (tr_tool);
            }
341

Michael Natterer's avatar
Michael Natterer committed
342 343 344 345
          /*  Set the pointer to the active display  */
          tool->gdisp    = gdisp;
          tool->drawable = drawable;
          gimp_tool_control_activate (tool->control);
346

Michael Natterer's avatar
Michael Natterer committed
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);
352

Michael Natterer's avatar
Michael Natterer committed
353 354 355
          /*  Initialize the transform tool */
          if (! tr_tool->info_dialog)
            gimp_transform_tool_dialog (tr_tool);
356

Michael Natterer's avatar
Michael Natterer committed
357
          gimp_transform_tool_prepare (tr_tool, gdisp);
358

Michael Natterer's avatar
Michael Natterer committed
359 360
          /*  Recalculate the transform tool  */
          gimp_transform_tool_recalc (tr_tool, gdisp);
361

Michael Natterer's avatar
Michael Natterer committed
362 363
          /*  start drawing the bounding box and handles...  */
          gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), gdisp);
364

Michael Natterer's avatar
Michael Natterer committed
365 366 367 368
          /*  find which handle we're dragging  */
          gimp_transform_tool_oper_update (tool, coords, state, gdisp);

          tr_tool->function = TRANSFORM_CREATING;
369 370 371
        }
    }

372 373
  if (tr_tool->function == TRANSFORM_CREATING &&
      gimp_tool_control_is_active (tool->control))
Nate Summers's avatar
Nate Summers committed
374
    {
375 376
      gint i;

Nate Summers's avatar
Nate Summers committed
377 378
      /*  Save the current transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
379
	tr_tool->old_trans_info[i] = tr_tool->trans_info[i];
Nate Summers's avatar
Nate Summers committed
380 381 382 383 384 385
    }

  /*  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
386
  if (gdisp == tool->gdisp)
Nate Summers's avatar
Nate Summers committed
387 388
    {
      /*  Save the current pointer position  */
Michael Natterer's avatar
Michael Natterer committed
389 390
      tr_tool->lastx = tr_tool->startx = coords->x;
      tr_tool->lasty = tr_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
391

392
      gimp_tool_control_activate (tool->control);
393
    }
Nate Summers's avatar
Nate Summers committed
394 395
}

396
static void
397 398 399 400 401
gimp_transform_tool_button_release (GimpTool        *tool,
                                    GimpCoords      *coords,
                                    guint32          time,
			            GdkModifierType  state,
			            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
402
{
Michael Natterer's avatar
Michael Natterer committed
403
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
404
  gint               i;
Nate Summers's avatar
Nate Summers committed
405

Michael Natterer's avatar
Michael Natterer committed
406
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
407 408

  /*  if we are creating, there is nothing to be done...exit  */
409
  if (tr_tool->function == TRANSFORM_CREATING && tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
410 411 412
    return;

  /*  if the 3rd button isn't pressed, transform the selected mask  */
413
  if (! (state & GDK_BUTTON3_MASK))
Nate Summers's avatar
Nate Summers committed
414 415
    {
      /* Shift-clicking is another way to approve the transform  */
416
      if ((state & GDK_SHIFT_MASK) || ! tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
417
	{
Michael Natterer's avatar
Michael Natterer committed
418
	  gimp_transform_tool_doit (tr_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
419 420 421 422 423
	}
      else
	{
	  /*  Only update the paths preview */
	  path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
424
				       tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
425 426 427 428
	}
    }
  else
    {
429
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
430 431 432

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

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

438
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
439 440 441

      /* Update the paths preview */
      path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
442
				   tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
443 444 445
    }
}

446
static void
447 448 449 450 451
gimp_transform_tool_motion (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
		            GdkModifierType  state,
		            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
452
{
Michael Natterer's avatar
Michael Natterer committed
453 454
  GimpTransformToolClass *tr_tool_class;
  GimpTransformTool      *tr_tool;
Nate Summers's avatar
Nate Summers committed
455

Michael Natterer's avatar
Michael Natterer committed
456
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
457

458
  /*  if we are creating, there is nothing to be done so exit.  */
459
  if (tr_tool->function == TRANSFORM_CREATING || ! tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
460 461
    return;

462
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
463

Michael Natterer's avatar
Michael Natterer committed
464 465 466
  tr_tool->curx  = coords->x;
  tr_tool->cury  = coords->y;
  tr_tool->state = state;
Nate Summers's avatar
Nate Summers committed
467 468

  /*  recalculate the tool's transformation matrix  */
Michael Natterer's avatar
Michael Natterer committed
469 470 471 472 473
  tr_tool_class = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool);

  if (tr_tool_class->motion)
    {
      tr_tool_class->motion (tr_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
474

Michael Natterer's avatar
Michael Natterer committed
475 476 477 478 479 480
      if (tr_tool_class->recalc)
        tr_tool_class->recalc (tr_tool, gdisp);
    }

  tr_tool->lastx = tr_tool->curx;
  tr_tool->lasty = tr_tool->cury;
Nate Summers's avatar
Nate Summers committed
481

482
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
483 484
}

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
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);
    }
}

508 509 510 511 512 513 514 515 516 517 518 519
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);

520 521 522
  if (! tr_tool->use_grid)
    return;

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 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
  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;
	}
    }
}

573
static void
574 575 576 577
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
			           GdkModifierType  state,
			           GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
578
{
579 580 581 582
  GimpTransformTool  *tr_tool;
  GimpDrawable       *drawable;

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

Michael Natterer's avatar
Michael Natterer committed
584
  if (tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
585
    {
Michael Natterer's avatar
Michael Natterer committed
586 587
      GdkCursorType      ctype     = GDK_TOP_LEFT_ARROW;
      GimpCursorModifier cmodifier = GIMP_CURSOR_MODIFIER_NONE;
588

Michael Natterer's avatar
Michael Natterer committed
589 590 591
     if ((drawable = gimp_image_active_drawable (gdisp->gimage)))
        {
          gint off_x, off_y;
592

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

Michael Natterer's avatar
Michael Natterer committed
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
          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;
                }
            }
        }
612

Michael Natterer's avatar
Michael Natterer committed
613 614 615 616 617 618 619 620
      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);
    }
621 622

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

625
static void
626
gimp_transform_tool_draw (GimpDrawTool *draw_tool)
Nate Summers's avatar
Nate Summers committed
627
{
628
  GimpTransformTool *tr_tool;
Michael Natterer's avatar
Michael Natterer committed
629
  TransformOptions  *options;
630 631 632
  gint               i, k, gci;

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

634 635 636
  if (! tr_tool->use_grid)
    return;

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

Nate Summers's avatar
Nate Summers committed
639
  /*  draw the bounding box  */
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
  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
656 657 658

  /*  Draw the grid */

659
  if ((tr_tool->grid_coords != NULL) && (tr_tool->tgrid_coords != NULL))
Nate Summers's avatar
Nate Summers committed
660 661
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
662
      k = tr_tool->ngx + tr_tool->ngy;
663

Nate Summers's avatar
Nate Summers committed
664 665
      for (i = 0; i < k; i++)
	{
666 667 668 669 670 671
          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
672 673 674 675 676
	  gci += 4;
	}
    }

  /*  draw the tool handles  */
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
  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
701 702

  /*  draw the center  */
703 704 705 706 707 708 709 710 711
  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
712

Michael Natterer's avatar
Michael Natterer committed
713
  if (options->show_path)
Nate Summers's avatar
Nate Summers committed
714 715 716
    {
      GimpMatrix3 tmp_matrix;

Michael Natterer's avatar
Michael Natterer committed
717
      if (options->direction == GIMP_TRANSFORM_BACKWARD)
Nate Summers's avatar
Nate Summers committed
718
	{
Nate Summers's avatar
Nate Summers committed
719
	  gimp_matrix3_invert (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
720 721 722
	}
      else
	{
Nate Summers's avatar
Nate Summers committed
723
	  gimp_matrix3_duplicate (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
724 725
	}

726 727
      path_transform_draw_current (GIMP_TOOL (draw_tool)->gdisp,
                                   draw_tool, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
728 729 730
    }
}

Michael Natterer's avatar
Michael Natterer committed
731 732 733 734
static void
gimp_transform_tool_doit (GimpTransformTool  *tr_tool,
		          GimpDisplay        *gdisp)
{
Michael Natterer's avatar
Michael Natterer committed
735 736 737 738
  GimpTool    *tool;
  TileManager *new_tiles;
  GSList      *path_undo;
  gboolean     new_layer;
Michael Natterer's avatar
Michael Natterer committed
739 740 741 742 743 744 745 746 747 748 749

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

  /*  Start a transform undo group  */
Michael Natterer's avatar
Michael Natterer committed
753
  undo_push_group_start (gdisp->gimage, TRANSFORM_UNDO_GROUP);
Michael Natterer's avatar
Michael Natterer committed
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768

  /* 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
769
  path_undo = path_transform_start_undo (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
770 771 772

  /*  Send the request for the transformation to the tool...
   */
Michael Natterer's avatar
Michael Natterer committed
773 774 775 776 777
  if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->transform)
    new_tiles = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->transform (tr_tool,
                                                                    gdisp);
  else
    new_tiles = NULL;
Michael Natterer's avatar
Michael Natterer committed
778

Michael Natterer's avatar
Michael Natterer committed
779
  gimp_transform_tool_prepare (tr_tool, gdisp);
Michael Natterer's avatar
Michael Natterer committed
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
  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
797 798 799 800 801 802
      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
803 804 805 806 807 808 809 810
    }

  /*  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
   */
811
  gimp_tool_control_set_preserve (tool->control, FALSE);
Michael Natterer's avatar
Michael Natterer committed
812 813 814

  gimp_unset_busy (gdisp->gimage->gimp);

815
  gimp_image_flush (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
816

Michael Natterer's avatar
Michael Natterer committed
817
  gimp_transform_tool_reset (tr_tool);
Michael Natterer's avatar
Michael Natterer committed
818 819 820
}

TileManager *
Michael Natterer's avatar
Michael Natterer committed
821
gimp_transform_tool_transform_tiles (GimpTransformTool *tr_tool,
Michael Natterer's avatar
Michael Natterer committed
822 823 824 825 826 827 828
                                     const gchar       *progress_text)
{
  GimpTool         *tool;
  TransformOptions *options;
  GimpProgress     *progress;
  TileManager      *ret;

Michael Natterer's avatar
Michael Natterer committed
829
  g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool), NULL);
Michael Natterer's avatar
Michael Natterer committed
830 831
  g_return_val_if_fail (progress_text != NULL, NULL);

Michael Natterer's avatar
Michael Natterer committed
832 833
  if (tr_tool->info_dialog)
    gtk_widget_set_sensitive (GTK_WIDGET (tr_tool->info_dialog->shell), FALSE);
Michael Natterer's avatar
Michael Natterer committed
834

Michael Natterer's avatar
Michael Natterer committed
835
  tool = GIMP_TOOL (tr_tool);
Michael Natterer's avatar
Michael Natterer committed
836 837 838

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

Michael Natterer's avatar
Michael Natterer committed
839 840
  progress = gimp_progress_start (tool->gdisp, progress_text, FALSE,
                                  NULL, NULL);
Michael Natterer's avatar
Michael Natterer committed
841 842

  ret = gimp_drawable_transform_tiles_affine (gimp_image_active_drawable (tool->gdisp->gimage),
Michael Natterer's avatar
Michael Natterer committed
843
                                              tr_tool->original,
844
                                              options->interpolation,
Michael Natterer's avatar
Michael Natterer committed
845
                                              options->clip,
Michael Natterer's avatar
Michael Natterer committed
846
                                              tr_tool->transform,
Michael Natterer's avatar
Michael Natterer committed
847
                                              options->direction,
Michael Natterer's avatar
Michael Natterer committed
848 849 850
                                              progress ?
                                              gimp_progress_update_and_flush : 
                                              NULL,
Michael Natterer's avatar
Michael Natterer committed
851 852 853
                                              progress);

  if (progress)
Michael Natterer's avatar
Michael Natterer committed
854
    gimp_progress_end (progress);
Michael Natterer's avatar
Michael Natterer committed
855 856 857 858

  return ret;
}

Nate Summers's avatar
Nate Summers committed
859
void
Nate Summers's avatar
Nate Summers committed
860
gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
861
{
862
  g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
Nate Summers's avatar
Nate Summers committed
863 864 865 866 867 868 869 870 871 872 873 874 875

  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
876

877 878 879
  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
880

881
  if (tr_tool->grid_coords != NULL && tr_tool->tgrid_coords != NULL)
Nate Summers's avatar
Nate Summers committed
882
    {
883 884 885
      gint i, k;
      gint gci;

Nate Summers's avatar
Nate Summers committed
886
      gci = 0;
887
      k   = (tr_tool->ngx + tr_tool->ngy) * 2;
888

Nate Summers's avatar
Nate Summers committed
889 890
      for (i = 0; i < k; i++)
	{
Nate Summers's avatar
Nate Summers committed
891 892 893 894 895
	  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
896 897 898 899 900
	  gci += 2;
	}
    }
}

901
static void
Michael Natterer's avatar
Michael Natterer committed
902
gimp_transform_tool_reset (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
903
{
Nate Summers's avatar
Nate Summers committed
904
  GimpTool *tool;
Nate Summers's avatar
Nate Summers committed
905

906
  tool = GIMP_TOOL (tr_tool);
Nate Summers's avatar
Nate Summers committed
907

Nate Summers's avatar
Nate Summers committed
908
  if (tr_tool->original)
909 910 911 912
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
Nate Summers's avatar
Nate Summers committed
913 914

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

917
  gimp_draw_tool_stop (GIMP_DRAW_TOOL (tr_tool));
918 919 920

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

922
  gimp_tool_control_halt (tool->control);    /* sets paused_count to 0 -- is this ok? */
Nate Summers's avatar
Nate Summers committed
923 924 925 926 927
  tool->gdisp    = NULL;
  tool->drawable = NULL;
}

static void
928
gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
929
		            GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
930
{
931 932
  TileManager  *tiles;
  GimpDrawable *drawable;
Nate Summers's avatar
Nate Summers committed
933

934 935
  tiles    = tr_tool->original;
  drawable = gimp_image_active_drawable (gdisp->gimage);
Nate Summers's avatar
Nate Summers committed
936 937 938 939

  /*  find the boundaries  */
  if (tiles)
    {
940 941
      tile_manager_get_offsets (tiles, &tr_tool->x1, &tr_tool->y1);

Nate Summers's avatar
Nate Summers committed
942 943
      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
944 945 946
    }
  else
    {
947 948
      gint offset_x, offset_y;

Nate Summers's avatar
Nate Summers committed
949
      gimp_drawable_offsets (drawable, &offset_x, &offset_y);
950

Nate Summers's avatar
Nate Summers committed
951
      gimp_drawable_mask_bounds (drawable,
Nate Summers's avatar
Nate Summers committed
952 953 954 955 956 957
				 &tr_tool->x1, &tr_tool->y1,
				 &tr_tool->x2, &tr_tool->y2);
      tr_tool->x1 += offset_x;
      tr_tool->y1 +=