1
/* GIMP - The GNU Image Manipulation Program
2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
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.
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.
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.
24
#include <gdk/gdkkeysyms.h>
26
#include "libgimpbase/gimpbase.h"
27
#include "libgimpmath/gimpmath.h"
28
#include "libgimpwidgets/gimpwidgets.h"
30
#include "tools-types.h"
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"
38
#include "display/gimpdisplay.h"
39
#include "display/gimpdisplayshell.h"
40
#include "display/gimpdisplayshell-transform.h"
42
#include "gimpdrawtool.h"
43
#include "gimprectangleoptions.h"
44
#include "gimprectangletool.h"
45
#include "gimptoolcontrol.h"
47
#include "gimp-intl.h"
56
/* speed of key movement */
57
#define ARROW_VELOCITY 25
59
#define HANDLE_SIZE 50
60
#define MIN_HANDLE_SIZE 6
62
#define SQRT5 2.236067977
65
#define GIMP_RECTANGLE_TOOL_GET_PRIVATE(obj) \
66
(gimp_rectangle_tool_get_private (GIMP_RECTANGLE_TOOL (obj)))
69
typedef struct _GimpRectangleToolPrivate GimpRectangleToolPrivate;
71
struct _GimpRectangleToolPrivate
73
gint pressx; /* x where button pressed */
74
gint pressy; /* y where button pressed */
76
gint x1, y1; /* upper left hand coordinate */
77
gint x2, y2; /* lower right hand coords */
79
guint function; /* moving or resizing */
81
GimpRectangleConstraint constraint; /* how to constrain rectangle */
84
gint startx; /* starting x coord */
85
gint starty; /* starting y coord */
87
gint lastx; /* previous x coord */
88
gint lasty; /* previous y coord */
90
gint handle_w; /* handle width */
91
gint handle_h; /* handle height */
93
gint saved_x1; /* for saving in case action */
94
gint saved_y1; /* is canceled */
97
gdouble saved_center_x;
98
gdouble saved_center_y;
100
gint suppress_updates;
102
GimpRectangleGuide guide; /* synced with options->guide, only exists for drawing */
106
static void gimp_rectangle_tool_iface_base_init (GimpRectangleToolInterface *iface);
108
static GimpRectangleToolPrivate *
109
gimp_rectangle_tool_get_private (GimpRectangleTool *rectangle);
111
GimpRectangleConstraint
112
gimp_rectangle_tool_get_constraint (GimpRectangleTool *rectangle);
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);
120
/* Rectangle dialog functions */
121
static void gimp_rectangle_tool_update_options (GimpRectangleTool *rectangle,
122
GimpDisplay *display);
124
static void gimp_rectangle_tool_options_notify (GimpRectangleOptions *options,
126
GimpRectangleTool *rectangle);
128
static void gimp_rectangle_tool_check_function (GimpRectangleTool *rectangle,
133
static void gimp_rectangle_tool_rectangle_changed (GimpRectangleTool *rectangle);
135
static void gimp_rectangle_tool_constrain (GimpRectangleTool *rectangle,
141
static void gimp_rectangle_tool_auto_shrink (GimpRectangleTool *rectangle);
143
static GtkAnchorType gimp_rectangle_tool_get_anchor (GimpRectangleToolPrivate *private,
146
static void gimp_rectangle_tool_set_highlight (GimpRectangleTool *rectangle);
149
static guint gimp_rectangle_tool_signals[LAST_SIGNAL] = { 0 };
153
gimp_rectangle_tool_interface_get_type (void)
155
static GType iface_type = 0;
159
const GTypeInfo iface_info =
161
sizeof (GimpRectangleToolInterface),
162
(GBaseInitFunc) gimp_rectangle_tool_iface_base_init,
163
(GBaseFinalizeFunc) NULL,
166
iface_type = g_type_register_static (G_TYPE_INTERFACE,
167
"GimpRectangleToolInterface",
170
g_type_interface_add_prerequisite (iface_type, GIMP_TYPE_DRAW_TOOL);
177
gimp_rectangle_tool_iface_base_init (GimpRectangleToolInterface *iface)
179
static gboolean initialized = FALSE;
183
gimp_rectangle_tool_signals[RECTANGLE_CHANGED] =
184
g_signal_new ("rectangle-changed",
185
G_TYPE_FROM_INTERFACE (iface),
187
G_STRUCT_OFFSET (GimpRectangleToolInterface,
190
gimp_marshal_VOID__VOID,
193
g_object_interface_install_property (iface,
194
g_param_spec_int ("x1",
196
-GIMP_MAX_IMAGE_SIZE,
199
GIMP_PARAM_READWRITE));
201
g_object_interface_install_property (iface,
202
g_param_spec_int ("y1",
204
-GIMP_MAX_IMAGE_SIZE,
207
GIMP_PARAM_READWRITE));
209
g_object_interface_install_property (iface,
210
g_param_spec_int ("x2",
212
-GIMP_MAX_IMAGE_SIZE,
215
GIMP_PARAM_READWRITE));
217
g_object_interface_install_property (iface,
218
g_param_spec_int ("y2",
220
-GIMP_MAX_IMAGE_SIZE,
223
GIMP_PARAM_READWRITE));
225
g_object_interface_install_property (iface,
226
g_param_spec_enum ("constraint",
228
GIMP_TYPE_RECTANGLE_CONSTRAINT,
229
GIMP_RECTANGLE_CONSTRAIN_NONE,
230
GIMP_PARAM_READWRITE));
232
iface->execute = NULL;
233
iface->cancel = NULL;
234
iface->rectangle_changed = NULL;
241
gimp_rectangle_tool_private_finalize (GimpRectangleToolPrivate *private)
246
static GimpRectangleToolPrivate *
247
gimp_rectangle_tool_get_private (GimpRectangleTool *tool)
249
static GQuark private_key = 0;
251
GimpRectangleToolPrivate *private;
253
if (G_UNLIKELY (private_key == 0))
254
private_key = g_quark_from_static_string ("gimp-rectangle-tool-private");
256
private = g_object_get_qdata (G_OBJECT (tool), private_key);
260
private = g_new0 (GimpRectangleToolPrivate, 1);
262
g_object_set_qdata_full (G_OBJECT (tool), private_key, private,
264
gimp_rectangle_tool_private_finalize);
271
* gimp_rectangle_tool_install_properties:
272
* @klass: the class structure for a type deriving from #GObject
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).
282
gimp_rectangle_tool_install_properties (GObjectClass *klass)
284
g_object_class_override_property (klass,
285
GIMP_RECTANGLE_TOOL_PROP_X1,
287
g_object_class_override_property (klass,
288
GIMP_RECTANGLE_TOOL_PROP_Y1,
290
g_object_class_override_property (klass,
291
GIMP_RECTANGLE_TOOL_PROP_X2,
293
g_object_class_override_property (klass,
294
GIMP_RECTANGLE_TOOL_PROP_Y2,
296
g_object_class_override_property (klass,
297
GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT,
302
gimp_rectangle_tool_set_constraint (GimpRectangleTool *tool,
303
GimpRectangleConstraint constraint)
305
GimpRectangleToolPrivate *private;
307
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
309
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
311
private->constraint = constraint;
313
g_object_notify (G_OBJECT (tool), "constraint");
316
GimpRectangleConstraint
317
gimp_rectangle_tool_get_constraint (GimpRectangleTool *tool)
319
GimpRectangleToolPrivate *private;
321
g_return_val_if_fail (GIMP_IS_RECTANGLE_TOOL (tool), 0);
323
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
325
return private->constraint;
329
gimp_rectangle_tool_get_press_coords (GimpRectangleTool *rectangle,
333
GimpRectangleToolPrivate *private;
335
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
337
*pressx_ptr = private->pressx;
338
*pressy_ptr = private->pressy;
342
gimp_rectangle_tool_set_property (GObject *object,
347
GimpRectangleTool *rectangle = GIMP_RECTANGLE_TOOL (object);
348
GimpRectangleToolPrivate *private;
350
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
354
case GIMP_RECTANGLE_TOOL_PROP_X1:
355
private->x1 = g_value_get_int (value);
357
case GIMP_RECTANGLE_TOOL_PROP_Y1:
358
private->y1 = g_value_get_int (value);
360
case GIMP_RECTANGLE_TOOL_PROP_X2:
361
private->x2 = g_value_get_int (value);
363
case GIMP_RECTANGLE_TOOL_PROP_Y2:
364
private->y2 = g_value_get_int (value);
366
case GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT:
367
gimp_rectangle_tool_set_constraint (rectangle, g_value_get_enum (value));
370
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
376
gimp_rectangle_tool_get_property (GObject *object,
381
GimpRectangleTool *rectangle = GIMP_RECTANGLE_TOOL (object);
382
GimpRectangleToolPrivate *private;
384
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
388
case GIMP_RECTANGLE_TOOL_PROP_X1:
389
g_value_set_int (value, private->x1);
391
case GIMP_RECTANGLE_TOOL_PROP_Y1:
392
g_value_set_int (value, private->y1);
394
case GIMP_RECTANGLE_TOOL_PROP_X2:
395
g_value_set_int (value, private->x2);
397
case GIMP_RECTANGLE_TOOL_PROP_Y2:
398
g_value_set_int (value, private->y2);
400
case GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT:
401
g_value_set_enum (value, gimp_rectangle_tool_get_constraint (rectangle));
404
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
410
gimp_rectangle_tool_constructor (GObject *object)
412
GimpRectangleTool *rectangle = GIMP_RECTANGLE_TOOL (object);
413
GimpRectangleToolPrivate *private;
414
GimpRectangleOptions *options;
416
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (object);
417
options = GIMP_RECTANGLE_TOOL_GET_OPTIONS (object);
419
g_object_get (options,
420
"guide", &private->guide,
423
g_signal_connect_object (options, "notify",
424
G_CALLBACK (gimp_rectangle_tool_options_notify),
429
gimp_rectangle_tool_control (GimpTool *tool,
430
GimpToolAction action,
431
GimpDisplay *display)
433
GimpRectangleTool *rectangle = GIMP_RECTANGLE_TOOL (tool);
437
case GIMP_TOOL_ACTION_PAUSE:
440
case GIMP_TOOL_ACTION_RESUME:
441
gimp_rectangle_tool_configure (rectangle);
444
case GIMP_TOOL_ACTION_HALT:
445
gimp_rectangle_tool_halt (rectangle);
454
gimp_rectangle_tool_button_press (GimpTool *tool,
457
GdkModifierType state,
458
GimpDisplay *display)
460
GimpRectangleTool *rectangle;
461
GimpDrawTool *draw_tool;
462
GimpRectangleToolPrivate *private;
463
GimpRectangleOptions *options;
464
GimpRectangleOptionsPrivate *options_private;
468
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
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);
476
x = ROUND (coords->x);
477
y = ROUND (coords->y);
479
gimp_draw_tool_pause (draw_tool);
481
if (display != tool->display)
483
if (gimp_draw_tool_is_active (draw_tool))
484
gimp_draw_tool_stop (draw_tool);
486
gimp_rectangle_tool_set_function (rectangle, RECT_CREATING);
488
g_object_set (rectangle,
495
gimp_rectangle_tool_start (rectangle, display);
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;
504
private->saved_center_x = options_private->center_x;
505
private->saved_center_y = options_private->center_y;
507
switch (private->function)
510
g_object_set (options,
511
"center-x", (gdouble) x,
512
"center-y", (gdouble) y,
515
g_object_set (rectangle,
522
gimp_tool_control_set_snap_offsets (tool->control, 0, 0, 0, 0);
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,
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,
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,
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,
553
case RECT_RESIZING_LEFT:
554
gimp_tool_control_set_snap_offsets (tool->control,
555
private->x1 - coords->x, 0,
559
case RECT_RESIZING_RIGHT:
560
gimp_tool_control_set_snap_offsets (tool->control,
561
private->x2 - coords->x, 0,
565
case RECT_RESIZING_TOP:
566
gimp_tool_control_set_snap_offsets (tool->control,
567
0, private->y1 - coords->y,
571
case RECT_RESIZING_BOTTOM:
572
gimp_tool_control_set_snap_offsets (tool->control,
573
0, private->y2 - coords->y,
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);
589
gimp_tool_control_get_snap_offsets (tool->control,
590
&snap_x, &snap_y, NULL, NULL);
603
gimp_tool_control_activate (tool->control);
605
gimp_draw_tool_resume (draw_tool);
609
gimp_rectangle_tool_button_release (GimpTool *tool,
612
GdkModifierType state,
613
GimpButtonReleaseType release_type,
614
GimpDisplay *display)
616
GimpRectangleTool *rectangle;
617
GimpRectangleToolPrivate *private;
618
GimpRectangleOptions *options;
620
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
622
rectangle = GIMP_RECTANGLE_TOOL (tool);
623
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
624
options = GIMP_RECTANGLE_TOOL_GET_OPTIONS (tool);
626
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
628
gimp_tool_control_halt (tool->control);
630
if (private->function == RECT_EXECUTING)
631
gimp_tool_pop_status (tool, display);
633
switch (release_type)
635
case GIMP_BUTTON_RELEASE_NORMAL:
636
gimp_rectangle_tool_rectangle_changed (rectangle);
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,
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,
653
case GIMP_BUTTON_RELEASE_CLICK:
654
if (gimp_rectangle_tool_execute (rectangle))
655
gimp_rectangle_tool_halt (rectangle);
658
case GIMP_BUTTON_RELEASE_NO_MOTION:
662
gimp_tool_control_set_snap_offsets (tool->control, 0, 0, 0, 0);
664
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
668
gimp_rectangle_tool_motion (GimpTool *tool,
671
GdkModifierType state,
672
GimpDisplay *display)
674
GimpRectangleTool *rectangle;
675
GimpRectangleToolPrivate *private;
676
GimpRectangleOptions *options;
677
GimpRectangleOptionsPrivate *options_private;
682
gboolean created_now = FALSE;
684
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
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);
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.
694
if (private->function == RECT_EXECUTING)
697
curx = ROUND (coords->x);
698
cury = ROUND (coords->y);
700
gimp_tool_control_get_snap_offsets (tool->control,
701
&snap_x, &snap_y, NULL, NULL);
705
/* If there have been no changes... return */
706
if (private->lastx == curx && private->lasty == cury)
709
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
712
inc_x = curx - private->startx;
713
inc_y = cury - private->starty;
720
switch (private->function)
723
g_warning ("function is RECT_INACTIVE while mouse is moving");
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);
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);
749
case RECT_RESIZING_BOTTOM:
750
case RECT_RESIZING_TOP:
756
x1 = private->x1 + inc_x;
757
x2 = private->x2 + inc_x;
761
switch (private->function)
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);
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);
786
case RECT_RESIZING_RIGHT:
787
case RECT_RESIZING_LEFT:
793
y1 = private->y1 + inc_y;
794
y2 = private->y2 + inc_y;
798
if (options_private->fixed_aspect)
802
aspect = CLAMP (options_private->aspect_numerator /
803
options_private->aspect_denominator,
804
1.0 / display->image->height,
805
display->image->width);
807
switch (private->function)
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.
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))
829
if (options_private->fixed_center)
831
x2 = x1 + 2 * (options_private->center_x - x1);
832
y2 = y1 + 2 * (options_private->center_y - y1);
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))
843
if (options_private->fixed_center)
845
x1 = x2 - 2 * (x2 - options_private->center_x);
846
y2 = y1 + 2 * (options_private->center_y - y1);
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))
857
if (options_private->fixed_center)
859
x2 = x1 + 2 * (options_private->center_x - x1);
860
y1 = y2 - 2 * (y2 - options_private->center_y);
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))
871
if (options_private->fixed_center)
873
x1 = x2 - 2 * (x2 - options_private->center_x);
874
y1 = y2 - 2 * (y2 - options_private->center_y);
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);
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
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);
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);
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
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);
915
private->lastx = curx;
916
private->lasty = cury;
918
/* Check to see whether the new rectangle obeys the boundary
919
* constraints, if any, and constrain it.
922
gimp_rectangle_tool_constrain (rectangle, &x1, &y1, &x2, &y2);
925
/* set startx, starty according to function, to keep rect on cursor */
926
switch (private->function)
928
case RECT_RESIZING_UPPER_LEFT:
929
private->startx = x1;
930
private->starty = y1;
933
case RECT_RESIZING_UPPER_RIGHT:
934
private->startx = x2;
935
private->starty = y1;
938
case RECT_RESIZING_LOWER_LEFT:
939
private->startx = x1;
940
private->starty = y2;
943
case RECT_RESIZING_LOWER_RIGHT:
944
private->startx = x2;
945
private->starty = y2;
948
case RECT_RESIZING_TOP:
949
private->startx = curx;
950
private->starty = y1;
953
case RECT_RESIZING_LEFT:
954
private->startx = x1;
955
private->starty = cury;
958
case RECT_RESIZING_BOTTOM:
959
private->startx = curx;
960
private->starty = y2;
964
case RECT_RESIZING_RIGHT:
965
private->startx = x2;
966
private->starty = cury;
970
private->startx = curx;
971
private->starty = cury;
978
/* fix function if user has "flipped" the rectangle */
980
gimp_rectangle_tool_check_function (rectangle, &x1, &y1, &x2, &y2);
982
/* make sure that the coords are in bounds */
983
g_object_set (rectangle,
990
/* recalculate the coordinates for rectangle_draw based on the new values */
991
gimp_rectangle_tool_configure (rectangle);
993
gimp_rectangle_tool_update_options (rectangle, display);
995
if (private->function != RECT_MOVING &&
996
private->function != RECT_EXECUTING)
1000
gimp_tool_pop_status (tool, display);
1002
w = private->x2 - private->x1;
1003
h = private->y2 - private->y1;
1006
gimp_tool_push_status_coords (tool, display,
1007
_("Rectangle: "), w, " × ", h, NULL);
1010
if (private->function == RECT_CREATING)
1012
GimpRectangleFunction function = RECT_CREATING;
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;
1025
gimp_rectangle_tool_set_function (rectangle, function);
1028
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
1032
gimp_rectangle_tool_active_modifier_key (GimpTool *tool,
1033
GdkModifierType key,
1035
GdkModifierType state,
1036
GimpDisplay *display)
1038
GimpRectangleTool *rectangle;
1039
GimpRectangleOptions *options;
1040
GimpRectangleOptionsPrivate *options_private;
1042
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
1044
rectangle = GIMP_RECTANGLE_TOOL (tool);
1045
options = GIMP_RECTANGLE_TOOL_GET_OPTIONS (tool);
1046
options_private = GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (options);
1048
if (key == GDK_SHIFT_MASK)
1050
g_object_set (options,
1051
"fixed-aspect", ! options_private->fixed_aspect,
1055
if (key == GDK_CONTROL_MASK)
1057
g_object_set (options,
1058
"fixed-center", ! options_private->fixed_center,
1061
if (options_private->fixed_center)
1063
gint press_x, press_y;
1065
gimp_rectangle_tool_get_press_coords (rectangle, &press_x, &press_y);
1067
g_object_set (options,
1068
"center-x", (gdouble) press_x,
1069
"center-y", (gdouble) press_y,
1075
static void swap_ints (gint *i,
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.
1090
gimp_rectangle_tool_check_function (GimpRectangleTool *rectangle,
1096
GimpRectangleToolPrivate *private;
1097
GimpRectangleFunction function;
1099
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
1101
function = private->function;
1108
case RECT_RESIZING_UPPER_LEFT:
1109
function = RECT_RESIZING_UPPER_RIGHT;
1111
case RECT_RESIZING_UPPER_RIGHT:
1112
function = RECT_RESIZING_UPPER_LEFT;
1114
case RECT_RESIZING_LOWER_LEFT:
1115
function = RECT_RESIZING_LOWER_RIGHT;
1117
case RECT_RESIZING_LOWER_RIGHT:
1118
function = RECT_RESIZING_LOWER_LEFT;
1120
case RECT_RESIZING_LEFT:
1121
function = RECT_RESIZING_RIGHT;
1123
case RECT_RESIZING_RIGHT:
1124
function = RECT_RESIZING_LEFT;
1126
/* avoid annoying warnings about unhandled enums */
1137
case RECT_RESIZING_UPPER_LEFT:
1138
function = RECT_RESIZING_LOWER_LEFT;
1140
case RECT_RESIZING_UPPER_RIGHT:
1141
function = RECT_RESIZING_LOWER_RIGHT;
1143
case RECT_RESIZING_LOWER_LEFT:
1144
function = RECT_RESIZING_UPPER_LEFT;
1146
case RECT_RESIZING_LOWER_RIGHT:
1147
function = RECT_RESIZING_UPPER_RIGHT;
1149
case RECT_RESIZING_TOP:
1150
function = RECT_RESIZING_BOTTOM;
1152
case RECT_RESIZING_BOTTOM:
1153
function = RECT_RESIZING_TOP;
1160
gimp_rectangle_tool_set_function (rectangle, function);
1166
gimp_rectangle_tool_key_press (GimpTool *tool,
1167
GdkEventKey *kevent,
1168
GimpDisplay *display)
1170
GimpRectangleTool *rectangle;
1171
GimpRectangleToolPrivate *private;
1181
g_return_val_if_fail (GIMP_IS_RECTANGLE_TOOL (tool), FALSE);
1183
if (display != tool->display)
1186
rectangle = GIMP_RECTANGLE_TOOL (tool);
1187
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
1189
switch (kevent->keyval)
1206
if (gimp_rectangle_tool_execute (rectangle))
1207
gimp_rectangle_tool_halt (rectangle);
1211
gimp_rectangle_tool_cancel (rectangle);
1212
gimp_rectangle_tool_halt (rectangle);
1219
/* If the shift key is down, move by an accelerated increment */
1220
if (kevent->state & GDK_SHIFT_MASK)
1222
dx *= ARROW_VELOCITY;
1223
dy *= ARROW_VELOCITY;
1226
/* Resize the rectangle if the mouse is over a handle, otherwise move it */
1227
switch (private->function)
1229
case RECT_RESIZING_UPPER_LEFT:
1233
case RECT_RESIZING_UPPER_RIGHT:
1237
case RECT_RESIZING_LOWER_LEFT:
1241
case RECT_RESIZING_LOWER_RIGHT:
1245
case RECT_RESIZING_LEFT:
1248
case RECT_RESIZING_RIGHT:
1251
case RECT_RESIZING_TOP:
1254
case RECT_RESIZING_BOTTOM:
1259
inc_x1 = inc_x2 = dx;
1260
inc_y1 = inc_y2 = dy;
1264
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
1266
x1 = private->x1 + inc_x1;
1267
y1 = private->y1 + inc_y1;
1268
x2 = private->x2 + inc_x2;
1269
y2 = private->y2 + inc_y2;
1271
gimp_rectangle_tool_check_function (rectangle, &x1, &y1, &x2, &y2);
1273
g_object_set (rectangle,
1280
gimp_rectangle_tool_configure (rectangle);
1282
gimp_rectangle_tool_update_options (rectangle, display);
1284
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
1286
gimp_rectangle_tool_rectangle_changed (rectangle);
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.
1292
private->suppress_updates = 2;
1298
gimp_rectangle_tool_oper_update (GimpTool *tool,
1300
GdkModifierType state,
1302
GimpDisplay *display)
1304
GimpRectangleToolPrivate *private;
1305
GimpDrawTool *draw_tool;
1308
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
1310
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
1311
draw_tool = GIMP_DRAW_TOOL (tool);
1313
if (tool->display != display)
1316
if (private->suppress_updates)
1318
private->suppress_updates--;
1322
if (coords->x > private->x1 && coords->x < private->x2 &&
1323
coords->y > private->y1 && coords->y < private->y2)
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;
1329
if (gimp_draw_tool_on_handle (draw_tool, display,
1330
coords->x, coords->y,
1332
private->x1, private->y1,
1333
private->handle_w, private->handle_h,
1334
GTK_ANCHOR_NORTH_WEST,
1337
function = RECT_RESIZING_UPPER_LEFT;
1339
else if (gimp_draw_tool_on_handle (draw_tool, display,
1340
coords->x, coords->y,
1342
private->x2, private->y2,
1343
private->handle_w, private->handle_h,
1344
GTK_ANCHOR_SOUTH_EAST,
1347
function = RECT_RESIZING_LOWER_RIGHT;
1349
else if (gimp_draw_tool_on_handle (draw_tool, display,
1350
coords->x, coords->y,
1352
private->x2, private->y1,
1353
private->handle_w, private->handle_h,
1354
GTK_ANCHOR_NORTH_EAST,
1357
function = RECT_RESIZING_UPPER_RIGHT;
1359
else if (gimp_draw_tool_on_handle (draw_tool, display,
1360
coords->x, coords->y,
1362
private->x1, private->y2,
1363
private->handle_w, private->handle_h,
1364
GTK_ANCHOR_SOUTH_WEST,
1367
function = RECT_RESIZING_LOWER_LEFT;
1369
else if ((fabs (coords->x - private->x1) < (handle_w * 2) / 3))
1371
function = RECT_RESIZING_LEFT;
1373
else if ((fabs (coords->x - private->x2) < (handle_w * 2) / 3))
1375
function = RECT_RESIZING_RIGHT;
1377
else if ((fabs (coords->y - private->y1) < (handle_h * 2) / 3))
1379
function = RECT_RESIZING_TOP;
1381
else if ((fabs (coords->y - private->y2) < (handle_h * 2) / 3))
1383
function = RECT_RESIZING_BOTTOM;
1387
function = RECT_MOVING;
1392
/* otherwise, the new function will be creating, since we want
1393
* to start a new rectangle
1395
function = RECT_CREATING;
1398
gimp_rectangle_tool_set_function (GIMP_RECTANGLE_TOOL (tool), function);
1402
gimp_rectangle_tool_cursor_update (GimpTool *tool,
1404
GdkModifierType state,
1405
GimpDisplay *display)
1407
GimpRectangleTool *rectangle;
1408
GimpRectangleToolPrivate *private;
1409
GimpCursorType cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
1411
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
1413
rectangle = GIMP_RECTANGLE_TOOL (tool);
1414
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
1416
if (tool->display == display)
1418
switch (private->function)
1421
cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
1424
cursor = GIMP_CURSOR_MOVE;
1426
case RECT_RESIZING_UPPER_LEFT:
1427
cursor = GIMP_CURSOR_CORNER_TOP_LEFT;
1429
case RECT_RESIZING_UPPER_RIGHT:
1430
cursor = GIMP_CURSOR_CORNER_TOP_RIGHT;
1432
case RECT_RESIZING_LOWER_LEFT:
1433
cursor = GIMP_CURSOR_CORNER_BOTTOM_LEFT;
1435
case RECT_RESIZING_LOWER_RIGHT:
1436
cursor = GIMP_CURSOR_CORNER_BOTTOM_RIGHT;
1438
case RECT_RESIZING_LEFT:
1439
cursor = GIMP_CURSOR_SIDE_LEFT;
1441
case RECT_RESIZING_RIGHT:
1442
cursor = GIMP_CURSOR_SIDE_RIGHT;
1444
case RECT_RESIZING_TOP:
1445
cursor = GIMP_CURSOR_SIDE_TOP;
1447
case RECT_RESIZING_BOTTOM:
1448
cursor = GIMP_CURSOR_SIDE_BOTTOM;
1456
gimp_tool_control_set_cursor (tool->control, cursor);
1460
gimp_rectangle_tool_draw (GimpDrawTool *draw_tool)
1463
GimpRectangleToolPrivate *private;
1465
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (draw_tool));
1467
tool = GIMP_TOOL (draw_tool);
1468
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
1470
if (private->function == RECT_INACTIVE)
1473
gimp_draw_tool_draw_rectangle (draw_tool, FALSE,
1476
private->x2 - private->x1,
1477
private->y2 - private->y1,
1480
switch (private->function)
1483
if (gimp_tool_control_is_active (tool->control))
1485
/* else fallthrough */
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);
1512
GtkAnchorType anchor;
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,
1526
gimp_rectangle_tool_draw_guides (draw_tool);
1530
gimp_rectangle_tool_draw_guides (GimpDrawTool *draw_tool)
1533
GimpRectangleToolPrivate *private;
1534
gint x1, x2, y1, y2;
1536
tool = GIMP_TOOL (draw_tool);
1537
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (draw_tool);
1544
switch (private->guide)
1546
case GIMP_RECTANGLE_GUIDE_NONE:
1549
case GIMP_RECTANGLE_GUIDE_CENTER_LINES:
1550
gimp_draw_tool_draw_line (draw_tool,
1552
x2, (y1 + y2) / 2, FALSE);
1553
gimp_draw_tool_draw_line (draw_tool,
1555
(x1 + x2) / 2, y2, FALSE);
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);
1573
case GIMP_RECTANGLE_GUIDE_GOLDEN:
1574
gimp_draw_tool_draw_line (draw_tool,
1576
(2 * y1 + (1 + SQRT5) * y2) / (3 + SQRT5),
1578
(2 * y1 + (1 + SQRT5) * y2) / (3 + SQRT5),
1580
gimp_draw_tool_draw_line (draw_tool,
1582
((1 + SQRT5) * y1 + 2 * y2) / (3 + SQRT5),
1584
((1 + SQRT5) * y1 + 2 * y2) / (3 + SQRT5),
1586
gimp_draw_tool_draw_line (draw_tool,
1587
(2 * x1 + (1 + SQRT5) * x2) / (3 + SQRT5),
1589
(2 * x1 + (1 + SQRT5) * x2) / (3 + SQRT5),
1592
gimp_draw_tool_draw_line (draw_tool,
1593
((1 + SQRT5) * x1 + 2 * x2) / (3 + SQRT5),
1595
((1 + SQRT5) * x1 + 2 * x2) / (3 + SQRT5),
1602
gimp_rectangle_tool_configure (GimpRectangleTool *rectangle)
1604
GimpTool *tool = GIMP_TOOL (rectangle);
1605
GimpRectangleToolPrivate *private;
1606
GimpRectangleOptions *options;
1607
GimpDisplayShell *shell;
1611
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
1612
options = GIMP_RECTANGLE_TOOL_GET_OPTIONS (tool);
1614
if (! tool->display)
1617
gimp_rectangle_tool_set_highlight (rectangle);
1619
shell = GIMP_DISPLAY_SHELL (tool->display->shell);
1621
gimp_display_shell_transform_xy (shell,
1622
private->x1, private->y1,
1625
gimp_display_shell_transform_xy (shell,
1626
private->x2, private->y2,
1630
private->handle_w = (dx2 - dx1) / 3;
1631
private->handle_h = (dy2 - dy1) / 3;
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);
1638
gimp_rectangle_tool_start (GimpRectangleTool *rectangle,
1639
GimpDisplay *display)
1641
GimpTool *tool = GIMP_TOOL (rectangle);
1642
GimpRectangleOptionsPrivate *options_private;
1645
GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (gimp_tool_get_options (tool));
1647
tool->display = display;
1648
gimp_rectangle_tool_configure (rectangle);
1650
/* initialize the statusbar display */
1651
gimp_tool_push_status_coords (tool, tool->display,
1652
_("Rectangle: "), 0, " x ", 0, NULL);
1654
gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), tool->display);
1656
if (options_private->auto_shrink_button)
1658
g_signal_connect_swapped (options_private->auto_shrink_button, "clicked",
1659
G_CALLBACK (gimp_rectangle_tool_auto_shrink),
1662
gtk_widget_set_sensitive (options_private->auto_shrink_button, TRUE);
1667
gimp_rectangle_tool_halt (GimpRectangleTool *rectangle)
1669
GimpTool *tool = GIMP_TOOL (rectangle);
1670
GimpRectangleOptionsPrivate *options_private;
1673
GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (gimp_tool_get_options (tool));
1676
gimp_display_shell_set_highlight (GIMP_DISPLAY_SHELL (tool->display->shell),
1679
if (gimp_draw_tool_is_active (GIMP_DRAW_TOOL (rectangle)))
1680
gimp_draw_tool_stop (GIMP_DRAW_TOOL (rectangle));
1682
if (gimp_tool_control_is_active (tool->control))
1683
gimp_tool_control_halt (tool->control);
1685
tool->display = NULL;
1686
tool->drawable = NULL;
1688
gimp_rectangle_tool_set_function (rectangle, RECT_INACTIVE);
1690
if (options_private->auto_shrink_button)
1692
gtk_widget_set_sensitive (options_private->auto_shrink_button, FALSE);
1694
g_signal_handlers_disconnect_by_func (options_private->auto_shrink_button,
1695
gimp_rectangle_tool_auto_shrink,
1701
gimp_rectangle_tool_execute (GimpRectangleTool *rectangle)
1703
GimpRectangleToolInterface *iface;
1704
gboolean retval = FALSE;
1706
iface = GIMP_RECTANGLE_TOOL_GET_INTERFACE (rectangle);
1710
GimpRectangleToolPrivate *private;
1712
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
1714
gimp_draw_tool_pause (GIMP_DRAW_TOOL (rectangle));
1716
retval = iface->execute (rectangle,
1719
private->x2 - private->x1,
1720
private->y2 - private->y1);
1722
gimp_rectangle_tool_configure (rectangle);
1724
gimp_draw_tool_resume (GIMP_DRAW_TOOL (rectangle));
1731
gimp_rectangle_tool_cancel (GimpRectangleTool *rectangle)
1733
GimpRectangleToolInterface *iface;
1735
iface = GIMP_RECTANGLE_TOOL_GET_INTERFACE (rectangle);
1738
iface->cancel (rectangle);
1742
gimp_rectangle_tool_update_options (GimpRectangleTool *rectangle,
1743
GimpDisplay *display)
1745
GimpRectangleToolPrivate *private;
1746
GimpRectangleOptions *options;
1747
GimpRectangleOptionsPrivate *options_private;
1752
gdouble center_x, center_y;
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);
1760
width = private->x2 - private->x1;
1761
height = private->y2 - private->y1;
1763
center_x = (private->x1 + private->x2) / 2.0;
1764
center_y = (private->y1 + private->y2) / 2.0;
1766
g_signal_handlers_block_by_func (options,
1767
gimp_rectangle_tool_options_notify,
1770
g_object_set (options,
1775
if (! options_private->fixed_width)
1776
g_object_set (options,
1780
if (! options_private->fixed_height)
1781
g_object_set (options,
1785
g_signal_handlers_unblock_by_func (options,
1786
gimp_rectangle_tool_options_notify,
1789
g_object_set (options,
1790
"center-x", center_x,
1791
"center-y", center_y,
1796
gimp_rectangle_tool_synthesize_motion (GimpRectangleTool *rectangle,
1802
GimpRectangleToolPrivate *private;
1803
GimpRectangleFunction old_function;
1805
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
1807
private->startx = startx;
1808
private->starty = starty;
1810
old_function = private->function;
1812
gimp_draw_tool_pause (GIMP_DRAW_TOOL (rectangle));
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);
1819
gimp_draw_tool_resume (GIMP_DRAW_TOOL (rectangle));
1821
gimp_rectangle_tool_rectangle_changed (rectangle);
1825
gimp_rectangle_tool_options_notify (GimpRectangleOptions *options,
1827
GimpRectangleTool *rectangle)
1829
GimpRectangleToolPrivate *private;
1830
GimpRectangleOptionsPrivate *options_private;
1832
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
1833
options_private = GIMP_RECTANGLE_OPTIONS_GET_PRIVATE (options);
1835
if (! strcmp (pspec->name, "guide"))
1837
gimp_draw_tool_pause (GIMP_DRAW_TOOL (rectangle));
1839
private->guide = options_private->guide;
1841
gimp_draw_tool_resume (GIMP_DRAW_TOOL (rectangle));
1846
if (! GIMP_TOOL (rectangle)->display)
1849
if (! strcmp (pspec->name, "x0"))
1853
coords.x = options_private->x0;
1854
coords.y = private->y1;
1856
gimp_rectangle_tool_synthesize_motion (rectangle,
1862
else if (! strcmp (pspec->name, "y0"))
1866
coords.x = private->x1;
1867
coords.y = options_private->y0;
1869
gimp_rectangle_tool_synthesize_motion (rectangle,
1875
else if (! strcmp (pspec->name, "width"))
1879
coords.x = private->x1 + options_private->width;
1880
coords.y = private->y2;
1882
gimp_rectangle_tool_synthesize_motion (rectangle,
1883
RECT_RESIZING_RIGHT,
1888
else if (! strcmp (pspec->name, "height"))
1892
coords.x = private->x2;
1893
coords.y = private->y1 + options_private->height;
1895
gimp_rectangle_tool_synthesize_motion (rectangle,
1896
RECT_RESIZING_BOTTOM,
1901
else if (! strcmp (pspec->name, "fixed-aspect") ||
1902
! strcmp (pspec->name, "aspect-numerator") ||
1903
! strcmp (pspec->name, "aspect-denominator"))
1905
if (options_private->fixed_aspect)
1910
aspect = (options_private->aspect_numerator /
1911
options_private->aspect_denominator);
1913
coords.x = private->x2;
1914
coords.y = private->y1 + (private->x2 - private->x1) / aspect;
1916
gimp_rectangle_tool_synthesize_motion (rectangle,
1917
RECT_RESIZING_BOTTOM,
1923
else if (! strcmp (pspec->name, "highlight"))
1925
gimp_rectangle_tool_set_highlight (rectangle);
1929
GimpRectangleFunction
1930
gimp_rectangle_tool_get_function (GimpRectangleTool *rectangle)
1932
g_return_val_if_fail (GIMP_IS_RECTANGLE_TOOL (rectangle), RECT_INACTIVE);
1934
return GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle)->function;
1938
gimp_rectangle_tool_set_function (GimpRectangleTool *rectangle,
1939
GimpRectangleFunction function)
1941
GimpRectangleToolPrivate *private;
1943
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (rectangle));
1945
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
1947
/* redraw the tool when the function changes */
1948
/* FIXME: should also update the cursor */
1949
if (private->function != function)
1951
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (rectangle);
1953
gimp_draw_tool_pause (draw_tool);
1955
private->function = function;
1957
gimp_draw_tool_resume (draw_tool);
1962
gimp_rectangle_tool_rectangle_changed (GimpRectangleTool *rectangle)
1964
g_signal_emit (rectangle,
1965
gimp_rectangle_tool_signals[RECTANGLE_CHANGED], 0);
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.
1974
gimp_rectangle_tool_constrain (GimpRectangleTool *rectangle,
1980
GimpTool *tool = GIMP_TOOL (rectangle);
1981
GimpRectangleToolPrivate *private;
1982
GimpRectangleConstraint constraint;
1987
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
1988
constraint = gimp_rectangle_tool_get_constraint (rectangle);
1989
image = tool->display->image;
1993
case GIMP_RECTANGLE_CONSTRAIN_NONE:
1996
case GIMP_RECTANGLE_CONSTRAIN_IMAGE:
1999
max_x = image->width;
2000
max_y = image->height;
2003
case GIMP_RECTANGLE_CONSTRAIN_DRAWABLE:
2005
GimpItem *item = GIMP_ITEM (tool->drawable);
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);
2014
g_warning ("Invalid rectangle constraint.\n");
2037
gimp_rectangle_tool_auto_shrink (GimpRectangleTool *rectangle)
2039
GimpTool *tool = GIMP_TOOL (rectangle);
2040
GimpRectangleToolPrivate *private;
2041
GimpDisplay *display = tool->display;
2052
gboolean shrink_merged;
2054
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (rectangle);
2059
width = display->image->width;
2060
height = display->image->height;
2062
g_object_get (gimp_tool_get_options (tool),
2063
"shrink-merged", &shrink_merged,
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;
2071
if (gimp_image_crop_auto_shrink (display->image,
2079
gimp_draw_tool_pause (GIMP_DRAW_TOOL (rectangle));
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,
2088
gimp_rectangle_tool_configure (rectangle);
2090
gimp_draw_tool_resume (GIMP_DRAW_TOOL (rectangle));
2094
static GtkAnchorType
2095
gimp_rectangle_tool_get_anchor (GimpRectangleToolPrivate *private,
2099
*w = private->handle_w;
2100
*h = private->handle_h;
2102
switch (private->function)
2104
case RECT_RESIZING_UPPER_LEFT:
2105
return GTK_ANCHOR_NORTH_WEST;
2107
case RECT_RESIZING_UPPER_RIGHT:
2108
return GTK_ANCHOR_NORTH_EAST;
2110
case RECT_RESIZING_LOWER_LEFT:
2111
return GTK_ANCHOR_SOUTH_WEST;
2113
case RECT_RESIZING_LOWER_RIGHT:
2114
return GTK_ANCHOR_SOUTH_EAST;
2116
case RECT_RESIZING_LEFT:
2118
return GTK_ANCHOR_WEST;
2120
case RECT_RESIZING_RIGHT:
2122
return GTK_ANCHOR_EAST;
2124
case RECT_RESIZING_TOP:
2126
return GTK_ANCHOR_NORTH;
2128
case RECT_RESIZING_BOTTOM:
2130
return GTK_ANCHOR_SOUTH;
2133
return GTK_ANCHOR_CENTER;
2138
gimp_rectangle_tool_set_highlight (GimpRectangleTool *rectangle)
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;
2145
g_object_get (options, "highlight", &highlight, NULL);
2149
GimpRectangleToolPrivate *private;
2152
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
2154
rect.x = private->x1;
2155
rect.y = private->y1;
2156
rect.width = private->x2 - private->x1;
2157
rect.height = private->y2 - private->y1;
2159
gimp_display_shell_set_highlight (shell, &rect);
2163
gimp_display_shell_set_highlight (shell, NULL);