gimptransformtool.c 52.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
 * 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 27 28

#include "libgimpmath/gimpmath.h"
#include "libgimpwidgets/gimpwidgets.h"

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

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

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

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

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

50
#include "display/gimpdisplay.h"
Michael Natterer's avatar
Michael Natterer committed
51
#include "display/gimpprogress.h"
52 53 54
#include "display/gimpdisplayshell.h"
#include "display/gimpdisplayshell-appearance.h"
#include "display/gimpdisplayshell-transform.h"
Nate Summers's avatar
Nate Summers committed
55

56 57 58 59
#ifdef __GNUC__
#warning FIXME #include "gui/gui-types.h"
#endif
#include "gui/gui-types.h"
60 61
#include "gui/info-dialog.h"

62
#include "gimptoolcontrol.h"
63
#include "gimptransformoptions.h"
64 65
#include "gimptransformtool.h"
#include "gimptransformtool-undo.h"
66

67
#include "gimp-intl.h"
Nate Summers's avatar
Nate Summers committed
68

69

70
#define HANDLE_SIZE 10
Michael Natterer's avatar
Michael Natterer committed
71

72

Michael Natterer's avatar
Michael Natterer committed
73 74 75 76 77
/*  local function prototypes  */

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

78 79 80
static GObject * gimp_transform_tool_constructor   (GType              type,
                                                    guint              n_params,
                                                    GObjectConstructParam *params);
81
static void     gimp_transform_tool_finalize       (GObject           *object);
Michael Natterer's avatar
Michael Natterer committed
82

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

120
static void     gimp_transform_tool_draw           (GimpDrawTool      *draw_tool);
Michael Natterer's avatar
Michael Natterer committed
121

122
static TileManager *
123
                gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
124
                                                    GimpItem          *item,
125 126
                                                    GimpDisplay       *gdisp);

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

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 149 150 151
static void     gimp_transform_tool_notify_type    (GimpTransformOptions *options,
                                                    GParamSpec           *pspec,
                                                    GimpTransformTool    *tr_tool);
static void     gimp_transform_tool_notify_grid    (GimpTransformOptions *options,
                                                    GParamSpec           *pspec,
                                                    GimpTransformTool    *tr_tool);
static void     gimp_transform_tool_notify_preview (GimpTransformOptions *options,
                                                    GParamSpec           *pspec,
                                                    GimpTransformTool    *tr_tool);
152

153
static GimpDrawToolClass *parent_class = NULL;
154

155 156

GType
Nate Summers's avatar
Nate Summers committed
157 158
gimp_transform_tool_get_type (void)
{
159
  static GType tool_type = 0;
Nate Summers's avatar
Nate Summers committed
160 161 162

  if (! tool_type)
    {
163
      static const GTypeInfo tool_info =
Nate Summers's avatar
Nate Summers committed
164 165
      {
        sizeof (GimpTransformToolClass),
166 167 168 169 170 171 172 173
        (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
174 175
      };

176
      tool_type = g_type_register_static (GIMP_TYPE_DRAW_TOOL,
177
                                          "GimpTransformTool",
178
                                          &tool_info, 0);
Nate Summers's avatar
Nate Summers committed
179 180 181 182 183 184 185 186
    }

  return tool_type;
}

static void
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
{
187
  GObjectClass      *object_class;
Nate Summers's avatar
Nate Summers committed
188 189
  GimpToolClass     *tool_class;
  GimpDrawToolClass *draw_class;
Nate Summers's avatar
Nate Summers committed
190

191 192 193
  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
194

195
  parent_class = g_type_class_peek_parent (klass);
Nate Summers's avatar
Nate Summers committed
196

197
  object_class->constructor  = gimp_transform_tool_constructor;
198
  object_class->finalize     = gimp_transform_tool_finalize;
Nate Summers's avatar
Nate Summers committed
199

200
  tool_class->initialize     = gimp_transform_tool_initialize;
201
  tool_class->control        = gimp_transform_tool_control;
Nate Summers's avatar
Nate Summers committed
202 203 204
  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;
205
  tool_class->key_press      = gimp_transform_tool_key_press;
206
  tool_class->modifier_key   = gimp_transform_tool_modifier_key;
207
  tool_class->oper_update    = gimp_transform_tool_oper_update;
Nate Summers's avatar
Nate Summers committed
208
  tool_class->cursor_update  = gimp_transform_tool_cursor_update;
Nate Summers's avatar
Nate Summers committed
209 210

  draw_class->draw           = gimp_transform_tool_draw;
Michael Natterer's avatar
Michael Natterer committed
211 212 213 214 215

  klass->dialog              = NULL;
  klass->prepare             = NULL;
  klass->motion              = NULL;
  klass->recalc              = NULL;
216
  klass->transform           = gimp_transform_tool_real_transform;
Nate Summers's avatar
Nate Summers committed
217 218 219
}

static void
Michael Natterer's avatar
Michael Natterer committed
220
gimp_transform_tool_init (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
221
{
Michael Natterer's avatar
Michael Natterer committed
222
  GimpTool *tool;
223
  gint      i;
Nate Summers's avatar
Nate Summers committed
224

Michael Natterer's avatar
Michael Natterer committed
225
  tool = GIMP_TOOL (tr_tool);
Michael Natterer's avatar
Michael Natterer committed
226

Michael Natterer's avatar
Michael Natterer committed
227 228 229
  gimp_tool_control_set_scroll_lock (tool->control, TRUE);
  gimp_tool_control_set_preserve    (tool->control, FALSE);

Michael Natterer's avatar
Michael Natterer committed
230 231
  tr_tool->function = TRANSFORM_CREATING;
  tr_tool->original = NULL;
Nate Summers's avatar
Nate Summers committed
232 233

  for (i = 0; i < TRAN_INFO_SIZE; i++)
234
    {
Michael Natterer's avatar
Michael Natterer committed
235 236
      tr_tool->trans_info[i]     = 0.0;
      tr_tool->old_trans_info[i] = 0.0;
237
    }
Nate Summers's avatar
Nate Summers committed
238

239
  gimp_matrix3_identity (&tr_tool->transform);
240

241 242 243 244 245 246 247
  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;

248
  tr_tool->type             = GIMP_TRANSFORM_TYPE_LAYER;
249
  tr_tool->direction        = GIMP_TRANSFORM_FORWARD;
250

251 252 253
  tr_tool->shell_desc       = NULL;
  tr_tool->progress_text    = _("Transforming...");
  tr_tool->info_dialog      = NULL;
Nate Summers's avatar
Nate Summers committed
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 290 291 292 293 294
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);
295 296 297 298
      g_signal_connect_object (tool->tool_info->tool_options,
                               "notify::show-preview",
                               G_CALLBACK (gimp_transform_tool_notify_preview),
                               tr_tool, 0);
299 300 301 302 303
    }

  return object;
}

304
static void
305
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
306
{
307
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (object);
308 309

  if (tr_tool->original)
310
    {
311
      tile_manager_unref (tr_tool->original);
312 313
      tr_tool->original = NULL;
    }
314

315
  if (tr_tool->info_dialog)
316
    {
317 318
      info_dialog_free (tr_tool->info_dialog);
      tr_tool->info_dialog = NULL;
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
    }

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

336
static gboolean
337
gimp_transform_tool_initialize (GimpTool    *tool,
338
                                GimpDisplay *gdisp)
339 340 341 342 343 344
{
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);

  if (gdisp != tool->gdisp)
    {
      GimpDrawable *drawable = gimp_image_active_drawable (gdisp->gimage);
345
      gint          i;
346 347 348 349

      if (GIMP_IS_LAYER (drawable) &&
          gimp_layer_get_mask (GIMP_LAYER (drawable)))
        {
350
          g_message (_("Transformations do not work on "
351
                       "layers that contain layer masks."));
352
          return FALSE;
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
        }

      /*  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++)
381
        tr_tool->old_trans_info[i] = tr_tool->trans_info[i];
382
    }
383 384

  return TRUE;
385 386
}

387
static void
388
gimp_transform_tool_control (GimpTool       *tool,
389 390
                             GimpToolAction  action,
                             GimpDisplay    *gdisp)
391
{
392
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
393

394 395 396 397
  switch (action)
    {
    case PAUSE:
      break;
398

399
    case RESUME:
Michael Natterer's avatar
Michael Natterer committed
400
      gimp_transform_tool_recalc (tr_tool, gdisp);
401
      break;
402

403
    case HALT:
404
      gimp_transform_tool_halt (tr_tool);
405
      return; /* don't upchain */
406
      break;
407

408 409 410 411
    default:
      break;
    }

Michael Natterer's avatar
Michael Natterer committed
412
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
413 414 415
}

static void
416 417 418 419
gimp_transform_tool_button_press (GimpTool        *tool,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
420
                                  GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
421
{
422
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
423

424 425
  if (tr_tool->function == TRANSFORM_CREATING && tr_tool->use_grid)
    gimp_transform_tool_oper_update (tool, coords, state, gdisp);
426

427 428
  tr_tool->lastx = tr_tool->startx = coords->x;
  tr_tool->lasty = tr_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
429

430
  gimp_tool_control_activate (tool->control);
Nate Summers's avatar
Nate Summers committed
431 432
}

433
static void
434 435 436
gimp_transform_tool_button_release (GimpTool        *tool,
                                    GimpCoords      *coords,
                                    guint32          time,
437 438
                                    GdkModifierType  state,
                                    GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
439
{
440
  GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
441
  gint               i;
Nate Summers's avatar
Nate Summers committed
442 443

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

  /*  if the 3rd button isn't pressed, transform the selected mask  */
448
  if (! (state & GDK_BUTTON3_MASK))
Nate Summers's avatar
Nate Summers committed
449 450
    {
      /* Shift-clicking is another way to approve the transform  */
451
      if ((state & GDK_SHIFT_MASK) || ! tr_tool->use_grid)
452 453 454
        {
          gimp_transform_tool_doit (tr_tool, gdisp);
        }
Nate Summers's avatar
Nate Summers committed
455 456 457
    }
  else
    {
458
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
459 460 461

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

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

467
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
468
    }
469 470

  gimp_tool_control_halt (tool->control);
Nate Summers's avatar
Nate Summers committed
471 472
}

473
static void
474 475 476
gimp_transform_tool_motion (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
477 478
                            GdkModifierType  state,
                            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
479
{
480
  GimpTransformTool      *tr_tool = GIMP_TRANSFORM_TOOL (tool);
Michael Natterer's avatar
Michael Natterer committed
481
  GimpTransformToolClass *tr_tool_class;
Nate Summers's avatar
Nate Summers committed
482

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

487
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
488

Michael Natterer's avatar
Michael Natterer committed
489 490 491
  tr_tool->curx  = coords->x;
  tr_tool->cury  = coords->y;
  tr_tool->state = state;
Nate Summers's avatar
Nate Summers committed
492 493

  /*  recalculate the tool's transformation matrix  */
Michael Natterer's avatar
Michael Natterer committed
494 495 496 497 498
  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
499

Michael Natterer's avatar
Michael Natterer committed
500 501 502 503 504 505
      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
506

507
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
508 509
}

510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
#define RESPONSE_RESET 1

static void
gimp_transform_tool_key_press (GimpTool    *tool,
                               GdkEventKey *kevent,
                               GimpDisplay *gdisp)
{
  GimpTransformTool *trans_tool = GIMP_TRANSFORM_TOOL (tool);
  GimpDrawTool      *draw_tool = GIMP_DRAW_TOOL (tool);

  if (gdisp == draw_tool->gdisp)
    {
      switch (kevent->keyval)
        {
          case GDK_KP_Enter:
          case GDK_Return:
            gimp_transform_tool_response (NULL, GTK_RESPONSE_OK, trans_tool);
            break;

          case GDK_Delete:
          case GDK_BackSpace:
            gimp_transform_tool_response (NULL, RESPONSE_RESET, trans_tool);
            break;

          default:
            break;
        }
    }
}

540 541 542 543 544 545 546
static void
gimp_transform_tool_modifier_key (GimpTool        *tool,
                                  GdkModifierType  key,
                                  gboolean         press,
                                  GdkModifierType  state,
                                  GimpDisplay     *gdisp)
{
547
  GimpTransformOptions *options;
548

549
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
550

551
  if (key == GDK_CONTROL_MASK)
552
    {
553
      g_object_set (options,
554 555
                    "constrain-1", ! options->constrain_1,
                    NULL);
556
    }
557
  else if (key == GDK_MOD1_MASK)
558
    {
559
      g_object_set (options,
560 561
                    "constrain-2", ! options->constrain_2,
                    NULL);
562 563 564
    }
}

565 566 567 568 569 570
static void
gimp_transform_tool_oper_update (GimpTool        *tool,
                                 GimpCoords      *coords,
                                 GdkModifierType  state,
                                 GimpDisplay     *gdisp)
{
571 572
  GimpTransformTool *tr_tool   = GIMP_TRANSFORM_TOOL (tool);
  GimpDrawTool      *draw_tool = GIMP_DRAW_TOOL (tool);
573

574 575 576
  if (! tr_tool->use_grid)
    return;

577 578 579 580 581 582 583 584 585 586 587 588 589 590
  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)
591 592 593 594
        {
          closest_dist = dist;
          tr_tool->function = TRANSFORM_HANDLE_2;
        }
595 596 597 598 599

      dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                           coords->x, coords->y,
                                           tr_tool->tx3, tr_tool->ty3);
      if (dist < closest_dist)
600 601 602 603
        {
          closest_dist = dist;
          tr_tool->function = TRANSFORM_HANDLE_3;
        }
604 605 606 607 608

      dist = gimp_draw_tool_calc_distance (draw_tool, gdisp,
                                           coords->x, coords->y,
                                           tr_tool->tx4, tr_tool->ty4);
      if (dist < closest_dist)
609 610 611 612
        {
          closest_dist = dist;
          tr_tool->function = TRANSFORM_HANDLE_4;
        }
613 614 615 616 617

      if (gimp_draw_tool_on_handle (draw_tool, gdisp,
                                    coords->x, coords->y,
                                    GIMP_HANDLE_CIRCLE,
                                    tr_tool->tcx, tr_tool->tcy,
618
                                    HANDLE_SIZE, HANDLE_SIZE,
619 620
                                    GTK_ANCHOR_CENTER,
                                    FALSE))
621 622 623
        {
          tr_tool->function = TRANSFORM_HANDLE_CENTER;
        }
624 625 626
    }
}

627
static void
628 629
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
630 631
                                   GdkModifierType  state,
                                   GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
632
{
633
  GimpTransformTool    *tr_tool = GIMP_TRANSFORM_TOOL (tool);
634
  GimpTransformOptions *options;
635

636
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
Nate Summers's avatar
Nate Summers committed
637

Michael Natterer's avatar
Michael Natterer committed
638
  if (tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
639
    {
640
      GimpChannel        *selection = gimp_image_get_mask (gdisp->gimage);
641 642
      GimpCursorType      cursor    = GDK_TOP_LEFT_ARROW;
      GimpCursorModifier  modifier  = GIMP_CURSOR_MODIFIER_NONE;
643

644
      switch (options->type)
Michael Natterer's avatar
Michael Natterer committed
645
        {
646 647
        case GIMP_TRANSFORM_TYPE_LAYER:
          {
648
            GimpDrawable *drawable = gimp_image_active_drawable (gdisp->gimage);
649 650 651 652 653 654

            if (drawable)
              {
                if (GIMP_IS_LAYER (drawable) &&
                    gimp_layer_get_mask (GIMP_LAYER (drawable)))
                  {
655
                    cursor = GIMP_CURSOR_BAD;
656 657 658
                  }
                else if (gimp_display_coords_in_active_drawable (gdisp, coords))
                  {
659 660
                    if (gimp_channel_is_empty (selection) ||
                        gimp_channel_value (selection, coords->x, coords->y))
661
                      {
662
                        cursor = GIMP_CURSOR_MOUSE;
663 664 665 666 667 668 669
                      }
                  }
              }
          }
          break;

        case GIMP_TRANSFORM_TYPE_SELECTION:
670 671
          if (gimp_channel_is_empty (selection) ||
              gimp_channel_value (selection, coords->x, coords->y))
Michael Natterer's avatar
Michael Natterer committed
672
            {
673
              cursor = GIMP_CURSOR_MOUSE;
Michael Natterer's avatar
Michael Natterer committed
674
            }
675 676 677 678
          break;

        case GIMP_TRANSFORM_TYPE_PATH:
          if (gimp_image_get_active_vectors (gdisp->gimage))
679
            cursor = GIMP_CURSOR_MOUSE;
680
          else
681
            cursor = GIMP_CURSOR_BAD;
682
          break;
Michael Natterer's avatar
Michael Natterer committed
683
        }
684

Michael Natterer's avatar
Michael Natterer committed
685 686
      if (tr_tool->use_center && tr_tool->function == TRANSFORM_HANDLE_CENTER)
        {
687
          modifier = GIMP_CURSOR_MODIFIER_MOVE;
Michael Natterer's avatar
Michael Natterer committed
688 689
        }

690 691
      gimp_tool_control_set_cursor          (tool->control, cursor);
      gimp_tool_control_set_cursor_modifier (tool->control, modifier);
Michael Natterer's avatar
Michael Natterer committed
692
    }
693 694

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

697
static void
698
gimp_transform_tool_draw (GimpDrawTool *draw_tool)
Nate Summers's avatar
Nate Summers committed
699
{
700 701
  GimpTool             *tool    = GIMP_TOOL (draw_tool);
  GimpTransformTool    *tr_tool = GIMP_TRANSFORM_TOOL (draw_tool);
702
  GimpTransformOptions *options;
703
  gdouble               z1, z2, z3, z4;
Nate Summers's avatar
Nate Summers committed
704

705 706 707
  if (! tr_tool->use_grid)
    return;

708
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
709

Nate Summers's avatar
Nate Summers committed
710
  /*  draw the bounding box  */
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
  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
727

728 729
  /* We test if the transformed polygon is convex.
   * if z1 and z2 have the same sign as well as z3 and z4
730 731
   * the polygon is convex.
   */
732 733 734 735 736 737 738 739
  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));
740

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

743 744 745
  if (tr_tool->type != GIMP_TRANSFORM_TYPE_PATH &&
      tr_tool->grid_coords                      &&
      tr_tool->tgrid_coords                     &&
746 747
      z1 * z2 > 0                               &&
      z3 * z4 > 0)
Nate Summers's avatar
Nate Summers committed
748
    {
749 750
      gint gci, i, k;

Nate Summers's avatar
Nate Summers committed
751
      k = tr_tool->ngx + tr_tool->ngy;
752

753
      for (i = 0, gci = 0; i < k; i++, gci += 4)
754
        {
755 756 757 758 759 760
          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);
761
        }
Nate Summers's avatar
Nate Summers committed
762 763 764
    }

  /*  draw the tool handles  */
765 766 767
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx1, tr_tool->ty1,
768
                              HANDLE_SIZE, HANDLE_SIZE,
769 770 771 772 773
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx2, tr_tool->ty2,
774
                              HANDLE_SIZE, HANDLE_SIZE,
775 776 777 778 779
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx3, tr_tool->ty3,
780
                              HANDLE_SIZE, HANDLE_SIZE,
781 782 783 784 785
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx4, tr_tool->ty4,
786
                              HANDLE_SIZE, HANDLE_SIZE,
787 788
                              GTK_ANCHOR_CENTER,
                              FALSE);
Nate Summers's avatar
Nate Summers committed
789 790

  /*  draw the center  */
791 792 793 794 795
  if (tr_tool->use_center)
    {
      gimp_draw_tool_draw_handle (draw_tool,
                                  GIMP_HANDLE_FILLED_CIRCLE,
                                  tr_tool->tcx, tr_tool->tcy,
796
                                  HANDLE_SIZE, HANDLE_SIZE,
797 798 799
                                  GTK_ANCHOR_CENTER,
                                  FALSE);
    }
Nate Summers's avatar
Nate Summers committed
800

801
  if (tr_tool->type == GIMP_TRANSFORM_TYPE_PATH)
Nate Summers's avatar
Nate Summers committed
802
    {
803 804 805
      GimpVectors *vectors;
      GimpStroke  *stroke = NULL;
      GimpMatrix3  matrix = tr_tool->transform;
806

807 808 809
      vectors = gimp_image_get_active_vectors (tool->gdisp->gimage);

      if (vectors)
810
        {
811 812 813 814 815 816 817 818 819 820
          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);

821
              if (coords && coords->len)
822
                {
823 824
                  gint i;

825 826 827 828 829 830 831 832 833
                  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);
                    }

834 835 836 837
                  gimp_draw_tool_draw_strokes (draw_tool,
                                               &g_array_index (coords,
                                                               GimpCoords, 0),
                                               coords->len, FALSE, FALSE);
838
                }
839 840 841

              if (coords)
                g_array_free (coords, TRUE);
842
            }
843
        }
Nate Summers's avatar
Nate Summers committed
844 845 846
    }
}

847 848
static TileManager *
gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
849
                                    GimpItem          *active_item,
850 851
                                    GimpDisplay       *gdisp)
{
852
  GimpTool             *tool = GIMP_TOOL (tr_tool);