Bill Skaggs <weskaggs@primate.ucdavis.edu>

* app/tools/tools-enums.[ch]: add GimpRectangleConstraint
	enum.

	* app/tools/gimprectangletool.[ch]: replace "constrain"
	boolean with "constraint" enum property.  Implement
	constraints in motion handler -- the implementation
	is rather elegant but pretty tricky.

	* app/tools/gimpcroptool.c: constrain to image bounds,
	or to active drawable bounds if "current layer only"
	option is checked.

	* app/tools/gimpellipseselecttool.c
	* app/tools/gimprectangleselecttool.c: no constraint.

	This addresses bug #353936 -- I would say fixes it, but it
	probably needs some fine-tuning.  Also perhaps fixes
	bug #329817 a bit better than before.
This commit is contained in:
William Skaggs 2006-09-06 22:51:54 +00:00
parent e077975358
commit 5e9dc3c0d8
8 changed files with 409 additions and 126 deletions

View file

@ -1,3 +1,24 @@
2006-09-06 Bill Skaggs <weskaggs@primate.ucdavis.edu>
* app/tools/tools-enums.[ch]: add GimpRectangleConstraint
enum.
* app/tools/gimprectangletool.[ch]: replace "constrain"
boolean with "constraint" enum property. Implement
constraints in motion handler -- the implementation
is rather elegant but pretty tricky.
* app/tools/gimpcroptool.c: constrain to image bounds,
or to active drawable bounds if "current layer only"
option is checked.
* app/tools/gimpellipseselecttool.c
* app/tools/gimprectangleselecttool.c: no constraint.
This addresses bug #353936 -- I would say fixes it, but it
probably needs some fine-tuning. Also perhaps fixes
bug #329817 a bit better than before.
2006-09-06 Sven Neumann <sven@gimp.org> 2006-09-06 Sven Neumann <sven@gimp.org>
* app/plug-in/gimppluginmanager-history.c * app/plug-in/gimppluginmanager-history.c

View file

@ -46,8 +46,10 @@ static GObject *
gimp_crop_tool_constructor (GType type, gimp_crop_tool_constructor (GType type,
guint n_params, guint n_params,
GObjectConstructParam *params); GObjectConstructParam *params);
static void gimp_crop_tool_dispose (GObject *object);
static void gimp_crop_tool_finalize (GObject *object); static void gimp_crop_tool_finalize (GObject *object);
static gboolean gimp_crop_tool_initialize (GimpTool *tool,
GimpDisplay *display);
static void gimp_crop_tool_control (GimpTool *tool, static void gimp_crop_tool_control (GimpTool *tool,
GimpToolAction action, GimpToolAction action,
GimpDisplay *display); GimpDisplay *display);
@ -71,13 +73,14 @@ static void gimp_crop_tool_cursor_update (GimpTool *tool,
GimpCoords *coords, GimpCoords *coords,
GdkModifierType state, GdkModifierType state,
GimpDisplay *display); GimpDisplay *display);
static gboolean gimp_crop_tool_execute (GimpRectangleTool *rectangle, static gboolean gimp_crop_tool_execute (GimpRectangleTool *rectangle,
gint x, gint x,
gint y, gint y,
gint w, gint w,
gint h); gint h);
static void gimp_crop_tool_notify_layer_only (GimpCropOptions *options,
GParamSpec *pspec,
GimpTool *tool);
G_DEFINE_TYPE_WITH_CODE (GimpCropTool, gimp_crop_tool, GIMP_TYPE_DRAW_TOOL, G_DEFINE_TYPE_WITH_CODE (GimpCropTool, gimp_crop_tool, GIMP_TYPE_DRAW_TOOL,
G_IMPLEMENT_INTERFACE (GIMP_TYPE_RECTANGLE_TOOL, G_IMPLEMENT_INTERFACE (GIMP_TYPE_RECTANGLE_TOOL,
@ -113,13 +116,13 @@ gimp_crop_tool_class_init (GimpCropToolClass *klass)
GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass); GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
object_class->constructor = gimp_crop_tool_constructor; object_class->constructor = gimp_crop_tool_constructor;
object_class->dispose = gimp_rectangle_tool_dispose; object_class->dispose = gimp_crop_tool_dispose;
object_class->finalize = gimp_crop_tool_finalize; object_class->finalize = gimp_crop_tool_finalize;
object_class->set_property = gimp_rectangle_tool_set_property; object_class->set_property = gimp_rectangle_tool_set_property;
object_class->get_property = gimp_rectangle_tool_get_property; object_class->get_property = gimp_rectangle_tool_get_property;
gimp_rectangle_tool_install_properties (object_class); gimp_rectangle_tool_install_properties (object_class);
tool_class->initialize = gimp_rectangle_tool_initialize; tool_class->initialize = gimp_crop_tool_initialize;
tool_class->control = gimp_crop_tool_control; tool_class->control = gimp_crop_tool_control;
tool_class->button_press = gimp_crop_tool_button_press; tool_class->button_press = gimp_crop_tool_button_press;
tool_class->button_release = gimp_crop_tool_button_release; tool_class->button_release = gimp_crop_tool_button_release;
@ -139,7 +142,7 @@ gimp_crop_tool_init (GimpCropTool *crop_tool)
GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (crop_tool); GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (crop_tool);
gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_CROP); gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_CROP);
gimp_rectangle_tool_set_constrain (rect_tool, TRUE); gimp_rectangle_tool_set_constraint (rect_tool, TRUE);
} }
static void static void
@ -162,12 +165,49 @@ gimp_crop_tool_constructor (GType type,
return object; return object;
} }
static gboolean
gimp_crop_tool_initialize (GimpTool *tool,
GimpDisplay *display)
{
GimpRectangleTool *rectangle = GIMP_RECTANGLE_TOOL (tool);
GObject *options = G_OBJECT (gimp_tool_get_options (tool));
gboolean layer_only;
g_object_get (options,
"layer-only", &layer_only,
NULL);
g_signal_connect_object (options, "notify::layer-only",
G_CALLBACK (gimp_crop_tool_notify_layer_only),
tool, 0);
if (layer_only)
gimp_rectangle_tool_set_constraint (rectangle, GIMP_RECTANGLE_CONSTRAIN_DRAWABLE);
else
gimp_rectangle_tool_set_constraint (rectangle, GIMP_RECTANGLE_CONSTRAIN_IMAGE);
return gimp_rectangle_tool_initialize (tool, display);
}
static void static void
gimp_crop_tool_finalize (GObject *object) gimp_crop_tool_finalize (GObject *object)
{ {
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
static void
gimp_crop_tool_dispose (GObject *object)
{
GimpTool *tool = GIMP_TOOL (object);
GObject *options = G_OBJECT (gimp_tool_get_options (tool));
gimp_rectangle_tool_dispose (object);
g_signal_handlers_disconnect_by_func (options,
G_CALLBACK (gimp_crop_tool_notify_layer_only),
tool);
}
static void static void
gimp_crop_tool_control (GimpTool *tool, gimp_crop_tool_control (GimpTool *tool,
GimpToolAction action, GimpToolAction action,
@ -286,3 +326,20 @@ gimp_crop_tool_execute (GimpRectangleTool *rectangle,
return TRUE; return TRUE;
} }
static void
gimp_crop_tool_notify_layer_only (GimpCropOptions *options,
GParamSpec *pspec,
GimpTool *tool)
{
GimpRectangleTool *rectangle = GIMP_RECTANGLE_TOOL (tool);
gboolean layer_only;
g_object_get (options,
"layer-only", &layer_only,
NULL);
if (layer_only)
gimp_rectangle_tool_set_constraint (rectangle, GIMP_RECTANGLE_CONSTRAIN_DRAWABLE);
else
gimp_rectangle_tool_set_constraint (rectangle, GIMP_RECTANGLE_CONSTRAIN_IMAGE);
}

View file

@ -98,11 +98,9 @@ static void
gimp_ellipse_select_tool_init (GimpEllipseSelectTool *ellipse_select) gimp_ellipse_select_tool_init (GimpEllipseSelectTool *ellipse_select)
{ {
GimpTool *tool = GIMP_TOOL (ellipse_select); GimpTool *tool = GIMP_TOOL (ellipse_select);
GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (ellipse_select);
gimp_tool_control_set_tool_cursor (tool->control, gimp_tool_control_set_tool_cursor (tool->control,
GIMP_TOOL_CURSOR_ELLIPSE_SELECT); GIMP_TOOL_CURSOR_ELLIPSE_SELECT);
gimp_rectangle_tool_set_constrain (rect_tool, FALSE);
} }
static void static void

View file

@ -177,15 +177,12 @@ static void
gimp_rect_select_tool_init (GimpRectSelectTool *rect_select) gimp_rect_select_tool_init (GimpRectSelectTool *rect_select)
{ {
GimpTool *tool = GIMP_TOOL (rect_select); GimpTool *tool = GIMP_TOOL (rect_select);
GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (rect_select);
gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_RECT_SELECT); gimp_tool_control_set_tool_cursor (tool->control, GIMP_TOOL_CURSOR_RECT_SELECT);
gimp_tool_control_set_dirty_mask (tool->control, gimp_tool_control_set_dirty_mask (tool->control,
GIMP_DIRTY_IMAGE_SIZE | GIMP_DIRTY_IMAGE_SIZE |
GIMP_DIRTY_SELECTION); GIMP_DIRTY_SELECTION);
gimp_rectangle_tool_set_constrain (rect_tool, TRUE);
rect_select->undo = NULL; rect_select->undo = NULL;
rect_select->redo = NULL; rect_select->redo = NULL;
} }

View file

@ -49,7 +49,6 @@ enum
LAST_SIGNAL LAST_SIGNAL
}; };
/* speed of key movement */ /* speed of key movement */
#define ARROW_VELOCITY 25 #define ARROW_VELOCITY 25
@ -62,36 +61,36 @@ typedef struct _GimpRectangleToolPrivate GimpRectangleToolPrivate;
struct _GimpRectangleToolPrivate struct _GimpRectangleToolPrivate
{ {
gint pressx; /* x where button pressed */ gint pressx; /* x where button pressed */
gint pressy; /* y where button pressed */ gint pressy; /* y where button pressed */
gint x1, y1; /* upper left hand coordinate */ gint x1, y1; /* upper left hand coordinate */
gint x2, y2; /* lower right hand coords */ gint x2, y2; /* lower right hand coords */
guint function; /* moving or resizing */ guint function; /* moving or resizing */
gboolean constrain; /* constrain to image bounds */ GimpRectangleConstraint constraint; /* how to constrain rectangle */
/* Internal state */ /* Internal state */
gint startx; /* starting x coord */ gint startx; /* starting x coord */
gint starty; /* starting y coord */ gint starty; /* starting y coord */
gint lastx; /* previous x coord */ gint lastx; /* previous x coord */
gint lasty; /* previous y coord */ gint lasty; /* previous y coord */
gint dx1, dy1; /* display coords */ gint dx1, dy1; /* display coords */
gint dx2, dy2; /* */ gint dx2, dy2; /* */
gint dcw, dch; /* width and height of edges */ gint dcw, dch; /* width and height of edges */
gint saved_x1; /* for saving in case action is canceled */ gint saved_x1; /* for saving in case action is canceled */
gint saved_y1; gint saved_y1;
gint saved_x2; gint saved_x2;
gint saved_y2; gint saved_y2;
gdouble saved_center_x; gdouble saved_center_x;
gdouble saved_center_y; gdouble saved_center_y;
GimpRectangleGuide guide; /* synced with options->guide, only exists for drawing */ GimpRectangleGuide guide; /* synced with options->guide, only exists for drawing */
}; };
@ -123,7 +122,9 @@ gint gimp_rectangle_tool_get_y2 (GimpRectangleTool *tool);
void gimp_rectangle_tool_set_function (GimpRectangleTool *tool, void gimp_rectangle_tool_set_function (GimpRectangleTool *tool,
guint function); guint function);
guint gimp_rectangle_tool_get_function (GimpRectangleTool *tool); guint gimp_rectangle_tool_get_function (GimpRectangleTool *tool);
gboolean gimp_rectangle_tool_get_constrain (GimpRectangleTool *tool);
GimpRectangleConstraint
gimp_rectangle_tool_get_constraint (GimpRectangleTool *tool);
/* Rectangle helper functions */ /* Rectangle helper functions */
static void rectangle_tool_start (GimpRectangleTool *rectangle); static void rectangle_tool_start (GimpRectangleTool *rectangle);
@ -154,6 +155,12 @@ static void gimp_rectangle_tool_notify_dimensions (GimpRectangleOptions *op
static void gimp_rectangle_tool_check_function (GimpRectangleTool *rectangle, static void gimp_rectangle_tool_check_function (GimpRectangleTool *rectangle,
gint curx, gint curx,
gint cury); gint cury);
gboolean gimp_rectangle_tool_constraint_violated (GimpRectangleTool *rectangle,
gint x1,
gint y1,
gint x2,
gint y2,
gdouble *alpha);
static guint gimp_rectangle_tool_signals[LAST_SIGNAL] = { 0 }; static guint gimp_rectangle_tool_signals[LAST_SIGNAL] = { 0 };
@ -254,10 +261,12 @@ gimp_rectangle_tool_iface_base_init (GimpRectangleToolInterface *iface)
GIMP_PARAM_READWRITE)); GIMP_PARAM_READWRITE));
g_object_interface_install_property (iface, g_object_interface_install_property (iface,
g_param_spec_boolean ("constrain", g_param_spec_uint ("constraint",
NULL, NULL, NULL, NULL,
FALSE, GIMP_RECTANGLE_CONSTRAIN_NONE,
GIMP_PARAM_READWRITE)); GIMP_RECTANGLE_CONSTRAIN_DRAWABLE,
GIMP_RECTANGLE_CONSTRAIN_NONE,
GIMP_PARAM_READWRITE));
iface->rectangle_changed = NULL; iface->rectangle_changed = NULL;
@ -331,8 +340,8 @@ gimp_rectangle_tool_install_properties (GObjectClass *klass)
GIMP_RECTANGLE_TOOL_PROP_FUNCTION, GIMP_RECTANGLE_TOOL_PROP_FUNCTION,
"function"); "function");
g_object_class_override_property (klass, g_object_class_override_property (klass,
GIMP_RECTANGLE_TOOL_PROP_CONSTRAIN, GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT,
"constrain"); "constraint");
} }
void void
@ -525,8 +534,8 @@ gimp_rectangle_tool_get_function (GimpRectangleTool *tool)
} }
void void
gimp_rectangle_tool_set_constrain (GimpRectangleTool *tool, gimp_rectangle_tool_set_constraint (GimpRectangleTool *tool,
gboolean constrain) GimpRectangleConstraint constraint)
{ {
GimpRectangleToolPrivate *private; GimpRectangleToolPrivate *private;
@ -534,13 +543,13 @@ gimp_rectangle_tool_set_constrain (GimpRectangleTool *tool,
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool); private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
private->constrain = constrain ? TRUE : FALSE; private->constraint = constraint;
g_object_notify (G_OBJECT (tool), "constrain"); g_object_notify (G_OBJECT (tool), "constraint");
} }
gboolean GimpRectangleConstraint
gimp_rectangle_tool_get_constrain (GimpRectangleTool *tool) gimp_rectangle_tool_get_constraint (GimpRectangleTool *tool)
{ {
GimpRectangleToolPrivate *private; GimpRectangleToolPrivate *private;
@ -548,7 +557,7 @@ gimp_rectangle_tool_get_constrain (GimpRectangleTool *tool)
private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool); private = GIMP_RECTANGLE_TOOL_GET_PRIVATE (tool);
return private->constrain; return private->constraint;
} }
void void
@ -582,8 +591,8 @@ gimp_rectangle_tool_set_property (GObject *object,
case GIMP_RECTANGLE_TOOL_PROP_FUNCTION: case GIMP_RECTANGLE_TOOL_PROP_FUNCTION:
gimp_rectangle_tool_set_function (tool, g_value_get_uint (value)); gimp_rectangle_tool_set_function (tool, g_value_get_uint (value));
break; break;
case GIMP_RECTANGLE_TOOL_PROP_CONSTRAIN: case GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT:
gimp_rectangle_tool_set_constrain (tool, g_value_get_boolean (value)); gimp_rectangle_tool_set_constraint (tool, g_value_get_uint (value));
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -622,8 +631,8 @@ gimp_rectangle_tool_get_property (GObject *object,
case GIMP_RECTANGLE_TOOL_PROP_FUNCTION: case GIMP_RECTANGLE_TOOL_PROP_FUNCTION:
g_value_set_uint (value, gimp_rectangle_tool_get_function (tool)); g_value_set_uint (value, gimp_rectangle_tool_get_function (tool));
break; break;
case GIMP_RECTANGLE_TOOL_PROP_CONSTRAIN: case GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT:
g_value_set_boolean (value, gimp_rectangle_tool_get_constrain (tool)); g_value_set_uint (value, gimp_rectangle_tool_get_constraint (tool));
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -660,6 +669,8 @@ gimp_rectangle_tool_constructor (GObject *object)
g_signal_connect_object (options, "notify::dimensions-entry", g_signal_connect_object (options, "notify::dimensions-entry",
G_CALLBACK (gimp_rectangle_tool_notify_dimensions), G_CALLBACK (gimp_rectangle_tool_notify_dimensions),
rectangle, 0); rectangle, 0);
gimp_rectangle_tool_set_constraint (rectangle, GIMP_RECTANGLE_CONSTRAIN_NONE);
} }
void void
@ -912,7 +923,6 @@ gimp_rectangle_tool_motion (GimpTool *tool,
gint x1, y1, x2, y2; gint x1, y1, x2, y2;
gint curx, cury; gint curx, cury;
gint inc_x, inc_y; gint inc_x, inc_y;
gint min_x, min_y, max_x, max_y;
gint rx1, ry1, rx2, ry2; gint rx1, ry1, rx2, ry2;
gboolean fixed_width; gboolean fixed_width;
gboolean fixed_height; gboolean fixed_height;
@ -921,6 +931,7 @@ gimp_rectangle_tool_motion (GimpTool *tool,
gdouble width, height; gdouble width, height;
gdouble center_x, center_y; gdouble center_x, center_y;
gboolean aspect_square; gboolean aspect_square;
gdouble alpha;
g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool)); g_return_if_fail (GIMP_IS_RECTANGLE_TOOL (tool));
@ -956,12 +967,6 @@ gimp_rectangle_tool_motion (GimpTool *tool,
"aspect-square", &aspect_square, "aspect-square", &aspect_square,
NULL); NULL);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
min_x = min_y = 0;
max_x = display->image->width;
max_y = display->image->height;
g_object_get (options, g_object_get (options,
"width", &width, "width", &width,
"height", &height, "height", &height,
@ -1075,7 +1080,9 @@ gimp_rectangle_tool_motion (GimpTool *tool,
else else
{ {
g_object_get (options, "aspect", &aspect, NULL); g_object_get (options, "aspect", &aspect, NULL);
aspect = CLAMP (aspect, 1.0 / max_y, max_x); aspect = CLAMP (aspect,
1.0 / display->image->height,
display->image->width);
} }
switch (function) switch (function)
@ -1186,6 +1193,88 @@ gimp_rectangle_tool_motion (GimpTool *tool,
break; break;
} }
} }
private->lastx = curx;
private->lasty = cury;
/*
* Check to see whether the new rectangle obeys the boundary constraints, if any.
* If not, see whether we can downscale the mouse movement and call this
* motion handler again recursively. The reason for the recursive call is
* to avoid leaving the rectangle edge hanging some pixels away from the
* constraining boundary if the user moves the pointer quickly.
*/
if (gimp_rectangle_tool_constraint_violated (rectangle, x1, y1, x2, y2, &alpha))
{
GimpCoords new_coords;
inc_x *= alpha;
inc_y *= alpha;
if (inc_x != 0 || inc_y != 0)
{
new_coords.x = private->startx + inc_x;
new_coords.y = private->starty + inc_y;
gimp_rectangle_tool_motion (tool, &new_coords, time, state, display);
}
return;
}
/* set startx, starty according to function, to keep rect on cursor */
switch (function)
{
case RECT_RESIZING_UPPER_LEFT:
private->startx = x1;
private->starty = y1;
break;
case RECT_RESIZING_UPPER_RIGHT:
private->startx = x2;
private->starty = y1;
break;
case RECT_RESIZING_LOWER_LEFT:
private->startx = x1;
private->starty = y2;
break;
case RECT_RESIZING_LOWER_RIGHT:
private->startx = x2;
private->starty = y2;
break;
case RECT_RESIZING_TOP:
private->startx = curx;
private->starty = y1;
break;
case RECT_RESIZING_LEFT:
private->startx = x1;
private->starty = cury;
break;
case RECT_RESIZING_BOTTOM:
private->startx = curx;
private->starty = y2;
break;
case RECT_RESIZING_RIGHT:
private->startx = x2;
private->starty = cury;
break;
case RECT_MOVING:
private->startx = curx;
private->starty = cury;
break;
default:
break;
}
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
/* make sure that the coords are in bounds */ /* make sure that the coords are in bounds */
g_object_set (rectangle, g_object_set (rectangle,
"x1", MIN (x1, x2), "x1", MIN (x1, x2),
@ -1194,15 +1283,6 @@ gimp_rectangle_tool_motion (GimpTool *tool,
"y2", MAX (y1, y2), "y2", MAX (y1, y2),
NULL); NULL);
if (function != RECT_CREATING)
{
private->startx = curx;
private->starty = cury;
}
private->lastx = curx;
private->lasty = cury;
/* recalculate the coordinates for rectangle_draw based on the new values */ /* recalculate the coordinates for rectangle_draw based on the new values */
gimp_rectangle_tool_configure (rectangle); gimp_rectangle_tool_configure (rectangle);
@ -1283,16 +1363,8 @@ gimp_rectangle_tool_motion (GimpTool *tool,
gimp_tool_pop_status (tool, display); gimp_tool_pop_status (tool, display);
if (gimp_rectangle_tool_get_constrain (rectangle)) w = rx2 - rx1;
{ h = ry2 - ry1;
w = MIN (rx2, max_x) - MAX (rx1, min_x);
h = MIN (ry2, max_y) - MAX (ry1, min_y);
}
else
{
w = rx2 - rx1;
h = ry2 - ry1;
}
if (w > 0 && h > 0) if (w > 0 && h > 0)
gimp_tool_push_status_coords (tool, display, gimp_tool_push_status_coords (tool, display,
@ -2450,3 +2522,102 @@ gimp_rectangle_tool_no_movement (GimpRectangleTool *rectangle)
return (private->lastx == pressx && private->lasty == pressy); return (private->lastx == pressx && private->lasty == pressy);
} }
/*
* check whether the coordinates extend outside the bounds of the image
* or active drawable, if it is constrained not to. If it does,
* caculate how much the current movement needs to be downscaled in
* order to obey the constraint.
*/
gboolean
gimp_rectangle_tool_constraint_violated (GimpRectangleTool *rectangle,
gint x1,
gint y1,
gint x2,
gint y2,
gdouble *alpha)
{
GimpRectangleConstraint constraint = gimp_rectangle_tool_get_constraint (rectangle);
GimpTool *tool = GIMP_TOOL (rectangle);
GimpImage *image = tool->display->image;
gint min_x, min_y;
gint max_x, max_y;
switch (constraint)
{
case GIMP_RECTANGLE_CONSTRAIN_NONE:
return FALSE;
case GIMP_RECTANGLE_CONSTRAIN_IMAGE:
min_x = 0;
min_y = 0;
max_x = image->width;
max_y = image->height;
break;
case GIMP_RECTANGLE_CONSTRAIN_DRAWABLE:
{
GimpItem *item = GIMP_ITEM (tool->drawable);
gimp_item_offsets (item, &min_x, &min_y);
max_x = min_x + gimp_item_width (item);
max_y = min_y + gimp_item_height (item);
}
break;
default:
g_warning ("Invalid rectangle constraint.\n");
return FALSE;
}
if (x1 < min_x)
{
gint rx1;
g_object_get (rectangle,
"x1", &rx1,
NULL);
*alpha = (rx1 - min_x) / (gdouble) (rx1 - x1);
return TRUE;
}
if (y1 < min_y)
{
gint ry1;
g_object_get (rectangle,
"y1", &ry1,
NULL);
*alpha = (ry1 - min_y) / (gdouble) (ry1 - y1);
return TRUE;
}
if (x2 > max_x)
{
gint rx2;
g_object_get (rectangle,
"x2", &rx2,
NULL);
*alpha = (max_x - rx2) / (gdouble) (x2 - rx2);
return TRUE;
}
if (y2 > max_y)
{
gint ry2;
g_object_get (rectangle,
"y2", &ry2,
NULL);
*alpha = (max_y - ry2) / (gdouble) (y2 - ry2);
return TRUE;
}
return FALSE;
}

View file

@ -35,8 +35,8 @@ typedef enum
GIMP_RECTANGLE_TOOL_PROP_X2, GIMP_RECTANGLE_TOOL_PROP_X2,
GIMP_RECTANGLE_TOOL_PROP_Y2, GIMP_RECTANGLE_TOOL_PROP_Y2,
GIMP_RECTANGLE_TOOL_PROP_FUNCTION, GIMP_RECTANGLE_TOOL_PROP_FUNCTION,
GIMP_RECTANGLE_TOOL_PROP_CONSTRAIN, GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT,
GIMP_RECTANGLE_TOOL_PROP_LAST = GIMP_RECTANGLE_TOOL_PROP_CONSTRAIN GIMP_RECTANGLE_TOOL_PROP_LAST = GIMP_RECTANGLE_TOOL_PROP_CONSTRAINT
} GimpRectangleToolProp; } GimpRectangleToolProp;
@ -87,53 +87,53 @@ struct _GimpRectangleToolInterface
GType gimp_rectangle_tool_interface_get_type (void) G_GNUC_CONST; GType gimp_rectangle_tool_interface_get_type (void) G_GNUC_CONST;
void gimp_rectangle_tool_constructor (GObject *object); void gimp_rectangle_tool_constructor (GObject *object);
void gimp_rectangle_tool_dispose (GObject *object); void gimp_rectangle_tool_dispose (GObject *object);
gboolean gimp_rectangle_tool_initialize (GimpTool *tool, gboolean gimp_rectangle_tool_initialize (GimpTool *tool,
GimpDisplay *display); GimpDisplay *display);
void gimp_rectangle_tool_control (GimpTool *tool, void gimp_rectangle_tool_control (GimpTool *tool,
GimpToolAction action, GimpToolAction action,
GimpDisplay *display); GimpDisplay *display);
void gimp_rectangle_tool_button_press (GimpTool *tool, void gimp_rectangle_tool_button_press (GimpTool *tool,
GimpCoords *coords, GimpCoords *coords,
guint32 time, guint32 time,
GdkModifierType state, GdkModifierType state,
GimpDisplay *display); GimpDisplay *display);
void gimp_rectangle_tool_button_release (GimpTool *tool, void gimp_rectangle_tool_button_release (GimpTool *tool,
GimpCoords *coords, GimpCoords *coords,
guint32 time, guint32 time,
GdkModifierType state, GdkModifierType state,
GimpDisplay *display); GimpDisplay *display);
void gimp_rectangle_tool_motion (GimpTool *tool, void gimp_rectangle_tool_motion (GimpTool *tool,
GimpCoords *coords, GimpCoords *coords,
guint32 time, guint32 time,
GdkModifierType state, GdkModifierType state,
GimpDisplay *display); GimpDisplay *display);
gboolean gimp_rectangle_tool_key_press (GimpTool *tool, gboolean gimp_rectangle_tool_key_press (GimpTool *tool,
GdkEventKey *kevent, GdkEventKey *kevent,
GimpDisplay *display); GimpDisplay *display);
void gimp_rectangle_tool_modifier_key (GimpTool *tool, void gimp_rectangle_tool_modifier_key (GimpTool *tool,
GdkModifierType key, GdkModifierType key,
gboolean press, gboolean press,
GdkModifierType state, GdkModifierType state,
GimpDisplay *display); GimpDisplay *display);
void gimp_rectangle_tool_oper_update (GimpTool *tool, void gimp_rectangle_tool_oper_update (GimpTool *tool,
GimpCoords *coords, GimpCoords *coords,
GdkModifierType state, GdkModifierType state,
gboolean proximity, gboolean proximity,
GimpDisplay *display); GimpDisplay *display);
void gimp_rectangle_tool_cursor_update (GimpTool *tool, void gimp_rectangle_tool_cursor_update (GimpTool *tool,
GimpCoords *coords, GimpCoords *coords,
GdkModifierType state, GdkModifierType state,
GimpDisplay *display); GimpDisplay *display);
void gimp_rectangle_tool_draw (GimpDrawTool *draw); void gimp_rectangle_tool_draw (GimpDrawTool *draw);
gboolean gimp_rectangle_tool_execute (GimpRectangleTool *rect_tool); gboolean gimp_rectangle_tool_execute (GimpRectangleTool *rect_tool);
void gimp_rectangle_tool_cancel (GimpRectangleTool *rect_tool); void gimp_rectangle_tool_cancel (GimpRectangleTool *rect_tool);
void gimp_rectangle_tool_halt (GimpRectangleTool *rectangle); void gimp_rectangle_tool_halt (GimpRectangleTool *rectangle);
void gimp_rectangle_tool_configure (GimpRectangleTool *rectangle); void gimp_rectangle_tool_configure (GimpRectangleTool *rectangle);
void gimp_rectangle_tool_set_constrain (GimpRectangleTool *rectangle, void gimp_rectangle_tool_set_constraint (GimpRectangleTool *rectangle,
gboolean constrain); GimpRectangleConstraint constraint);
gboolean gimp_rectangle_tool_no_movement (GimpRectangleTool *rectangle); gboolean gimp_rectangle_tool_no_movement (GimpRectangleTool *rectangle);
/* convenience functions */ /* convenience functions */

View file

@ -73,6 +73,36 @@ gimp_rectangle_guide_get_type (void)
return type; return type;
} }
GType
gimp_rectangle_constraint_get_type (void)
{
static const GEnumValue values[] =
{
{ GIMP_RECTANGLE_CONSTRAIN_NONE, "GIMP_RECTANGLE_CONSTRAIN_NONE", "none" },
{ GIMP_RECTANGLE_CONSTRAIN_IMAGE, "GIMP_RECTANGLE_CONSTRAIN_IMAGE", "image" },
{ GIMP_RECTANGLE_CONSTRAIN_DRAWABLE, "GIMP_RECTANGLE_CONSTRAIN_DRAWABLE", "drawable" },
{ 0, NULL, NULL }
};
static const GimpEnumDesc descs[] =
{
{ GIMP_RECTANGLE_CONSTRAIN_NONE, N_("No constraint"), NULL },
{ GIMP_RECTANGLE_CONSTRAIN_IMAGE, N_("Image bounds"), NULL },
{ GIMP_RECTANGLE_CONSTRAIN_DRAWABLE, N_("Drawable bounds"), NULL },
{ 0, NULL, NULL }
};
static GType type = 0;
if (! type)
{
type = g_enum_register_static ("GimpRectangleConstraint", values);
gimp_enum_set_value_descriptions (type, descs);
}
return type;
}
GType GType
gimp_rect_select_mode_get_type (void) gimp_rect_select_mode_get_type (void)
{ {

View file

@ -48,6 +48,15 @@ typedef enum
GIMP_RECTANGLE_GUIDE_GOLDEN /*< desc="Golden sections" >*/ GIMP_RECTANGLE_GUIDE_GOLDEN /*< desc="Golden sections" >*/
} GimpRectangleGuide; } GimpRectangleGuide;
GType gimp_rectangle_constraint_get_type (void) G_GNUC_CONST;
typedef enum
{
GIMP_RECTANGLE_CONSTRAIN_NONE, /*< desc="No constraint" >*/
GIMP_RECTANGLE_CONSTRAIN_IMAGE, /*< desc="Image bounds" >*/
GIMP_RECTANGLE_CONSTRAIN_DRAWABLE /*< desc="Drawable bounds" >*/
} GimpRectangleConstraint;
#define GIMP_TYPE_RECT_SELECT_MODE (gimp_rect_select_mode_get_type ()) #define GIMP_TYPE_RECT_SELECT_MODE (gimp_rect_select_mode_get_type ())