gimptransformtool.c 55 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
 * 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>
24
#include <gdk/gdkkeysyms.h>
Nate Summers's avatar
Nate Summers committed
25 26

#include "libgimpmath/gimpmath.h"
27
#include "libgimpconfig/gimpconfig.h"
Nate Summers's avatar
Nate Summers committed
28 29
#include "libgimpwidgets/gimpwidgets.h"

Michael Natterer's avatar
Michael Natterer committed
30
#include "tools-types.h"
31

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

Michael Natterer's avatar
Michael Natterer committed
34
#include "core/gimp.h"
35
#include "core/gimpchannel.h"
36
#include "core/gimpcontext.h"
Michael Natterer's avatar
Michael Natterer committed
37
#include "core/gimpdrawable-transform.h"
38
#include "core/gimpimage.h"
39
#include "core/gimpimage-undo.h"
40
#include "core/gimpimage-undo-push.h"
41
#include "core/gimpitem-linked.h"
42
#include "core/gimplayer.h"
43
#include "core/gimplayermask.h"
44
#include "core/gimppickable.h"
45
#include "core/gimpprogress.h"
Michael Natterer's avatar
Michael Natterer committed
46
#include "core/gimptoolinfo.h"
47

48 49 50
#include "vectors/gimpvectors.h"
#include "vectors/gimpstroke.h"

51
#include "widgets/gimpdialogfactory.h"
52
#include "widgets/gimptooldialog.h"
Michael Natterer's avatar
Michael Natterer committed
53 54
#include "widgets/gimpviewabledialog.h"

55
#include "display/gimpdisplay.h"
56 57 58
#include "display/gimpdisplayshell.h"
#include "display/gimpdisplayshell-appearance.h"
#include "display/gimpdisplayshell-transform.h"
Nate Summers's avatar
Nate Summers committed
59

60
#include "gimptoolcontrol.h"
61
#include "gimptransformoptions.h"
62 63
#include "gimptransformtool.h"
#include "gimptransformtool-undo.h"
64

65
#include "gimp-intl.h"
Nate Summers's avatar
Nate Summers committed
66

67

68
#define HANDLE_SIZE 10
Michael Natterer's avatar
Michael Natterer committed
69

70

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

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

78
static gboolean gimp_transform_tool_initialize     (GimpTool          *tool,
79
                                                    GimpDisplay       *display);
80
static void     gimp_transform_tool_control        (GimpTool          *tool,
81
                                                    GimpToolAction     action,
82
                                                    GimpDisplay       *display);
83
static void     gimp_transform_tool_button_press   (GimpTool          *tool,
Michael Natterer's avatar
Michael Natterer committed
84 85 86
                                                    GimpCoords        *coords,
                                                    guint32            time,
                                                    GdkModifierType    state,
87
                                                    GimpDisplay       *display);
88
static void     gimp_transform_tool_button_release (GimpTool          *tool,
Michael Natterer's avatar
Michael Natterer committed
89 90 91
                                                    GimpCoords        *coords,
                                                    guint32            time,
                                                    GdkModifierType    state,
92
                                                    GimpDisplay       *display);
93
static void     gimp_transform_tool_motion         (GimpTool          *tool,
Michael Natterer's avatar
Michael Natterer committed
94 95 96
                                                    GimpCoords        *coords,
                                                    guint32            time,
                                                    GdkModifierType    state,
97
                                                    GimpDisplay       *display);
98
static gboolean gimp_transform_tool_key_press      (GimpTool          *tool,
99
                                                    GdkEventKey       *kevent,
100
                                                    GimpDisplay       *display);
101
static void     gimp_transform_tool_modifier_key   (GimpTool          *tool,
102 103 104
                                                    GdkModifierType    key,
                                                    gboolean           press,
                                                    GdkModifierType    state,
105
                                                    GimpDisplay       *display);
106
static void     gimp_transform_tool_oper_update    (GimpTool          *tool,
107 108
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
109
                                                    gboolean           proximity,
110
                                                    GimpDisplay       *display);
111
static void     gimp_transform_tool_cursor_update  (GimpTool          *tool,
Michael Natterer's avatar
Michael Natterer committed
112 113
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
114
                                                    GimpDisplay       *display);
Michael Natterer's avatar
Michael Natterer committed
115

116
static void     gimp_transform_tool_draw           (GimpDrawTool      *draw_tool);
Michael Natterer's avatar
Michael Natterer committed
117

118 119
static void     gimp_transform_tool_dialog_update  (GimpTransformTool *tr_tool);

120
static TileManager *
121
                gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
122
                                                    GimpItem          *item,
123
                                                    gboolean           mask_empty,
124
                                                    GimpDisplay       *display);
125

126 127
static void     gimp_transform_tool_halt           (GimpTransformTool *tr_tool);
static void     gimp_transform_tool_bounds         (GimpTransformTool *tr_tool,
128
                                                    GimpDisplay       *display);
129 130
static void     gimp_transform_tool_dialog         (GimpTransformTool *tr_tool);
static void     gimp_transform_tool_prepare        (GimpTransformTool *tr_tool,
131
                                                    GimpDisplay       *display);
132
static void     gimp_transform_tool_doit           (GimpTransformTool *tr_tool,
133
                                                    GimpDisplay       *display);
Michael Natterer's avatar
Michael Natterer committed
134
static void     gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool);
135
static void     gimp_transform_tool_grid_recalc    (GimpTransformTool *tr_tool);
Michael Natterer's avatar
Michael Natterer committed
136

137 138
static void     gimp_transform_tool_force_expose_preview (GimpTransformTool *tr_tool);

139
static void     gimp_transform_tool_response       (GtkWidget         *widget,
140
                                                    gint               response_id,
Michael Natterer's avatar
Michael Natterer committed
141
                                                    GimpTransformTool *tr_tool);
142

143 144 145 146 147 148
static void     gimp_transform_tool_notify_type    (GimpTransformOptions *options,
                                                    GParamSpec           *pspec,
                                                    GimpTransformTool    *tr_tool);
static void     gimp_transform_tool_notify_preview (GimpTransformOptions *options,
                                                    GParamSpec           *pspec,
                                                    GimpTransformTool    *tr_tool);
149 150


151
G_DEFINE_TYPE (GimpTransformTool, gimp_transform_tool, GIMP_TYPE_DRAW_TOOL)
152 153

#define parent_class gimp_transform_tool_parent_class
154

Nate Summers's avatar
Nate Summers committed
155 156 157 158

static void
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
{
159 160 161
  GObjectClass      *object_class = G_OBJECT_CLASS (klass);
  GimpToolClass     *tool_class   = GIMP_TOOL_CLASS (klass);
  GimpDrawToolClass *draw_class   = GIMP_DRAW_TOOL_CLASS (klass);
Nate Summers's avatar
Nate Summers committed
162

163
  object_class->constructor  = gimp_transform_tool_constructor;
164
  object_class->finalize     = gimp_transform_tool_finalize;
Nate Summers's avatar
Nate Summers committed
165

166
  tool_class->initialize     = gimp_transform_tool_initialize;
167
  tool_class->control        = gimp_transform_tool_control;
Nate Summers's avatar
Nate Summers committed
168 169 170
  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;
171
  tool_class->key_press      = gimp_transform_tool_key_press;
172
  tool_class->modifier_key   = gimp_transform_tool_modifier_key;
173
  tool_class->oper_update    = gimp_transform_tool_oper_update;
Nate Summers's avatar
Nate Summers committed
174
  tool_class->cursor_update  = gimp_transform_tool_cursor_update;
Nate Summers's avatar
Nate Summers committed
175 176

  draw_class->draw           = gimp_transform_tool_draw;
Michael Natterer's avatar
Michael Natterer committed
177 178

  klass->dialog              = NULL;
Michael Natterer's avatar
Michael Natterer committed
179
  klass->dialog_update       = NULL;
Michael Natterer's avatar
Michael Natterer committed
180 181 182
  klass->prepare             = NULL;
  klass->motion              = NULL;
  klass->recalc              = NULL;
183
  klass->transform           = gimp_transform_tool_real_transform;
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 *tr_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
  tool = GIMP_TOOL (tr_tool);
Michael Natterer's avatar
Michael Natterer committed
193

Michael Natterer's avatar
Michael Natterer committed
194 195
  gimp_tool_control_set_scroll_lock (tool->control, TRUE);
  gimp_tool_control_set_preserve    (tool->control, FALSE);
196 197 198 199
  gimp_tool_control_set_dirty_mask  (tool->control,
                                     GIMP_DIRTY_IMAGE_SIZE |
                                     GIMP_DIRTY_DRAWABLE   |
                                     GIMP_DIRTY_SELECTION);
Michael Natterer's avatar
Michael Natterer committed
200

Michael Natterer's avatar
Michael Natterer committed
201 202
  tr_tool->function = TRANSFORM_CREATING;
  tr_tool->original = NULL;
Nate Summers's avatar
Nate Summers committed
203 204

  for (i = 0; i < TRAN_INFO_SIZE; i++)
205
    {
Michael Natterer's avatar
Michael Natterer committed
206 207
      tr_tool->trans_info[i]     = 0.0;
      tr_tool->old_trans_info[i] = 0.0;
208
    }
Nate Summers's avatar
Nate Summers committed
209

210
  gimp_matrix3_identity (&tr_tool->transform);
211

212 213 214
  tr_tool->use_grid         = FALSE;
  tr_tool->use_handles      = FALSE;
  tr_tool->use_center       = FALSE;
215 216 217 218 219
  tr_tool->ngx              = 0;
  tr_tool->ngy              = 0;
  tr_tool->grid_coords      = NULL;
  tr_tool->tgrid_coords     = NULL;

220
  tr_tool->type             = GIMP_TRANSFORM_TYPE_LAYER;
221
  tr_tool->direction        = GIMP_TRANSFORM_FORWARD;
222

223 224
  tr_tool->undo_desc        = NULL;

225
  tr_tool->shell_desc       = NULL;
226
  tr_tool->progress_text    = _("Transforming");
227
  tr_tool->dialog           = NULL;
Nate Summers's avatar
Nate Summers committed
228 229
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
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;
250

251 252 253 254 255 256 257
      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);
258 259 260 261
      g_signal_connect_object (tool->tool_info->tool_options,
                               "notify::type",
                               G_CALLBACK (gimp_transform_tool_notify_preview),
                               tr_tool, 0);
262

263 264 265 266
      g_signal_connect_object (tool->tool_info->tool_options,
                               "notify::direction",
                               G_CALLBACK (gimp_transform_tool_notify_type),
                               tr_tool, 0);
267 268 269 270
      g_signal_connect_object (tool->tool_info->tool_options,
                               "notify::direction",
                               G_CALLBACK (gimp_transform_tool_notify_preview),
                               tr_tool, 0);
271

272
      g_signal_connect_object (tool->tool_info->tool_options,
273 274
                               "notify::preview-type",
                               G_CALLBACK (gimp_transform_tool_notify_preview),
275 276
                               tr_tool, 0);
      g_signal_connect_object (tool->tool_info->tool_options,
277 278
                               "notify::grid-type",
                               G_CALLBACK (gimp_transform_tool_notify_preview),
279
                               tr_tool, 0);
280
      g_signal_connect_object (tool->tool_info->tool_options,
281
                               "notify::grid-size",
282 283
                               G_CALLBACK (gimp_transform_tool_notify_preview),
                               tr_tool, 0);
284 285
    }

286 287 288 289 290
  g_signal_connect_object (tool->tool_info->tool_options,
                           "notify::constrain",
                           G_CALLBACK (gimp_transform_tool_dialog_update),
                           tr_tool, G_CONNECT_SWAPPED);

291 292 293
  return object;
}

294
static void
295
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
296
{
297
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (object);
298 299

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

305
  if (tr_tool->dialog)
306
    {
307 308
      gtk_widget_destroy (tr_tool->dialog);
      tr_tool->dialog = NULL;
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
    }

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

326
static gboolean
327
gimp_transform_tool_initialize (GimpTool    *tool,
328
                                GimpDisplay *display)
329 330 331
{
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);

332
  if (display != tool->display)
333
    {
334
      gint i;
335 336

      /*  Set the pointer to the active display  */
Michael Natterer's avatar
Michael Natterer committed
337
      tool->display  = display;
338
      tool->drawable = gimp_image_active_drawable (display->image);
339 340

      /*  Initialize the transform tool dialog */
341
      if (! tr_tool->dialog)
342 343 344 345 346 347
        gimp_transform_tool_dialog (tr_tool);

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

350
      gimp_transform_tool_prepare (tr_tool, display);
351 352

      /*  Recalculate the transform tool  */
353
      gimp_transform_tool_recalc (tr_tool, display);
354 355

      /*  start drawing the bounding box and handles...  */
356
      gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
357 358 359 360 361

      tr_tool->function = TRANSFORM_CREATING;

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

  return TRUE;
366 367
}

368
static void
369
gimp_transform_tool_control (GimpTool       *tool,
370
                             GimpToolAction  action,
371
                             GimpDisplay    *display)
372
{
373
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
374

375 376
  switch (action)
    {
377
    case GIMP_TOOL_ACTION_PAUSE:
378
      break;
379

380
    case GIMP_TOOL_ACTION_RESUME:
381 382
      gimp_transform_tool_bounds (tr_tool, display);
      gimp_transform_tool_recalc (tr_tool, display);
383
      break;
384

385
    case GIMP_TOOL_ACTION_HALT:
386
      gimp_transform_tool_halt (tr_tool);
387 388 389
      break;
    }

390
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
391 392 393
}

static void
394 395 396 397
gimp_transform_tool_button_press (GimpTool        *tool,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
398
                                  GimpDisplay     *display)
Nate Summers's avatar
Nate Summers committed
399
{
400
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
401

402
  if (tr_tool->function == TRANSFORM_CREATING)
403
    gimp_transform_tool_oper_update (tool, coords, state, TRUE, display);
404

405 406
  tr_tool->lastx = tr_tool->startx = coords->x;
  tr_tool->lasty = tr_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
407

408
  gimp_tool_control_activate (tool->control);
Nate Summers's avatar
Nate Summers committed
409 410
}

411
static void
412 413 414
gimp_transform_tool_button_release (GimpTool        *tool,
                                    GimpCoords      *coords,
                                    guint32          time,
415
                                    GdkModifierType  state,
416
                                    GimpDisplay     *display)
Nate Summers's avatar
Nate Summers committed
417
{
418
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
419
  gint               i;
Nate Summers's avatar
Nate Summers committed
420 421

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

  /*  if the 3rd button isn't pressed, transform the selected mask  */
426
  if (! (state & GDK_BUTTON3_MASK))
Nate Summers's avatar
Nate Summers committed
427 428
    {
      /* Shift-clicking is another way to approve the transform  */
429
      if ((state & GDK_SHIFT_MASK) || ! tr_tool->use_grid)
430
        {
431
          gimp_transform_tool_doit (tr_tool, display);
432
        }
Nate Summers's avatar
Nate Summers committed
433 434 435
    }
  else
    {
436
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
437

Michael Natterer's avatar
Michael Natterer committed
438 439 440
      /* get rid of preview artifacts left outside the drawable's area */
      gimp_transform_tool_expose_preview (tr_tool);

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

Michael Natterer's avatar
Michael Natterer committed
445
      /*  reget the selection bounds  */
446
      gimp_transform_tool_bounds (tr_tool, display);
Michael Natterer's avatar
Michael Natterer committed
447

Nate Summers's avatar
Nate Summers committed
448
      /*  recalculate the tool's transformation matrix  */
449
      gimp_transform_tool_recalc (tr_tool, display);
Nate Summers's avatar
Nate Summers committed
450

451
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
452
    }
453 454

  gimp_tool_control_halt (tool->control);
Nate Summers's avatar
Nate Summers committed
455 456
}

457
static void
458 459 460
gimp_transform_tool_motion (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
461
                            GdkModifierType  state,
462
                            GimpDisplay     *display)
Nate Summers's avatar
Nate Summers committed
463
{
464
  GimpTransformTool      *tr_tool = GIMP_TRANSFORM_TOOL (tool);
Michael Natterer's avatar
Michael Natterer committed
465
  GimpTransformToolClass *tr_tool_class;
Nate Summers's avatar
Nate Summers committed
466

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

471
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
472

Michael Natterer's avatar
Michael Natterer committed
473 474 475
  tr_tool->curx  = coords->x;
  tr_tool->cury  = coords->y;
  tr_tool->state = state;
Nate Summers's avatar
Nate Summers committed
476 477

  /*  recalculate the tool's transformation matrix  */
Michael Natterer's avatar
Michael Natterer committed
478 479 480 481
  tr_tool_class = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool);

  if (tr_tool_class->motion)
    {
482
      tr_tool_class->motion (tr_tool, display);
Nate Summers's avatar
Nate Summers committed
483

484 485
      gimp_transform_tool_expose_preview (tr_tool);

486
      gimp_transform_tool_recalc (tr_tool, display);
Michael Natterer's avatar
Michael Natterer committed
487 488 489 490
    }

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

492
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
493 494
}

495 496
#define RESPONSE_RESET 1

497
static gboolean
498 499
gimp_transform_tool_key_press (GimpTool    *tool,
                               GdkEventKey *kevent,
500
                               GimpDisplay *display)
501 502
{
  GimpTransformTool *trans_tool = GIMP_TRANSFORM_TOOL (tool);
503
  GimpDrawTool      *draw_tool  = GIMP_DRAW_TOOL (tool);
504

505
  if (display == draw_tool->display)
506 507 508
    {
      switch (kevent->keyval)
        {
509 510 511
        case GDK_KP_Enter:
        case GDK_Return:
          gimp_transform_tool_response (NULL, GTK_RESPONSE_OK, trans_tool);
512
          return TRUE;
513 514 515 516

        case GDK_Delete:
        case GDK_BackSpace:
          gimp_transform_tool_response (NULL, RESPONSE_RESET, trans_tool);
517
          return TRUE;
518 519 520 521

        case GDK_Escape:
          gimp_transform_tool_response (NULL, GTK_RESPONSE_CANCEL, trans_tool);
          return TRUE;
522 523
        }
    }
524 525

  return FALSE;
526 527
}

528 529 530 531 532
static void
gimp_transform_tool_modifier_key (GimpTool        *tool,
                                  GdkModifierType  key,
                                  gboolean         press,
                                  GdkModifierType  state,
533
                                  GimpDisplay     *display)
534
{
535
  GimpTransformOptions *options;
536

537
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
538

539
  if (key == GDK_CONTROL_MASK)
540 541 542
    g_object_set (options,
                  "constrain", ! options->constrain,
                  NULL);
543 544
}

545 546 547 548
static void
gimp_transform_tool_oper_update (GimpTool        *tool,
                                 GimpCoords      *coords,
                                 GdkModifierType  state,
549
                                 gboolean         proximity,
550
                                 GimpDisplay     *display)
551
{
552 553
  GimpTransformTool *tr_tool   = GIMP_TRANSFORM_TOOL (tool);
  GimpDrawTool      *draw_tool = GIMP_DRAW_TOOL (tool);
554

555 556 557
  tr_tool->function = TRANSFORM_HANDLE_NONE;

  if (display != tool->display)
558 559
    return;

560
  if (tr_tool->use_handles)
561 562 563 564
    {
      gdouble closest_dist;
      gdouble dist;

565
      closest_dist = gimp_draw_tool_calc_distance (draw_tool, display,
566 567
                                                   coords->x, coords->y,
                                                   tr_tool->tx1, tr_tool->ty1);
568
      tr_tool->function = TRANSFORM_HANDLE_NW;
569

570
      dist = gimp_draw_tool_calc_distance (draw_tool, display,
571 572 573
                                           coords->x, coords->y,
                                           tr_tool->tx2, tr_tool->ty2);
      if (dist < closest_dist)
574 575
        {
          closest_dist = dist;
576
          tr_tool->function = TRANSFORM_HANDLE_NE;
577
        }
578

579
      dist = gimp_draw_tool_calc_distance (draw_tool, display,
580 581 582
                                           coords->x, coords->y,
                                           tr_tool->tx3, tr_tool->ty3);
      if (dist < closest_dist)
583 584
        {
          closest_dist = dist;
585
          tr_tool->function = TRANSFORM_HANDLE_SW;
586
        }
587

588
      dist = gimp_draw_tool_calc_distance (draw_tool, display,
589 590 591
                                           coords->x, coords->y,
                                           tr_tool->tx4, tr_tool->ty4);
      if (dist < closest_dist)
592 593
        {
          closest_dist = dist;
594
          tr_tool->function = TRANSFORM_HANDLE_SE;
595
        }
596
    }
597

598 599 600 601 602 603 604 605 606 607
  if (tr_tool->use_center &&
      gimp_draw_tool_on_handle (draw_tool, display,
                                coords->x, coords->y,
                                GIMP_HANDLE_CIRCLE,
                                tr_tool->tcx, tr_tool->tcy,
                                HANDLE_SIZE, HANDLE_SIZE,
                                GTK_ANCHOR_CENTER,
                                FALSE))
    {
      tr_tool->function = TRANSFORM_HANDLE_CENTER;
608 609 610
    }
}

611
static void
612 613
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
614
                                   GdkModifierType  state,
615
                                   GimpDisplay     *display)
Nate Summers's avatar
Nate Summers committed
616
{
617 618
  GimpTransformTool    *tr_tool = GIMP_TRANSFORM_TOOL (tool);
  GimpTransformOptions *options;
Michael Natterer's avatar
Michael Natterer committed
619
  GimpCursorType        cursor;
620
  GimpCursorModifier    modifier = GIMP_CURSOR_MODIFIER_NONE;
Nate Summers's avatar
Nate Summers committed
621

622 623
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);

Michael Natterer's avatar
Michael Natterer committed
624 625
  cursor = gimp_tool_control_get_cursor (tool->control);

626
  if (tr_tool->use_handles)
Nate Summers's avatar
Nate Summers committed
627
    {
628 629 630
      switch (tr_tool->function)
        {
        case TRANSFORM_HANDLE_NW:
Michael Natterer's avatar
Michael Natterer committed
631
          cursor = GIMP_CURSOR_CORNER_TOP_LEFT;
632
          break;
Sven Neumann's avatar
Sven Neumann committed
633

634
        case TRANSFORM_HANDLE_NE:
Michael Natterer's avatar
Michael Natterer committed
635
          cursor = GIMP_CURSOR_CORNER_TOP_RIGHT;
636
          break;
637

638
        case TRANSFORM_HANDLE_SW:
Michael Natterer's avatar
Michael Natterer committed
639
          cursor = GIMP_CURSOR_CORNER_BOTTOM_LEFT;
640 641
          break;

642
        case TRANSFORM_HANDLE_SE:
Michael Natterer's avatar
Michael Natterer committed
643
          cursor = GIMP_CURSOR_CORNER_BOTTOM_RIGHT;
644
          break;
645

646
        default:
Michael Natterer's avatar
Michael Natterer committed
647 648
          cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
          break;
Michael Natterer's avatar
Michael Natterer committed
649
        }
650
    }
Michael Natterer's avatar
Michael Natterer committed
651

652 653 654
  if (tr_tool->use_center && tr_tool->function == TRANSFORM_HANDLE_CENTER)
    {
      modifier = GIMP_CURSOR_MODIFIER_MOVE;
Michael Natterer's avatar
Michael Natterer committed
655
    }
656

657 658 659 660 661 662 663 664 665 666 667 668
  switch (options->type)
    {
    case GIMP_TRANSFORM_TYPE_LAYER:
    case GIMP_TRANSFORM_TYPE_SELECTION:
      break;

    case GIMP_TRANSFORM_TYPE_PATH:
      if (! gimp_image_get_active_vectors (display->image))
        modifier = GIMP_CURSOR_MODIFIER_BAD;
      break;
    }

Michael Natterer's avatar
Michael Natterer committed
669
  gimp_tool_control_set_cursor          (tool->control, cursor);
670 671
  gimp_tool_control_set_cursor_modifier (tool->control, modifier);

672
  GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
Nate Summers's avatar
Nate Summers committed
673 674
}

675
static void
676
gimp_transform_tool_draw (GimpDrawTool *draw_tool)
Nate Summers's avatar
Nate Summers committed
677
{
678 679
  GimpTool             *tool    = GIMP_TOOL (draw_tool);
  GimpTransformTool    *tr_tool = GIMP_TRANSFORM_TOOL (draw_tool);
680
  GimpTransformOptions *options;
681
  gdouble               z1, z2, z3, z4;
Nate Summers's avatar
Nate Summers committed
682

683
  if (tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
684
    {
685
      options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
686

687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
      /*  draw the bounding box  */
      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);

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

      /*  Draw the grid (not for path transform since it looks ugly)  */

      if (tr_tool->type != GIMP_TRANSFORM_TYPE_PATH &&
          tr_tool->grid_coords                      &&
          tr_tool->tgrid_coords                     &&
          z1 * z2 > 0                               &&
          z3 * z4 > 0)
725
        {
726 727 728 729 730 731 732 733 734 735 736 737 738
          gint gci, i, k;

          k = tr_tool->ngx + tr_tool->ngy;

          for (i = 0, gci = 0; i < k; i++, gci += 4)
            {
              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);
            }
739
        }
Nate Summers's avatar
Nate Summers committed
740 741
    }

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

  /*  draw the center  */
772 773 774 775 776
  if (tr_tool->use_center)
    {
      gimp_draw_tool_draw_handle (draw_tool,
                                  GIMP_HANDLE_FILLED_CIRCLE,
                                  tr_tool->tcx, tr_tool->tcy,