gimptransformtool.c 47.4 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
#include "gui/gui-types.h"
Nate Summers's avatar
Nate Summers committed
30

Michael Natterer's avatar
Michael Natterer committed
31 32 33 34 35 36
#include "base/base-config.h"
#include "base/pixel-region.h"
#include "base/pixel-surround.h"
#include "base/tile-manager.h"
#include "base/tile.h"

37 38
#include "paint-funcs/paint-funcs.h"

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

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/gimpdisplayshell.h"
Nate Summers's avatar
Nate Summers committed
54

55 56 57 58
#include "tool_manager.h"
#include "tool_options.h"
#include "transform_options.h"
#include "gimptransformtool.h"
Michael Natterer's avatar
Michael Natterer committed
59 60 61 62 63
#include "gimpperspectivetool.h"
#include "gimprotatetool.h"
#include "gimpscaletool.h"
#include "gimpsheartool.h"
#include "gimpfliptool.h"
64

Michael Natterer's avatar
Michael Natterer committed
65 66 67 68
#include "app_procs.h"
#include "floating_sel.h"
#include "undo.h"
#include "path_transform.h"
Nate Summers's avatar
Nate Summers committed
69 70 71

#include "libgimp/gimpintl.h"

72

Nate Summers's avatar
Nate Summers committed
73 74 75 76
enum
{
  TRANSFORM,
  LAST_SIGNAL
Nate Summers's avatar
Nate Summers committed
77
};
Nate Summers's avatar
Nate Summers committed
78 79 80 81 82 83 84

#define BILINEAR(jk,j1k,jk1,j1k1,dx,dy) \
                ((1-dy) * (jk + dx * (j1k - jk)) + \
		    dy  * (jk1 + dx * (j1k1 - jk1)))

/* access interleaved pixels */
#define CUBIC_ROW(dx, row, step) \
Nate Summers's avatar
Nate Summers committed
85
  gimp_transform_tool_cubic(dx, (row)[0], (row)[step], (row)[step+step], (row)[step+step+step])
Nate Summers's avatar
Nate Summers committed
86
#define CUBIC_SCALED_ROW(dx, row, step, i) \
Nate Summers's avatar
Nate Summers committed
87
  gimp_transform_tool_cubic(dx, (row)[0] * (row)[i], \
Nate Summers's avatar
Nate Summers committed
88 89 90 91 92 93 94 95
            (row)[step] * (row)[step + i], \
            (row)[step+step]* (row)[step+step + i], \
            (row)[step+step+step] * (row)[step+step+step + i])

#define REF_TILE(i,x,y) \
     tile[i] = tile_manager_get_tile (float_tiles, x, y, TRUE, FALSE); \
     src[i] = tile_data_pointer (tile[i], (x) % TILE_WIDTH, (y) % TILE_HEIGHT);

96

Nate Summers's avatar
Nate Summers committed
97
/*  forward function declarations  */
Nate Summers's avatar
Nate Summers committed
98
static void      gimp_transform_tool_bounds    (GimpTransformTool      *tool,
99
                                                GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
100
static void      gimp_transform_tool_recalc    (GimpTransformTool      *tool,
101
					        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
102
static void      gimp_transform_tool_doit      (GimpTransformTool      *tool,
103
					        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
104 105 106 107 108 109 110 111 112
static gdouble   gimp_transform_tool_cubic     (gdouble                 dx,
					        gint                    jm1,
					        gint                    j,
					        gint                    jp1,
					        gint                    jp2);
static void    gimp_transform_tool_setup_grid  (GimpTransformTool      *tool);
static void    gimp_transform_tool_grid_recalc (GimpTransformTool      *gimp_transform_tool);
static void    gimp_transform_tool_init        (GimpTransformTool      *tool);
static void    gimp_transform_tool_class_init  (GimpTransformToolClass *tool);
Nate Summers's avatar
Nate Summers committed
113

114
static void    gimp_transform_tool_finalize    (GObject                *object);
115 116

static void   gimp_transform_tool_button_press (GimpTool               *tool,
Nate Summers's avatar
Nate Summers committed
117
                                                GdkEventButton         *bevent,
118
			                        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
119
			          
120
static void gimp_transform_tool_button_release (GimpTool               *tool,
Nate Summers's avatar
Nate Summers committed
121
			                        GdkEventButton         *bevent,
122
			                        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
123
			                        
124
static void    gimp_transform_tool_motion      (GimpTool               *tool,
Nate Summers's avatar
Nate Summers committed
125
		                                GdkEventMotion         *mevent,
126
		                                GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
127
		                                
128
static void  gimp_transform_tool_cursor_update (GimpTool               *tool,
Nate Summers's avatar
Nate Summers committed
129
	                 		        GdkEventMotion         *mevent,
130
			                        GimpDisplay            *gdisp);
Nate Summers's avatar
Nate Summers committed
131
			                        
132
static void    gimp_transform_tool_control     (GimpTool               *tool,
Nate Summers's avatar
Nate Summers committed
133
			                        ToolAction              action,
134
			                        GimpDisplay            *gdisp);
135 136 137 138

static void    gimp_transform_tool_draw        (GimpDrawTool           *draw_tool);


Nate Summers's avatar
Nate Summers committed
139
/*  variables  */
Nate Summers's avatar
Nate Summers committed
140 141 142
static TranInfo           old_trans_info;
InfoDialog               *transform_info        = NULL;
static gboolean           transform_info_inited = FALSE;
Nate Summers's avatar
Nate Summers committed
143

144
static GimpDrawToolClass *parent_class = NULL;
145

146 147 148 149
static guint   gimp_transform_tool_signals[LAST_SIGNAL] = { 0 };


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

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

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

  return tool_type;
}

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

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

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

  gimp_transform_tool_signals[TRANSFORM] =
191 192 193 194 195 196 197 198 199
    g_signal_new ("transform",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GimpTransformToolClass, transform),
		  NULL, NULL,
		  gimp_cclosure_marshal_POINTER__POINTER_INT,
		  G_TYPE_POINTER, 2,
		  G_TYPE_POINTER,
		  G_TYPE_INT);
Nate Summers's avatar
Nate Summers committed
200

201
  object_class->finalize     = gimp_transform_tool_finalize;
Nate Summers's avatar
Nate Summers committed
202 203 204 205 206 207

  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;
  tool_class->cursor_update  = gimp_transform_tool_cursor_update;
  tool_class->control        = gimp_transform_tool_control;
Nate Summers's avatar
Nate Summers committed
208 209

  draw_class->draw           = gimp_transform_tool_draw;
Nate Summers's avatar
Nate Summers committed
210 211 212
}

static void
Nate Summers's avatar
Nate Summers committed
213
gimp_transform_tool_init (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
214
{
215 216
  GimpTool *tool = GIMP_TOOL (tr_tool);
  gint      i;
Nate Summers's avatar
Nate Summers committed
217 218 219 220 221 222 223 224 225 226 227

  tr_tool->function = TRANSFORM_CREATING;
  tr_tool->original = NULL;

  tr_tool->bpressed = FALSE;

  for (i = 0; i < TRAN_INFO_SIZE; i++)
    tr_tool->trans_info[i] = 0;

  tr_tool->grid_coords = tr_tool->tgrid_coords = NULL;

228 229 230
  /* FIXME */
  tr_tool->interactive = TRUE;

Nate Summers's avatar
Nate Summers committed
231 232
  tool->scroll_lock = TRUE;   /*  Disallow scrolling  */
  tool->preserve    = FALSE;  /*  Don't preserve on drawable change  */
233

Nate Summers's avatar
Nate Summers committed
234 235
}

Nate Summers's avatar
Nate Summers committed
236 237
TileManager *
gimp_transform_tool_transform (GimpTransformTool   *tool,
238
                               GimpDisplay         *gdisp,
Nate Summers's avatar
Nate Summers committed
239 240 241 242 243 244 245
			       TransformState       state)
{
  TileManager *retval;

  g_return_val_if_fail (tool, NULL);
  g_return_val_if_fail (GIMP_IS_TRANSFORM_TOOL (tool), NULL);

246 247
  g_signal_emit (G_OBJECT (tool), gimp_transform_tool_signals[TRANSFORM], 0,
                 gdisp, state, &retval);
Nate Summers's avatar
Nate Summers committed
248 249 250 251

  return retval;
}

Nate Summers's avatar
Nate Summers committed
252 253 254 255
static void
transform_ok_callback (GtkWidget *widget,
		       gpointer   data)
{
Nate Summers's avatar
Nate Summers committed
256
  GimpTool *tool;
Nate Summers's avatar
Nate Summers committed
257

Nate Summers's avatar
Nate Summers committed
258 259
  tool = GIMP_TOOL(data);
  gimp_transform_tool_doit (GIMP_TRANSFORM_TOOL(tool), tool->gdisp);
Nate Summers's avatar
Nate Summers committed
260 261 262 263 264 265 266 267 268 269
}

static void
transform_reset_callback (GtkWidget *widget,
			  gpointer   data)
{
  GimpTransformTool   *tool;
  GimpDrawTool        *dr_tool;
  gint                 i;

270 271
  tool    = GIMP_TRANSFORM_TOOL (data);
  dr_tool = GIMP_DRAW_TOOL (data);
Nate Summers's avatar
Nate Summers committed
272 273

  /*  stop the current tool drawing process  */
Nate Summers's avatar
Nate Summers committed
274
  gimp_draw_tool_pause (dr_tool);
Nate Summers's avatar
Nate Summers committed
275 276 277 278 279 280

  /*  Restore the previous transformation info  */
  for (i = 0; i < TRAN_INFO_SIZE; i++)
    tool->trans_info [i] = old_trans_info [i];

  /*  recalculate the tool's transformation matrix  */
Nate Summers's avatar
Nate Summers committed
281
  gimp_transform_tool_recalc (tool, GIMP_TOOL(tool)->gdisp);
Nate Summers's avatar
Nate Summers committed
282 283

  /*  resume drawing the current tool  */
Nate Summers's avatar
Nate Summers committed
284
  gimp_draw_tool_resume (dr_tool);
Nate Summers's avatar
Nate Summers committed
285 286
}

287
static void
288
gimp_transform_tool_finalize (GObject *object)
Nate Summers's avatar
Nate Summers committed
289
{
290
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
291

292 293 294
  tr_tool = GIMP_TRANSFORM_TOOL (object);

  if (tr_tool->original)
295 296 297 298
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
299 300

  if (transform_info)
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
    {
      info_dialog_free (transform_info);
      transform_info        = NULL;
      transform_info_inited = FALSE;
    }

  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
323 324 325
gimp_transform_tool_control (GimpTool    *tool,
			     ToolAction   action,
			     GimpDisplay *gdisp)
326 327 328 329 330 331
{
  GimpDrawTool      *dr_tool;
  GimpTransformTool *tr_tool;

  dr_tool = GIMP_DRAW_TOOL (tool);
  tr_tool = GIMP_TRANSFORM_TOOL (tool);
332

333 334 335 336
  switch (action)
    {
    case PAUSE:
      break;
337

338 339 340
    case RESUME:
      gimp_transform_tool_recalc (tr_tool, gdisp);
      break;
341

342 343 344
    case HALT:
      gimp_transform_tool_reset (tr_tool, gdisp);
      break;
345

346 347 348 349 350 351
    default:
      break;
    }

  if (GIMP_TOOL_CLASS (parent_class)->control)
    GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
352 353 354
}

static void
355 356 357
gimp_transform_tool_button_press (GimpTool       *tool,
                                  GdkEventButton *bevent,
			          GimpDisplay    *gdisp)
Nate Summers's avatar
Nate Summers committed
358
{
Michael Natterer's avatar
Michael Natterer committed
359 360 361 362 363 364 365 366
  GimpTransformTool *gt_tool;
  GimpDisplayShell  *shell;
  GimpDrawable      *drawable;
  gint               dist;
  gint               closest_dist;
  gint               x, y;
  gint               i;
  gint               off_x, off_y;
Nate Summers's avatar
Nate Summers committed
367

368
  gt_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
369

Michael Natterer's avatar
Michael Natterer committed
370 371
  shell = GIMP_DISPLAY_SHELL (gdisp->shell);

Nate Summers's avatar
Nate Summers committed
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
  gt_tool->bpressed = TRUE; /* ALT */

  drawable = gimp_image_active_drawable (gdisp->gimage);

  if (gt_tool->function == TRANSFORM_CREATING && tool->state == ACTIVE)
    {
      /*  Save the current transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
	old_trans_info [i] = gt_tool->trans_info [i];
    }

  /*  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
   */
  if ((gdisp == tool->gdisp) && gt_tool->interactive)
    {
      /*  start drawing the bounding box and handles...  */
Michael Natterer's avatar
Michael Natterer committed
390
      gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), shell->canvas->window);
391

Nate Summers's avatar
Nate Summers committed
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
      x = bevent->x;
      y = bevent->y;

      closest_dist = SQR (x - gt_tool->sx1) + SQR (y - gt_tool->sy1);
      gt_tool->function = TRANSFORM_HANDLE_1;

      dist = SQR (x - gt_tool->sx2) + SQR (y - gt_tool->sy2);
      if (dist < closest_dist)
	{
	  closest_dist = dist;
	  gt_tool->function = TRANSFORM_HANDLE_2;
	}

      dist = SQR (x - gt_tool->sx3) + SQR (y - gt_tool->sy3);
      if (dist < closest_dist)
	{
	  closest_dist = dist;
	  gt_tool->function = TRANSFORM_HANDLE_3;
	}

      dist = SQR (x - gt_tool->sx4) + SQR (y - gt_tool->sy4);
      if (dist < closest_dist)
	{
	  closest_dist = dist;
	  gt_tool->function = TRANSFORM_HANDLE_4;
	}

419 420
      if ((SQR (x - gt_tool->scx) +
	   SQR (y - gt_tool->scy)) <= 100)
Nate Summers's avatar
Nate Summers committed
421 422 423 424 425 426 427 428 429 430 431
	{
	  gt_tool->function = TRANSFORM_HANDLE_CENTER;
	}

      /*  Save the current pointer position  */
      gdisplay_untransform_coords (gdisp, bevent->x, bevent->y,
				   &gt_tool->startx,
				   &gt_tool->starty, TRUE, 0);
      gt_tool->lastx = gt_tool->startx;
      gt_tool->lasty = gt_tool->starty;

Michael Natterer's avatar
Michael Natterer committed
432
      gdk_pointer_grab (shell->canvas->window, FALSE,
Nate Summers's avatar
Nate Summers committed
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
			GDK_POINTER_MOTION_HINT_MASK |
			GDK_BUTTON1_MOTION_MASK |
			GDK_BUTTON_RELEASE_MASK,
			NULL, NULL, bevent->time);

      tool->state = ACTIVE;
      return;
    }


  /*  Initialisation stuff: if the cursor is clicked inside the current
   *  selection, show the bounding box and handles...
   */
  gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y,
			       FALSE, FALSE);

  gimp_drawable_offsets (drawable, &off_x, &off_y);
  if (x >= off_x && y >= off_y &&
      x < (off_x + gimp_drawable_width (drawable)) &&
      y < (off_y + gimp_drawable_height (drawable)))
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
    {
      if (gimage_mask_is_empty (gdisp->gimage) ||
	  gimage_mask_value (gdisp->gimage, x, y))
	{
	  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."));
	      tool->state = INACTIVE;
	      return;
	    }

	  /*  If the tool is already active, clear the current state
	   *  and reset
	   */
	  if (tool->state == ACTIVE)
	    gimp_transform_tool_reset (gt_tool, gdisp);

	  /*  Set the pointer to the active display  */
	  tool->gdisp    = gdisp;
	  tool->drawable = drawable;
	  tool->state    = ACTIVE;

	  /*  Grab the pointer if we're in non-interactive mode  */
	  if (!gt_tool->interactive)
Michael Natterer's avatar
Michael Natterer committed
479 480 481 482
	    gdk_pointer_grab (shell->canvas->window, FALSE,
			      GDK_POINTER_MOTION_HINT_MASK |
                              GDK_BUTTON1_MOTION_MASK |
                              GDK_BUTTON_RELEASE_MASK,
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
			      NULL, NULL, bevent->time);

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

	  /*  Calculate the grid line endpoints  */
	  if (gimp_transform_tool_show_grid ())
	    gimp_transform_tool_setup_grid (gt_tool);

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

	  if (transform_info && !transform_info_inited)
	    {
500
	      GType tool_type;
501 502

	      tool_type =
Michael Natterer's avatar
Michael Natterer committed
503
		gimp_context_get_tool (gimp_get_user_context (gdisp->gimage->gimp))->tool_type;
504 505

	      gimp_dialog_create_action_area
506
		(GIMP_DIALOG (transform_info->shell),
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

		 /* FIXME: this does not belong here */
		 (tool_type == GIMP_TYPE_ROTATE_TOOL)      ? _("Rotate")    :
		 (tool_type == GIMP_TYPE_SCALE_TOOL)       ? _("Scale")     :
		 (tool_type == GIMP_TYPE_SHEAR_TOOL)       ? _("Shear")     :
		 (tool_type == GIMP_TYPE_PERSPECTIVE_TOOL) ? _("Transform") :
		 "EEK",
		 transform_ok_callback,
		 tool, NULL, NULL, TRUE, FALSE,

		 _("Reset"), transform_reset_callback,
		 tool, NULL, NULL, FALSE, FALSE,

		 NULL);

	      transform_info_inited = TRUE;
	    }

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

	  /*  recall this function to find which handle we're dragging  */
	  if (gt_tool->interactive)
	    gimp_transform_tool_button_press (tool, bevent, gdisp);
	}
    }
Nate Summers's avatar
Nate Summers committed
533 534
}

535
static void
536 537 538
gimp_transform_tool_button_release (GimpTool       *tool,
			            GdkEventButton *bevent,
			            GimpDisplay    *gdisp)
Nate Summers's avatar
Nate Summers committed
539
{
Nate Summers's avatar
Nate Summers committed
540 541
  GimpTransformTool *gt_tool;
  gint               i;
Nate Summers's avatar
Nate Summers committed
542

543
  gt_tool = GIMP_TRANSFORM_TOOL (tool);
Nate Summers's avatar
Nate Summers committed
544 545 546 547

  gt_tool->bpressed = FALSE; /* ALT */

  /*  if we are creating, there is nothing to be done...exit  */
548
  if (gt_tool->function == TRANSFORM_CREATING && gt_tool->interactive)
Nate Summers's avatar
Nate Summers committed
549 550 551 552 553 554 555 556 557 558
    return;

  /*  release of the pointer grab  */
  gdk_pointer_ungrab (bevent->time);
  gdk_flush ();

  /*  if the 3rd button isn't pressed, transform the selected mask  */
  if (! (bevent->state & GDK_BUTTON3_MASK))
    {
      /* Shift-clicking is another way to approve the transform  */
559
      if ((bevent->state & GDK_SHIFT_MASK) || GIMP_IS_FLIP_TOOL (tool))
Nate Summers's avatar
Nate Summers committed
560
	{
Nate Summers's avatar
Nate Summers committed
561
	  gimp_transform_tool_doit (gt_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
562 563 564 565 566 567 568 569 570 571 572
	}
      else
	{
	  /*  Only update the paths preview */
	  path_transform_current_path (gdisp->gimage,
				       gt_tool->transform, TRUE);
	}
    }
  else
    {
      /*  stop the current tool drawing process  */
573
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
574 575 576 577 578 579 580 581 582

      /*  Restore the previous transformation info  */
      for (i = 0; i < TRAN_INFO_SIZE; i++)
	gt_tool->trans_info [i] = old_trans_info [i];

      /*  recalculate the tool's transformation matrix  */
      gimp_transform_tool_recalc (gt_tool, gdisp);

      /*  resume drawing the current tool  */
583
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
584 585 586 587 588 589 590 591 592 593 594

      /* Update the paths preview */
      path_transform_current_path (gdisp->gimage,
				   gt_tool->transform, TRUE);
    }

  /*  if this tool is non-interactive, make it inactive after use  */
  if (!gt_tool->interactive)
    tool->state = INACTIVE;
}

595
static void
Nate Summers's avatar
Nate Summers committed
596
gimp_transform_tool_doit (GimpTransformTool  *gt_tool,
597
		          GimpDisplay        *gdisp)
Nate Summers's avatar
Nate Summers committed
598
{
Michael Natterer's avatar
Michael Natterer committed
599 600 601 602 603 604
  GimpDisplayShell *shell;
  GimpTool         *tool;
  TileManager      *new_tiles;
  TransformUndo    *tu;
  PathUndo         *pundo;
  gboolean          new_layer;
605
  gint              i;
Nate Summers's avatar
Nate Summers committed
606

607
  gimp_set_busy (gdisp->gimage->gimp);
Nate Summers's avatar
Nate Summers committed
608

609
  tool = GIMP_TOOL (gt_tool);
Nate Summers's avatar
Nate Summers committed
610

Michael Natterer's avatar
Michael Natterer committed
611 612
  shell = GIMP_DISPLAY_SHELL (gdisp->shell);

Nate Summers's avatar
Nate Summers committed
613
  /* undraw the tool before we muck around with the transform matrix */
614
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (gt_tool));
Nate Summers's avatar
Nate Summers committed
615 616 617 618 619 620 621 622 623

  /*  We're going to dirty this image, but we want to keep the tool
   *  around
   */
  tool->preserve = TRUE;

  /*  Start a transform undo group  */
  undo_push_group_start (gdisp->gimage, TRANSFORM_CORE_UNDO);

624 625 626
  /* With the old UI, if original is NULL, then this is the
   * first transformation. In the new UI, it is always so, right?
   */
Nate Summers's avatar
Nate Summers committed
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
  g_assert (gt_tool->original == NULL);

  /* If we're in interactive mode, we need to 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);

  gt_tool->original = gimp_transform_tool_cut (gdisp->gimage,
					       tool->drawable,
					       &new_layer);

  pundo = path_transform_start_undo (gdisp->gimage);

  /*  Send the request for the transformation to the tool...
   */
Nate Summers's avatar
Nate Summers committed
643
  new_tiles = gimp_transform_tool_transform (gt_tool, gdisp,
644
					     TRANSFORM_FINISH);
Nate Summers's avatar
Nate Summers committed
645

Nate Summers's avatar
Nate Summers committed
646
  gimp_transform_tool_transform (gt_tool, gdisp, TRANSFORM_INIT);
Nate Summers's avatar
Nate Summers committed
647 648 649 650 651 652 653 654 655 656

  gimp_transform_tool_recalc (gt_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_transform_tool_paste (gdisp->gimage, tool->drawable,
657
				 new_tiles, new_layer);
Nate Summers's avatar
Nate Summers committed
658 659

      /*  create and initialize the transform_undo structure  */
660 661
      tu = g_new0 (TransformUndo, 1);
      tu->tool_ID   = tool->ID;
662
      tu->tool_type = G_TYPE_FROM_INSTANCE (tool);
Nate Summers's avatar
Nate Summers committed
663

Nate Summers's avatar
Nate Summers committed
664 665
      for (i = 0; i < TRAN_INFO_SIZE; i++)
	tu->trans_info[i] = old_trans_info[i];
666 667

      tu->original  = NULL;
Nate Summers's avatar
Nate Summers committed
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
      tu->path_undo = pundo;

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

      undo_push_transform (gdisp->gimage, (void *) tu);
    }

  /*  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
   */
  tool->preserve = FALSE;

686 687 688 689
#ifdef __GNUC__
#warning FIXME: investigate why display update was done here
#endif
#if 0
Nate Summers's avatar
Nate Summers committed
690 691 692
  /*  Flush the gdisplays  */
  if (gdisp->disp_xoffset || gdisp->disp_yoffset)
    {
693 694 695 696
      gint x, y;

      x = shell->disp_width;
      y = shell->disp_height;
697

Nate Summers's avatar
Nate Summers committed
698 699
      if (gdisp->disp_yoffset)
	{
Michael Natterer's avatar
Michael Natterer committed
700 701 702 703 704 705 706
	  gimp_display_shell_add_expose_area (shell,
                                              0, 0,
                                              gdisp->disp_width,
                                              gdisp->disp_yoffset);
	  gimp_display_shell_add_expose_area (shell,
                                              0, gdisp->disp_yoffset + y,
                                              gdisp->disp_width, gdisp->disp_height);
Nate Summers's avatar
Nate Summers committed
707
	}
Michael Natterer's avatar
Michael Natterer committed
708

Nate Summers's avatar
Nate Summers committed
709 710
      if (gdisp->disp_xoffset)
	{
Michael Natterer's avatar
Michael Natterer committed
711 712 713 714 715 716
	  gimp_display_shell_add_expose_area (shell,
                                              0, 0,
                                              gdisp->disp_xoffset, gdisp->disp_height);
	  gimp_display_shell_add_expose_area (shell,
                                              gdisp->disp_xoffset + x, 0,
                                              gdisp->disp_width, gdisp->disp_height);
Nate Summers's avatar
Nate Summers committed
717 718
	}
    }
719
#endif
Nate Summers's avatar
Nate Summers committed
720

721
  gimp_unset_busy (gdisp->gimage->gimp);
Nate Summers's avatar
Nate Summers committed
722 723 724

  gdisplays_flush ();

725
  gimp_transform_tool_reset (gt_tool, gdisp);
Nate Summers's avatar
Nate Summers committed
726 727

  /*  if this tool is non-interactive, make it inactive after use  */
Nate Summers's avatar
Nate Summers committed
728
  if (!gt_tool->interactive)
Nate Summers's avatar
Nate Summers committed
729 730 731
    tool->state = INACTIVE;
}

732
static void
733 734 735
gimp_transform_tool_motion (GimpTool       *tool,
		            GdkEventMotion *mevent,
		            GimpDisplay    *gdisp)
Nate Summers's avatar
Nate Summers committed
736
{
Nate Summers's avatar
Nate Summers committed
737
  GimpTransformTool *tr_tool;
Nate Summers's avatar
Nate Summers committed
738

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

741
  if (! tr_tool->bpressed)
Nate Summers's avatar
Nate Summers committed
742 743 744 745 746
    return;

  /*  if we are creating or this tool is non-interactive, there is
   *  nothing to be done so exit.
   */
Nate Summers's avatar
Nate Summers committed
747 748
  if (tr_tool->function == TRANSFORM_CREATING ||
      !tr_tool->interactive)
Nate Summers's avatar
Nate Summers committed
749 750 751
    return;

  /*  stop the current tool drawing process  */
752
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
753 754

  gdisplay_untransform_coords (gdisp, mevent->x, mevent->y,
Nate Summers's avatar
Nate Summers committed
755 756 757
			       &tr_tool->curx,
			       &tr_tool->cury, TRUE, 0);
  tr_tool->state = mevent->state;
Nate Summers's avatar
Nate Summers committed
758 759

  /*  recalculate the tool's transformation matrix  */
Nate Summers's avatar
Nate Summers committed
760
  gimp_transform_tool_transform (tr_tool, gdisp, TRANSFORM_MOTION);
Nate Summers's avatar
Nate Summers committed
761

Nate Summers's avatar
Nate Summers committed
762 763
  tr_tool->lastx = tr_tool->curx;
  tr_tool->lasty = tr_tool->cury;
Nate Summers's avatar
Nate Summers committed
764 765

  /*  resume drawing the current tool  */
766
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
Nate Summers's avatar
Nate Summers committed
767 768
}

769
static void
770 771 772
gimp_transform_tool_cursor_update (GimpTool       *tool,
			           GdkEventMotion *mevent,
			           GimpDisplay    *gdisp)
Nate Summers's avatar
Nate Summers committed
773
{
Nate Summers's avatar
Nate Summers committed
774
  GimpTransformTool  *tr_tool;
Michael Natterer's avatar
Michael Natterer committed
775
  GimpDisplayShell   *shell;
Nate Summers's avatar
Nate Summers committed
776 777 778
  GimpDrawable       *drawable;
  GdkCursorType       ctype = GDK_TOP_LEFT_ARROW;
  gint                x, y;
Nate Summers's avatar
Nate Summers committed
779

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

Michael Natterer's avatar
Michael Natterer committed
782 783
  shell = GIMP_DISPLAY_SHELL (gdisp->shell);

Nate Summers's avatar
Nate Summers committed
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
  gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y,
			       FALSE, FALSE);

  if ((drawable = gimp_image_active_drawable (gdisp->gimage)))
    {
      if (GIMP_IS_LAYER (drawable) &&
	  gimp_layer_get_mask (GIMP_LAYER (drawable)))
	{
	  ctype = GIMP_BAD_CURSOR;
	}
      else if (x >= drawable->offset_x &&
	       y >= drawable->offset_y &&
	       x < (drawable->offset_x + drawable->width) &&
	       y < (drawable->offset_y + drawable->height))
	{
	  if (gimage_mask_is_empty (gdisp->gimage) ||
	      gimage_mask_value (gdisp->gimage, x, y))
	    {
	      ctype = GIMP_MOUSE_CURSOR;
	    }
	}
    }

Michael Natterer's avatar
Michael Natterer committed
807 808 809 810
  gimp_display_shell_install_tool_cursor (shell,
                                          ctype,
                                          tool->tool_cursor,
                                          GIMP_CURSOR_MODIFIER_NONE);
Nate Summers's avatar
Nate Summers committed
811 812
}

813
static void
Nate Summers's avatar
Nate Summers committed
814
gimp_transform_tool_draw (GimpDrawTool *dr_tool)
Nate Summers's avatar
Nate Summers committed
815
{
816
  GimpDisplay        *gdisp;
Nate Summers's avatar
Nate Summers committed
817 818 819 820 821 822 823
  GimpTransformTool  *tr_tool;
  GimpTool           *tool;
  gint                x1, y1, x2, y2, x3, y3, x4, y4;
  gint                srw, srh;
  gint                i, k, gci;
  gint                xa, ya, xb, yb;

824 825
  tr_tool = GIMP_TRANSFORM_TOOL (dr_tool);
  tool    = GIMP_TOOL (dr_tool);
Nate Summers's avatar
Nate Summers committed
826

827
  gdisp   = tool->gdisp;
Nate Summers's avatar
Nate Summers committed
828 829 830 831 832 833 834 835 836 837 838 839 840 841

  gdisplay_transform_coords (gdisp, tr_tool->tx1, tr_tool->ty1,
			     &tr_tool->sx1, &tr_tool->sy1, FALSE);
  gdisplay_transform_coords (gdisp, tr_tool->tx2, tr_tool->ty2,
			     &tr_tool->sx2, &tr_tool->sy2, FALSE);
  gdisplay_transform_coords (gdisp, tr_tool->tx3, tr_tool->ty3,
			     &tr_tool->sx3, &tr_tool->sy3, FALSE);
  gdisplay_transform_coords (gdisp, tr_tool->tx4, tr_tool->ty4,
			     &tr_tool->sx4, &tr_tool->sy4, FALSE);

  x1 = tr_tool->sx1;  y1 = tr_tool->sy1;
  x2 = tr_tool->sx2;  y2 = tr_tool->sy2;
  x3 = tr_tool->sx3;  y3 = tr_tool->sy3;
  x4 = tr_tool->sx4;  y4 = tr_tool->sy4;
Nate Summers's avatar
Nate Summers committed
842 843 844 845 846 847

  /*  find the handles' width and height  */
  srw = 10;
  srh = 10;

  /*  draw the bounding box  */
Nate Summers's avatar
Nate Summers committed
848
  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
849
		 x1, y1, x2, y2);
Nate Summers's avatar
Nate Summers committed
850
  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
851
		 x2, y2, x4, y4);
Nate Summers's avatar
Nate Summers committed
852
  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
853
		 x3, y3, x4, y4);
Nate Summers's avatar
Nate Summers committed
854
  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
855 856 857 858
		 x3, y3, x1, y1);

  /*  Draw the grid */

Nate Summers's avatar
Nate Summers committed
859
  if ((tr_tool->grid_coords != NULL) &&
Nate Summers's avatar
Nate Summers committed
860 861
      (tr_tool->tgrid_coords != NULL) /* FIXME!!! this doesn't belong here &&
      ((tool->type != PERSPECTIVE)  ||
Nate Summers's avatar
Nate Summers committed
862
       ((tr_tool->transform[0][0] >=0.0) &&
Nate Summers's avatar
Nate Summers committed
863
	(tr_tool->transform[1][1] >=0.0)) */ ) 
Nate Summers's avatar
Nate Summers committed
864 865
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
866
      k = tr_tool->ngx + tr_tool->ngy;
867

Nate Summers's avatar
Nate Summers committed
868 869
      for (i = 0; i < k; i++)
	{
Nate Summers's avatar
Nate Summers committed
870 871
	  gdisplay_transform_coords (gdisp, tr_tool->tgrid_coords[gci],
				     tr_tool->tgrid_coords[gci+1],
Nate Summers's avatar
Nate Summers committed
872
				     &xa, &ya, FALSE);
Nate Summers's avatar
Nate Summers committed
873 874
	  gdisplay_transform_coords (gdisp, tr_tool->tgrid_coords[gci+2],
				     tr_tool->tgrid_coords[gci+3],
Nate Summers's avatar
Nate Summers committed
875 876
				     &xb, &yb, FALSE);

Nate Summers's avatar
Nate Summers committed
877
	  gdk_draw_line (dr_tool->win, dr_tool->gc,
Nate Summers's avatar
Nate Summers committed
878 879 880 881 882 883
			 xa, ya, xb, yb);
	  gci += 4;
	}
    }

  /*  draw the tool handles  */
Nate Summers's avatar
Nate Summers committed
884
  gdk_draw_rectangle (dr_tool->win, dr_tool->gc, 0,
Nate Summers's avatar
Nate Summers committed
885
		      x1 - (srw >> 1), y1 - (srh >> 1), srw, srh);
Nate Summers's avatar
Nate Summers committed
886
  gdk_draw_rectangle (dr_tool->win, dr_tool->gc, 0,
Nate Summers's avatar
Nate Summers committed
887
		      x2 - (srw >> 1), y2 - (srh >> 1), srw, srh);
Nate Summers's avatar
Nate Summers committed
888
  gdk_draw_rectangle (dr_tool->win, dr_tool->gc, 0,
Nate Summers's avatar
Nate Summers committed
889
		      x3 - (srw >> 1), y3 - (srh >> 1), srw, srh);
Nate Summers's avatar
Nate Summers committed
890
  gdk_draw_rectangle (dr_tool->win, dr_tool->gc, 0,
Nate Summers's avatar
Nate Summers committed
891 892 893
		      x4 - (srw >> 1), y4 - (srh >> 1), srw, srh);

  /*  draw the center  */
894 895 896
  gdisplay_transform_coords (gdisp,
			     tr_tool->tcx, tr_tool->tcy,
			     &tr_tool->scx, &tr_tool->scy, FALSE);
Nate Summers's avatar
Nate Summers committed
897

898 899 900 901 902 903
  gdk_draw_arc (dr_tool->win,
		dr_tool->gc,
		1,
		tr_tool->scx - (srw >> 1),
		tr_tool->scy - (srh >> 1),
		srw, srh, 0, 23040);
Nate Summers's avatar
Nate Summers committed
904

905
  if (gimp_transform_tool_showpath ())
Nate Summers's avatar
Nate Summers committed
906 907 908
    {
      GimpMatrix3 tmp_matrix;

909
      if (gimp_transform_tool_direction () == TRANSFORM_CORRECTIVE)
Nate Summers's avatar
Nate Summers committed
910
	{
Nate Summers's avatar
Nate Summers committed
911
	  gimp_matrix3_invert (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
912 913 914
	}
      else
	{
Nate Summers's avatar
Nate Summers committed
915
	  gimp_matrix3_duplicate (tr_tool->transform, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
916 917
	}

Nate Summers's avatar
Nate Summers committed
918
      path_transform_draw_current (gdisp, dr_tool, tmp_matrix);
Nate Summers's avatar
Nate Summers committed
919 920 921 922
    }
}

void
Nate Summers's avatar
Nate Summers committed
923
gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool)
Nate Summers's avatar
Nate Summers committed
924
{
Nate Summers's avatar
Nate Summers committed
925 926 927 928
  GimpTool  *tool;
  gint       i, k;
  gint       gci;

929
  tool = GIMP_TOOL (tr_tool);
Nate Summers's avatar
Nate Summers committed
930 931 932 933 934 935 936 937 938 939 940 941 942

  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
943

944 945 946
  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
947

Nate Summers's avatar
Nate Summers committed
948 949
  if (tr_tool->grid_coords != NULL &&
      tr_tool->tgrid_coords != NULL)
Nate Summers's avatar
Nate Summers committed
950 951
    {
      gci = 0;
Nate Summers's avatar
Nate Summers committed
952
      k  = (tr_tool->ngx + tr_tool->ngy) * 2;
953

Nate Summers's avatar
Nate Summers committed
954 955
      for (i = 0; i < k; i++)
	{
Nate Summers's avatar
Nate Summers committed
956 957 958 959 960
	  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
961 962 963 964 965 966
	  gci += 2;
	}
    }
}

void
967
gimp_transform_tool_reset (GimpTransformTool *tr_tool,
968
		           GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
969
{
Nate Summers's avatar
Nate Summers committed
970
  GimpTool *tool;
Nate Summers's avatar
Nate Summers committed
971

972
  tool = GIMP_TOOL (tr_tool);
Nate Summers's avatar
Nate Summers committed
973

Nate Summers's avatar
Nate Summers committed
974
  if (tr_tool->original)
975 976 977 978
    {
      tile_manager_destroy (tr_tool->original);
      tr_tool->original = NULL;
    }
Nate Summers's avatar
Nate Summers committed
979 980

  /*  inactivate the tool  */
Nate Summers's avatar
Nate Summers committed
981
  tr_tool->function = TRANSFORM_CREATING;
982
  gimp_draw_tool_stop (GIMP_DRAW_TOOL (tr_tool));
Nate Summers's avatar
Nate Summers committed
983 984 985 986 987 988 989 990
  info_dialog_popdown (transform_info);

  tool->state    = INACTIVE;
  tool->gdisp    = NULL;
  tool->drawable = NULL;
}

static void
991
gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
992
		            GimpDisplay       *gdisp)
Nate Summers's avatar
Nate Summers committed
993
{
994 995 996
  TileManager  *tiles;
  GimpDrawable *drawable;
  gint          offset_x, offset_y;
Nate Summers's avatar
Nate Summers committed
997

998 999
  tiles    = tr_tool->original;
  drawable = gimp_image_active_drawable (gdisp->gimage);
Nate Summers's avatar
Nate Summers committed
1000 1001 1002 1003 1004

  /*  find the boundaries  */
  if (tiles)
    {
      tile_manager_get_offsets (tiles,
Nate Summers's avatar
Nate Summers committed
1005 1006 1007 1008
				&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);