~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to app/tools/gimprectangletool.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GIMP - The GNU Image Manipulation Program
 
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 */
 
18
 
 
19
#include "config.h"
 
20
 
 
21
#include <string.h>
 
22
 
 
23
#include <gtk/gtk.h>
 
24
#include <gdk/gdkkeysyms.h>
 
25
 
 
26
#include "libgimpbase/gimpbase.h"
 
27
#include "libgimpmath/gimpmath.h"
 
28
#include "libgimpwidgets/gimpwidgets.h"
 
29
 
 
30
#include "tools-types.h"
 
31
 
 
32
#include "core/gimpchannel.h"
 
33
#include "core/gimpimage.h"
 
34
#include "core/gimpimage-crop.h"
 
35
#include "core/gimppickable.h"
 
36
#include "core/gimpmarshal.h"
 
37
 
 
38
#include "display/gimpdisplay.h"
 
39
#include "display/gimpdisplayshell.h"
 
40
#include "display/gimpdisplayshell-transform.h"
 
41
 
 
42
#include "gimpdrawtool.h"
 
43
#include "gimprectangleoptions.h"
 
44
#include "gimprectangletool.h"
 
45
#include "gimptoolcontrol.h"
 
46
 
 
47
#include "gimp-intl.h"
 
48
 
 
49
 
 
50
enum
 
51
{
 
52
  RECTANGLE_CHANGED,
 
53
  LAST_SIGNAL
 
54
};
 
55
 
 
56
/*  speed of key movement  */
 
57
#define ARROW_VELOCITY   25
 
58
 
 
59
#define HANDLE_SIZE      50
 
60
#define MIN_HANDLE_SIZE   6
 
61
 
 
62
#define SQRT5   2.236067977
 
63
 
 
64
 
 
65
#define GIMP_RECTANGLE_TOOL_GET_PRIVATE(obj) \
 
66
  (gimp_rectangle_tool_get_private (GIMP_RECTANGLE_TOOL (obj)))
 
67
 
 
68
 
 
69
typedef struct _GimpRectangleToolPrivate GimpRectangleToolPrivate;
 
70
 
 
71
struct _GimpRectangleToolPrivate
 
72
{
 
73
  gint                    pressx;     /*  x where button pressed         */
 
74
  gint                    pressy;     /*  y where button pressed         */
 
75
 
 
76
  gint                    x1, y1;     /*  upper left hand coordinate     */
 
77
  gint                    x2, y2;     /*  lower right hand coords        */
 
78
 
 
79
  guint                   function;   /*  moving or resizing             */
 
80
 
 
81
  GimpRectangleConstraint constraint; /* how to constrain rectangle     */
 
82
 
 
83
  /* Internal state */
 
84
  gint                    startx;     /*  starting x coord               */
 
85
  gint                    starty;     /*  starting y coord               */
 
86
 
 
87
  gint                    lastx;      /*  previous x coord               */
 
88
  gint                    lasty;      /*  previous y coord               */
 
89
 
 
90
  gint                    handle_w;   /*  handle width                   */
 
91
  gint                    handle_h;   /*  handle height                  */
 
92
 
 
93
  gint                    saved_x1;   /*  for saving in case action      */
 
94
  gint                    saved_y1;   /*  is canceled                    */
 
95
  gint                    saved_x2;
 
96
  gint                    saved_y2;
 
97
  gdouble                 saved_center_x;
 
98
  gdouble                 saved_center_y;
 
99
 
 
100
  gint                    suppress_updates;
 
101
 
 
102
  GimpRectangleGuide      guide; /* synced with options->guide, only exists for drawing */
 
103
};
 
104
 
 
105
 
 
106
static void gimp_rectangle_tool_iface_base_init     (GimpRectangleToolInterface *iface);
 
107
 
 
108
static GimpRectangleToolPrivate *
 
109
                gimp_rectangle_tool_get_private     (GimpRectangleTool *rectangle);
 
110
 
 
111
GimpRectangleConstraint
 
112
                gimp_rectangle_tool_get_constraint  (GimpRectangleTool *rectangle);
 
113
 
 
114
/*  Rectangle helper functions  */
 
115
static void     gimp_rectangle_tool_start           (GimpRectangleTool *rectangle,
 
116
                                                     GimpDisplay       *display);
 
117
static void     gimp_rectangle_tool_halt            (GimpRectangleTool *rectangle);
 
118
static void     gimp_rectangle_tool_draw_guides     (GimpDrawTool      *draw_tool);
 
119
 
 
120
/*  Rectangle dialog functions  */
 
121
static void     gimp_rectangle_tool_update_options  (GimpRectangleTool *rectangle,
 
122
                                                     GimpDisplay       *display);
 
123
 
 
124
static void     gimp_rectangle_tool_options_notify  (GimpRectangleOptions *options,
 
125
                                                     GParamSpec         *pspec,
 
126
                                                     GimpRectangleTool  *rectangle);
 
127
 
 
128
static void     gimp_rectangle_tool_check_function  (GimpRectangleTool *rectangle,
 
129
                                                     gint              *x1,
 
130
                                                     gint              *y1,
 
131
                                                     gint              *x2,
 
132
                                                     gint              *y2);
 
133
static void gimp_rectangle_tool_rectangle_changed   (GimpRectangleTool *rectangle);
 
134
 
 
135
static void gimp_rectangle_tool_constrain           (GimpRectangleTool *rectangle,
 
136
                                                     gint               *x1,
 
137
                                                     gint               *y1,
 
138
                                                     gint               *x2,
 
139
                                                     gint               *y2);
 
140
 
 
141
static void     gimp_rectangle_tool_auto_shrink     (GimpRectangleTool *rectangle);
 
142
 
 
143
static GtkAnchorType gimp_rectangle_tool_get_anchor (GimpRectangleToolPrivate *private,
 
144
                                                     gint                     *w,
 
145
                                                     gint                     *h);
 
146
static void     gimp_rectangle_tool_set_highlight   (GimpRectangleTool *rectangle);
 
147
 
 
148
 
 
149
static guint gimp_rectangle_tool_signals[LAST_SIGNAL] = { 0 };
 
150
 
 
151
 
 
152
GType
 
153
gimp_rectangle_tool_interface_get_type (void)
 
154
{
 
155
  static GType iface_type = 0;
 
156
 
 
157
  if (! iface_type)
 
158
    {
 
159
      const GTypeInfo iface_info =
 
160
      {
 
161
        sizeof (GimpRectangleToolInterface),
 
162
        (GBaseInitFunc)     gimp_rectangle_tool_iface_base_init,
 
163
        (GBaseFinalizeFunc) NULL,
 
164
      };
 
165
 
 
166
      iface_type = g_type_register_static (G_TYPE_INTERFACE,
 
167
                                           "GimpRectangleToolInterface",
 
168
                                           &iface_info, 0);
 
169
 
 
170
      g_type_interface_add_prerequisite (iface_type, GIMP_TYPE_DRAW_TOOL);
 
171
    }
 
172
 
 
173
  return iface_type;
 
174
}
 
175
 
 
176
static void
 
177
gimp_rectangle_tool_iface_base_init (GimpRectangleToolInterface *iface)
 
178
{
 
179
  static gboolean initialized = FALSE;
 
180
 
 
181
  if (! initialized)
 
182
    {
 
183
      gimp_rectangle_tool_signals[RECTANGLE_CHANGED] =
 
184
        g_signal_new ("rectangle-changed",
 
185
                      G_TYPE_FROM_INTERFACE (iface),
 
186
                      G_SIGNAL_RUN_FIRST,
 
187
                      G_STRUCT_OFFSET (GimpRectangleToolInterface,
 
188
                                       rectangle_changed),
 
189
                      NULL, NULL,
 
190
                      gimp_marshal_VOID__VOID,
 
191
                      G_TYPE_NONE, 0);
 
192
 
 
193
      g_object_interface_install_property (iface,
 
194
                                           g_param_spec_int ("x1",
 
195
                                                             NULL, NULL,
 
196
                                                             -GIMP_MAX_IMAGE_SIZE,
 
197
                                                             GIMP_MAX_IMAGE_SIZE,
 
198
                                                             0,
 
199
                                                             GIMP_PARAM_READWRITE));
 
200
 
 
201
      g_object_interface_install_property (iface,
 
202
                                           g_param_spec_int ("y1",
 
203
                                                             NULL, NULL,
 
204
                                                             -GIMP_MAX_IMAGE_SIZE,
 
205
                                                             GIMP_MAX_IMAGE_SIZE,
 
206
                                                             0,
 
207
                                                             GIMP_PARAM_READWRITE));
 
208
 
 
209
      g_object_interface_install_property (iface,
 
210
                                           g_param_spec_int ("x2",
 
211
                                                             NULL, NULL,
 
212
                                                             -GIMP_MAX_IMAGE_SIZE,
 
213
                                                             GIMP_MAX_IMAGE_SIZE,
 
214
                                                             0,
 
215
                                                             GIMP_PARAM_READWRITE));
 
216
 
 
217
      g_object_interface_install_property (iface,
 
218
                                           g_param_spec_int ("y2",
 
219
                                                             NULL, NULL,
 
220
                                                             -GIMP_MAX_IMAGE_SIZE,
 
221
                                                             GIMP_MAX_IMAGE_SIZE,
 
222
                                                             0,
 
223
                                                             GIMP_PARAM_READWRITE));
 
224
 
 
225
      g_object_interface_install_property (iface,
 
226
                                           g_param_spec_enum ("constraint",
 
227
                                                              NULL, NULL,
 
228
                                                              GIMP_TYPE_RECTANGLE_CONSTRAINT,
 
229
                                                              GIMP_RECTANGLE_CONSTRAIN_NONE,
 
230
                                                              GIMP_PARAM_READWRITE));
 
231
 
 
232
      iface->execute           = NULL;
 
233
      iface->cancel            = NULL;
 
234
      iface->rectangle_changed = NULL;
 
235
 
 
236
      initialized = TRUE;
 
237
    }
 
238
}
 
239
 
 
240
static void
 
241
gimp_rectangle_tool_private_finalize (GimpRectangleToolPrivate *private)
 
242
{
 
243
  g_free (private);
 
244
}
 
245
 
 
246
static GimpRectangleToolPrivate *
 
247
gimp_rectangle_tool_get_private (GimpRectangleTool *tool)
 
248
{
 
249
  static GQuark private_key = 0;
 
250
 
 
251
  GimpRectangleToolPrivate *private;
 
252
 
 
253
  if (G_UNLIKELY (private_key == 0))
 
254
    private_key = g_quark_from_static_string ("gimp-rectangle-tool-private");
 
255
 
 
256
  private = g_object_get_qdata (G_OBJECT (tool), private_key);
 
257
 
 
258
  if (! private)
 
259
    {
 
260
      private = g_new0 (GimpRectangleToolPrivate, 1);
 
261
 
 
262
      g_object_set_qdata_full (G_OBJECT (tool), private_key, private,
 
263
                               (GDestroyNotify)
 
264
                               gimp_rectangle_tool_private_finalize);
 
265
    }
 
266
 
 
267
  return private;
 
268
}
 
269
 
 
270
/**
 
271
 * gimp_rectangle_tool_install_properties:
 
272
 * @klass: the class structure for a type deriving from #GObject
 
273
 *
 
274
 * Installs the necessary properties for a class implementing
 
275
 * #GimpToolOptions. A #GimpRectangleToolProp property is installed
 
276
 * for each property, using the values from the #GimpRectangleToolProp
 
277
 * enumeration. The caller must make sure itself that the enumeration
 
278
 * values don't collide with some other property values they
 
279
 * are using (that's what %GIMP_RECTANGLE_TOOL_PROP_LAST is good for).
 
280
 **/
 
281
void
 
282
gimp_rectangle_tool_install_properties (GObjectClass *klass)
 
283
{
 
284
  g_object_class_override_property (klass,
 
285
                                    GIMP_RECTANGLE_TOOL_PROP_X1,
 
286
                                    "x1");
 
287
  g_object_class_override_property (klass,
 
288
                                    GIMP_RECTANGLE_TOOL_PROP_Y1,
 
289
                                    "y1");
 
290
  g_object_class_override_property (klass,
 
291
                                    GIMP_RECTANGLE_TOOL_PROP_X2,
 
292
                                    "x2");
 
293
  g_object_class_override_property (klass,
 
294
                                    GIMP_RECTANGLE_TOOL_PROP_Y2,
 
295
                                    "y2");
 
296
  g_object_class_override_property (klass,
 
297
                                    GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT,
 
298
                                    "constraint");
 
299
}
 
300
 
 
301
void
 
302
gimp_rectangle_tool_set_constraint (GimpRectangleTool       *tool,
 
303
                                    GimpRectangleConstraint  constraint)
 
304
{
 
305
  GimpRectangleToolPrivate *private;
 
306
 
 
307
  g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
 
308
 
 
309
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
310
 
 
311
  private->constraint = constraint;
 
312
 
 
313
  g_object_notify (G_OBJECT (tool), "constraint");
 
314
}
 
315
 
 
316
GimpRectangleConstraint
 
317
gimp_rectangle_tool_get_constraint (GimpRectangleTool *tool)
 
318
{
 
319
  GimpRectangleToolPrivate *private;
 
320
 
 
321
  g_return_val_if_fail (GIMP_IS_RECTANGLE_TOOL (tool), 0);
 
322
 
 
323
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
324
 
 
325
  return private->constraint;
 
326
}
 
327
 
 
328
void
 
329
gimp_rectangle_tool_get_press_coords (GimpRectangleTool *rectangle,
 
330
                                      gint              *pressx_ptr,
 
331
                                      gint              *pressy_ptr)
 
332
{
 
333
  GimpRectangleToolPrivate *private;
 
334
 
 
335
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
336
 
 
337
  *pressx_ptr = private->pressx;
 
338
  *pressy_ptr = private->pressy;
 
339
}
 
340
 
 
341
void
 
342
gimp_rectangle_tool_set_property (GObject      *object,
 
343
                                  guint         property_id,
 
344
                                  const GValue *value,
 
345
                                  GParamSpec   *pspec)
 
346
{
 
347
  GimpRectangleTool        *rectangle = GIMP_RECTANGLE_TOOL (object);
 
348
  GimpRectangleToolPrivate *private;
 
349
 
 
350
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
351
 
 
352
  switch (property_id)
 
353
    {
 
354
    case GIMP_RECTANGLE_TOOL_PROP_X1:
 
355
      private->x1 = g_value_get_int (value);
 
356
      break;
 
357
    case GIMP_RECTANGLE_TOOL_PROP_Y1:
 
358
      private->y1 = g_value_get_int (value);
 
359
      break;
 
360
    case GIMP_RECTANGLE_TOOL_PROP_X2:
 
361
      private->x2 = g_value_get_int (value);
 
362
      break;
 
363
    case GIMP_RECTANGLE_TOOL_PROP_Y2:
 
364
      private->y2 = g_value_get_int (value);
 
365
      break;
 
366
    case GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT:
 
367
      gimp_rectangle_tool_set_constraint (rectangle, g_value_get_enum (value));
 
368
      break;
 
369
    default:
 
370
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
371
      break;
 
372
    }
 
373
}
 
374
 
 
375
void
 
376
gimp_rectangle_tool_get_property (GObject      *object,
 
377
                                  guint         property_id,
 
378
                                  GValue       *value,
 
379
                                  GParamSpec   *pspec)
 
380
{
 
381
  GimpRectangleTool        *rectangle = GIMP_RECTANGLE_TOOL (object);
 
382
  GimpRectangleToolPrivate *private;
 
383
 
 
384
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
385
 
 
386
  switch (property_id)
 
387
    {
 
388
    case GIMP_RECTANGLE_TOOL_PROP_X1:
 
389
      g_value_set_int (value, private->x1);
 
390
      break;
 
391
    case GIMP_RECTANGLE_TOOL_PROP_Y1:
 
392
      g_value_set_int (value, private->y1);
 
393
      break;
 
394
    case GIMP_RECTANGLE_TOOL_PROP_X2:
 
395
      g_value_set_int (value, private->x2);
 
396
      break;
 
397
    case GIMP_RECTANGLE_TOOL_PROP_Y2:
 
398
      g_value_set_int (value, private->y2);
 
399
      break;
 
400
    case GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT:
 
401
      g_value_set_enum (value, gimp_rectangle_tool_get_constraint (rectangle));
 
402
      break;
 
403
    default:
 
404
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
405
      break;
 
406
    }
 
407
}
 
408
 
 
409
void
 
410
gimp_rectangle_tool_constructor (GObject *object)
 
411
{
 
412
  GimpRectangleTool        *rectangle = GIMP_RECTANGLE_TOOL (object);
 
413
  GimpRectangleToolPrivate *private;
 
414
  GimpRectangleOptions     *options;
 
415
 
 
416
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (object);
 
417
  options = GIMP_RECTANGLE_TOOL_GET_OPTIONS (object);
 
418
 
 
419
  g_object_get (options,
 
420
                "guide", &private->guide,
 
421
                NULL);
 
422
 
 
423
  g_signal_connect_object (options, "notify",
 
424
                           G_CALLBACK (gimp_rectangle_tool_options_notify),
 
425
                           rectangle, 0);
 
426
}
 
427
 
 
428
void
 
429
gimp_rectangle_tool_control (GimpTool       *tool,
 
430
                             GimpToolAction  action,
 
431
                             GimpDisplay    *display)
 
432
{
 
433
  GimpRectangleTool *rectangle = GIMP_RECTANGLE_TOOL (tool);
 
434
 
 
435
  switch (action)
 
436
    {
 
437
    case GIMP_TOOL_ACTION_PAUSE:
 
438
      break;
 
439
 
 
440
    case GIMP_TOOL_ACTION_RESUME:
 
441
      gimp_rectangle_tool_configure (rectangle);
 
442
      break;
 
443
 
 
444
    case GIMP_TOOL_ACTION_HALT:
 
445
      gimp_rectangle_tool_halt (rectangle);
 
446
      break;
 
447
 
 
448
    default:
 
449
      break;
 
450
    }
 
451
}
 
452
 
 
453
void
 
454
gimp_rectangle_tool_button_press (GimpTool        *tool,
 
455
                                  GimpCoords      *coords,
 
456
                                  guint32          time,
 
457
                                  GdkModifierType  state,
 
458
                                  GimpDisplay     *display)
 
459
{
 
460
  GimpRectangleTool           *rectangle;
 
461
  GimpDrawTool                *draw_tool;
 
462
  GimpRectangleToolPrivate    *private;
 
463
  GimpRectangleOptions        *options;
 
464
  GimpRectangleOptionsPrivate *options_private;
 
465
  gint                         x, y;
 
466
  gint                         snap_x, snap_y;
 
467
 
 
468
  g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
 
469
 
 
470
  rectangle       = GIMP_RECTANGLE_TOOL (tool);
 
471
  draw_tool       = GIMP_DRAW_TOOL (tool);
 
472
  private         = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
473
  options         = GIMP_RECTANGLE_TOOL_GET_OPTIONS (tool);
 
474
  options_private = GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (options);
 
475
 
 
476
  x = ROUND (coords->x);
 
477
  y = ROUND (coords->y);
 
478
 
 
479
  gimp_draw_tool_pause (draw_tool);
 
480
 
 
481
  if (display != tool->display)
 
482
    {
 
483
      if (gimp_draw_tool_is_active (draw_tool))
 
484
        gimp_draw_tool_stop (draw_tool);
 
485
 
 
486
      gimp_rectangle_tool_set_function (rectangle, RECT_CREATING);
 
487
 
 
488
      g_object_set (rectangle,
 
489
                    "x1", x,
 
490
                    "y1", y,
 
491
                    "x2", x,
 
492
                    "y2", y,
 
493
                    NULL);
 
494
 
 
495
      gimp_rectangle_tool_start (rectangle, display);
 
496
    }
 
497
 
 
498
  /* save existing shape in case of cancellation */
 
499
  private->saved_x1 = private->x1;
 
500
  private->saved_y1 = private->y1;
 
501
  private->saved_x2 = private->x2;
 
502
  private->saved_y2 = private->y2;
 
503
 
 
504
  private->saved_center_x = options_private->center_x;
 
505
  private->saved_center_y = options_private->center_y;
 
506
 
 
507
  switch (private->function)
 
508
    {
 
509
    case RECT_CREATING:
 
510
      g_object_set (options,
 
511
                    "center-x", (gdouble) x,
 
512
                    "center-y", (gdouble) y,
 
513
                    NULL);
 
514
 
 
515
      g_object_set (rectangle,
 
516
                    "x1", x,
 
517
                    "y1", y,
 
518
                    "x2", x,
 
519
                    "y2", y,
 
520
                    NULL);
 
521
 
 
522
      gimp_tool_control_set_snap_offsets (tool->control, 0, 0, 0, 0);
 
523
      break;
 
524
 
 
525
    case RECT_RESIZING_UPPER_LEFT:
 
526
      gimp_tool_control_set_snap_offsets (tool->control,
 
527
                                          private->x1 - coords->x,
 
528
                                          private->y1 - coords->y,
 
529
                                          0, 0);
 
530
      break;
 
531
 
 
532
    case RECT_RESIZING_UPPER_RIGHT:
 
533
      gimp_tool_control_set_snap_offsets (tool->control,
 
534
                                          private->x2 - coords->x,
 
535
                                          private->y1 - coords->y,
 
536
                                          0, 0);
 
537
      break;
 
538
 
 
539
    case RECT_RESIZING_LOWER_LEFT:
 
540
      gimp_tool_control_set_snap_offsets (tool->control,
 
541
                                          private->x1 - coords->x,
 
542
                                          private->y2 - coords->y,
 
543
                                          0, 0);
 
544
      break;
 
545
 
 
546
    case RECT_RESIZING_LOWER_RIGHT:
 
547
      gimp_tool_control_set_snap_offsets (tool->control,
 
548
                                          private->x2 - coords->x,
 
549
                                          private->y2 - coords->y,
 
550
                                          0, 0);
 
551
      break;
 
552
 
 
553
    case RECT_RESIZING_LEFT:
 
554
      gimp_tool_control_set_snap_offsets (tool->control,
 
555
                                          private->x1 - coords->x, 0,
 
556
                                          0, 0);
 
557
      break;
 
558
 
 
559
    case RECT_RESIZING_RIGHT:
 
560
      gimp_tool_control_set_snap_offsets (tool->control,
 
561
                                          private->x2 - coords->x, 0,
 
562
                                          0, 0);
 
563
      break;
 
564
 
 
565
    case RECT_RESIZING_TOP:
 
566
      gimp_tool_control_set_snap_offsets (tool->control,
 
567
                                          0, private->y1 - coords->y,
 
568
                                          0, 0);
 
569
      break;
 
570
 
 
571
    case RECT_RESIZING_BOTTOM:
 
572
      gimp_tool_control_set_snap_offsets (tool->control,
 
573
                                          0, private->y2 - coords->y,
 
574
                                          0, 0);
 
575
      break;
 
576
 
 
577
    case RECT_MOVING:
 
578
      gimp_tool_control_set_snap_offsets (tool->control,
 
579
                                          private->x1 - coords->x,
 
580
                                          private->y1 - coords->y,
 
581
                                          private->x2 - private->x1,
 
582
                                          private->y2 - private->y1);
 
583
      break;
 
584
 
 
585
    default:
 
586
      break;
 
587
    }
 
588
 
 
589
  gimp_tool_control_get_snap_offsets (tool->control,
 
590
                                      &snap_x, &snap_y, NULL, NULL);
 
591
 
 
592
  x += snap_x;
 
593
  y += snap_y;
 
594
 
 
595
  private->pressx = x;
 
596
  private->pressy = y;
 
597
 
 
598
  private->startx = x;
 
599
  private->starty = y;
 
600
  private->lastx  = x;
 
601
  private->lasty  = y;
 
602
 
 
603
  gimp_tool_control_activate (tool->control);
 
604
 
 
605
  gimp_draw_tool_resume (draw_tool);
 
606
}
 
607
 
 
608
void
 
609
gimp_rectangle_tool_button_release (GimpTool              *tool,
 
610
                                    GimpCoords            *coords,
 
611
                                    guint32                time,
 
612
                                    GdkModifierType        state,
 
613
                                    GimpButtonReleaseType  release_type,
 
614
                                    GimpDisplay           *display)
 
615
{
 
616
  GimpRectangleTool        *rectangle;
 
617
  GimpRectangleToolPrivate *private;
 
618
  GimpRectangleOptions     *options;
 
619
 
 
620
  g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
 
621
 
 
622
  rectangle = GIMP_RECTANGLE_TOOL (tool);
 
623
  private   = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
624
  options   = GIMP_RECTANGLE_TOOL_GET_OPTIONS (tool);
 
625
 
 
626
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
627
 
 
628
  gimp_tool_control_halt (tool->control);
 
629
 
 
630
  if (private->function == RECT_EXECUTING)
 
631
    gimp_tool_pop_status (tool, display);
 
632
 
 
633
  switch (release_type)
 
634
    {
 
635
    case GIMP_BUTTON_RELEASE_NORMAL:
 
636
      gimp_rectangle_tool_rectangle_changed (rectangle);
 
637
      break;
 
638
 
 
639
    case GIMP_BUTTON_RELEASE_CANCEL:
 
640
      g_object_set (options,
 
641
                    "center-x", private->saved_center_x,
 
642
                    "center-y", private->saved_center_y,
 
643
                    NULL);
 
644
 
 
645
      g_object_set (rectangle,
 
646
                    "x1", private->saved_x1,
 
647
                    "y1", private->saved_y1,
 
648
                    "x2", private->saved_x2,
 
649
                    "y2", private->saved_y2,
 
650
                    NULL);
 
651
      break;
 
652
 
 
653
    case GIMP_BUTTON_RELEASE_CLICK:
 
654
      if (gimp_rectangle_tool_execute (rectangle))
 
655
        gimp_rectangle_tool_halt (rectangle);
 
656
      break;
 
657
 
 
658
    case GIMP_BUTTON_RELEASE_NO_MOTION:
 
659
      break;
 
660
    }
 
661
 
 
662
  gimp_tool_control_set_snap_offsets (tool->control, 0, 0, 0, 0);
 
663
 
 
664
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 
665
}
 
666
 
 
667
void
 
668
gimp_rectangle_tool_motion (GimpTool        *tool,
 
669
                            GimpCoords      *coords,
 
670
                            guint32          time,
 
671
                            GdkModifierType  state,
 
672
                            GimpDisplay     *display)
 
673
{
 
674
  GimpRectangleTool           *rectangle;
 
675
  GimpRectangleToolPrivate    *private;
 
676
  GimpRectangleOptions        *options;
 
677
  GimpRectangleOptionsPrivate *options_private;
 
678
  gint                         x1, y1, x2, y2;
 
679
  gint                         curx, cury;
 
680
  gint                         snap_x, snap_y;
 
681
  gint                         inc_x, inc_y;
 
682
  gboolean                     created_now = FALSE;
 
683
 
 
684
  g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
 
685
 
 
686
  rectangle       = GIMP_RECTANGLE_TOOL (tool);
 
687
  private         = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
688
  options         = GIMP_RECTANGLE_TOOL_GET_OPTIONS (tool);
 
689
  options_private = GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (options);
 
690
 
 
691
  /*  This is the only case when the motion events should be ignored --
 
692
   *  we're just waiting for the button release event to execute.
 
693
   */
 
694
  if (private->function == RECT_EXECUTING)
 
695
    return;
 
696
 
 
697
  curx = ROUND (coords->x);
 
698
  cury = ROUND (coords->y);
 
699
 
 
700
  gimp_tool_control_get_snap_offsets (tool->control,
 
701
                                      &snap_x, &snap_y, NULL, NULL);
 
702
  curx += snap_x;
 
703
  cury += snap_y;
 
704
 
 
705
  /*  If there have been no changes... return  */
 
706
  if (private->lastx == curx && private->lasty == cury)
 
707
    return;
 
708
 
 
709
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
710
 
 
711
 
 
712
  inc_x = curx - private->startx;
 
713
  inc_y = cury - private->starty;
 
714
 
 
715
  x1 = private->x1;
 
716
  y1 = private->y1;
 
717
  x2 = private->x2;
 
718
  y2 = private->y2;
 
719
 
 
720
  switch (private->function)
 
721
    {
 
722
    case RECT_INACTIVE:
 
723
      g_warning ("function is RECT_INACTIVE while mouse is moving");
 
724
      break;
 
725
 
 
726
    case RECT_CREATING:
 
727
      break;
 
728
 
 
729
    case RECT_RESIZING_UPPER_LEFT:
 
730
    case RECT_RESIZING_LOWER_LEFT:
 
731
    case RECT_RESIZING_LEFT:
 
732
      x1 = private->x1 + inc_x;
 
733
      if (options_private->fixed_width)
 
734
        x2 = x1 + options_private->width;
 
735
      else if (options_private->fixed_center)
 
736
        x2 = x1 + 2 * (options_private->center_x - x1);
 
737
      break;
 
738
 
 
739
    case RECT_RESIZING_UPPER_RIGHT:
 
740
    case RECT_RESIZING_LOWER_RIGHT:
 
741
    case RECT_RESIZING_RIGHT:
 
742
      x2 = private->x2 + inc_x;
 
743
      if (options_private->fixed_width)
 
744
        x1 = x2 - options_private->width;
 
745
      else if (options_private->fixed_center)
 
746
        x1 = x2 - 2 * (x2 - options_private->center_x);
 
747
      break;
 
748
 
 
749
    case RECT_RESIZING_BOTTOM:
 
750
    case RECT_RESIZING_TOP:
 
751
      x1 = private->x1;
 
752
      x2 = private->x2;
 
753
      break;
 
754
 
 
755
    case RECT_MOVING:
 
756
      x1 = private->x1 + inc_x;
 
757
      x2 = private->x2 + inc_x;
 
758
      break;
 
759
    }
 
760
 
 
761
  switch (private->function)
 
762
    {
 
763
    case RECT_CREATING:
 
764
      break;
 
765
 
 
766
    case RECT_RESIZING_UPPER_LEFT:
 
767
    case RECT_RESIZING_UPPER_RIGHT:
 
768
    case RECT_RESIZING_TOP:
 
769
      y1 = private->y1 + inc_y;
 
770
      if (options_private->fixed_height)
 
771
        y2 = y1 + options_private->height;
 
772
      else if (options_private->fixed_center)
 
773
        y2 = y1 + 2 * (options_private->center_y - y1);
 
774
      break;
 
775
 
 
776
    case RECT_RESIZING_LOWER_LEFT:
 
777
    case RECT_RESIZING_LOWER_RIGHT:
 
778
    case RECT_RESIZING_BOTTOM:
 
779
      y2 = private->y2 + inc_y;
 
780
      if (options_private->fixed_height)
 
781
        y1 = y2 - options_private->height;
 
782
      else if (options_private->fixed_center)
 
783
        y1 = y2 - 2 * (y2 - options_private->center_y);
 
784
      break;
 
785
 
 
786
    case RECT_RESIZING_RIGHT:
 
787
    case RECT_RESIZING_LEFT:
 
788
      y1 = private->y1;
 
789
      y2 = private->y2;
 
790
      break;
 
791
 
 
792
    case RECT_MOVING:
 
793
      y1 = private->y1 + inc_y;
 
794
      y2 = private->y2 + inc_y;
 
795
      break;
 
796
    }
 
797
 
 
798
  if (options_private->fixed_aspect)
 
799
    {
 
800
      gdouble aspect;
 
801
 
 
802
      aspect = CLAMP (options_private->aspect_numerator /
 
803
                      options_private->aspect_denominator,
 
804
                      1.0 / display->image->height,
 
805
                      display->image->width);
 
806
 
 
807
      switch (private->function)
 
808
        {
 
809
        case RECT_RESIZING_UPPER_LEFT:
 
810
          /* The same basically happens for each corner, just with a
 
811
           * different fixed corner. To keep within aspect ratio and
 
812
           * at the same time keep the cursor on one edge if not the
 
813
           * corner itself: - calculate the two positions of the
 
814
           * corner in question on the base of the current mouse
 
815
           * cursor position and the fixed corner opposite the one
 
816
           * selected.  - decide on which egde we are inside the
 
817
           * rectangle dimension - if we are on the inside of the
 
818
           * vertical edge then we use the x position of the cursor,
 
819
           * otherwise we are on the inside (or close enough) of the
 
820
           * horizontal edge and then we use the y position of the
 
821
           * cursor for the base of our new corner.
 
822
           */
 
823
          x1 = private->x2 - (private->y2 - cury) * aspect + 0.5;
 
824
          y1 = private->y2 - (private->x2 - curx) / aspect + 0.5;
 
825
          if ((y1 < cury) && (cury < y2))
 
826
            x1 = curx;
 
827
          else
 
828
            y1 = cury;
 
829
          if (options_private->fixed_center)
 
830
            {
 
831
              x2 = x1 + 2 * (options_private->center_x - x1);
 
832
              y2 = y1 + 2 * (options_private->center_y - y1);
 
833
            }
 
834
          break;
 
835
 
 
836
        case RECT_RESIZING_UPPER_RIGHT:
 
837
          x2 = private->x1 + (private->y2 - cury) * aspect + 0.5;
 
838
          y1 = private->y2 - (curx - private->x1) / aspect + 0.5;
 
839
          if ((y1 < cury) && (cury < y2))
 
840
            x2 = curx;
 
841
          else
 
842
            y1 = cury;
 
843
          if (options_private->fixed_center)
 
844
            {
 
845
              x1 = x2 - 2 * (x2 - options_private->center_x);
 
846
              y2 = y1 + 2 * (options_private->center_y - y1);
 
847
            }
 
848
          break;
 
849
 
 
850
        case RECT_RESIZING_LOWER_LEFT:
 
851
          x1 = private->x2 - (cury - private->y1) * aspect + 0.5;
 
852
          y2 = private->y1 + (private->x2 - curx) / aspect + 0.5;
 
853
          if ((y1 < cury) && (cury < y2))
 
854
            x1 = curx;
 
855
          else
 
856
            y2 = cury;
 
857
          if (options_private->fixed_center)
 
858
            {
 
859
              x2 = x1 + 2 * (options_private->center_x - x1);
 
860
              y1 = y2 - 2 * (y2 - options_private->center_y);
 
861
            }
 
862
          break;
 
863
 
 
864
        case RECT_RESIZING_LOWER_RIGHT:
 
865
          x2 = private->x1 + (cury - private->y1) * aspect + 0.5;
 
866
          y2 = private->y1 + (curx - private->x1) / aspect + 0.5;
 
867
          if ((y1 < cury) && (cury < y2))
 
868
            x2 = curx;
 
869
          else
 
870
            y2 = cury;
 
871
          if (options_private->fixed_center)
 
872
            {
 
873
              x1 = x2 - 2 * (x2 - options_private->center_x);
 
874
              y1 = y2 - 2 * (y2 - options_private->center_y);
 
875
            }
 
876
          break;
 
877
 
 
878
        case RECT_RESIZING_TOP:
 
879
          x2 = private->x1 + (private->y2 - y1) * aspect + 0.5;
 
880
          if (options_private->fixed_center)
 
881
            x1 = x2 - 2 * (x2 - options_private->center_x);
 
882
          break;
 
883
 
 
884
        case RECT_RESIZING_LEFT:
 
885
          /* When resizing the left hand delimiter then the aspect
 
886
           * dictates the height of the result, any inc_y is redundant
 
887
           * and not relevant to the result
 
888
           */
 
889
          y2 = private->y1 + (private->x2 - x1) / aspect + 0.5;
 
890
          if (options_private->fixed_center)
 
891
            y1 = y2 - 2 * (y2 - options_private->center_y);
 
892
          break;
 
893
 
 
894
        case RECT_RESIZING_BOTTOM:
 
895
          x2 = private->x1 + (y2 - private->y1) * aspect + 0.5;
 
896
          if (options_private->fixed_center)
 
897
            x1 = x2 - 2 * (x2 - options_private->center_x);
 
898
          break;
 
899
 
 
900
        case RECT_RESIZING_RIGHT:
 
901
          /* When resizing the right hand delimiter then the aspect
 
902
           * dictates the height of the result, any inc_y is redundant
 
903
           * and not relevant to the result
 
904
           */
 
905
          y2 = private->y1 + (x2 - private->x1) / aspect + 0.5;
 
906
          if (options_private->fixed_center)
 
907
            y1 = y2 - 2 * (y2 - options_private->center_y);
 
908
          break;
 
909
 
 
910
        default:
 
911
          break;
 
912
        }
 
913
    }
 
914
 
 
915
  private->lastx = curx;
 
916
  private->lasty = cury;
 
917
 
 
918
  /* Check to see whether the new rectangle obeys the boundary
 
919
   * constraints, if any, and constrain it.
 
920
   */
 
921
 
 
922
  gimp_rectangle_tool_constrain (rectangle, &x1, &y1, &x2, &y2);
 
923
 
 
924
 
 
925
  /* set startx, starty according to function, to keep rect on cursor */
 
926
  switch (private->function)
 
927
    {
 
928
    case RECT_RESIZING_UPPER_LEFT:
 
929
      private->startx = x1;
 
930
      private->starty = y1;
 
931
      break;
 
932
 
 
933
    case RECT_RESIZING_UPPER_RIGHT:
 
934
      private->startx = x2;
 
935
      private->starty = y1;
 
936
      break;
 
937
 
 
938
    case RECT_RESIZING_LOWER_LEFT:
 
939
      private->startx = x1;
 
940
      private->starty = y2;
 
941
      break;
 
942
 
 
943
    case RECT_RESIZING_LOWER_RIGHT:
 
944
      private->startx = x2;
 
945
      private->starty = y2;
 
946
      break;
 
947
 
 
948
    case RECT_RESIZING_TOP:
 
949
      private->startx = curx;
 
950
      private->starty = y1;
 
951
      break;
 
952
 
 
953
    case RECT_RESIZING_LEFT:
 
954
      private->startx = x1;
 
955
      private->starty = cury;
 
956
      break;
 
957
 
 
958
    case RECT_RESIZING_BOTTOM:
 
959
      private->startx = curx;
 
960
      private->starty = y2;
 
961
 
 
962
      break;
 
963
 
 
964
    case RECT_RESIZING_RIGHT:
 
965
      private->startx = x2;
 
966
      private->starty = cury;
 
967
      break;
 
968
 
 
969
    case RECT_MOVING:
 
970
      private->startx = curx;
 
971
      private->starty = cury;
 
972
      break;
 
973
 
 
974
    default:
 
975
      break;
 
976
    }
 
977
 
 
978
  /* fix function if user has "flipped" the rectangle */
 
979
  if (! created_now)
 
980
    gimp_rectangle_tool_check_function (rectangle, &x1, &y1, &x2, &y2);
 
981
 
 
982
  /*  make sure that the coords are in bounds  */
 
983
  g_object_set (rectangle,
 
984
                "x1", MIN (x1, x2),
 
985
                "y1", MIN (y1, y2),
 
986
                "x2", MAX (x1, x2),
 
987
                "y2", MAX (y1, y2),
 
988
                NULL);
 
989
 
 
990
  /*  recalculate the coordinates for rectangle_draw based on the new values  */
 
991
  gimp_rectangle_tool_configure (rectangle);
 
992
 
 
993
  gimp_rectangle_tool_update_options (rectangle, display);
 
994
 
 
995
  if (private->function != RECT_MOVING &&
 
996
      private->function != RECT_EXECUTING)
 
997
    {
 
998
      gint w, h;
 
999
 
 
1000
      gimp_tool_pop_status (tool, display);
 
1001
 
 
1002
      w = private->x2 - private->x1;
 
1003
      h = private->y2 - private->y1;
 
1004
 
 
1005
      if (w > 0 && h > 0)
 
1006
        gimp_tool_push_status_coords (tool, display,
 
1007
                                      _("Rectangle: "), w, " × ", h, NULL);
 
1008
    }
 
1009
 
 
1010
  if (private->function == RECT_CREATING)
 
1011
    {
 
1012
      GimpRectangleFunction function = RECT_CREATING;
 
1013
 
 
1014
      if (inc_x < 0 && inc_y < 0)
 
1015
        function = RECT_RESIZING_UPPER_LEFT;
 
1016
      else if (inc_x < 0 && inc_y > 0)
 
1017
        function = RECT_RESIZING_LOWER_LEFT;
 
1018
      else if (inc_x > 0 && inc_y < 0)
 
1019
        function = RECT_RESIZING_UPPER_RIGHT;
 
1020
      else if (inc_x > 0 && inc_y > 0)
 
1021
        function = RECT_RESIZING_LOWER_RIGHT;
 
1022
 
 
1023
      created_now = TRUE;
 
1024
 
 
1025
      gimp_rectangle_tool_set_function (rectangle, function);
 
1026
    }
 
1027
 
 
1028
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 
1029
}
 
1030
 
 
1031
void
 
1032
gimp_rectangle_tool_active_modifier_key (GimpTool        *tool,
 
1033
                                         GdkModifierType  key,
 
1034
                                         gboolean         press,
 
1035
                                         GdkModifierType  state,
 
1036
                                         GimpDisplay     *display)
 
1037
{
 
1038
  GimpRectangleTool           *rectangle;
 
1039
  GimpRectangleOptions        *options;
 
1040
  GimpRectangleOptionsPrivate *options_private;
 
1041
 
 
1042
  g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
 
1043
 
 
1044
  rectangle       = GIMP_RECTANGLE_TOOL (tool);
 
1045
  options         = GIMP_RECTANGLE_TOOL_GET_OPTIONS (tool);
 
1046
  options_private = GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (options);
 
1047
 
 
1048
  if (key == GDK_SHIFT_MASK)
 
1049
    {
 
1050
      g_object_set (options,
 
1051
                    "fixed-aspect", ! options_private->fixed_aspect,
 
1052
                    NULL);
 
1053
    }
 
1054
 
 
1055
  if (key == GDK_CONTROL_MASK)
 
1056
    {
 
1057
      g_object_set (options,
 
1058
                    "fixed-center", ! options_private->fixed_center,
 
1059
                    NULL);
 
1060
 
 
1061
      if (options_private->fixed_center)
 
1062
        {
 
1063
          gint press_x, press_y;
 
1064
 
 
1065
          gimp_rectangle_tool_get_press_coords (rectangle, &press_x, &press_y);
 
1066
 
 
1067
          g_object_set (options,
 
1068
                        "center-x", (gdouble) press_x,
 
1069
                        "center-y", (gdouble) press_y,
 
1070
                        NULL);
 
1071
        }
 
1072
    }
 
1073
}
 
1074
 
 
1075
static void swap_ints (gint *i,
 
1076
                       gint *j)
 
1077
{
 
1078
  gint tmp;
 
1079
 
 
1080
  tmp = *i;
 
1081
  *i = *j;
 
1082
  *j = tmp;
 
1083
}
 
1084
 
 
1085
/* gimp_rectangle_tool_check_function() is needed to deal with
 
1086
 * situations where the user drags a corner or edge across one of the
 
1087
 * existing edges, thereby changing its function.  Ugh.
 
1088
 */
 
1089
static void
 
1090
gimp_rectangle_tool_check_function (GimpRectangleTool *rectangle,
 
1091
                                    gint              *x1,
 
1092
                                    gint              *y1,
 
1093
                                    gint              *x2,
 
1094
                                    gint              *y2)
 
1095
{
 
1096
  GimpRectangleToolPrivate *private;
 
1097
  GimpRectangleFunction     function;
 
1098
 
 
1099
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
1100
 
 
1101
  function = private->function;
 
1102
 
 
1103
  if (*x2 < *x1)
 
1104
    {
 
1105
      swap_ints (x1, x2);
 
1106
      switch (function)
 
1107
        {
 
1108
          case RECT_RESIZING_UPPER_LEFT:
 
1109
            function = RECT_RESIZING_UPPER_RIGHT;
 
1110
            break;
 
1111
          case RECT_RESIZING_UPPER_RIGHT:
 
1112
            function = RECT_RESIZING_UPPER_LEFT;
 
1113
            break;
 
1114
          case RECT_RESIZING_LOWER_LEFT:
 
1115
            function = RECT_RESIZING_LOWER_RIGHT;
 
1116
            break;
 
1117
          case RECT_RESIZING_LOWER_RIGHT:
 
1118
            function = RECT_RESIZING_LOWER_LEFT;
 
1119
            break;
 
1120
          case RECT_RESIZING_LEFT:
 
1121
            function = RECT_RESIZING_RIGHT;
 
1122
            break;
 
1123
          case RECT_RESIZING_RIGHT:
 
1124
            function = RECT_RESIZING_LEFT;
 
1125
            break;
 
1126
          /* avoid annoying warnings about unhandled enums */
 
1127
          default:
 
1128
            break;
 
1129
        }
 
1130
    }
 
1131
 
 
1132
  if (*y2 < *y1)
 
1133
    {
 
1134
      swap_ints (y1, y2);
 
1135
      switch (function)
 
1136
        {
 
1137
          case RECT_RESIZING_UPPER_LEFT:
 
1138
           function = RECT_RESIZING_LOWER_LEFT;
 
1139
            break;
 
1140
          case RECT_RESIZING_UPPER_RIGHT:
 
1141
            function = RECT_RESIZING_LOWER_RIGHT;
 
1142
            break;
 
1143
          case RECT_RESIZING_LOWER_LEFT:
 
1144
            function = RECT_RESIZING_UPPER_LEFT;
 
1145
            break;
 
1146
          case RECT_RESIZING_LOWER_RIGHT:
 
1147
            function = RECT_RESIZING_UPPER_RIGHT;
 
1148
            break;
 
1149
          case RECT_RESIZING_TOP:
 
1150
            function = RECT_RESIZING_BOTTOM;
 
1151
            break;
 
1152
          case RECT_RESIZING_BOTTOM:
 
1153
            function = RECT_RESIZING_TOP;
 
1154
            break;
 
1155
          default:
 
1156
            break;
 
1157
        }
 
1158
    }
 
1159
 
 
1160
  gimp_rectangle_tool_set_function (rectangle, function);
 
1161
 
 
1162
#undef SWAP
 
1163
}
 
1164
 
 
1165
gboolean
 
1166
gimp_rectangle_tool_key_press (GimpTool    *tool,
 
1167
                               GdkEventKey *kevent,
 
1168
                               GimpDisplay *display)
 
1169
{
 
1170
  GimpRectangleTool        *rectangle;
 
1171
  GimpRectangleToolPrivate *private;
 
1172
  gint                      dx = 0;
 
1173
  gint                      dy = 0;
 
1174
  gint                      inc_x1 = 0;
 
1175
  gint                      inc_y1 = 0;
 
1176
  gint                      inc_x2 = 0;
 
1177
  gint                      inc_y2 = 0;
 
1178
  gint                      x1, y1;
 
1179
  gint                      x2, y2;
 
1180
 
 
1181
  g_return_val_if_fail (GIMP_IS_RECTANGLE_TOOL (tool), FALSE);
 
1182
 
 
1183
  if (display != tool->display)
 
1184
    return FALSE;
 
1185
 
 
1186
  rectangle = GIMP_RECTANGLE_TOOL (tool);
 
1187
  private   = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
1188
 
 
1189
  switch (kevent->keyval)
 
1190
    {
 
1191
    case GDK_Up:
 
1192
      dy = -1;
 
1193
      break;
 
1194
    case GDK_Left:
 
1195
      dx = -1;
 
1196
      break;
 
1197
    case GDK_Right:
 
1198
      dx = 1;
 
1199
      break;
 
1200
    case GDK_Down:
 
1201
      dy = 1;
 
1202
      break;
 
1203
 
 
1204
    case GDK_KP_Enter:
 
1205
    case GDK_Return:
 
1206
      if (gimp_rectangle_tool_execute (rectangle))
 
1207
        gimp_rectangle_tool_halt (rectangle);
 
1208
      return TRUE;
 
1209
 
 
1210
    case GDK_Escape:
 
1211
      gimp_rectangle_tool_cancel (rectangle);
 
1212
      gimp_rectangle_tool_halt (rectangle);
 
1213
      return TRUE;
 
1214
 
 
1215
    default:
 
1216
      return FALSE;
 
1217
    }
 
1218
 
 
1219
  /*  If the shift key is down, move by an accelerated increment  */
 
1220
  if (kevent->state & GDK_SHIFT_MASK)
 
1221
    {
 
1222
      dx *= ARROW_VELOCITY;
 
1223
      dy *= ARROW_VELOCITY;
 
1224
    }
 
1225
 
 
1226
  /*  Resize the rectangle if the mouse is over a handle, otherwise move it  */
 
1227
  switch (private->function)
 
1228
    {
 
1229
    case RECT_RESIZING_UPPER_LEFT:
 
1230
      inc_x1 = dx;
 
1231
      inc_y1 = dy;
 
1232
      break;
 
1233
    case RECT_RESIZING_UPPER_RIGHT:
 
1234
      inc_x2 = dx;
 
1235
      inc_y1 = dy;
 
1236
      break;
 
1237
    case RECT_RESIZING_LOWER_LEFT:
 
1238
      inc_x1 = dx;
 
1239
      inc_y2 = dy;
 
1240
      break;
 
1241
    case RECT_RESIZING_LOWER_RIGHT:
 
1242
      inc_x2 = dx;
 
1243
      inc_y2 = dy;
 
1244
      break;
 
1245
    case RECT_RESIZING_LEFT:
 
1246
      inc_x1 = dx;
 
1247
      break;
 
1248
    case RECT_RESIZING_RIGHT:
 
1249
      inc_x2 = dx;
 
1250
      break;
 
1251
    case RECT_RESIZING_TOP:
 
1252
      inc_y1 = dy;
 
1253
      break;
 
1254
    case RECT_RESIZING_BOTTOM:
 
1255
      inc_y2 = dy;
 
1256
      break;
 
1257
 
 
1258
    default:
 
1259
      inc_x1 = inc_x2 = dx;
 
1260
      inc_y1 = inc_y2 = dy;
 
1261
      break;
 
1262
    }
 
1263
 
 
1264
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
1265
 
 
1266
  x1 = private->x1 + inc_x1;
 
1267
  y1 = private->y1 + inc_y1;
 
1268
  x2 = private->x2 + inc_x2;
 
1269
  y2 = private->y2 + inc_y2;
 
1270
 
 
1271
  gimp_rectangle_tool_check_function (rectangle, &x1, &y1, &x2, &y2);
 
1272
 
 
1273
  g_object_set (rectangle,
 
1274
                "x1", x1,
 
1275
                "y1", y1,
 
1276
                "x2", x2,
 
1277
                "y2", y2,
 
1278
                NULL);
 
1279
 
 
1280
  gimp_rectangle_tool_configure (rectangle);
 
1281
 
 
1282
  gimp_rectangle_tool_update_options (rectangle, display);
 
1283
 
 
1284
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
 
1285
 
 
1286
  gimp_rectangle_tool_rectangle_changed (rectangle);
 
1287
 
 
1288
  /*  Evil hack to suppress oper updates. We do this because we don't
 
1289
   *  want the rectangle tool to change function while the rectangle
 
1290
   *  is being resized or moved using the keyboard.
 
1291
   */
 
1292
  private->suppress_updates = 2;
 
1293
 
 
1294
  return TRUE;
 
1295
}
 
1296
 
 
1297
void
 
1298
gimp_rectangle_tool_oper_update (GimpTool        *tool,
 
1299
                                 GimpCoords      *coords,
 
1300
                                 GdkModifierType  state,
 
1301
                                 gboolean         proximity,
 
1302
                                 GimpDisplay     *display)
 
1303
{
 
1304
  GimpRectangleToolPrivate *private;
 
1305
  GimpDrawTool             *draw_tool;
 
1306
  gint                      function;
 
1307
 
 
1308
  g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
 
1309
 
 
1310
  private   = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
1311
  draw_tool = GIMP_DRAW_TOOL (tool);
 
1312
 
 
1313
  if (tool->display != display)
 
1314
    return;
 
1315
 
 
1316
  if (private->suppress_updates)
 
1317
    {
 
1318
      private->suppress_updates--;
 
1319
      return;
 
1320
    }
 
1321
 
 
1322
  if (coords->x > private->x1 && coords->x < private->x2 &&
 
1323
      coords->y > private->y1 && coords->y < private->y2)
 
1324
    {
 
1325
      GimpDisplayShell *shell    = GIMP_DISPLAY_SHELL (tool->display->shell);
 
1326
      gdouble           handle_w = private->handle_w / shell->scale_x;
 
1327
      gdouble           handle_h = private->handle_h / shell->scale_y;
 
1328
 
 
1329
      if (gimp_draw_tool_on_handle (draw_tool, display,
 
1330
                                    coords->x, coords->y,
 
1331
                                    GIMP_HANDLE_SQUARE,
 
1332
                                    private->x1, private->y1,
 
1333
                                    private->handle_w, private->handle_h,
 
1334
                                    GTK_ANCHOR_NORTH_WEST,
 
1335
                                    FALSE))
 
1336
        {
 
1337
          function = RECT_RESIZING_UPPER_LEFT;
 
1338
        }
 
1339
      else if (gimp_draw_tool_on_handle (draw_tool, display,
 
1340
                                         coords->x, coords->y,
 
1341
                                         GIMP_HANDLE_SQUARE,
 
1342
                                         private->x2, private->y2,
 
1343
                                         private->handle_w, private->handle_h,
 
1344
                                         GTK_ANCHOR_SOUTH_EAST,
 
1345
                                         FALSE))
 
1346
        {
 
1347
          function = RECT_RESIZING_LOWER_RIGHT;
 
1348
        }
 
1349
      else if  (gimp_draw_tool_on_handle (draw_tool, display,
 
1350
                                          coords->x, coords->y,
 
1351
                                          GIMP_HANDLE_SQUARE,
 
1352
                                          private->x2, private->y1,
 
1353
                                          private->handle_w, private->handle_h,
 
1354
                                          GTK_ANCHOR_NORTH_EAST,
 
1355
                                          FALSE))
 
1356
        {
 
1357
          function = RECT_RESIZING_UPPER_RIGHT;
 
1358
        }
 
1359
      else if (gimp_draw_tool_on_handle (draw_tool, display,
 
1360
                                         coords->x, coords->y,
 
1361
                                         GIMP_HANDLE_SQUARE,
 
1362
                                         private->x1, private->y2,
 
1363
                                         private->handle_w, private->handle_h,
 
1364
                                         GTK_ANCHOR_SOUTH_WEST,
 
1365
                                         FALSE))
 
1366
        {
 
1367
          function = RECT_RESIZING_LOWER_LEFT;
 
1368
        }
 
1369
      else if ((fabs (coords->x - private->x1) < (handle_w * 2) / 3))
 
1370
        {
 
1371
          function = RECT_RESIZING_LEFT;
 
1372
        }
 
1373
      else if ((fabs (coords->x - private->x2) < (handle_w * 2) / 3))
 
1374
        {
 
1375
          function = RECT_RESIZING_RIGHT;
 
1376
        }
 
1377
      else if ((fabs (coords->y - private->y1) < (handle_h * 2) / 3))
 
1378
        {
 
1379
          function = RECT_RESIZING_TOP;
 
1380
        }
 
1381
      else if ((fabs (coords->y - private->y2) < (handle_h * 2) / 3))
 
1382
        {
 
1383
          function = RECT_RESIZING_BOTTOM;
 
1384
        }
 
1385
      else
 
1386
        {
 
1387
          function = RECT_MOVING;
 
1388
        }
 
1389
    }
 
1390
  else
 
1391
    {
 
1392
      /*  otherwise, the new function will be creating, since we want
 
1393
       *  to start a new rectangle
 
1394
       */
 
1395
      function = RECT_CREATING;
 
1396
    }
 
1397
 
 
1398
  gimp_rectangle_tool_set_function (GIMP_RECTANGLE_TOOL (tool), function);
 
1399
}
 
1400
 
 
1401
void
 
1402
gimp_rectangle_tool_cursor_update (GimpTool        *tool,
 
1403
                                   GimpCoords      *coords,
 
1404
                                   GdkModifierType  state,
 
1405
                                   GimpDisplay     *display)
 
1406
{
 
1407
  GimpRectangleTool        *rectangle;
 
1408
  GimpRectangleToolPrivate *private;
 
1409
  GimpCursorType            cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
 
1410
 
 
1411
  g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
 
1412
 
 
1413
  rectangle = GIMP_RECTANGLE_TOOL (tool);
 
1414
  private   = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
1415
 
 
1416
  if (tool->display == display)
 
1417
    {
 
1418
      switch (private->function)
 
1419
        {
 
1420
        case RECT_CREATING:
 
1421
          cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
 
1422
          break;
 
1423
        case RECT_MOVING:
 
1424
          cursor = GIMP_CURSOR_MOVE;
 
1425
          break;
 
1426
        case RECT_RESIZING_UPPER_LEFT:
 
1427
          cursor = GIMP_CURSOR_CORNER_TOP_LEFT;
 
1428
          break;
 
1429
        case RECT_RESIZING_UPPER_RIGHT:
 
1430
          cursor = GIMP_CURSOR_CORNER_TOP_RIGHT;
 
1431
          break;
 
1432
        case RECT_RESIZING_LOWER_LEFT:
 
1433
          cursor = GIMP_CURSOR_CORNER_BOTTOM_LEFT;
 
1434
          break;
 
1435
        case RECT_RESIZING_LOWER_RIGHT:
 
1436
          cursor = GIMP_CURSOR_CORNER_BOTTOM_RIGHT;
 
1437
          break;
 
1438
        case RECT_RESIZING_LEFT:
 
1439
          cursor = GIMP_CURSOR_SIDE_LEFT;
 
1440
          break;
 
1441
        case RECT_RESIZING_RIGHT:
 
1442
          cursor = GIMP_CURSOR_SIDE_RIGHT;
 
1443
          break;
 
1444
        case RECT_RESIZING_TOP:
 
1445
          cursor = GIMP_CURSOR_SIDE_TOP;
 
1446
          break;
 
1447
        case RECT_RESIZING_BOTTOM:
 
1448
          cursor = GIMP_CURSOR_SIDE_BOTTOM;
 
1449
          break;
 
1450
 
 
1451
        default:
 
1452
          break;
 
1453
        }
 
1454
    }
 
1455
 
 
1456
  gimp_tool_control_set_cursor (tool->control, cursor);
 
1457
}
 
1458
 
 
1459
void
 
1460
gimp_rectangle_tool_draw (GimpDrawTool *draw_tool)
 
1461
{
 
1462
  GimpTool                 *tool;
 
1463
  GimpRectangleToolPrivate *private;
 
1464
 
 
1465
  g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (draw_tool));
 
1466
 
 
1467
  tool    = GIMP_TOOL (draw_tool);
 
1468
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
1469
 
 
1470
  if (private->function == RECT_INACTIVE)
 
1471
    return;
 
1472
 
 
1473
  gimp_draw_tool_draw_rectangle (draw_tool, FALSE,
 
1474
                                 private->x1,
 
1475
                                 private->y1,
 
1476
                                 private->x2 - private->x1,
 
1477
                                 private->y2 - private->y1,
 
1478
                                 FALSE);
 
1479
 
 
1480
  switch (private->function)
 
1481
    {
 
1482
    case RECT_MOVING:
 
1483
      if (gimp_tool_control_is_active (tool->control))
 
1484
        break;
 
1485
      /* else fallthrough */
 
1486
 
 
1487
    case RECT_CREATING:
 
1488
      gimp_draw_tool_draw_corner (draw_tool, FALSE,
 
1489
                                  private->x1, private->y1,
 
1490
                                  private->x2, private->y2,
 
1491
                                  private->handle_w, private->handle_h,
 
1492
                                  GTK_ANCHOR_NORTH_WEST, FALSE);
 
1493
      gimp_draw_tool_draw_corner (draw_tool, FALSE,
 
1494
                                  private->x1, private->y1,
 
1495
                                  private->x2, private->y2,
 
1496
                                  private->handle_w, private->handle_h,
 
1497
                                  GTK_ANCHOR_NORTH_EAST, FALSE);
 
1498
      gimp_draw_tool_draw_corner (draw_tool, FALSE,
 
1499
                                  private->x1, private->y1,
 
1500
                                  private->x2, private->y2,
 
1501
                                  private->handle_w, private->handle_h,
 
1502
                                  GTK_ANCHOR_SOUTH_WEST, FALSE);
 
1503
      gimp_draw_tool_draw_corner (draw_tool, FALSE,
 
1504
                                  private->x1, private->y1,
 
1505
                                  private->x2, private->y2,
 
1506
                                  private->handle_w, private->handle_h,
 
1507
                                  GTK_ANCHOR_SOUTH_EAST, FALSE);
 
1508
      break;
 
1509
 
 
1510
    default:
 
1511
      {
 
1512
        GtkAnchorType anchor;
 
1513
        gint          w, h;
 
1514
 
 
1515
        anchor = gimp_rectangle_tool_get_anchor (private, &w, &h);
 
1516
        gimp_draw_tool_draw_corner (draw_tool,
 
1517
                                    ! gimp_tool_control_is_active (tool->control),
 
1518
                                    private->x1, private->y1,
 
1519
                                    private->x2, private->y2,
 
1520
                                    w, h,
 
1521
                                    anchor, FALSE);
 
1522
      }
 
1523
      break;
 
1524
    }
 
1525
 
 
1526
  gimp_rectangle_tool_draw_guides (draw_tool);
 
1527
}
 
1528
 
 
1529
static void
 
1530
gimp_rectangle_tool_draw_guides (GimpDrawTool *draw_tool)
 
1531
{
 
1532
  GimpTool                 *tool;
 
1533
  GimpRectangleToolPrivate *private;
 
1534
  gint                      x1, x2, y1, y2;
 
1535
 
 
1536
  tool    = GIMP_TOOL (draw_tool);
 
1537
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (draw_tool);
 
1538
 
 
1539
  x1 = private->x1;
 
1540
  x2 = private->x2;
 
1541
  y1 = private->y1;
 
1542
  y2 = private->y2;
 
1543
 
 
1544
  switch (private->guide)
 
1545
    {
 
1546
    case GIMP_RECTANGLE_GUIDE_NONE:
 
1547
      break;
 
1548
 
 
1549
    case GIMP_RECTANGLE_GUIDE_CENTER_LINES:
 
1550
      gimp_draw_tool_draw_line (draw_tool,
 
1551
                                x1, (y1 + y2) / 2,
 
1552
                                x2, (y1 + y2) / 2, FALSE);
 
1553
      gimp_draw_tool_draw_line (draw_tool,
 
1554
                                (x1 + x2) / 2, y1,
 
1555
                                (x1 + x2) / 2, y2, FALSE);
 
1556
      break;
 
1557
 
 
1558
    case GIMP_RECTANGLE_GUIDE_THIRDS:
 
1559
      gimp_draw_tool_draw_line (draw_tool,
 
1560
                                x1, (2 * y1 + y2) / 3,
 
1561
                                x2, (2 * y1 + y2) / 3, FALSE);
 
1562
      gimp_draw_tool_draw_line (draw_tool,
 
1563
                                x1, (y1 + 2 * y2) / 3,
 
1564
                                x2, (y1 + 2 * y2) / 3, FALSE);
 
1565
      gimp_draw_tool_draw_line (draw_tool,
 
1566
                                (2 * x1 + x2) / 3, y1,
 
1567
                                (2 * x1 + x2) / 3, y2, FALSE);
 
1568
      gimp_draw_tool_draw_line (draw_tool,
 
1569
                                (x1 + 2 * x2) / 3, y1,
 
1570
                                (x1 + 2 * x2) / 3, y2, FALSE);
 
1571
      break;
 
1572
 
 
1573
    case GIMP_RECTANGLE_GUIDE_GOLDEN:
 
1574
      gimp_draw_tool_draw_line (draw_tool,
 
1575
                                x1,
 
1576
                                (2 * y1 + (1 + SQRT5) * y2) / (3 + SQRT5),
 
1577
                                x2,
 
1578
                                (2 * y1 + (1 + SQRT5) * y2) / (3 + SQRT5),
 
1579
                                FALSE);
 
1580
      gimp_draw_tool_draw_line (draw_tool,
 
1581
                                x1,
 
1582
                                ((1 + SQRT5) * y1 + 2 * y2) / (3 + SQRT5),
 
1583
                                x2,
 
1584
                                ((1 + SQRT5) * y1 + 2 * y2) / (3 + SQRT5),
 
1585
                                FALSE);
 
1586
      gimp_draw_tool_draw_line (draw_tool,
 
1587
                                (2 * x1 + (1 + SQRT5) * x2) / (3 + SQRT5),
 
1588
                                y1,
 
1589
                                (2 * x1 + (1 + SQRT5) * x2) / (3 + SQRT5),
 
1590
                                y2,
 
1591
                                FALSE);
 
1592
      gimp_draw_tool_draw_line (draw_tool,
 
1593
                                ((1 + SQRT5) * x1 + 2 * x2) / (3 + SQRT5),
 
1594
                                y1,
 
1595
                                ((1 + SQRT5) * x1 + 2 * x2) / (3 + SQRT5),
 
1596
                                y2, FALSE);
 
1597
      break;
 
1598
    }
 
1599
}
 
1600
 
 
1601
void
 
1602
gimp_rectangle_tool_configure (GimpRectangleTool *rectangle)
 
1603
{
 
1604
  GimpTool                 *tool = GIMP_TOOL (rectangle);
 
1605
  GimpRectangleToolPrivate *private;
 
1606
  GimpRectangleOptions     *options;
 
1607
  GimpDisplayShell         *shell;
 
1608
  gint                      dx1, dx2;
 
1609
  gint                      dy1, dy2;
 
1610
 
 
1611
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
1612
  options = GIMP_RECTANGLE_TOOL_GET_OPTIONS (tool);
 
1613
 
 
1614
  if (! tool->display)
 
1615
    return;
 
1616
 
 
1617
  gimp_rectangle_tool_set_highlight (rectangle);
 
1618
 
 
1619
  shell = GIMP_DISPLAY_SHELL (tool->display->shell);
 
1620
 
 
1621
  gimp_display_shell_transform_xy (shell,
 
1622
                                   private->x1, private->y1,
 
1623
                                   &dx1, &dy1,
 
1624
                                   FALSE);
 
1625
  gimp_display_shell_transform_xy (shell,
 
1626
                                   private->x2, private->y2,
 
1627
                                   &dx2, &dy2,
 
1628
                                   FALSE);
 
1629
 
 
1630
  private->handle_w = (dx2 - dx1) / 3;
 
1631
  private->handle_h = (dy2 - dy1) / 3;
 
1632
 
 
1633
  private->handle_w = CLAMP (private->handle_w, MIN_HANDLE_SIZE, HANDLE_SIZE);
 
1634
  private->handle_h = CLAMP (private->handle_h, MIN_HANDLE_SIZE, HANDLE_SIZE);
 
1635
}
 
1636
 
 
1637
static void
 
1638
gimp_rectangle_tool_start (GimpRectangleTool *rectangle,
 
1639
                           GimpDisplay       *display)
 
1640
{
 
1641
  GimpTool                    *tool = GIMP_TOOL (rectangle);
 
1642
  GimpRectangleOptionsPrivate *options_private;
 
1643
 
 
1644
  options_private =
 
1645
    GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (gimp_tool_get_options (tool));
 
1646
 
 
1647
  tool->display = display;
 
1648
  gimp_rectangle_tool_configure (rectangle);
 
1649
 
 
1650
  /* initialize the statusbar display */
 
1651
  gimp_tool_push_status_coords (tool, tool->display,
 
1652
                                _("Rectangle: "), 0, " x ", 0, NULL);
 
1653
 
 
1654
  gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), tool->display);
 
1655
 
 
1656
  if (options_private->auto_shrink_button)
 
1657
    {
 
1658
      g_signal_connect_swapped (options_private->auto_shrink_button, "clicked",
 
1659
                                G_CALLBACK (gimp_rectangle_tool_auto_shrink),
 
1660
                                rectangle);
 
1661
 
 
1662
      gtk_widget_set_sensitive (options_private->auto_shrink_button, TRUE);
 
1663
    }
 
1664
}
 
1665
 
 
1666
static void
 
1667
gimp_rectangle_tool_halt (GimpRectangleTool *rectangle)
 
1668
{
 
1669
  GimpTool                    *tool = GIMP_TOOL (rectangle);
 
1670
  GimpRectangleOptionsPrivate *options_private;
 
1671
 
 
1672
  options_private =
 
1673
    GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (gimp_tool_get_options (tool));
 
1674
 
 
1675
  if (tool->display)
 
1676
    gimp_display_shell_set_highlight (GIMP_DISPLAY_SHELL (tool->display->shell),
 
1677
                                      NULL);
 
1678
 
 
1679
  if (gimp_draw_tool_is_active (GIMP_DRAW_TOOL (rectangle)))
 
1680
    gimp_draw_tool_stop (GIMP_DRAW_TOOL (rectangle));
 
1681
 
 
1682
  if (gimp_tool_control_is_active (tool->control))
 
1683
    gimp_tool_control_halt (tool->control);
 
1684
 
 
1685
  tool->display  = NULL;
 
1686
  tool->drawable = NULL;
 
1687
 
 
1688
  gimp_rectangle_tool_set_function (rectangle, RECT_INACTIVE);
 
1689
 
 
1690
  if (options_private->auto_shrink_button)
 
1691
    {
 
1692
      gtk_widget_set_sensitive (options_private->auto_shrink_button, FALSE);
 
1693
 
 
1694
      g_signal_handlers_disconnect_by_func (options_private->auto_shrink_button,
 
1695
                                            gimp_rectangle_tool_auto_shrink,
 
1696
                                            rectangle);
 
1697
    }
 
1698
}
 
1699
 
 
1700
gboolean
 
1701
gimp_rectangle_tool_execute (GimpRectangleTool *rectangle)
 
1702
{
 
1703
  GimpRectangleToolInterface *iface;
 
1704
  gboolean                    retval = FALSE;
 
1705
 
 
1706
  iface = GIMP_RECTANGLE_TOOL_GET_INTERFACE (rectangle);
 
1707
 
 
1708
  if (iface->execute)
 
1709
    {
 
1710
      GimpRectangleToolPrivate *private;
 
1711
 
 
1712
      private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
1713
 
 
1714
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (rectangle));
 
1715
 
 
1716
      retval = iface->execute (rectangle,
 
1717
                               private->x1,
 
1718
                               private->y1,
 
1719
                               private->x2 - private->x1,
 
1720
                               private->y2 - private->y1);
 
1721
 
 
1722
      gimp_rectangle_tool_configure (rectangle);
 
1723
 
 
1724
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (rectangle));
 
1725
    }
 
1726
 
 
1727
  return retval;
 
1728
}
 
1729
 
 
1730
void
 
1731
gimp_rectangle_tool_cancel (GimpRectangleTool *rectangle)
 
1732
{
 
1733
  GimpRectangleToolInterface *iface;
 
1734
 
 
1735
  iface = GIMP_RECTANGLE_TOOL_GET_INTERFACE (rectangle);
 
1736
 
 
1737
  if (iface->cancel)
 
1738
    iface->cancel (rectangle);
 
1739
}
 
1740
 
 
1741
static void
 
1742
gimp_rectangle_tool_update_options (GimpRectangleTool *rectangle,
 
1743
                                    GimpDisplay       *display)
 
1744
{
 
1745
  GimpRectangleToolPrivate    *private;
 
1746
  GimpRectangleOptions        *options;
 
1747
  GimpRectangleOptionsPrivate *options_private;
 
1748
  gdouble                      x;
 
1749
  gdouble                      y;
 
1750
  gdouble                      width;
 
1751
  gdouble                      height;
 
1752
  gdouble                      center_x, center_y;
 
1753
 
 
1754
  private         = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
1755
  options         = GIMP_RECTANGLE_TOOL_GET_OPTIONS (rectangle);
 
1756
  options_private = GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (options);
 
1757
 
 
1758
  x      = private->x1;
 
1759
  y      = private->y1;
 
1760
  width  = private->x2 - private->x1;
 
1761
  height = private->y2 - private->y1;
 
1762
 
 
1763
  center_x = (private->x1 + private->x2) / 2.0;
 
1764
  center_y = (private->y1 + private->y2) / 2.0;
 
1765
 
 
1766
  g_signal_handlers_block_by_func (options,
 
1767
                                   gimp_rectangle_tool_options_notify,
 
1768
                                   rectangle);
 
1769
 
 
1770
  g_object_set (options,
 
1771
                "x0", x,
 
1772
                "y0", y,
 
1773
                NULL);
 
1774
 
 
1775
  if (! options_private->fixed_width)
 
1776
    g_object_set (options,
 
1777
                  "width",  width,
 
1778
                  NULL);
 
1779
 
 
1780
  if (! options_private->fixed_height)
 
1781
    g_object_set (options,
 
1782
                  "height", height,
 
1783
                  NULL);
 
1784
 
 
1785
  g_signal_handlers_unblock_by_func (options,
 
1786
                                     gimp_rectangle_tool_options_notify,
 
1787
                                     rectangle);
 
1788
 
 
1789
  g_object_set (options,
 
1790
                "center-x", center_x,
 
1791
                "center-y", center_y,
 
1792
                NULL);
 
1793
}
 
1794
 
 
1795
static void
 
1796
gimp_rectangle_tool_synthesize_motion (GimpRectangleTool *rectangle,
 
1797
                                       gint               function,
 
1798
                                       gint               startx,
 
1799
                                       gint               starty,
 
1800
                                       GimpCoords        *coords)
 
1801
{
 
1802
  GimpRectangleToolPrivate *private;
 
1803
  GimpRectangleFunction     old_function;
 
1804
 
 
1805
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
1806
 
 
1807
  private->startx = startx;
 
1808
  private->starty = starty;
 
1809
 
 
1810
  old_function = private->function;
 
1811
 
 
1812
  gimp_draw_tool_pause (GIMP_DRAW_TOOL (rectangle));
 
1813
 
 
1814
  gimp_rectangle_tool_set_function (rectangle, function);
 
1815
  gimp_rectangle_tool_motion (GIMP_TOOL (rectangle),
 
1816
                              coords, 0, 0, GIMP_TOOL (rectangle)->display);
 
1817
  gimp_rectangle_tool_set_function (rectangle, old_function);
 
1818
 
 
1819
  gimp_draw_tool_resume (GIMP_DRAW_TOOL (rectangle));
 
1820
 
 
1821
  gimp_rectangle_tool_rectangle_changed (rectangle);
 
1822
}
 
1823
 
 
1824
static void
 
1825
gimp_rectangle_tool_options_notify (GimpRectangleOptions *options,
 
1826
                                    GParamSpec           *pspec,
 
1827
                                    GimpRectangleTool    *rectangle)
 
1828
{
 
1829
  GimpRectangleToolPrivate    *private;
 
1830
  GimpRectangleOptionsPrivate *options_private;
 
1831
 
 
1832
  private         = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
1833
  options_private = GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (options);
 
1834
 
 
1835
  if (! strcmp (pspec->name, "guide"))
 
1836
    {
 
1837
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (rectangle));
 
1838
 
 
1839
      private->guide = options_private->guide;
 
1840
 
 
1841
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (rectangle));
 
1842
 
 
1843
      return;
 
1844
    }
 
1845
 
 
1846
  if (! GIMP_TOOL (rectangle)->display)
 
1847
    return;
 
1848
 
 
1849
  if (! strcmp (pspec->name, "x0"))
 
1850
    {
 
1851
      GimpCoords coords;
 
1852
 
 
1853
      coords.x = options_private->x0;
 
1854
      coords.y = private->y1;
 
1855
 
 
1856
      gimp_rectangle_tool_synthesize_motion (rectangle,
 
1857
                                             RECT_RESIZING_LEFT,
 
1858
                                             private->x1,
 
1859
                                             private->y1,
 
1860
                                             &coords);
 
1861
    }
 
1862
  else if (! strcmp (pspec->name, "y0"))
 
1863
    {
 
1864
      GimpCoords coords;
 
1865
 
 
1866
      coords.x = private->x1;
 
1867
      coords.y = options_private->y0;
 
1868
 
 
1869
      gimp_rectangle_tool_synthesize_motion (rectangle,
 
1870
                                             RECT_RESIZING_TOP,
 
1871
                                             private->x1,
 
1872
                                             private->y1,
 
1873
                                             &coords);
 
1874
    }
 
1875
  else if (! strcmp (pspec->name, "width"))
 
1876
    {
 
1877
      GimpCoords coords;
 
1878
 
 
1879
      coords.x = private->x1 + options_private->width;
 
1880
      coords.y = private->y2;
 
1881
 
 
1882
      gimp_rectangle_tool_synthesize_motion (rectangle,
 
1883
                                             RECT_RESIZING_RIGHT,
 
1884
                                             private->x2,
 
1885
                                             private->y2,
 
1886
                                             &coords);
 
1887
    }
 
1888
  else if (! strcmp (pspec->name, "height"))
 
1889
    {
 
1890
      GimpCoords coords;
 
1891
 
 
1892
      coords.x = private->x2;
 
1893
      coords.y = private->y1 + options_private->height;
 
1894
 
 
1895
      gimp_rectangle_tool_synthesize_motion (rectangle,
 
1896
                                             RECT_RESIZING_BOTTOM,
 
1897
                                             private->x2,
 
1898
                                             private->y2,
 
1899
                                             &coords);
 
1900
    }
 
1901
  else if (! strcmp (pspec->name, "fixed-aspect")     ||
 
1902
           ! strcmp (pspec->name, "aspect-numerator") ||
 
1903
           ! strcmp (pspec->name, "aspect-denominator"))
 
1904
    {
 
1905
      if (options_private->fixed_aspect)
 
1906
        {
 
1907
          GimpCoords coords;
 
1908
          gdouble    aspect;
 
1909
 
 
1910
          aspect = (options_private->aspect_numerator /
 
1911
                    options_private->aspect_denominator);
 
1912
 
 
1913
          coords.x = private->x2;
 
1914
          coords.y = private->y1 + (private->x2 - private->x1) / aspect;
 
1915
 
 
1916
          gimp_rectangle_tool_synthesize_motion (rectangle,
 
1917
                                                 RECT_RESIZING_BOTTOM,
 
1918
                                                 private->x2,
 
1919
                                                 private->y2,
 
1920
                                                 &coords);
 
1921
        }
 
1922
    }
 
1923
  else if (! strcmp (pspec->name, "highlight"))
 
1924
    {
 
1925
      gimp_rectangle_tool_set_highlight (rectangle);
 
1926
    }
 
1927
}
 
1928
 
 
1929
GimpRectangleFunction
 
1930
gimp_rectangle_tool_get_function (GimpRectangleTool *rectangle)
 
1931
{
 
1932
  g_return_val_if_fail (GIMP_IS_RECTANGLE_TOOL (rectangle), RECT_INACTIVE);
 
1933
 
 
1934
  return GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle)->function;
 
1935
}
 
1936
 
 
1937
void
 
1938
gimp_rectangle_tool_set_function (GimpRectangleTool     *rectangle,
 
1939
                                  GimpRectangleFunction  function)
 
1940
{
 
1941
  GimpRectangleToolPrivate *private;
 
1942
 
 
1943
  g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (rectangle));
 
1944
 
 
1945
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
1946
 
 
1947
  /* redraw the tool when the function changes */
 
1948
  /* FIXME: should also update the cursor      */
 
1949
  if (private->function != function)
 
1950
    {
 
1951
      GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (rectangle);
 
1952
 
 
1953
      gimp_draw_tool_pause (draw_tool);
 
1954
 
 
1955
      private->function = function;
 
1956
 
 
1957
      gimp_draw_tool_resume (draw_tool);
 
1958
    }
 
1959
}
 
1960
 
 
1961
static void
 
1962
gimp_rectangle_tool_rectangle_changed (GimpRectangleTool *rectangle)
 
1963
{
 
1964
  g_signal_emit (rectangle,
 
1965
                 gimp_rectangle_tool_signals[RECTANGLE_CHANGED], 0);
 
1966
}
 
1967
 
 
1968
/*
 
1969
 * check whether the coordinates extend outside the bounds of the image
 
1970
 * or active drawable, if it is constrained not to.  If it does,truncates
 
1971
 * the corrners to the constraints.
 
1972
 */
 
1973
void
 
1974
gimp_rectangle_tool_constrain (GimpRectangleTool *rectangle,
 
1975
                               gint               *x1,
 
1976
                               gint               *y1,
 
1977
                               gint               *x2,
 
1978
                               gint               *y2)
 
1979
{
 
1980
  GimpTool                 *tool = GIMP_TOOL (rectangle);
 
1981
  GimpRectangleToolPrivate *private;
 
1982
  GimpRectangleConstraint   constraint;
 
1983
  GimpImage                *image;
 
1984
  gint                      min_x, min_y;
 
1985
  gint                      max_x, max_y;
 
1986
 
 
1987
  private    = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
1988
  constraint = gimp_rectangle_tool_get_constraint (rectangle);
 
1989
  image      = tool->display->image;
 
1990
 
 
1991
  switch (constraint)
 
1992
    {
 
1993
    case GIMP_RECTANGLE_CONSTRAIN_NONE:
 
1994
      return ;
 
1995
 
 
1996
    case GIMP_RECTANGLE_CONSTRAIN_IMAGE:
 
1997
      min_x = 0;
 
1998
      min_y = 0;
 
1999
      max_x = image->width;
 
2000
      max_y = image->height;
 
2001
      break;
 
2002
 
 
2003
    case GIMP_RECTANGLE_CONSTRAIN_DRAWABLE:
 
2004
      {
 
2005
        GimpItem *item = GIMP_ITEM (tool->drawable);
 
2006
 
 
2007
        gimp_item_offsets (item, &min_x, &min_y);
 
2008
        max_x = min_x + gimp_item_width (item);
 
2009
        max_y = min_y + gimp_item_height (item);
 
2010
      }
 
2011
      break;
 
2012
 
 
2013
    default:
 
2014
      g_warning ("Invalid rectangle constraint.\n");
 
2015
      return;
 
2016
    }
 
2017
 
 
2018
  if (*x1 < min_x)
 
2019
    {
 
2020
      *x1 = min_x;
 
2021
    }
 
2022
  if (*x2 > max_x)
 
2023
    {
 
2024
      *x2 = max_x;
 
2025
    }
 
2026
  if (*y1 < min_y)
 
2027
    {
 
2028
      *y1 = min_y;
 
2029
    }
 
2030
  if (*y2 > max_y)
 
2031
    {
 
2032
      *y2 = max_y;
 
2033
    }
 
2034
}
 
2035
 
 
2036
static void
 
2037
gimp_rectangle_tool_auto_shrink (GimpRectangleTool *rectangle)
 
2038
{
 
2039
  GimpTool                 *tool     = GIMP_TOOL (rectangle);
 
2040
  GimpRectangleToolPrivate *private;
 
2041
  GimpDisplay              *display  = tool->display;
 
2042
  gint                      width;
 
2043
  gint                      height;
 
2044
  gint                      offset_x = 0;
 
2045
  gint                      offset_y = 0;
 
2046
  gint                      x1, y1;
 
2047
  gint                      x2, y2;
 
2048
  gint                      shrunk_x1;
 
2049
  gint                      shrunk_y1;
 
2050
  gint                      shrunk_x2;
 
2051
  gint                      shrunk_y2;
 
2052
  gboolean                  shrink_merged;
 
2053
 
 
2054
  private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
 
2055
 
 
2056
  if (! display)
 
2057
    return;
 
2058
 
 
2059
  width  = display->image->width;
 
2060
  height = display->image->height;
 
2061
 
 
2062
  g_object_get (gimp_tool_get_options (tool),
 
2063
                "shrink-merged", &shrink_merged,
 
2064
                NULL);
 
2065
 
 
2066
  x1 = private->x1 - offset_x  > 0      ? private->x1 - offset_x : 0;
 
2067
  x2 = private->x2 - offset_x  < width  ? private->x2 - offset_x : width;
 
2068
  y1 = private->y1 - offset_y  > 0      ? private->y1 - offset_y : 0;
 
2069
  y2 = private->y2 - offset_y  < height ? private->y2 - offset_y : height;
 
2070
 
 
2071
  if (gimp_image_crop_auto_shrink (display->image,
 
2072
                                   x1, y1, x2, y2,
 
2073
                                   ! shrink_merged,
 
2074
                                   &shrunk_x1,
 
2075
                                   &shrunk_y1,
 
2076
                                   &shrunk_x2,
 
2077
                                   &shrunk_y2))
 
2078
    {
 
2079
      gimp_draw_tool_pause (GIMP_DRAW_TOOL (rectangle));
 
2080
 
 
2081
      g_object_set (rectangle,
 
2082
                    "x1", offset_x + shrunk_x1,
 
2083
                    "y1", offset_y + shrunk_y1,
 
2084
                    "x2", offset_x + shrunk_x2,
 
2085
                    "y2", offset_y + shrunk_y2,
 
2086
                    NULL);
 
2087
 
 
2088
      gimp_rectangle_tool_configure (rectangle);
 
2089
 
 
2090
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (rectangle));
 
2091
    }
 
2092
}
 
2093
 
 
2094
static GtkAnchorType
 
2095
gimp_rectangle_tool_get_anchor (GimpRectangleToolPrivate *private,
 
2096
                                gint                     *w,
 
2097
                                gint                     *h)
 
2098
{
 
2099
  *w = private->handle_w;
 
2100
  *h = private->handle_h;
 
2101
 
 
2102
  switch (private->function)
 
2103
    {
 
2104
    case RECT_RESIZING_UPPER_LEFT:
 
2105
      return GTK_ANCHOR_NORTH_WEST;
 
2106
 
 
2107
    case RECT_RESIZING_UPPER_RIGHT:
 
2108
      return GTK_ANCHOR_NORTH_EAST;
 
2109
 
 
2110
    case RECT_RESIZING_LOWER_LEFT:
 
2111
      return GTK_ANCHOR_SOUTH_WEST;
 
2112
 
 
2113
    case RECT_RESIZING_LOWER_RIGHT:
 
2114
      return GTK_ANCHOR_SOUTH_EAST;
 
2115
 
 
2116
    case RECT_RESIZING_LEFT:
 
2117
      *w = (*w * 2) / 3;
 
2118
      return GTK_ANCHOR_WEST;
 
2119
 
 
2120
    case RECT_RESIZING_RIGHT:
 
2121
      *w = (*w * 2) / 3;
 
2122
      return GTK_ANCHOR_EAST;
 
2123
 
 
2124
    case RECT_RESIZING_TOP:
 
2125
      *h = (*h * 2) / 3;
 
2126
      return GTK_ANCHOR_NORTH;
 
2127
 
 
2128
    case RECT_RESIZING_BOTTOM:
 
2129
      *h = (*h * 2) / 3;
 
2130
      return GTK_ANCHOR_SOUTH;
 
2131
 
 
2132
    default:
 
2133
      return GTK_ANCHOR_CENTER;
 
2134
    }
 
2135
}
 
2136
 
 
2137
static void
 
2138
gimp_rectangle_tool_set_highlight (GimpRectangleTool *rectangle)
 
2139
{
 
2140
  GimpTool             *tool      = GIMP_TOOL (rectangle);
 
2141
  GimpRectangleOptions *options   = GIMP_RECTANGLE_TOOL_GET_OPTIONS (tool);
 
2142
  GimpDisplayShell     *shell     = GIMP_DISPLAY_SHELL (tool->display->shell);
 
2143
  gboolean              highlight = FALSE;
 
2144
 
 
2145
  g_object_get (options, "highlight", &highlight, NULL);
 
2146
 
 
2147
  if (highlight)
 
2148
    {
 
2149
      GimpRectangleToolPrivate *private;
 
2150
      GdkRectangle              rect;
 
2151
 
 
2152
      private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
 
2153
 
 
2154
      rect.x      = private->x1;
 
2155
      rect.y      = private->y1;
 
2156
      rect.width  = private->x2 - private->x1;
 
2157
      rect.height = private->y2 - private->y1;
 
2158
 
 
2159
      gimp_display_shell_set_highlight (shell, &rect);
 
2160
    }
 
2161
  else
 
2162
    {
 
2163
      gimp_display_shell_set_highlight (shell, NULL);
 
2164
    }
 
2165
}