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

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

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

43 44 45
#include "vectors/gimpvectors.h"
#include "vectors/gimpstroke.h"

46
#include "widgets/gimpdialogfactory.h"
Michael Natterer's avatar
Michael Natterer committed
47 48
#include "widgets/gimpviewabledialog.h"

49
#include "display/gimpdisplay.h"
Michael Natterer's avatar
Michael Natterer committed
50
#include "display/gimpprogress.h"
Nate Summers's avatar
Nate Summers committed
51

52 53 54 55
#ifdef __GNUC__
#warning FIXME #include "gui/gui-types.h"
#endif
#include "gui/gui-types.h"
56 57
#include "gui/info-dialog.h"

58
#include "gimptoolcontrol.h"
59
#include "gimptransformoptions.h"
60 61
#include "gimptransformtool.h"
#include "gimptransformtool-undo.h"
62

63
#include "gimp-intl.h"
Nate Summers's avatar
Nate Summers committed
64

65

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

68

Michael Natterer's avatar
Michael Natterer committed
69 70 71 72 73
/*  local function prototypes  */

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

74 75 76
static GObject * gimp_transform_tool_constructor   (GType              type,
                                                    guint              n_params,
                                                    GObjectConstructParam *params);
Michael Natterer's avatar
Michael Natterer committed
77 78
static void   gimp_transform_tool_finalize         (GObject           *object);

79 80
static void   gimp_transform_tool_initialize       (GimpTool          *tool,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
81
static void   gimp_transform_tool_control          (GimpTool          *tool,
82
                                                    GimpToolAction     action,
Michael Natterer's avatar
Michael Natterer committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
                                                    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);
99 100 101 102 103
static void   gimp_transform_tool_modifier_key     (GimpTool          *tool,
                                                    GdkModifierType    key,
                                                    gboolean           press,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
104 105 106 107
static void   gimp_transform_tool_oper_update      (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
108 109 110 111 112 113 114
static void   gimp_transform_tool_cursor_update    (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);

static void   gimp_transform_tool_draw             (GimpDrawTool      *draw_tool);

115 116
static TileManager *
              gimp_transform_tool_real_transform   (GimpTransformTool *tr_tool,
117
                                                    GimpItem          *item,
118 119
                                                    GimpDisplay       *gdisp);

120
static void   gimp_transform_tool_halt             (GimpTransformTool *tr_tool);
Michael Natterer's avatar
Michael Natterer committed
121 122
static void   gimp_transform_tool_bounds           (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
123 124 125
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
126 127 128 129 130 131
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_grid_recalc      (GimpTransformTool *tr_tool);

132 133
static void   transform_response                   (GtkWidget         *widget,
                                                    gint               response_id,
Michael Natterer's avatar
Michael Natterer committed
134
                                                    GimpTransformTool *tr_tool);
135

136
static void   gimp_transform_tool_notify_type   (GimpTransformOptions *options,
137 138
                                                 GParamSpec           *pspec,
                                                 GimpTransformTool    *tr_tool);
139
static void   gimp_transform_tool_notify_grid   (GimpTransformOptions *options,
140 141 142
                                                 GParamSpec           *pspec,
                                                 GimpTransformTool    *tr_tool);

143

144
static GimpDrawToolClass *parent_class = NULL;
145

146 147

GType
Nate Summers's avatar
Nate Summers committed
148 149
gimp_transform_tool_get_type (void)
{
150
  static GType tool_type = 0;
Nate Summers's avatar
Nate Summers committed
151 152 153

  if (! tool_type)
    {
154
      static const GTypeInfo tool_info =
Nate Summers's avatar
Nate Summers committed
155 156
      {
        sizeof (GimpTransformToolClass),
157 158 159 160 161 162 163 164
	(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
165 166
      };

167
      tool_type = g_type_register_static (GIMP_TYPE_DRAW_TOOL,
168
					  "GimpTransformTool",
169
                                          &tool_info, 0);
Nate Summers's avatar
Nate Summers committed
170 171 172 173 174 175 176 177
    }

  return tool_type;
}

static void
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
{
178
  GObjectClass      *object_class;
Nate Summers's avatar
Nate Summers committed
179 180
  GimpToolClass     *tool_class;
  GimpDrawToolClass *draw_class;
Nate Summers's avatar
Nate Summers committed
181

182 183 184
  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
185

186
  parent_class = g_type_class_peek_parent (klass);
Nate Summers's avatar
Nate Summers committed
187

188
  object_class->constructor  = gimp_transform_tool_constructor;
189
  object_class->finalize     = gimp_transform_tool_finalize;
Nate Summers's avatar
Nate Summers committed
190

191
  tool_class->initialize     = gimp_transform_tool_initialize;
192
  tool_class->control        = gimp_transform_tool_control;
Nate Summers's avatar
Nate Summers committed
193 194 195
  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;
196
  tool_class->modifier_key   = gimp_transform_tool_modifier_key;
197
  tool_class->oper_update    = gimp_transform_tool_oper_update;
Nate Summers's avatar
Nate Summers committed
198
  tool_class->cursor_update  = gimp_transform_tool_cursor_update;
Nate Summers's avatar
Nate Summers committed
199 200

  draw_class->draw           = gimp_transform_tool_draw;
Michael Natterer's avatar
Michael Natterer committed
201 202 203 204 205

  klass->dialog              = NULL;
  klass->prepare             = NULL;
  klass->motion              = NULL;
  klass->recalc              = NULL;
206
  klass->transform           = gimp_transform_tool_real_transform;
Nate Summers's avatar
Nate Summers committed
207 208 209
}

static void
Michael Natterer's avatar
Michael Natterer committed
210
gimp_transform_tool_init (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
211
{
Michael Natterer's avatar
Michael Natterer committed
212
  GimpTool *tool;
213
  gint      i;
Nate Summers's avatar
Nate Summers committed
214

Michael Natterer's avatar
Michael Natterer committed
215
  tool = GIMP_TOOL (tr_tool);
Michael Natterer's avatar
Michael Natterer committed
216

Michael Natterer's avatar
Michael Natterer committed
217 218 219
  gimp_tool_control_set_scroll_lock (tool->control, TRUE);
  gimp_tool_control_set_preserve    (tool->control, FALSE);

Michael Natterer's avatar
Michael Natterer committed
220 221
  tr_tool->function = TRANSFORM_CREATING;
  tr_tool->original = NULL;
Nate Summers's avatar
Nate Summers committed
222 223

  for (i = 0; i < TRAN_INFO_SIZE; i++)
224
    {
Michael Natterer's avatar
Michael Natterer committed
225 226
      tr_tool->trans_info[i]     = 0.0;
      tr_tool->old_trans_info[i] = 0.0;
227
    }
Nate Summers's avatar
Nate Summers committed
228

229
  gimp_matrix3_identity (&tr_tool->transform);
230

231 232 233 234 235 236 237
  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;

238
  tr_tool->type             = GIMP_TRANSFORM_TYPE_LAYER;
239
  tr_tool->direction        = GIMP_TRANSFORM_FORWARD;
240

241 242 243
  tr_tool->shell_desc       = NULL;
  tr_tool->progress_text    = _("Transforming...");
  tr_tool->info_dialog      = NULL;
Nate Summers's avatar
Nate Summers committed
244 245
}

246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
static GObject *
gimp_transform_tool_constructor (GType                  type,
                                 guint                  n_params,
                                 GObjectConstructParam *params)
{
  GObject           *object;
  GimpTool          *tool;
  GimpTransformTool *tr_tool;

  object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);

  tool    = GIMP_TOOL (object);
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  g_assert (GIMP_IS_TOOL_INFO (tool->tool_info));

  if (tr_tool->use_grid)
    {
      tr_tool->type =
        GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options)->type;
      tr_tool->direction =
        GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options)->direction;

      g_signal_connect_object (tool->tool_info->tool_options,
                               "notify::type",
                               G_CALLBACK (gimp_transform_tool_notify_type),
                               tr_tool, 0);
      g_signal_connect_object (tool->tool_info->tool_options,
                               "notify::direction",
                               G_CALLBACK (gimp_transform_tool_notify_type),
                               tr_tool, 0);
      g_signal_connect_object (tool->tool_info->tool_options,
                               "notify::grid-type",
                               G_CALLBACK (gimp_transform_tool_notify_grid),
                               tr_tool, 0);
      g_signal_connect_object (tool->tool_info->tool_options,
                               "notify::grid-size",
                               G_CALLBACK (gimp_transform_tool_notify_grid),
                               tr_tool, 0);
    }

  return object;
}

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

295 296 297
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  if (tr_tool->original)
298
    {
299
      tile_manager_unref (tr_tool->original);
300 301
      tr_tool->original = NULL;
    }
302

303
  if (tr_tool->info_dialog)
304
    {
305 306
      info_dialog_free (tr_tool->info_dialog);
      tr_tool->info_dialog = NULL;
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
    }

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

324 325 326 327 328 329 330 331 332
static void
gimp_transform_tool_initialize (GimpTool    *tool,
				GimpDisplay *gdisp)
{
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);

  if (gdisp != tool->gdisp)
    {
      GimpDrawable *drawable = gimp_image_active_drawable (gdisp->gimage);
333
      gint          i;
334 335 336 337

      if (GIMP_IS_LAYER (drawable) &&
          gimp_layer_get_mask (GIMP_LAYER (drawable)))
        {
338
          g_message (_("Transformations do not work on "
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
                       "layers that contain layer masks."));
          return;
        }

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

      /*  Initialize the transform tool dialog */
      if (! tr_tool->info_dialog)
        gimp_transform_tool_dialog (tr_tool);

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

      gimp_transform_tool_prepare (tr_tool, gdisp);

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

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

      tr_tool->function = TRANSFORM_CREATING;

      /*  Save the current transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
	tr_tool->old_trans_info[i] = tr_tool->trans_info[i];
    }
}

373
static void
374 375 376
gimp_transform_tool_control (GimpTool       *tool,
			     GimpToolAction  action,
			     GimpDisplay    *gdisp)
377
{
Michael Natterer's avatar
Michael Natterer committed
378
  GimpTransformTool *tr_tool;
379

Michael Natterer's avatar
Michael Natterer committed
380
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
381

382 383 384 385
  switch (action)
    {
    case PAUSE:
      break;
386

387
    case RESUME:
Michael Natterer's avatar
Michael Natterer committed
388
      gimp_transform_tool_recalc (tr_tool, gdisp);
389
      break;
390

391
    case HALT:
392
      gimp_transform_tool_halt (tr_tool);
393
      return; /* don't upchain */
394
      break;
395

396 397 398 399
    default:
      break;
    }

Michael Natterer's avatar
Michael Natterer committed
400
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
401 402 403
}

static void
404 405 406 407 408
gimp_transform_tool_button_press (GimpTool        *tool,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
			          GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
409
{
Michael Natterer's avatar
Michael Natterer committed
410
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
411

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

414 415
  if (tr_tool->function == TRANSFORM_CREATING && tr_tool->use_grid)
    gimp_transform_tool_oper_update (tool, coords, state, gdisp);
416

417 418
  tr_tool->lastx = tr_tool->startx = coords->x;
  tr_tool->lasty = tr_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
419

420
  gimp_tool_control_activate (tool->control);
Nate Summers's avatar
Nate Summers committed
421 422
}

423
static void
424 425 426 427 428
gimp_transform_tool_button_release (GimpTool        *tool,
                                    GimpCoords      *coords,
                                    guint32          time,
			            GdkModifierType  state,
			            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
429
{
Michael Natterer's avatar
Michael Natterer committed
430
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
431
  gint               i;
Nate Summers's avatar
Nate Summers committed
432

Michael Natterer's avatar
Michael Natterer committed
433
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
434 435

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

  /*  if the 3rd button isn't pressed, transform the selected mask  */
440
  if (! (state & GDK_BUTTON3_MASK))
Nate Summers's avatar
Nate Summers committed
441 442
    {
      /* Shift-clicking is another way to approve the transform  */
443
      if ((state & GDK_SHIFT_MASK) || ! tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
444
	{
Michael Natterer's avatar
Michael Natterer committed
445
	  gimp_transform_tool_doit (tr_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
446 447 448 449
	}
    }
  else
    {
450
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
451 452 453

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

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

459
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
460
    }
461 462

  gimp_tool_control_halt (tool->control);
Nate Summers's avatar
Nate Summers committed
463 464
}

465
static void
466 467 468 469 470
gimp_transform_tool_motion (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
		            GdkModifierType  state,
		            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
471
{
Michael Natterer's avatar
Michael Natterer committed
472 473
  GimpTransformToolClass *tr_tool_class;
  GimpTransformTool      *tr_tool;
Nate Summers's avatar
Nate Summers committed
474

Michael Natterer's avatar
Michael Natterer committed
475
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
476

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

481
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
482

Michael Natterer's avatar
Michael Natterer committed
483 484 485
  tr_tool->curx  = coords->x;
  tr_tool->cury  = coords->y;
  tr_tool->state = state;
Nate Summers's avatar
Nate Summers committed
486 487

  /*  recalculate the tool's transformation matrix  */
Michael Natterer's avatar
Michael Natterer committed
488 489 490 491 492
  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
493

Michael Natterer's avatar
Michael Natterer committed
494 495 496 497 498 499
      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
500

501
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
502 503
}

504 505 506 507 508 509 510
static void
gimp_transform_tool_modifier_key (GimpTool        *tool,
                                  GdkModifierType  key,
                                  gboolean         press,
                                  GdkModifierType  state,
                                  GimpDisplay     *gdisp)
{
511
  GimpTransformOptions *options;
512

513
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
514

515
  if (key == GDK_CONTROL_MASK)
516
    {
517
      g_object_set (options,
518 519
                    "constrain-1", ! options->constrain_1,
                    NULL);
520
    }
521
  else if (key == GDK_MOD1_MASK)
522
    {
523
      g_object_set (options,
524 525
                    "constrain-2", ! options->constrain_2,
                    NULL);
526 527 528
    }
}

529 530 531 532 533 534 535 536 537 538 539 540
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);

541 542 543
  if (! tr_tool->use_grid)
    return;

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 573 574 575 576 577 578 579 580 581 582 583 584
  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,
585
                                    HANDLE_SIZE, HANDLE_SIZE,
586 587 588 589 590 591 592 593
                                    GTK_ANCHOR_CENTER,
                                    FALSE))
	{
	  tr_tool->function = TRANSFORM_HANDLE_CENTER;
	}
    }
}

594
static void
595 596 597 598
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
			           GdkModifierType  state,
			           GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
599
{
600 601
  GimpTransformTool    *tr_tool;
  GimpTransformOptions *options;
602 603

  tr_tool = GIMP_TRANSFORM_TOOL (tool);
604
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
Nate Summers's avatar
Nate Summers committed
605

Michael Natterer's avatar
Michael Natterer committed
606
  if (tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
607
    {
608 609 610
      GimpChannel        *selection = gimp_image_get_mask (gdisp->gimage);
      GdkCursorType       ctype     = GDK_TOP_LEFT_ARROW;
      GimpCursorModifier  cmodifier = GIMP_CURSOR_MODIFIER_NONE;
611

612
      switch (options->type)
Michael Natterer's avatar
Michael Natterer committed
613
        {
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
        case GIMP_TRANSFORM_TYPE_LAYER:
          {
            GimpDrawable *drawable;

            drawable = gimp_image_active_drawable (gdisp->gimage);

            if (drawable)
              {
                if (GIMP_IS_LAYER (drawable) &&
                    gimp_layer_get_mask (GIMP_LAYER (drawable)))
                  {
                    ctype = GIMP_BAD_CURSOR;
                  }
                else if (gimp_display_coords_in_active_drawable (gdisp, coords))
                  {
629 630
                    if (gimp_channel_is_empty (selection) ||
                        gimp_channel_value (selection, coords->x, coords->y))
631 632 633 634 635 636 637 638 639
                      {
                        ctype = GIMP_MOUSE_CURSOR;
                      }
                  }
              }
          }
          break;

        case GIMP_TRANSFORM_TYPE_SELECTION:
640 641
          if (gimp_channel_is_empty (selection) ||
              gimp_channel_value (selection, coords->x, coords->y))
Michael Natterer's avatar
Michael Natterer committed
642
            {
643
              ctype = GIMP_MOUSE_CURSOR;
Michael Natterer's avatar
Michael Natterer committed
644
            }
645 646 647 648 649 650 651 652
          break;

        case GIMP_TRANSFORM_TYPE_PATH:
          if (gimp_image_get_active_vectors (gdisp->gimage))
            ctype = GIMP_MOUSE_CURSOR;
          else
            ctype = GIMP_BAD_CURSOR;
          break;
Michael Natterer's avatar
Michael Natterer committed
653
        }
654

Michael Natterer's avatar
Michael Natterer committed
655 656 657 658 659 660 661 662
      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);
    }
663 664

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

667
static void
668
gimp_transform_tool_draw (GimpDrawTool *draw_tool)
Nate Summers's avatar
Nate Summers committed
669
{
670
  GimpTool             *tool;
671 672
  GimpTransformTool    *tr_tool;
  GimpTransformOptions *options;
673 674
  gdouble z1, z2, z3, z4;

675 676

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

678 679 680
  if (! tr_tool->use_grid)
    return;

681
  tool    = GIMP_TOOL (draw_tool);
682
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
683

Nate Summers's avatar
Nate Summers committed
684
  /*  draw the bounding box  */
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
  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
701

702 703 704 705 706 707 708 709 710 711 712 713 714
  /* We test if the transformed polygon is convex.
   * if z1 and z2 have the same sign as well as z3 and z4
   * the polygon is convex. */

  z1 = (tr_tool->tx2-tr_tool->tx1)*(tr_tool->ty4-tr_tool->ty1)
          -(tr_tool->tx4-tr_tool->tx1)*(tr_tool->ty2-tr_tool->ty1);
  z2 = (tr_tool->tx4-tr_tool->tx1)*(tr_tool->ty3-tr_tool->ty1)
          -(tr_tool->tx3-tr_tool->tx1)*(tr_tool->ty4-tr_tool->ty1);
  z3 = (tr_tool->tx4-tr_tool->tx2)*(tr_tool->ty3-tr_tool->ty2)
          -(tr_tool->tx3-tr_tool->tx2)*(tr_tool->ty4-tr_tool->ty2);
  z4 = (tr_tool->tx3-tr_tool->tx2)*(tr_tool->ty1-tr_tool->ty2)
          -(tr_tool->tx1-tr_tool->tx2)*(tr_tool->ty3-tr_tool->ty2);

715
  /*  Draw the grid (not for path transform since it looks ugly)  */
Nate Summers's avatar
Nate Summers committed
716

717 718 719
  if (tr_tool->type != GIMP_TRANSFORM_TYPE_PATH &&
      tr_tool->grid_coords                      &&
      tr_tool->tgrid_coords                     &&
720 721
      z1 * z2 > 0                               &&
      z3 * z4 > 0)
Nate Summers's avatar
Nate Summers committed
722
    {
723 724
      gint gci, i, k;

Nate Summers's avatar
Nate Summers committed
725
      k = tr_tool->ngx + tr_tool->ngy;
726

727
      for (i = 0, gci = 0; i < k; i++, gci += 4)
Nate Summers's avatar
Nate Summers committed
728
	{
729 730 731 732 733 734
          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
735 736 737 738
	}
    }

  /*  draw the tool handles  */
739 740 741
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx1, tr_tool->ty1,
742
                              HANDLE_SIZE, HANDLE_SIZE,
743 744 745 746 747
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx2, tr_tool->ty2,
748
                              HANDLE_SIZE, HANDLE_SIZE,
749 750 751 752 753
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx3, tr_tool->ty3,
754
                              HANDLE_SIZE, HANDLE_SIZE,
755 756 757 758 759
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx4, tr_tool->ty4,
760
                              HANDLE_SIZE, HANDLE_SIZE,
761 762
                              GTK_ANCHOR_CENTER,
                              FALSE);
Nate Summers's avatar
Nate Summers committed
763 764

  /*  draw the center  */
765 766 767 768 769
  if (tr_tool->use_center)
    {
      gimp_draw_tool_draw_handle (draw_tool,
                                  GIMP_HANDLE_FILLED_CIRCLE,
                                  tr_tool->tcx, tr_tool->tcy,
770
                                  HANDLE_SIZE, HANDLE_SIZE,
771 772 773
                                  GTK_ANCHOR_CENTER,
                                  FALSE);
    }
Nate Summers's avatar
Nate Summers committed
774

775
  if (tr_tool->type == GIMP_TRANSFORM_TYPE_PATH)
Nate Summers's avatar
Nate Summers committed
776
    {
777 778 779
      GimpVectors *vectors;
      GimpStroke  *stroke = NULL;
      GimpMatrix3  matrix = tr_tool->transform;
780

781 782 783
      vectors = gimp_image_get_active_vectors (tool->gdisp->gimage);

      if (vectors)
784
        {
785 786 787 788 789 790 791 792 793 794
          if (tr_tool->direction == GIMP_TRANSFORM_BACKWARD)
            gimp_matrix3_invert (&matrix);

          while ((stroke = gimp_vectors_stroke_get_next (vectors, stroke)))
            {
              GArray   *coords;
              gboolean  closed;

              coords = gimp_stroke_interpolate (stroke, 1.0, &closed);

795
              if (coords && coords->len)
796
                {
797 798
                  gint i;

799 800 801 802 803 804 805 806 807
                  for (i = 0; i < coords->len; i++)
                    {
                      GimpCoords *curr = &g_array_index (coords, GimpCoords, i);

                      gimp_matrix3_transform_point (&matrix,
                                                    curr->x, curr->y,
                                                    &curr->x, &curr->y);
                    }

808 809 810 811
                  gimp_draw_tool_draw_strokes (draw_tool,
                                               &g_array_index (coords,
                                                               GimpCoords, 0),
                                               coords->len, FALSE, FALSE);
812
                }
813 814 815

              if (coords)
                g_array_free (coords, TRUE);
816
            }
817
        }
Nate Summers's avatar
Nate Summers committed
818 819 820
    }
}

821 822
static TileManager *
gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
823
                                    GimpItem          *active_item,
824 825
                                    GimpDisplay       *gdisp)
{
826 827 828
  GimpTool             *tool;
  GimpTransformOptions *options;
  GimpProgress         *progress;
829
  TileManager          *ret = NULL;
830

831 832
  tool    = GIMP_TOOL (tr_tool);
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
833 834 835 836 837 838 839

  if (tr_tool->info_dialog)
    gtk_widget_set_sensitive (GTK_WIDGET (tr_tool->info_dialog->shell), FALSE);

  progress = gimp_progress_start (gdisp, tr_tool->progress_text, FALSE,
                                  NULL, NULL);

840
  if (gimp_item_get_linked (active_item))
841
    gimp_item_linked_transform (active_item, &tr_tool->transform,
842 843 844 845 846
                                options->direction,
                                options->interpolation, options->clip,
                                progress ?
                                gimp_progress_update_and_flush : NULL,
                                progress);
847

848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
  switch (options->type)
    {
    case GIMP_TRANSFORM_TYPE_LAYER:
    case GIMP_TRANSFORM_TYPE_SELECTION:
      {
        gboolean clip_result = options->clip;

        /*  always clip the selction and unfloated channels
         *  so they keep their size
         */
        if (GIMP_IS_CHANNEL (active_item) &&
            tile_manager_bpp (tr_tool->original) == 1)
          clip_result = TRUE;

        ret =
          gimp_drawable_transform_tiles_affine (GIMP_DRAWABLE (active_item),
                                                tr_tool->original,
865
                                                &tr_tool->transform,
866 867 868 869
                                                options->direction,
                                                options->interpolation,
                                                clip_result,
                                                progress ?
870
                                                gimp_progress_update_and_flush :
871 872 873 874
                                                NULL,
                                                progress);
      }
      break;
875

876
    case GIMP_TRANSFORM_TYPE_PATH:
877 878 879 880 881 882 883 884 885
      gimp_item_transform (active_item,
                           &tr_tool->transform,
                           options->direction,
                           options->interpolation,
                           options->clip,
                           progress ?
                           gimp_progress_update_and_flush :
                           NULL,
                           progress);
886 887
      break;
    }
888 889 890 891 892 893 894

  if (progress)
    gimp_progress_end (progress);

  return ret;
}

Michael Natterer's avatar
Michael Natterer committed
895 896 897 898
static void
gimp_transform_tool_doit (GimpTransformTool  *tr_tool,
		          GimpDisplay        *gdisp)
{
899 900
  GimpTool             *tool;
  GimpTransformOptions *options;
901
  GimpItem             *active_item = NULL;
902 903
  TileManager          *new_tiles;
  gboolean              new_layer;
Michael Natterer's avatar
Michael Natterer committed
904

905 906
  tool    = GIMP_TOOL (tr_tool);
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
Michael Natterer's avatar
Michael Natterer committed
907

908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
  switch (options->type)
    {
    case GIMP_TRANSFORM_TYPE_LAYER:
      active_item = (GimpItem *) gimp_image_active_drawable (gdisp->gimage);
      break;

    case GIMP_TRANSFORM_TYPE_SELECTION:
      active_item = (GimpItem *) gimp_image_get_mask (gdisp->gimage);
      break;

    case GIMP_TRANSFORM_TYPE_PATH:
      active_item = (GimpItem *) gimp_image_get_active_vectors (gdisp->gimage);
      break;
    }

  if (! active_item)
    return;

  gimp_set_busy (gdisp->gimage->gimp);

Michael Natterer's avatar
Michael Natterer committed
928
  /* undraw the tool before we muck around with the transform matrix */
929
  gimp_draw_tool_stop (GIMP_DRAW_TOOL (tr_tool));
Michael Natterer's avatar
Michael Natterer committed
930

931
  /*  We're going to dirty this image, but we want to keep the tool around  */
932
  gimp_tool_control_set_preserve (tool->control, TRUE);
Michael Natterer's avatar
Michael Natterer committed
933 934

  /*  Start a transform undo group  */
935
  gimp_image_undo_group_start (gdisp->gimage, GIMP_UNDO_GROUP_TRANSFORM,
936
                               tool->tool_info->blurb);
Michael Natterer's avatar
Michael Natterer committed
937 938 939 940 941 942 943 944 945 946 947 948

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