gimptransformtool.c 38.6 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
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
43
#include "core/gimpimage-undo.h"
44
#include "core/gimpimage-undo-push.h"
45 46
#include "core/gimplayer.h"
#include "core/gimpmarshal.h"
Michael Natterer's avatar
Michael Natterer committed
47
#include "core/gimptoolinfo.h"
48

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

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

56 57 58
#include "gui/dialogs.h"
#include "gui/info-dialog.h"

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

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

static void   gimp_transform_tool_draw             (GimpDrawTool      *draw_tool);

114 115 116 117
static TileManager *
              gimp_transform_tool_real_transform   (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);

Michael Natterer's avatar
Michael Natterer committed
118
static void   gimp_transform_tool_reset            (GimpTransformTool *tr_tool);
Michael Natterer's avatar
Michael Natterer committed
119 120
static void   gimp_transform_tool_bounds           (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
121 122 123
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
124 125 126 127 128 129 130
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
131 132 133 134 135
                                                    GimpTransformTool *tr_tool);
static void   transform_cancel_callback            (GtkWidget         *widget,
                                                    GimpTransformTool *tr_tool);
static void   transform_ok_callback                (GtkWidget         *widget,
                                                    GimpTransformTool *tr_tool);
136

137 138 139 140 141 142 143
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);

144

145
static GimpDrawToolClass *parent_class = NULL;
146

147 148

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

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

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

  return tool_type;
}

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

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

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

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

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

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

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

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

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

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

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

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

Michael Natterer's avatar
Michael Natterer committed
228
  gimp_matrix3_identity (tr_tool->transform);
229

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

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

245
static void
246
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
247
{
248
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
249

250 251 252
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  if (tr_tool->original)
253 254 255 256
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
257

258
  if (tr_tool->info_dialog)
259
    {
260 261
      info_dialog_free (tr_tool->info_dialog);
      tr_tool->info_dialog = NULL;
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
    }

  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
280 281 282
gimp_transform_tool_control (GimpTool       *tool,
			     GimpToolAction  action,
			     GimpDisplay    *gdisp)
283
{
Michael Natterer's avatar
Michael Natterer committed
284
  GimpTransformTool *tr_tool;
285

Michael Natterer's avatar
Michael Natterer committed
286
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
287

288 289 290 291
  switch (action)
    {
    case PAUSE:
      break;
292

293
    case RESUME:
Michael Natterer's avatar
Michael Natterer committed
294
      gimp_transform_tool_recalc (tr_tool, gdisp);
295
      break;
296

297
    case HALT:
Michael Natterer's avatar
Michael Natterer committed
298
      gimp_transform_tool_reset (tr_tool);
299
      return; /* don't upchain */
300
      break;
301

302 303 304 305
    default:
      break;
    }

Michael Natterer's avatar
Michael Natterer committed
306
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
307 308 309
}

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

Michael Natterer's avatar
Michael Natterer committed
321
  tr_tool   = GIMP_TRANSFORM_TOOL (tool);
322
  draw_tool = GIMP_DRAW_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
323 324 325

  drawable = gimp_image_active_drawable (gdisp->gimage);

326
  if (tr_tool->use_grid && ! tr_tool->notify_connected)
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
    {
      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;
    }

347 348 349 350 351
  if (gdisp != tool->gdisp)
    {
      /*  Initialisation stuff: if the cursor is clicked inside the current
       *  selection, show the bounding box and handles...
       */
352
      gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);
353 354 355

      if (coords->x >= off_x &&
          coords->y >= off_y &&
356 357
          coords->x < (off_x + gimp_item_width  (GIMP_ITEM (drawable))) &&
          coords->y < (off_y + gimp_item_height (GIMP_ITEM (drawable))) &&
Michael Natterer's avatar
Michael Natterer committed
358 359 360

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

Michael Natterer's avatar
Michael Natterer committed
371 372 373 374 375 376
          /*  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);
377

Michael Natterer's avatar
Michael Natterer committed
378 379
              gimp_transform_tool_reset (tr_tool);
            }
380

Michael Natterer's avatar
Michael Natterer committed
381 382 383 384
          /*  Set the pointer to the active display  */
          tool->gdisp    = gdisp;
          tool->drawable = drawable;
          gimp_tool_control_activate (tool->control);
385

Michael Natterer's avatar
Michael Natterer committed
386 387 388 389 390
          /*  Find the transform bounds for some tools (like scale,
           *  perspective) that actually need the bounds for
           *  initializing
           */
          gimp_transform_tool_bounds (tr_tool, gdisp);
391

Michael Natterer's avatar
Michael Natterer committed
392 393 394
          /*  Initialize the transform tool */
          if (! tr_tool->info_dialog)
            gimp_transform_tool_dialog (tr_tool);
395

Michael Natterer's avatar
Michael Natterer committed
396
          gimp_transform_tool_prepare (tr_tool, gdisp);
397

Michael Natterer's avatar
Michael Natterer committed
398 399
          /*  Recalculate the transform tool  */
          gimp_transform_tool_recalc (tr_tool, gdisp);
400

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

Michael Natterer's avatar
Michael Natterer committed
404 405 406 407
          /*  find which handle we're dragging  */
          gimp_transform_tool_oper_update (tool, coords, state, gdisp);

          tr_tool->function = TRANSFORM_CREATING;
408 409 410
        }
    }

411 412
  if (tr_tool->function == TRANSFORM_CREATING &&
      gimp_tool_control_is_active (tool->control))
Nate Summers's avatar
Nate Summers committed
413
    {
414 415
      gint i;

Nate Summers's avatar
Nate Summers committed
416 417
      /*  Save the current transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
418
	tr_tool->old_trans_info[i] = tr_tool->trans_info[i];
Nate Summers's avatar
Nate Summers committed
419 420 421 422 423 424
    }

  /*  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
425
  if (gdisp == tool->gdisp)
Nate Summers's avatar
Nate Summers committed
426 427
    {
      /*  Save the current pointer position  */
Michael Natterer's avatar
Michael Natterer committed
428 429
      tr_tool->lastx = tr_tool->startx = coords->x;
      tr_tool->lasty = tr_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
430

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

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

Michael Natterer's avatar
Michael Natterer committed
445
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
446 447

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

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

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

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

477
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
478 479 480

      /* Update the paths preview */
      path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
481
				   tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
482 483 484
    }
}

485
static void
486 487 488 489 490
gimp_transform_tool_motion (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
		            GdkModifierType  state,
		            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
491
{
Michael Natterer's avatar
Michael Natterer committed
492 493
  GimpTransformToolClass *tr_tool_class;
  GimpTransformTool      *tr_tool;
Nate Summers's avatar
Nate Summers committed
494

Michael Natterer's avatar
Michael Natterer committed
495
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
496

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

501
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
502

Michael Natterer's avatar
Michael Natterer committed
503 504 505
  tr_tool->curx  = coords->x;
  tr_tool->cury  = coords->y;
  tr_tool->state = state;
Nate Summers's avatar
Nate Summers committed
506 507

  /*  recalculate the tool's transformation matrix  */
Michael Natterer's avatar
Michael Natterer committed
508 509 510 511 512
  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
513

Michael Natterer's avatar
Michael Natterer committed
514 515 516 517 518 519
      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
520

521
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
522 523
}

524 525 526 527 528 529 530
static void
gimp_transform_tool_modifier_key (GimpTool        *tool,
                                  GdkModifierType  key,
                                  gboolean         press,
                                  GdkModifierType  state,
                                  GimpDisplay     *gdisp)
{
531
  GimpTransformOptions *options;
532

533
  options = GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options);
534

535
  if (key == GDK_CONTROL_MASK)
536
    {
537
      g_object_set (options,
538 539
                    "constrain-1", ! options->constrain_1,
                    NULL);
540
    }
541
  else if (key == GDK_MOD1_MASK)
542
    {
543
      g_object_set (options,
544 545
                    "constrain-2", ! options->constrain_2,
                    NULL);
546 547 548
    }
}

549 550 551 552 553 554 555 556 557 558 559 560
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);

561 562 563
  if (! tr_tool->use_grid)
    return;

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 600 601 602 603 604
  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,
605
                                    HANDLE_SIZE, HANDLE_SIZE,
606 607 608 609 610 611 612 613
                                    GTK_ANCHOR_CENTER,
                                    FALSE))
	{
	  tr_tool->function = TRANSFORM_HANDLE_CENTER;
	}
    }
}

614
static void
615 616 617 618
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
			           GdkModifierType  state,
			           GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
619
{
620 621 622 623
  GimpTransformTool  *tr_tool;
  GimpDrawable       *drawable;

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

Michael Natterer's avatar
Michael Natterer committed
625
  if (tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
626
    {
Michael Natterer's avatar
Michael Natterer committed
627 628
      GdkCursorType      ctype     = GDK_TOP_LEFT_ARROW;
      GimpCursorModifier cmodifier = GIMP_CURSOR_MODIFIER_NONE;
629

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

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

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

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

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

668 669 670
  if (! tr_tool->use_grid)
    return;

671 672
  options = GIMP_TRANSFORM_OPTIONS (GIMP_TOOL (draw_tool)->tool_info->tool_options);

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

  /*  Draw the grid */

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

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

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

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

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

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

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

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

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

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

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

  ret = gimp_drawable_transform_tiles_affine (drawable,
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
                                              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
803 804 805 806
static void
gimp_transform_tool_doit (GimpTransformTool  *tr_tool,
		          GimpDisplay        *gdisp)
{
Michael Natterer's avatar
Michael Natterer committed
807 808 809 810
  GimpTool    *tool;
  TileManager *new_tiles;
  GSList      *path_undo;
  gboolean     new_layer;
Michael Natterer's avatar
Michael Natterer committed
811 812 813 814 815 816 817 818 819 820 821

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

  /*  Start a transform undo group  */
825
  gimp_image_undo_group_start (gdisp->gimage, GIMP_UNDO_GROUP_TRANSFORM,
826
                               tool->tool_info->blurb);
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);

867 868 869 870 871 872
      gimp_transform_tool_push_undo (gdisp->gimage, NULL,
                                     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
    }

  /*  push the undo group end  */
876
  gimp_image_undo_group_end (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
877 878 879 880

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