gimptransformtool.c 34.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 40
#include "core/gimpchannel.h"
#include "core/gimpcontext.h"
#include "core/gimpdrawable.h"
Michael Natterer's avatar
Michael Natterer committed
41
#include "core/gimpdrawable-transform.h"
42 43 44 45
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
#include "core/gimplayer.h"
#include "core/gimpmarshal.h"
Michael Natterer's avatar
Michael Natterer committed
46
#include "core/gimptoolinfo.h"
47

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

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

54
#include "gimptransformtool.h"
55 56
#include "tool_manager.h"
#include "transform_options.h"
57

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

#include "libgimp/gimpintl.h"

63

Michael Natterer's avatar
Michael Natterer committed
64 65
#define HANDLE 10

66

Michael Natterer's avatar
Michael Natterer committed
67 68 69 70 71 72 73 74
/*  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,
75
                                                    GimpToolAction     action,
Michael Natterer's avatar
Michael Natterer committed
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
                                                    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);
92 93 94 95 96
static void   gimp_transform_tool_modifier_key     (GimpTool          *tool,
                                                    GdkModifierType    key,
                                                    gboolean           press,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
97 98 99 100
static void   gimp_transform_tool_oper_update      (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);
Michael Natterer's avatar
Michael Natterer committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
static void   gimp_transform_tool_cursor_update    (GimpTool          *tool,
                                                    GimpCoords        *coords,
                                                    GdkModifierType    state,
                                                    GimpDisplay       *gdisp);

static void   gimp_transform_tool_draw             (GimpDrawTool      *draw_tool);

static TileManager * gimp_transform_tool_transform (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp,
                                                    TransformState     state);
static void   gimp_transform_tool_reset            (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
static void   gimp_transform_tool_bounds           (GimpTransformTool *tr_tool,
                                                    GimpDisplay       *gdisp);
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_setup_grid       (GimpTransformTool *tr_tool,
                                                    TransformOptions  *options);
static void   gimp_transform_tool_grid_recalc      (GimpTransformTool *tr_tool);

static void   transform_ok_callback                (GtkWidget         *widget,
                                                    gpointer           data);
static void   transform_reset_callback             (GtkWidget         *widget,
                                                    gpointer           data);
127 128


129
static GimpDrawToolClass *parent_class = NULL;
130

131 132

GType
Nate Summers's avatar
Nate Summers committed
133 134
gimp_transform_tool_get_type (void)
{
135
  static GType tool_type = 0;
Nate Summers's avatar
Nate Summers committed
136 137 138

  if (! tool_type)
    {
139
      static const GTypeInfo tool_info =
Nate Summers's avatar
Nate Summers committed
140 141
      {
        sizeof (GimpTransformToolClass),
142 143 144 145 146 147 148 149
	(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
150 151
      };

152 153 154
      tool_type = g_type_register_static (GIMP_TYPE_DRAW_TOOL,
					  "GimpTransformTool", 
                                          &tool_info, 0);
Nate Summers's avatar
Nate Summers committed
155 156 157 158 159 160 161 162
    }

  return tool_type;
}

static void
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
{
163
  GObjectClass      *object_class;
Nate Summers's avatar
Nate Summers committed
164 165
  GimpToolClass     *tool_class;
  GimpDrawToolClass *draw_class;
Nate Summers's avatar
Nate Summers committed
166

167 168 169
  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
170

171
  parent_class = g_type_class_peek_parent (klass);
Nate Summers's avatar
Nate Summers committed
172

173
  object_class->finalize     = gimp_transform_tool_finalize;
Nate Summers's avatar
Nate Summers committed
174

175
  tool_class->control        = gimp_transform_tool_control;
Nate Summers's avatar
Nate Summers committed
176 177 178
  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;
179
  tool_class->modifier_key   = gimp_transform_tool_modifier_key;
180
  tool_class->oper_update    = gimp_transform_tool_oper_update;
Nate Summers's avatar
Nate Summers committed
181
  tool_class->cursor_update  = gimp_transform_tool_cursor_update;
Nate Summers's avatar
Nate Summers committed
182 183

  draw_class->draw           = gimp_transform_tool_draw;
Nate Summers's avatar
Nate Summers committed
184 185 186
}

static void
Michael Natterer's avatar
Michael Natterer committed
187
gimp_transform_tool_init (GimpTransformTool *transform_tool)
Nate Summers's avatar
Nate Summers committed
188
{
Michael Natterer's avatar
Michael Natterer committed
189
  GimpTool *tool;
190
  gint      i;
Nate Summers's avatar
Nate Summers committed
191

Michael Natterer's avatar
Michael Natterer committed
192 193 194 195
  tool = GIMP_TOOL (transform_tool);

  transform_tool->function = TRANSFORM_CREATING;
  transform_tool->original = NULL;
Nate Summers's avatar
Nate Summers committed
196 197

  for (i = 0; i < TRAN_INFO_SIZE; i++)
198 199 200 201
    {
      transform_tool->trans_info[i]     = 0.0;
      transform_tool->old_trans_info[i] = 0.0;
    }
Nate Summers's avatar
Nate Summers committed
202

Michael Natterer's avatar
Michael Natterer committed
203
  gimp_matrix3_identity (transform_tool->transform);
Nate Summers's avatar
Nate Summers committed
204

Michael Natterer's avatar
Michael Natterer committed
205
  transform_tool->use_grid     = TRUE;
206
  transform_tool->use_center   = TRUE;
Michael Natterer's avatar
Michael Natterer committed
207 208 209 210
  transform_tool->ngx          = 0;
  transform_tool->ngy          = 0;
  transform_tool->grid_coords  = NULL;
  transform_tool->tgrid_coords = NULL;
211

212 213
  transform_tool->info_dialog  = NULL;

Nate Summers's avatar
Nate Summers committed
214 215
}

216
static void
217
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
218
{
219
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
220

221 222 223
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  if (tr_tool->original)
224 225 226 227
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
228

229
  if (tr_tool->info_dialog)
230
    {
231 232
      info_dialog_free (tr_tool->info_dialog);
      tr_tool->info_dialog = NULL;
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    }

  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
251 252 253
gimp_transform_tool_control (GimpTool       *tool,
			     GimpToolAction  action,
			     GimpDisplay    *gdisp)
254
{
Michael Natterer's avatar
Michael Natterer committed
255
  GimpTransformTool *transform_tool;
256

Michael Natterer's avatar
Michael Natterer committed
257
  transform_tool = GIMP_TRANSFORM_TOOL (tool);
258

259 260 261 262
  switch (action)
    {
    case PAUSE:
      break;
263

264
    case RESUME:
Michael Natterer's avatar
Michael Natterer committed
265
      gimp_transform_tool_recalc (transform_tool, gdisp);
266
      break;
267

268
    case HALT:
Michael Natterer's avatar
Michael Natterer committed
269
      gimp_transform_tool_reset (transform_tool, gdisp);
270
      return; /* don't upchain */
271
      break;
272

273 274 275 276
    default:
      break;
    }

Michael Natterer's avatar
Michael Natterer committed
277
  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
278 279 280
}

static void
281 282 283 284 285
gimp_transform_tool_button_press (GimpTool        *tool,
                                  GimpCoords      *coords,
                                  guint32          time,
                                  GdkModifierType  state,
			          GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
286
{
Michael Natterer's avatar
Michael Natterer committed
287
  GimpTransformTool *tr_tool;
288
  GimpDrawTool      *draw_tool;
Michael Natterer's avatar
Michael Natterer committed
289 290
  GimpDrawable      *drawable;
  gint               off_x, off_y;
Nate Summers's avatar
Nate Summers committed
291

Michael Natterer's avatar
Michael Natterer committed
292
  tr_tool   = GIMP_TRANSFORM_TOOL (tool);
293
  draw_tool = GIMP_DRAW_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
294 295 296

  drawable = gimp_image_active_drawable (gdisp->gimage);

297 298 299 300 301 302 303 304 305 306 307 308
  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 &&
          coords->x < (off_x + gimp_drawable_width (drawable)) &&
          coords->y < (off_y + gimp_drawable_height (drawable)))
        {
309 310
          if (gimp_image_mask_is_empty (gdisp->gimage) ||
              gimp_image_mask_value (gdisp->gimage, coords->x, coords->y))
311 312 313 314 315 316
            {
              if (GIMP_IS_LAYER (drawable) &&
                  gimp_layer_get_mask (GIMP_LAYER (drawable)))
                {
                  g_message (_("Transformations do not work on\n"
                               "layers that contain layer masks."));
317
                  gimp_tool_control_halt (tool->control);    /* sets paused_count to 0 -- is this ok? */
318 319 320 321 322 323
                  return;
                }

              /*  If the tool is already active, clear the current state
               *  and reset
               */
324
              if (gimp_tool_control_is_active (tool->control))
325 326 327 328 329 330 331 332 333
                {
                  g_warning ("%s: tool_already ACTIVE", G_GNUC_FUNCTION);

                  gimp_transform_tool_reset (tr_tool, gdisp);
                }

              /*  Set the pointer to the active display  */
              tool->gdisp    = gdisp;
              tool->drawable = drawable;
334
              gimp_tool_control_activate (tool->control);
335 336 337 338 339 340 341 342 343 344 345 346 347 348

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

              /*  Initialize the transform tool */
              gimp_transform_tool_transform (tr_tool, gdisp, TRANSFORM_INIT);

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

              /*  start drawing the bounding box and handles...  */
349
              gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), gdisp);
350 351 352 353 354 355 356

              /*  find which handle we're dragging  */
              gimp_transform_tool_oper_update (tool, coords, state, gdisp);
            }
        }
    }

357
  if (tr_tool->function == TRANSFORM_CREATING && gimp_tool_control_is_active (tool->control))
Nate Summers's avatar
Nate Summers committed
358
    {
359 360
      gint i;

Nate Summers's avatar
Nate Summers committed
361 362
      /*  Save the current transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
363
	tr_tool->old_trans_info[i] = tr_tool->trans_info[i];
Nate Summers's avatar
Nate Summers committed
364 365 366 367 368 369
    }

  /*  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
370
  if (gdisp == tool->gdisp)
Nate Summers's avatar
Nate Summers committed
371 372
    {
      /*  Save the current pointer position  */
Michael Natterer's avatar
Michael Natterer committed
373 374
      tr_tool->lastx = tr_tool->startx = coords->x;
      tr_tool->lasty = tr_tool->starty = coords->y;
Nate Summers's avatar
Nate Summers committed
375

376
      gimp_tool_control_activate (tool->control);
377
    }
Nate Summers's avatar
Nate Summers committed
378 379
}

380
static void
381 382 383 384 385
gimp_transform_tool_button_release (GimpTool        *tool,
                                    GimpCoords      *coords,
                                    guint32          time,
			            GdkModifierType  state,
			            GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
386
{
Michael Natterer's avatar
Michael Natterer committed
387
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
388
  gint               i;
Nate Summers's avatar
Nate Summers committed
389

Michael Natterer's avatar
Michael Natterer committed
390
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
391 392

  /*  if we are creating, there is nothing to be done...exit  */
Michael Natterer's avatar
Michael Natterer committed
393
  if (tr_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
394 395 396
    return;

  /*  if the 3rd button isn't pressed, transform the selected mask  */
397
  if (! (state & GDK_BUTTON3_MASK))
Nate Summers's avatar
Nate Summers committed
398 399
    {
      /* Shift-clicking is another way to approve the transform  */
400
      if ((state & GDK_SHIFT_MASK) || ! tr_tool->use_grid)
Nate Summers's avatar
Nate Summers committed
401
	{
Michael Natterer's avatar
Michael Natterer committed
402
	  gimp_transform_tool_doit (tr_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
403 404 405 406 407
	}
      else
	{
	  /*  Only update the paths preview */
	  path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
408
				       tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
409 410 411 412
	}
    }
  else
    {
413
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
414 415 416

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

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

422
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
423 424 425

      /* Update the paths preview */
      path_transform_current_path (gdisp->gimage,
Michael Natterer's avatar
Michael Natterer committed
426
				   tr_tool->transform, TRUE);
Nate Summers's avatar
Nate Summers committed
427 428 429
    }
}

430
static void
431 432 433 434 435
gimp_transform_tool_motion (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 *transform_tool;
Nate Summers's avatar
Nate Summers committed
438

Michael Natterer's avatar
Michael Natterer committed
439
  transform_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
440

441
  /*  if we are creating, there is nothing to be done so exit.  */
Michael Natterer's avatar
Michael Natterer committed
442
  if (transform_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
443 444
    return;

445
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
446

Michael Natterer's avatar
Michael Natterer committed
447 448 449
  transform_tool->curx  = coords->x;
  transform_tool->cury  = coords->y;
  transform_tool->state = state;
Nate Summers's avatar
Nate Summers committed
450 451

  /*  recalculate the tool's transformation matrix  */
Michael Natterer's avatar
Michael Natterer committed
452
  gimp_transform_tool_transform (transform_tool, gdisp, TRANSFORM_MOTION);
Nate Summers's avatar
Nate Summers committed
453

Michael Natterer's avatar
Michael Natterer committed
454 455
  transform_tool->lastx = transform_tool->curx;
  transform_tool->lasty = transform_tool->cury;
Nate Summers's avatar
Nate Summers committed
456

457
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
458 459
}

460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
static void
gimp_transform_tool_modifier_key (GimpTool        *tool,
                                  GdkModifierType  key,
                                  gboolean         press,
                                  GdkModifierType  state,
                                  GimpDisplay     *gdisp)
{
  TransformOptions *options;

  options = (TransformOptions *) tool->tool_info->tool_options;

  if (key == GDK_CONTROL_MASK && options->constrain_1_w)
    {
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->constrain_1_w),
                                    ! options->constrain_1);
    }
  else if (key == GDK_MOD1_MASK && options->constrain_2_w)
    {
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->constrain_2_w),
                                    ! options->constrain_2);
    }
}

483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 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 540 541 542 543 544
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);

  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,
                                    HANDLE, HANDLE,
                                    GTK_ANCHOR_CENTER,
                                    FALSE))
	{
	  tr_tool->function = TRANSFORM_HANDLE_CENTER;
	}
    }
}

545
static void
546 547 548 549
gimp_transform_tool_cursor_update (GimpTool        *tool,
                                   GimpCoords      *coords,
			           GdkModifierType  state,
			           GimpDisplay     *gdisp)
Nate Summers's avatar
Nate Summers committed
550
{
551 552 553 554 555 556
  GimpTransformTool  *tr_tool;
  GimpDrawable       *drawable;
  GdkCursorType       ctype     = GDK_TOP_LEFT_ARROW;
  GimpCursorModifier  cmodifier = GIMP_CURSOR_MODIFIER_NONE;

  tr_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
557 558 559

  if ((drawable = gimp_image_active_drawable (gdisp->gimage)))
    {
560 561 562 563
      gint off_x, off_y;

      gimp_drawable_offsets (drawable, &off_x, &off_y);

Nate Summers's avatar
Nate Summers committed
564
      if (GIMP_IS_LAYER (drawable) &&
565
          gimp_layer_get_mask (GIMP_LAYER (drawable)))
Nate Summers's avatar
Nate Summers committed
566 567 568
	{
	  ctype = GIMP_BAD_CURSOR;
	}
569 570 571 572
      else if (coords->x >= off_x &&
	       coords->y >= off_y &&
	       coords->x < (off_x + drawable->width) &&
	       coords->y < (off_y + drawable->height))
Nate Summers's avatar
Nate Summers committed
573
	{
574 575
	  if (gimp_image_mask_is_empty (gdisp->gimage) ||
	      gimp_image_mask_value (gdisp->gimage, coords->x, coords->y))
Nate Summers's avatar
Nate Summers committed
576 577 578 579 580 581
	    {
	      ctype = GIMP_MOUSE_CURSOR;
	    }
	}
    }

582 583 584 585 586
  if (tr_tool->use_center && tr_tool->function == TRANSFORM_HANDLE_CENTER)
    {
      cmodifier = GIMP_CURSOR_MODIFIER_MOVE;
    }

587 588
  gimp_tool_control_set_cursor (tool->control, ctype);
  gimp_tool_control_set_cursor_modifier (tool->control, cmodifier);
589 590

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

593
static void
594
gimp_transform_tool_draw (GimpDrawTool *draw_tool)
Nate Summers's avatar
Nate Summers committed
595
{
596
  GimpTransformTool *tr_tool;
Michael Natterer's avatar
Michael Natterer committed
597
  TransformOptions  *options;
598 599 600
  gint               i, k, gci;

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

602 603 604
  if (! tr_tool->use_grid)
    return;

Michael Natterer's avatar
Michael Natterer committed
605 606
  options = (TransformOptions *) GIMP_TOOL (draw_tool)->tool_info->tool_options;

Nate Summers's avatar
Nate Summers committed
607
  /*  draw the bounding box  */
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
  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
624 625 626

  /*  Draw the grid */

627
  if ((tr_tool->grid_coords != NULL) && (tr_tool->tgrid_coords != NULL))
Nate Summers's avatar
Nate Summers committed
628 629
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
630
      k = tr_tool->ngx + tr_tool->ngy;
631

Nate Summers's avatar
Nate Summers committed
632 633
      for (i = 0; i < k; i++)
	{
634 635 636 637 638 639
          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
640 641 642 643 644
	  gci += 4;
	}
    }

  /*  draw the tool handles  */
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx1, tr_tool->ty1,
                              HANDLE, HANDLE,
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx2, tr_tool->ty2,
                              HANDLE, HANDLE,
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx3, tr_tool->ty3,
                              HANDLE, HANDLE,
                              GTK_ANCHOR_CENTER,
                              FALSE);
  gimp_draw_tool_draw_handle (draw_tool,
                              GIMP_HANDLE_SQUARE,
                              tr_tool->tx4, tr_tool->ty4,
                              HANDLE, HANDLE,
                              GTK_ANCHOR_CENTER,
                              FALSE);
Nate Summers's avatar
Nate Summers committed
669 670

  /*  draw the center  */
671 672 673 674 675 676 677 678 679
  if (tr_tool->use_center)
    {
      gimp_draw_tool_draw_handle (draw_tool,
                                  GIMP_HANDLE_FILLED_CIRCLE,
                                  tr_tool->tcx, tr_tool->tcy,
                                  HANDLE, HANDLE,
                                  GTK_ANCHOR_CENTER,
                                  FALSE);
    }
Nate Summers's avatar
Nate Summers committed
680

Michael Natterer's avatar
Michael Natterer committed
681
  if (options->show_path)
Nate Summers's avatar
Nate Summers committed
682 683 684
    {
      GimpMatrix3 tmp_matrix;

Michael Natterer's avatar
Michael Natterer committed
685
      if (options->direction == GIMP_TRANSFORM_BACKWARD)
Nate Summers's avatar
Nate Summers committed
686
	{
Nate Summers's avatar
Nate Summers committed
687
	  gimp_matrix3_invert (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
688 689 690
	}
      else
	{
Nate Summers's avatar
Nate Summers committed
691
	  gimp_matrix3_duplicate (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
692 693
	}

694 695
      path_transform_draw_current (GIMP_TOOL (draw_tool)->gdisp,
                                   draw_tool, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
696 697 698
    }
}

Michael Natterer's avatar
Michael Natterer committed
699 700 701 702 703 704 705
static TileManager *
gimp_transform_tool_transform (GimpTransformTool   *tool,
                               GimpDisplay         *gdisp,
			       TransformState       state)
{
  g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tool), NULL);

706
  return GIMP_TRANSFORM_TOOL_GET_CLASS (tool)->transform (tool, gdisp, state);
Michael Natterer's avatar
Michael Natterer committed
707 708 709 710 711 712
}

static void
gimp_transform_tool_doit (GimpTransformTool  *tr_tool,
		          GimpDisplay        *gdisp)
{
Michael Natterer's avatar
Michael Natterer committed
713 714 715 716
  GimpTool    *tool;
  TileManager *new_tiles;
  GSList      *path_undo;
  gboolean     new_layer;
Michael Natterer's avatar
Michael Natterer committed
717 718 719 720 721 722 723 724 725 726 727

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

  /*  Start a transform undo group  */
Michael Natterer's avatar
Michael Natterer committed
731
  undo_push_group_start (gdisp->gimage, TRANSFORM_UNDO_GROUP);
Michael Natterer's avatar
Michael Natterer committed
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746

  /* 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
747
  path_undo = path_transform_start_undo (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771

  /*  Send the request for the transformation to the tool...
   */
  new_tiles = gimp_transform_tool_transform (tr_tool, gdisp, TRANSFORM_FINISH);

  gimp_transform_tool_transform (tr_tool, gdisp, TRANSFORM_INIT);

  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
772 773 774 775 776 777
      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
778 779 780 781 782 783 784 785
    }

  /*  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
   */
786
  gimp_tool_control_set_preserve (tool->control, FALSE);
Michael Natterer's avatar
Michael Natterer committed
787 788 789

  gimp_unset_busy (gdisp->gimage->gimp);

790
  gimp_image_flush (gdisp->gimage);
Michael Natterer's avatar
Michael Natterer committed
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806

  gimp_transform_tool_reset (tr_tool, gdisp);
}

TileManager *
gimp_transform_tool_transform_tiles (GimpTransformTool *transform_tool,
                                     const gchar       *progress_text)
{
  GimpTool         *tool;
  TransformOptions *options;
  GimpProgress     *progress;
  TileManager      *ret;

  g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (transform_tool), NULL);
  g_return_val_if_fail (progress_text != NULL, NULL);

807
  if (transform_tool->info_dialog)
808 809
    gtk_widget_set_sensitive (GTK_WIDGET (transform_tool->info_dialog->shell),
                              FALSE);
Michael Natterer's avatar
Michael Natterer committed
810 811 812 813 814

  tool = GIMP_TOOL (transform_tool);

  options = (TransformOptions *) tool->tool_info->tool_options;

Michael Natterer's avatar
Michael Natterer committed
815 816
  progress = gimp_progress_start (tool->gdisp, progress_text, FALSE,
                                  NULL, NULL);
Michael Natterer's avatar
Michael Natterer committed
817 818 819

  ret = gimp_drawable_transform_tiles_affine (gimp_image_active_drawable (tool->gdisp->gimage),
                                              transform_tool->original,
820
                                              options->interpolation,
Michael Natterer's avatar
Michael Natterer committed
821 822 823
                                              options->clip,
                                              transform_tool->transform,
                                              options->direction,
Michael Natterer's avatar
Michael Natterer committed
824 825 826
                                              progress ?
                                              gimp_progress_update_and_flush : 
                                              NULL,
Michael Natterer's avatar
Michael Natterer committed
827 828 829
                                              progress);

  if (progress)
Michael Natterer's avatar
Michael Natterer committed
830
    gimp_progress_end (progress);
Michael Natterer's avatar
Michael Natterer committed
831 832 833 834

  return ret;
}

Nate Summers's avatar
Nate Summers committed
835
void
Nate Summers's avatar
Nate Summers committed
836
gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
837
{
838
  g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
Nate Summers's avatar
Nate Summers committed
839 840 841 842 843 844 845 846 847 848 849 850 851

  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
852

853 854 855
  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
856

857
  if (tr_tool->grid_coords != NULL && tr_tool->tgrid_coords != NULL)
Nate Summers's avatar
Nate Summers committed
858
    {
859 860 861
      gint i, k;
      gint gci;

Nate Summers's avatar
Nate Summers committed
862
      gci = 0;
863
      k   = (tr_tool->ngx + tr_tool->ngy) * 2;
864

Nate Summers's avatar
Nate Summers committed
865 866
      for (i = 0; i < k; i++)
	{
Nate Summers's avatar
Nate Summers committed
867 868 869 870 871
	  gimp_matrix3_transform_point (tr_tool->transform,
					tr_tool->grid_coords[gci],
					tr_tool->grid_coords[gci+1],
					&(tr_tool->tgrid_coords[gci]),
					&(tr_tool->tgrid_coords[gci+1]));
Nate Summers's avatar
Nate Summers committed
872 873 874 875 876
	  gci += 2;
	}
    }
}

877
static void
878
gimp_transform_tool_reset (GimpTransformTool *tr_tool,
879
		           GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
880
{
Nate Summers's avatar
Nate Summers committed
881
  GimpTool *tool;
Nate Summers's avatar
Nate Summers committed
882

883
  tool = GIMP_TOOL (tr_tool);
Nate Summers's avatar
Nate Summers committed
884

Nate Summers's avatar
Nate Summers committed
885
  if (tr_tool->original)
886 887 888 889
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
Nate Summers's avatar
Nate Summers committed
890 891

  /*  inactivate the tool  */
Nate Summers's avatar
Nate Summers committed
892
  tr_tool->function = TRANSFORM_CREATING;
893

894
  gimp_draw_tool_stop (GIMP_DRAW_TOOL (tr_tool));
895 896 897

  if (tr_tool->info_dialog)
    info_dialog_popdown (tr_tool->info_dialog);
Nate Summers's avatar
Nate Summers committed
898

899
  gimp_tool_control_halt (tool->control);    /* sets paused_count to 0 -- is this ok? */
Nate Summers's avatar
Nate Summers committed
900 901 902 903 904
  tool->gdisp    = NULL;
  tool->drawable = NULL;
}

static void
905
gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
906
		            GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
907
{
908 909
  TileManager  *tiles;
  GimpDrawable *drawable;
Nate Summers's avatar
Nate Summers committed
910

911 912
  tiles    = tr_tool->original;
  drawable = gimp_image_active_drawable (gdisp->gimage);
Nate Summers's avatar
Nate Summers committed
913 914 915 916 917

  /*  find the boundaries  */
  if (tiles)
    {
      tile_manager_get_offsets (tiles,
Nate Summers's avatar
Nate Summers committed
918 919 920 921
				&tr_tool->x1, &tr_tool->y1);
				
      tr_tool->x2 = tr_tool->x1 + tile_manager_width (tiles);
      tr_tool->y2 = tr_tool->y1 + tile_manager_height (tiles);
Nate Summers's avatar
Nate Summers committed
922 923 924
    }
  else
    {
925 926
      gint offset_x, offset_y;

Nate Summers's avatar
Nate Summers committed
927
      gimp_drawable_offsets (drawable, &offset_x, &offset_y);
928

Nate Summers's avatar
Nate Summers committed
929
      gimp_drawable_mask_bounds (drawable,
Nate Summers's avatar
Nate Summers committed
930 931 932 933 934 935
				 &tr_tool->x1, &tr_tool->y1,
				 &tr_tool->x2, &tr_tool->y2);
      tr_tool->x1 += offset_x;
      tr_tool->y1 += offset_y;
      tr_tool->x2 += offset_x;
      tr_tool->y2 += offset_y;
Nate Summers's avatar
Nate Summers committed
936
    }
Nate Summers's avatar
Nate Summers committed
937

938 939
  tr_tool->cx = (gdouble) (tr_tool->x1 + tr_tool->x2) / 2.0;
  tr_tool->cy = (gdouble) (tr_tool->y1 + tr_tool->y2) / 2.0;
Nate Summers's avatar
Nate Summers committed
940

Michael Natterer's avatar
Michael Natterer committed
941 942 943 944 945
  if (tr_tool->use_grid)
    {
      /*  changing the bounds invalidates any grid we may have  */
      gimp_transform_tool_grid_recalc (tr_tool);
    }
Nate Summers's avatar
Nate Summers committed
946 947
}

948 949 950 951 952 953 954 955 956 957 958
void
gimp_transform_tool_info_dialog_connect (GimpTransformTool *tr_tool,
                                         const gchar       *ok_button)
{
  g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
  g_return_if_fail (ok_button != NULL);

  if (tr_tool->info_dialog)
    {
      gimp_dialog_create_action_area (GIMP_DIALOG (tr_tool->info_dialog->shell),

959
                                      GIMP_STOCK_RESET, transform_reset_callback,
960 961
                                      tr_tool, NULL, NULL, FALSE, FALSE,

962 963 964
                                      ok_button, transform_ok_callback,
                                      tr_tool, NULL, NULL, TRUE, FALSE,

965 966 967 968
                                      NULL);
    }
}

Nate Summers's avatar
Nate Summers committed
969
void
Michael Natterer's avatar
Michael Natterer committed
970
gimp_transform_tool_grid_density_changed (GimpTransformTool *transform_tool)
Nate Summers's avatar
Nate Summers committed
971
{
Michael Natterer's avatar
Michael Natterer committed
972
  if (transform_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
973 974
    return;

Michael Natterer's avatar
Michael Natterer committed
975
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (transform_tool));
976

Michael Natterer's avatar
Michael Natterer committed
977 978
  gimp_transform_tool_grid_recalc (transform_tool);
  gimp_transform_tool_transform_bounding_box (transform_tool);
979

Michael Natterer's avatar
Michael Natterer committed
980
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (transform_tool));
Nate Summers's avatar
Nate Summers committed
981 982 983
}

void
Michael Natterer's avatar
Michael Natterer committed
984 985
gimp_transform_tool_show_path_changed (GimpTransformTool *transform_tool,
                                       gint               type /* a truly undescriptive name */)
Nate Summers's avatar
Nate Summers committed
986
{
Michael Natterer's avatar
Michael Natterer committed
987
  if (transform_tool->function == TRANSFORM_CREATING)
Nate Summers's avatar
Nate Summers committed
988 989 990
    return;

  if (type)
Michael Natterer's avatar
Michael Natterer committed
991
    gimp_draw_tool_pause (GIMP_DRAW_TOOL (transform_tool));