gimptransformtool.c 38.2 KB
Newer Older
Nate Summers's avatar
Nate Summers committed
1
/* The GIMP -- an image manipulation program
Nate Summers's avatar
Nate Summers committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 * Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <stdlib.h>

#include <gtk/gtk.h>

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

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

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

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

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

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

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

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

55
#include "gimptransformtool.h"
56
#include "gimptransformoptions.h"
57
#include "tool_manager.h"
58

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

#include "libgimp/gimpintl.h"

64

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

67

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

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

static void   gimp_transform_tool_finalize         (GObject           *object);

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

static void   gimp_transform_tool_draw             (GimpDrawTool      *draw_tool);

109 110 111 112
static TileManager *
              gimp_transform_tool_real_transform   (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);

Michael Natterer's avatar
Michael Natterer committed
113
static void   gimp_transform_tool_reset            (GimpTransformTool *tr_tool);
Michael Natterer's avatar
Michael Natterer committed
114 115
static void   gimp_transform_tool_bounds           (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
116 117 118
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
119 120 121 122 123 124 125
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);

static void   transform_reset_callback             (GtkWidget         *widget,
Michael Natterer's avatar
Michael Natterer committed
126 127 128 129 130
                                                    GimpTransformTool *tr_tool);
static void   transform_cancel_callback            (GtkWidget         *widget,
                                                    GimpTransformTool *tr_tool);
static void   transform_ok_callback                (GtkWidget         *widget,
                                                    GimpTransformTool *tr_tool);
131

132 133 134 135 136 137 138
static void   gimp_transform_tool_notify_grid   (GimpTransformOptions *options,
                                                 GParamSpec           *pspec,
                                                 GimpTransformTool    *tr_tool);
static void   gimp_transform_tool_notify_path   (GimpTransformOptions *options,
                                                 GParamSpec           *pspec,
                                                 GimpTransformTool    *tr_tool);

139

140
static GimpDrawToolClass *parent_class = NULL;
141

142 143

GType
Nate Summers's avatar
Nate Summers committed
144 145
gimp_transform_tool_get_type (void)
{
146
  static GType tool_type = 0;
Nate Summers's avatar
Nate Summers committed
147 148 149

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

163 164 165
      tool_type = g_type_register_static (GIMP_TYPE_DRAW_TOOL,
					  "GimpTransformTool", 
                                          &tool_info, 0);
Nate Summers's avatar
Nate Summers committed
166 167 168 169 170 171 172 173
    }

  return tool_type;
}

static void
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
{
174
  GObjectClass      *object_class;
Nate Summers's avatar
Nate Summers committed
175 176
  GimpToolClass     *tool_class;
  GimpDrawToolClass *draw_class;
Nate Summers's avatar
Nate Summers committed
177

178 179 180
  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
181

182
  parent_class = g_type_class_peek_parent (klass);
Nate Summers's avatar
Nate Summers committed
183

184
  object_class->finalize     = gimp_transform_tool_finalize;
Nate Summers's avatar
Nate Summers committed
185

186
  tool_class->control        = gimp_transform_tool_control;
Nate Summers's avatar
Nate Summers committed
187 188 189
  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;
190
  tool_class->modifier_key   = gimp_transform_tool_modifier_key;
191
  tool_class->oper_update    = gimp_transform_tool_oper_update;
Nate Summers's avatar
Nate Summers committed
192
  tool_class->cursor_update  = gimp_transform_tool_cursor_update;
Nate Summers's avatar
Nate Summers committed
193 194

  draw_class->draw           = gimp_transform_tool_draw;
Michael Natterer's avatar
Michael Natterer committed
195 196 197 198 199

  klass->dialog              = NULL;
  klass->prepare             = NULL;
  klass->motion              = NULL;
  klass->recalc              = NULL;
200
  klass->transform           = gimp_transform_tool_real_transform;
Nate Summers's avatar
Nate Summers committed
201 202 203
}

static void
Michael Natterer's avatar
Michael Natterer committed
204
gimp_transform_tool_init (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
205
{
Michael Natterer's avatar
Michael Natterer committed
206
  GimpTool *tool;
207
  gint      i;
Nate Summers's avatar
Nate Summers committed
208

Michael Natterer's avatar
Michael Natterer committed
209
  tool = GIMP_TOOL (tr_tool);
Michael Natterer's avatar
Michael Natterer committed
210

Michael Natterer's avatar
Michael Natterer committed
211 212 213
  gimp_tool_control_set_scroll_lock (tool->control, TRUE);
  gimp_tool_control_set_preserve    (tool->control, FALSE);

Michael Natterer's avatar
Michael Natterer committed
214 215
  tr_tool->function = TRANSFORM_CREATING;
  tr_tool->original = NULL;
Nate Summers's avatar
Nate Summers committed
216 217

  for (i = 0; i < TRAN_INFO_SIZE; i++)
218
    {
Michael Natterer's avatar
Michael Natterer committed
219 220
      tr_tool->trans_info[i]     = 0.0;
      tr_tool->old_trans_info[i] = 0.0;
221
    }
Nate Summers's avatar
Nate Summers committed
222

Michael Natterer's avatar
Michael Natterer committed
223
  gimp_matrix3_identity (tr_tool->transform);
224

225 226 227 228 229 230 231 232 233
  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;

  tr_tool->notify_connected = FALSE;
  tr_tool->show_path        = FALSE;
234

235 236 237
  tr_tool->shell_desc       = NULL;
  tr_tool->progress_text    = _("Transforming...");
  tr_tool->info_dialog      = NULL;
Nate Summers's avatar
Nate Summers committed
238 239
}

240
static void
241
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
242
{
243
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
244

245 246 247
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  if (tr_tool->original)
248 249 250 251
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
252

253
  if (tr_tool->info_dialog)
254
    {
255 256
      info_dialog_free (tr_tool->info_dialog);
      tr_tool->info_dialog = NULL;
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    }

  if (tr_tool->grid_coords)
    {
      g_free (tr_tool->grid_coords);
      tr_tool->grid_coords = NULL;
    }

  if (tr_tool->tgrid_coords)
    {
      g_free (tr_tool->tgrid_coords);
      tr_tool->tgrid_coords = NULL;
    }

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
275 276 277
gimp_transform_tool_control (GimpTool       *tool,
			     GimpToolAction  action,
			     GimpDisplay    *gdisp)
278
{
Michael Natterer's avatar
Michael Natterer committed
279
  GimpTransformTool *tr_tool;
280

Michael Natterer's avatar
Michael Natterer committed
281
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
282

283 284 285 286
  switch (action)
    {
    case PAUSE:
      break;
287

288
    case RESUME:
Michael Natterer's avatar
Michael Natterer committed
289
      gimp_transform_tool_recalc (tr_tool, gdisp);
290
      break;
291

292
    case HALT:
Michael Natterer's avatar
Michael Natterer committed
293
      gimp_transform_tool_reset (tr_tool);
294
      return; /* don't upchain */
295
      break;
296

297 298 299 300
    default:
      break;
    }

Michael Natterer's avatar
Michael Natterer committed
301
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
302 303 304
}

static void
305 306 307 308 309
gimp_transform_tool_button_press (GimpTool        *tool,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
			          GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
310
{
Michael Natterer's avatar
Michael Natterer committed
311
  GimpTransformTool *tr_tool;
312
  GimpDrawTool      *draw_tool;
Michael Natterer's avatar
Michael Natterer committed
313 314
  GimpDrawable      *drawable;
  gint               off_x, off_y;
Nate Summers's avatar
Nate Summers committed
315

Michael Natterer's avatar
Michael Natterer committed
316
  tr_tool   = GIMP_TRANSFORM_TOOL (tool);
317
  draw_tool = GIMP_DRAW_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
318 319 320

  drawable = gimp_image_active_drawable (gdisp->gimage);

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
  if (! tr_tool->notify_connected)
    {
      tr_tool->show_path =
        GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options)->show_path;

      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);
      g_signal_connect_object (tool->tool_info->tool_options,
                               "notify::show-path",
                               G_CALLBACK (gimp_transform_tool_notify_path),
                               tr_tool, 0);

      tr_tool->notify_connected = TRUE;
    }

342 343 344 345 346 347 348 349 350
  if (gdisp != tool->gdisp)
    {
      /*  Initialisation stuff: if the cursor is clicked inside the current
       *  selection, show the bounding box and handles...
       */
      gimp_drawable_offsets (drawable, &off_x, &off_y);

      if (coords->x >= off_x &&
          coords->y >= off_y &&
Michael Natterer's avatar
Michael Natterer committed
351 352 353 354 355
          coords->x < (off_x + gimp_drawable_width (drawable))  &&
          coords->y < (off_y + gimp_drawable_height (drawable)) &&

          (gimp_image_mask_is_empty (gdisp->gimage) ||
           gimp_image_mask_value (gdisp->gimage, coords->x, coords->y)))
356
        {
Michael Natterer's avatar
Michael Natterer committed
357 358
          if (GIMP_IS_LAYER (drawable) &&
              gimp_layer_get_mask (GIMP_LAYER (drawable)))
359
            {
Michael Natterer's avatar
Michael Natterer committed
360 361
              g_message (_("Transformations do not work on\n"
                           "layers that contain layer masks."));
362
              gimp_tool_control_halt (tool->control);
Michael Natterer's avatar
Michael Natterer committed
363 364
              return;
            }
365

Michael Natterer's avatar
Michael Natterer committed
366 367 368 369 370 371
          /*  If the tool is already active, clear the current state
           *  and reset
           */
          if (gimp_tool_control_is_active (tool->control))
            {
              g_warning ("%s: tool_already ACTIVE", G_GNUC_FUNCTION);
372

Michael Natterer's avatar
Michael Natterer committed
373 374
              gimp_transform_tool_reset (tr_tool);
            }
375

Michael Natterer's avatar
Michael Natterer committed
376 377 378 379
          /*  Set the pointer to the active display  */
          tool->gdisp    = gdisp;
          tool->drawable = drawable;
          gimp_tool_control_activate (tool->control);
380

Michael Natterer's avatar
Michael Natterer committed
381 382 383 384 385
          /*  Find the transform bounds for some tools (like scale,
           *  perspective) that actually need the bounds for
           *  initializing
           */
          gimp_transform_tool_bounds (tr_tool, gdisp);
386

Michael Natterer's avatar
Michael Natterer committed
387 388 389
          /*  Initialize the transform tool */
          if (! tr_tool->info_dialog)
            gimp_transform_tool_dialog (tr_tool);
390

Michael Natterer's avatar
Michael Natterer committed
391
          gimp_transform_tool_prepare (tr_tool, gdisp);
392

Michael Natterer's avatar
Michael Natterer committed
393 394
          /*  Recalculate the transform tool  */
          gimp_transform_tool_recalc (tr_tool, gdisp);
395

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

Michael Natterer's avatar
Michael Natterer committed
399 400 401 402
          /*  find which handle we're dragging  */
          gimp_transform_tool_oper_update (tool, coords, state, gdisp);

          tr_tool->function = TRANSFORM_CREATING;
403 404 405
        }
    }

406 407
  if (tr_tool->function == TRANSFORM_CREATING &&
      gimp_tool_control_is_active (tool->control))
Nate Summers's avatar
Nate Summers committed
408
    {
409 410
      gint i;

Nate Summers's avatar
Nate Summers committed
411 412
      /*  Save the current transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
413
	tr_tool->old_trans_info[i] = tr_tool->trans_info[i];
Nate Summers's avatar
Nate Summers committed
414 415 416 417 418 419
    }

  /*  if we have already displayed the bounding box and handles,
   *  check to make sure that the display which currently owns the
   *  tool is the one which just received the button pressed event
   */
Michael Natterer's avatar
Michael Natterer committed
420
  if (gdisp == tool->gdisp)
Nate Summers's avatar
Nate Summers committed
421 422
    {
      /*  Save the current pointer position  */
Michael Natterer's avatar
Michael Natterer committed
423 424
      tr_tool->lastx = tr_tool->startx = coords->x;
      tr_tool->lasty = tr_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
425

426
      gimp_tool_control_activate (tool->control);
427
    }
Nate Summers's avatar
Nate Summers committed
428 429
}

430
static void
431 432 433 434 435
gimp_transform_tool_button_release (GimpTool        *tool,
                                    GimpCoords      *coords,
                                    guint32          time,
			            GdkModifierType  state,
			            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
436
{
Michael Natterer's avatar
Michael Natterer committed
437
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
438
  gint               i;
Nate Summers's avatar
Nate Summers committed
439

Michael Natterer's avatar
Michael Natterer committed
440
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
441 442

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

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

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

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

472
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
473 474 475

      /* Update the paths preview */
      path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
476
				   tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
477 478 479
    }
}

480
static void
481 482 483 484 485
gimp_transform_tool_motion (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
		            GdkModifierType  state,
		            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
486
{
Michael Natterer's avatar
Michael Natterer committed
487 488
  GimpTransformToolClass *tr_tool_class;
  GimpTransformTool      *tr_tool;
Nate Summers's avatar
Nate Summers committed
489

Michael Natterer's avatar
Michael Natterer committed
490
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
491

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

496
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
497

Michael Natterer's avatar
Michael Natterer committed
498 499 500
  tr_tool->curx  = coords->x;
  tr_tool->cury  = coords->y;
  tr_tool->state = state;
Nate Summers's avatar
Nate Summers committed
501 502

  /*  recalculate the tool's transformation matrix  */
Michael Natterer's avatar
Michael Natterer committed
503 504 505 506 507
  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
508

Michael Natterer's avatar
Michael Natterer committed
509 510 511 512 513 514
      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
515

516
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
517 518
}

519 520 521 522 523 524 525
static void
gimp_transform_tool_modifier_key (GimpTool        *tool,
                                  GdkModifierType  key,
                                  gboolean         press,
                                  GdkModifierType  state,
                                  GimpDisplay     *gdisp)
{
526
  GimpTransformOptions *options;
527

528
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
529

530
  if (key == GDK_CONTROL_MASK)
531
    {
532 533 534
      g_object_set (G_OBJECT (options),
                    "constrain-1", ! options->constrain_1,
                    NULL);
535
    }
536
  else if (key == GDK_MOD1_MASK)
537
    {
538 539 540
      g_object_set (G_OBJECT (options),
                    "constrain-2", ! options->constrain_2,
                    NULL);
541 542 543
    }
}

544 545 546 547 548 549 550 551 552 553 554 555
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);

556 557 558
  if (! tr_tool->use_grid)
    return;

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 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
  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,
600
                                    HANDLE_SIZE, HANDLE_SIZE,
601 602 603 604 605 606 607 608
                                    GTK_ANCHOR_CENTER,
                                    FALSE))
	{
	  tr_tool->function = TRANSFORM_HANDLE_CENTER;
	}
    }
}

609
static void
610 611 612 613
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
			           GdkModifierType  state,
			           GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
614
{
615 616 617 618
  GimpTransformTool  *tr_tool;
  GimpDrawable       *drawable;

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

Michael Natterer's avatar
Michael Natterer committed
620
  if (tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
621
    {
Michael Natterer's avatar
Michael Natterer committed
622 623
      GdkCursorType      ctype     = GDK_TOP_LEFT_ARROW;
      GimpCursorModifier cmodifier = GIMP_CURSOR_MODIFIER_NONE;
624

Michael Natterer's avatar
Michael Natterer committed
625 626 627
     if ((drawable = gimp_image_active_drawable (gdisp->gimage)))
        {
          gint off_x, off_y;
628

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

Michael Natterer's avatar
Michael Natterer committed
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
          if (GIMP_IS_LAYER (drawable) &&
              gimp_layer_get_mask (GIMP_LAYER (drawable)))
            {
              ctype = GIMP_BAD_CURSOR;
            }
          else if (coords->x >= off_x &&
                   coords->y >= off_y &&
                   coords->x < (off_x + drawable->width) &&
                   coords->y < (off_y + drawable->height))
            {
              if (gimp_image_mask_is_empty (gdisp->gimage) ||
                  gimp_image_mask_value (gdisp->gimage, coords->x, coords->y))
                {
                  ctype = GIMP_MOUSE_CURSOR;
                }
            }
        }
648

Michael Natterer's avatar
Michael Natterer committed
649 650 651 652 653 654 655 656
      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);
    }
657 658

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

661
static void
662
gimp_transform_tool_draw (GimpDrawTool *draw_tool)
Nate Summers's avatar
Nate Summers committed
663
{
664 665 666
  GimpTransformTool    *tr_tool;
  GimpTransformOptions *options;
  gint                  i, k, gci;
667 668

  tr_tool = GIMP_TRANSFORM_TOOL (draw_tool);
669
  options = GIMP_TRANSFORM_OPTIONS (GIMP_TOOL (draw_tool)->tool_info->tool_options);
Nate Summers's avatar
Nate Summers committed
670

671 672 673
  if (! tr_tool->use_grid)
    return;

Nate Summers's avatar
Nate Summers committed
674
  /*  draw the bounding box  */
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
  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
691 692 693

  /*  Draw the grid */

694
  if ((tr_tool->grid_coords != NULL) && (tr_tool->tgrid_coords != NULL))
Nate Summers's avatar
Nate Summers committed
695 696
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
697
      k = tr_tool->ngx + tr_tool->ngy;
698

Nate Summers's avatar
Nate Summers committed
699 700
      for (i = 0; i < k; i++)
	{
701 702 703 704 705 706
          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
707 708 709 710 711
	  gci += 4;
	}
    }

  /*  draw the tool handles  */
712 713 714
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx1, tr_tool->ty1,
715
                              HANDLE_SIZE, HANDLE_SIZE,
716 717 718 719 720
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx2, tr_tool->ty2,
721
                              HANDLE_SIZE, HANDLE_SIZE,
722 723 724 725 726
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx3, tr_tool->ty3,
727
                              HANDLE_SIZE, HANDLE_SIZE,
728 729 730 731 732
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx4, tr_tool->ty4,
733
                              HANDLE_SIZE, HANDLE_SIZE,
734 735
                              GTK_ANCHOR_CENTER,
                              FALSE);
Nate Summers's avatar
Nate Summers committed
736 737

  /*  draw the center  */
738 739 740 741 742
  if (tr_tool->use_center)
    {
      gimp_draw_tool_draw_handle (draw_tool,
                                  GIMP_HANDLE_FILLED_CIRCLE,
                                  tr_tool->tcx, tr_tool->tcy,
743
                                  HANDLE_SIZE, HANDLE_SIZE,
744 745 746
                                  GTK_ANCHOR_CENTER,
                                  FALSE);
    }
Nate Summers's avatar
Nate Summers committed
747

748
  if (tr_tool->show_path)
Nate Summers's avatar
Nate Summers committed
749 750 751
    {
      GimpMatrix3 tmp_matrix;

Michael Natterer's avatar
Michael Natterer committed
752
      if (options->direction == GIMP_TRANSFORM_BACKWARD)
Nate Summers's avatar
Nate Summers committed
753
	{
Nate Summers's avatar
Nate Summers committed
754
	  gimp_matrix3_invert (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
755 756 757
	}
      else
	{
Nate Summers's avatar
Nate Summers committed
758
	  gimp_matrix3_duplicate (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
759 760
	}

761 762
      path_transform_draw_current (GIMP_TOOL (draw_tool)->gdisp,
                                   draw_tool, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
763 764 765
    }
}

766 767 768 769
static TileManager *
gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
                                    GimpDisplay       *gdisp)
{
770 771 772 773 774
  GimpTool             *tool;
  GimpDrawable         *drawable;
  GimpTransformOptions *options;
  GimpProgress         *progress;
  TileManager          *ret;
775

776 777
  tool    = GIMP_TOOL (tr_tool);
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
778 779 780 781 782 783 784

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

785 786 787
  drawable = gimp_image_active_drawable (gdisp->gimage);

  ret = gimp_drawable_transform_tiles_affine (drawable,
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
                                              tr_tool->original,
                                              options->interpolation,
                                              options->clip,
                                              tr_tool->transform,
                                              options->direction,
                                              progress ?
                                              gimp_progress_update_and_flush : 
                                              NULL,
                                              progress);

  if (progress)
    gimp_progress_end (progress);

  return ret;
}

Michael Natterer's avatar
Michael Natterer committed
804 805 806 807
static void
gimp_transform_tool_doit (GimpTransformTool  *tr_tool,
		          GimpDisplay        *gdisp)
{
Michael Natterer's avatar
Michael Natterer committed
808 809 810 811
  GimpTool    *tool;
  TileManager *new_tiles;
  GSList      *path_undo;
  gboolean     new_layer;
Michael Natterer's avatar
Michael Natterer committed
812 813 814 815 816 817 818 819 820 821 822

  gimp_set_busy (gdisp->gimage->gimp);

  tool = GIMP_TOOL (tr_tool);

  /* undraw the tool before we muck around with the transform matrix */
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tr_tool));

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

  /*  Start a transform undo group  */
Michael Natterer's avatar
Michael Natterer committed
826
  undo_push_group_start (gdisp->gimage, TRANSFORM_UNDO_GROUP);
Michael Natterer's avatar
Michael Natterer committed
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841

  /* With the old UI, if original is NULL, then this is the
   * first transformation. In the new UI, it is always so, right?
   */
  g_assert (tr_tool->original == NULL);

  /*  Copy the current selection to the transform tool's private
   *  selection pointer, so that the original source can be repeatedly
   *  modified.
   */
  tool->drawable = gimp_image_active_drawable (gdisp->gimage);

  tr_tool->original = gimp_drawable_transform_cut (tool->drawable,
                                                   &new_layer);

Michael Natterer's avatar
Michael Natterer committed
842
  path_undo = path_transform_start_undo (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
843 844 845

  /*  Send the request for the transformation to the tool...
   */
846 847
  new_tiles = GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->transform (tr_tool,
                                                                  gdisp);
Michael Natterer's avatar
Michael Natterer committed
848

Michael Natterer's avatar
Michael Natterer committed
849
  gimp_transform_tool_prepare (tr_tool, gdisp);
Michael Natterer's avatar
Michael Natterer committed
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
  gimp_transform_tool_recalc (tr_tool, gdisp);

  if (new_tiles)
    {
      /*  paste the new transformed image to the gimage...also implement
       *  undo...
       */
      /*  FIXME: we should check if the drawable is still valid  */
      gimp_drawable_transform_paste (tool->drawable,
                                     new_tiles,
                                     new_layer);

      /*  Make a note of the new current drawable (since we may have
       *  a floating selection, etc now.
       */
      tool->drawable = gimp_image_active_drawable (gdisp->gimage);

Michael Natterer's avatar
Michael Natterer committed
867 868 869 870 871 872
      undo_push_transform (gdisp->gimage,
                           tool->ID,
                           G_TYPE_FROM_INSTANCE (tool),
                           tr_tool->old_trans_info,
                           NULL,
                           path_undo);
Michael Natterer's avatar
Michael Natterer committed
873 874 875 876 877 878 879 880
    }

  /*  push the undo group end  */
  undo_push_group_end (gdisp->gimage);

  /*  We're done dirtying the image, and would like to be restarted
   *  if the image gets dirty while the tool exists
   */
881
  gimp_tool_control_set_preserve (tool->control, FALSE);
Michael Natterer's avatar
Michael Natterer committed
882 883 884

  gimp_unset_busy (gdisp->gimage->gimp);

885
  gimp_image_flush (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
886

Michael Natterer's avatar
Michael Natterer committed
887
  gimp_transform_tool_reset (tr_tool);
Michael Natterer's avatar
Michael Natterer committed
888 889
}

Nate Summers's avatar
Nate Summers committed
890
void
Nate Summers's avatar
Nate Summers committed
891
gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
892
{
893
  g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
Nate Summers's avatar
Nate Summers committed
894 895 896 897 898 899 900 901 902 903 904 905 906

  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->x1, tr_tool->y1,
				&tr_tool->tx1, &tr_tool->ty1);
  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->x2, tr_tool->y1,
				&tr_tool->tx2, &tr_tool->ty2);
  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->x1, tr_tool->y2,
				&tr_tool->tx3, &tr_tool->ty3);
  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->x2, tr_tool->y2,
				&tr_tool->tx4, &tr_tool->ty4);
Nate Summers's avatar
Nate Summers committed
907

908 909 910
  gimp_matrix3_transform_point (tr_tool->transform,
				tr_tool->cx, tr_tool->cy,
				&tr_tool->tcx, &tr_tool->tcy);
Nate Summers's avatar
Nate Summers committed
911

912
  if (tr_tool->grid_coords != NULL && tr_tool->tgrid_coords != NULL)
Nate Summers's avatar
Nate Summers committed
913
    {
914 915 916
      gint i, k;
      gint gci;

Nate Summers's avatar
Nate Summers committed
917
      gci = 0;
918
      k   = (tr_tool->ngx + tr_tool->ngy) * 2;
919

Nate Summers's avatar
Nate Summers committed
920 921
      for (i = 0; i < k; i++)
	{
Nate Summers's avatar
Nate Summers committed
922 923
	  gimp_matrix3_transform_point (tr_tool->transform,
					tr_tool->grid_coords[gci],
924 925 926
					tr_tool->grid_coords[gci + 1],
					&tr_tool->tgrid_coords[gci],
					&tr_tool->tgrid_coords[gci + 1]);
Nate Summers's avatar
Nate Summers committed
927 928 929 930 931
	  gci += 2;
	}
    }
}

932
static void
Michael Natterer's avatar
Michael Natterer committed
933
gimp_transform_tool_reset (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
934
{
Nate Summers's avatar
Nate Summers committed
935
  GimpTool *tool;
Nate Summers's avatar
Nate Summers committed
936

937
  tool = GIMP_TOOL (tr_tool);
Nate Summers's avatar
Nate Summers committed
938

Nate Summers's avatar
Nate Summers committed
939
  if (tr_tool->original)
940 941 942 943
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
Nate Summers's avatar
Nate Summers committed
944 945

  /*  inactivate the tool  */
Nate Summers's avatar
Nate Summers committed
946
  tr_tool->function = TRANSFORM_CREATING;
947 <