mirror of https://github.com/GNOME/gimp.git
Bug 670031 - Would like to undo intelligent scissors selections in progress
Add undo to the Isissors tool, along with some refactoring: - Always modify the actual curve, instead of a set of obscure states kept around in the tool instance - On cancel, simply go back to the curve on the undo stack - Draw handles on top of curve segments - Draw the currently edited segments and handles in the highlight color
This commit is contained in:
parent
565b0af74d
commit
4842e2a14f
|
@ -68,6 +68,7 @@
|
|||
#include "widgets/gimphelp-ids.h"
|
||||
#include "widgets/gimpwidgets-utils.h"
|
||||
|
||||
#include "display/gimpcanvasitem.h"
|
||||
#include "display/gimpdisplay.h"
|
||||
|
||||
#include "gimpiscissorsoptions.h"
|
||||
|
@ -148,9 +149,21 @@ static void gimp_iscissors_tool_cursor_update (GimpTool *tool,
|
|||
static gboolean gimp_iscissors_tool_key_press (GimpTool *tool,
|
||||
GdkEventKey *kevent,
|
||||
GimpDisplay *display);
|
||||
static const gchar * gimp_iscissors_tool_get_undo_desc (GimpTool *tool,
|
||||
GimpDisplay *display);
|
||||
static const gchar * gimp_iscissors_tool_get_redo_desc (GimpTool *tool,
|
||||
GimpDisplay *display);
|
||||
static gboolean gimp_iscissors_tool_undo (GimpTool *tool,
|
||||
GimpDisplay *display);
|
||||
static gboolean gimp_iscissors_tool_redo (GimpTool *tool,
|
||||
GimpDisplay *display);
|
||||
|
||||
static void gimp_iscissors_tool_draw (GimpDrawTool *draw_tool);
|
||||
|
||||
static void gimp_iscissors_tool_push_undo (GimpIscissorsTool *iscissors);
|
||||
static void gimp_iscissors_tool_pop_undo (GimpIscissorsTool *iscissors);
|
||||
static void gimp_iscissors_tool_free_redo (GimpIscissorsTool *iscissors);
|
||||
|
||||
static void gimp_iscissors_tool_halt (GimpIscissorsTool *iscissors,
|
||||
GimpDisplay *display);
|
||||
static void gimp_iscissors_tool_commit (GimpIscissorsTool *iscissors,
|
||||
|
@ -174,7 +187,7 @@ static void find_max_gradient (GimpIscissorsTool *iscissors,
|
|||
gint *y);
|
||||
static void calculate_segment (GimpIscissorsTool *iscissors,
|
||||
ISegment *segment);
|
||||
static void iscissors_draw_segment (GimpDrawTool *draw_tool,
|
||||
static GimpCanvasItem * iscissors_draw_segment (GimpDrawTool *draw_tool,
|
||||
ISegment *segment);
|
||||
|
||||
static gint mouse_over_vertex (GimpIscissorsTool *iscissors,
|
||||
|
@ -203,9 +216,11 @@ static ISegment * isegment_new (gint x1,
|
|||
gint y1,
|
||||
gint x2,
|
||||
gint y2);
|
||||
static ISegment * isegment_copy (ISegment *segment);
|
||||
static void isegment_free (ISegment *segment);
|
||||
|
||||
static ICurve * icurve_new (void);
|
||||
static ICurve * icurve_copy (ICurve *curve);
|
||||
static void icurve_clear (ICurve *curve);
|
||||
static void icurve_free (ICurve *curve);
|
||||
|
||||
|
@ -280,9 +295,13 @@ gimp_iscissors_tool_class_init (GimpIscissorsToolClass *klass)
|
|||
tool_class->button_press = gimp_iscissors_tool_button_press;
|
||||
tool_class->button_release = gimp_iscissors_tool_button_release;
|
||||
tool_class->motion = gimp_iscissors_tool_motion;
|
||||
tool_class->key_press = gimp_iscissors_tool_key_press;
|
||||
tool_class->oper_update = gimp_iscissors_tool_oper_update;
|
||||
tool_class->cursor_update = gimp_iscissors_tool_cursor_update;
|
||||
tool_class->key_press = gimp_iscissors_tool_key_press;
|
||||
tool_class->get_undo_desc = gimp_iscissors_tool_get_undo_desc;
|
||||
tool_class->get_redo_desc = gimp_iscissors_tool_get_redo_desc;
|
||||
tool_class->undo = gimp_iscissors_tool_undo;
|
||||
tool_class->redo = gimp_iscissors_tool_redo;
|
||||
|
||||
draw_tool_class->draw = gimp_iscissors_tool_draw;
|
||||
|
||||
|
@ -377,7 +396,9 @@ gimp_iscissors_tool_button_press (GimpTool *tool,
|
|||
GimpDisplay *display)
|
||||
{
|
||||
GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
|
||||
GimpIscissorsOptions *options = GIMP_ISCISSORS_TOOL_GET_OPTIONS (tool);
|
||||
GimpImage *image = gimp_display_get_image (display);
|
||||
ISegment *segment;
|
||||
|
||||
iscissors->x = RINT (coords->x);
|
||||
iscissors->y = RINT (coords->y);
|
||||
|
@ -389,6 +410,8 @@ gimp_iscissors_tool_button_press (GimpTool *tool,
|
|||
gimp_tool_control_activate (tool->control);
|
||||
tool->display = display;
|
||||
|
||||
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
||||
|
||||
switch (iscissors->state)
|
||||
{
|
||||
case NO_ACTION:
|
||||
|
@ -396,14 +419,19 @@ gimp_iscissors_tool_button_press (GimpTool *tool,
|
|||
|
||||
if (! (state & GDK_SHIFT_MASK))
|
||||
find_max_gradient (iscissors, image,
|
||||
&iscissors->x,
|
||||
&iscissors->y);
|
||||
&iscissors->x, &iscissors->y);
|
||||
|
||||
iscissors->x = CLAMP (iscissors->x, 0, gimp_image_get_width (image) - 1);
|
||||
iscissors->y = CLAMP (iscissors->y, 0, gimp_image_get_height (image) - 1);
|
||||
|
||||
iscissors->ix = iscissors->x;
|
||||
iscissors->iy = iscissors->y;
|
||||
gimp_iscissors_tool_push_undo (iscissors);
|
||||
|
||||
segment = isegment_new (iscissors->x,
|
||||
iscissors->y,
|
||||
iscissors->x,
|
||||
iscissors->y);
|
||||
|
||||
g_queue_push_tail (iscissors->curve->segments, segment);
|
||||
|
||||
/* Initialize the draw tool only on starting the tool */
|
||||
gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
|
||||
|
@ -413,13 +441,26 @@ gimp_iscissors_tool_button_press (GimpTool *tool,
|
|||
/* Check if the mouse click occurred on a vertex or the curve itself */
|
||||
if (clicked_on_vertex (iscissors, coords->x, coords->y))
|
||||
{
|
||||
gimp_draw_tool_pause (GIMP_DRAW_TOOL (iscissors));
|
||||
|
||||
iscissors->nx = iscissors->x;
|
||||
iscissors->ny = iscissors->y;
|
||||
iscissors->state = SEED_ADJUSTMENT;
|
||||
|
||||
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
||||
/* recalculate both segments */
|
||||
if (iscissors->segment1)
|
||||
{
|
||||
iscissors->segment1->x1 = iscissors->x;
|
||||
iscissors->segment1->y1 = iscissors->y;
|
||||
|
||||
if (options->interactive)
|
||||
calculate_segment (iscissors, iscissors->segment1);
|
||||
}
|
||||
|
||||
if (iscissors->segment2)
|
||||
{
|
||||
iscissors->segment2->x2 = iscissors->x;
|
||||
iscissors->segment2->y2 = iscissors->y;
|
||||
|
||||
if (options->interactive)
|
||||
calculate_segment (iscissors, iscissors->segment2);
|
||||
}
|
||||
}
|
||||
/* If the iscissors is connected, check if the click was inside */
|
||||
else if (iscissors->curve->connected && iscissors->mask &&
|
||||
|
@ -434,14 +475,38 @@ gimp_iscissors_tool_button_press (GimpTool *tool,
|
|||
{
|
||||
/* if we're not connected, we're adding a new point */
|
||||
|
||||
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
||||
ISegment *last = g_queue_peek_tail (iscissors->curve->segments);
|
||||
|
||||
iscissors->state = SEED_PLACEMENT;
|
||||
|
||||
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
||||
gimp_iscissors_tool_push_undo (iscissors);
|
||||
|
||||
if (last->x1 == last->x2 &&
|
||||
last->y1 == last->y2)
|
||||
{
|
||||
last->x2 = iscissors->x;
|
||||
last->y2 = iscissors->y;
|
||||
|
||||
if (options->interactive)
|
||||
calculate_segment (iscissors, last);
|
||||
}
|
||||
else
|
||||
{
|
||||
segment = isegment_new (last->x2,
|
||||
last->y2,
|
||||
iscissors->x,
|
||||
iscissors->y);
|
||||
|
||||
g_queue_push_tail (iscissors->curve->segments, segment);
|
||||
|
||||
if (options->interactive)
|
||||
calculate_segment (iscissors, segment);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
||||
}
|
||||
|
||||
|
||||
|
@ -518,6 +583,7 @@ gimp_iscissors_tool_button_release (GimpTool *tool,
|
|||
GimpDisplay *display)
|
||||
{
|
||||
GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
|
||||
GimpIscissorsOptions *options = GIMP_ISCISSORS_TOOL_GET_OPTIONS (tool);
|
||||
|
||||
gimp_tool_control_halt (tool->control);
|
||||
|
||||
|
@ -539,8 +605,7 @@ gimp_iscissors_tool_button_release (GimpTool *tool,
|
|||
if (! iscissors->curve->first_point)
|
||||
{
|
||||
/* Determine if we're connecting to the first point */
|
||||
if (! g_queue_is_empty (iscissors->curve->segments))
|
||||
{
|
||||
|
||||
ISegment *segment = g_queue_peek_head (iscissors->curve->segments);
|
||||
|
||||
if (gimp_draw_tool_on_handle (GIMP_DRAW_TOOL (tool), display,
|
||||
|
@ -553,30 +618,42 @@ gimp_iscissors_tool_button_release (GimpTool *tool,
|
|||
{
|
||||
iscissors->x = segment->x1;
|
||||
iscissors->y = segment->y1;
|
||||
|
||||
segment = g_queue_peek_tail (iscissors->curve->segments);
|
||||
|
||||
segment->x2 = iscissors->x;
|
||||
segment->y2 = iscissors->y;
|
||||
|
||||
iscissors->curve->connected = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the new curve segment */
|
||||
if (iscissors->ix != iscissors->x ||
|
||||
iscissors->iy != iscissors->y)
|
||||
{
|
||||
ISegment *segment = isegment_new (iscissors->ix,
|
||||
iscissors->iy,
|
||||
iscissors->x,
|
||||
iscissors->y);
|
||||
|
||||
iscissors->ix = iscissors->x;
|
||||
iscissors->iy = iscissors->y;
|
||||
|
||||
g_queue_push_tail (iscissors->curve->segments, segment);
|
||||
|
||||
if (! options->interactive)
|
||||
calculate_segment (iscissors, segment);
|
||||
|
||||
gimp_iscissors_tool_free_redo (iscissors);
|
||||
}
|
||||
else
|
||||
{
|
||||
segment = g_queue_peek_tail (iscissors->curve->segments);
|
||||
|
||||
if (segment->x1 != segment->x2 ||
|
||||
segment->y1 != segment->y2)
|
||||
{
|
||||
if (! options->interactive)
|
||||
calculate_segment (iscissors, segment);
|
||||
|
||||
gimp_iscissors_tool_free_redo (iscissors);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_iscissors_tool_pop_undo (iscissors);
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* this was our first point */
|
||||
{
|
||||
iscissors->curve->first_point = FALSE;
|
||||
|
||||
gimp_iscissors_tool_free_redo (iscissors);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -584,19 +661,33 @@ gimp_iscissors_tool_button_release (GimpTool *tool,
|
|||
/* recalculate both segments */
|
||||
if (iscissors->segment1)
|
||||
{
|
||||
iscissors->segment1->x1 = iscissors->nx;
|
||||
iscissors->segment1->y1 = iscissors->ny;
|
||||
|
||||
if (! options->interactive)
|
||||
calculate_segment (iscissors, iscissors->segment1);
|
||||
}
|
||||
|
||||
if (iscissors->segment2)
|
||||
{
|
||||
iscissors->segment2->x2 = iscissors->nx;
|
||||
iscissors->segment2->y2 = iscissors->ny;
|
||||
|
||||
if (! options->interactive)
|
||||
calculate_segment (iscissors, iscissors->segment2);
|
||||
}
|
||||
|
||||
gimp_iscissors_tool_free_redo (iscissors);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (iscissors->state)
|
||||
{
|
||||
case SEED_PLACEMENT:
|
||||
gimp_iscissors_tool_pop_undo (iscissors);
|
||||
break;
|
||||
|
||||
case SEED_ADJUSTMENT:
|
||||
gimp_iscissors_tool_pop_undo (iscissors);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -621,7 +712,9 @@ gimp_iscissors_tool_motion (GimpTool *tool,
|
|||
GimpDisplay *display)
|
||||
{
|
||||
GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
|
||||
GimpIscissorsOptions *options = GIMP_ISCISSORS_TOOL_GET_OPTIONS (tool);
|
||||
GimpImage *image = gimp_display_get_image (display);
|
||||
ISegment *segment;
|
||||
|
||||
if (iscissors->state == NO_ACTION)
|
||||
return;
|
||||
|
@ -631,9 +724,6 @@ gimp_iscissors_tool_motion (GimpTool *tool,
|
|||
iscissors->x = RINT (coords->x);
|
||||
iscissors->y = RINT (coords->y);
|
||||
|
||||
switch (iscissors->state)
|
||||
{
|
||||
case SEED_PLACEMENT:
|
||||
/* Hold the shift key down to disable the auto-edge snap feature */
|
||||
if (! (state & GDK_SHIFT_MASK))
|
||||
find_max_gradient (iscissors, image,
|
||||
|
@ -642,24 +732,44 @@ gimp_iscissors_tool_motion (GimpTool *tool,
|
|||
iscissors->x = CLAMP (iscissors->x, 0, gimp_image_get_width (image) - 1);
|
||||
iscissors->y = CLAMP (iscissors->y, 0, gimp_image_get_height (image) - 1);
|
||||
|
||||
switch (iscissors->state)
|
||||
{
|
||||
case SEED_PLACEMENT:
|
||||
segment = g_queue_peek_tail (iscissors->curve->segments);
|
||||
|
||||
segment->x2 = iscissors->x;
|
||||
segment->y2 = iscissors->y;
|
||||
|
||||
if (iscissors->curve->first_point)
|
||||
{
|
||||
iscissors->ix = iscissors->x;
|
||||
iscissors->iy = iscissors->y;
|
||||
segment->x1 = segment->x2;
|
||||
segment->y1 = segment->y2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (options->interactive)
|
||||
calculate_segment (iscissors, segment);
|
||||
}
|
||||
break;
|
||||
|
||||
case SEED_ADJUSTMENT:
|
||||
/* Move the current seed to the location of the cursor */
|
||||
if (! (state & GDK_SHIFT_MASK))
|
||||
find_max_gradient (iscissors, image,
|
||||
&iscissors->x, &iscissors->y);
|
||||
if (iscissors->segment1)
|
||||
{
|
||||
iscissors->segment1->x1 = iscissors->x;
|
||||
iscissors->segment1->y1 = iscissors->y;
|
||||
|
||||
iscissors->x = CLAMP (iscissors->x, 0, gimp_image_get_width (image) - 1);
|
||||
iscissors->y = CLAMP (iscissors->y, 0, gimp_image_get_height (image) - 1);
|
||||
if (options->interactive)
|
||||
calculate_segment (iscissors, iscissors->segment1);
|
||||
}
|
||||
|
||||
iscissors->nx = iscissors->x;
|
||||
iscissors->ny = iscissors->y;
|
||||
if (iscissors->segment2)
|
||||
{
|
||||
iscissors->segment2->x2 = iscissors->x;
|
||||
iscissors->segment2->y2 = iscissors->y;
|
||||
|
||||
if (options->interactive)
|
||||
calculate_segment (iscissors, iscissors->segment2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -674,83 +784,54 @@ gimp_iscissors_tool_draw (GimpDrawTool *draw_tool)
|
|||
{
|
||||
GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (draw_tool);
|
||||
GimpIscissorsOptions *options = GIMP_ISCISSORS_TOOL_GET_OPTIONS (draw_tool);
|
||||
|
||||
if (iscissors->state == SEED_PLACEMENT)
|
||||
{
|
||||
/* Draw the crosshairs target if we're placing a seed */
|
||||
gimp_draw_tool_add_handle (draw_tool,
|
||||
GIMP_HANDLE_CROSS,
|
||||
iscissors->x, iscissors->y,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_HANDLE_ANCHOR_CENTER);
|
||||
|
||||
/* Draw a line boundary */
|
||||
if (! iscissors->curve->first_point)
|
||||
{
|
||||
if (! options->interactive)
|
||||
{
|
||||
gimp_draw_tool_add_line (draw_tool,
|
||||
iscissors->ix, iscissors->iy,
|
||||
iscissors->x, iscissors->y);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* See if the mouse has moved. If so, create a new segment... */
|
||||
if (! iscissors->livewire ||
|
||||
(iscissors->ix != iscissors->livewire->x1 ||
|
||||
iscissors->iy != iscissors->livewire->y1 ||
|
||||
iscissors->x != iscissors->livewire->x2 ||
|
||||
iscissors->y != iscissors->livewire->y2))
|
||||
{
|
||||
if (iscissors->livewire)
|
||||
isegment_free (iscissors->livewire);
|
||||
|
||||
iscissors->livewire = isegment_new (iscissors->ix,
|
||||
iscissors->iy,
|
||||
iscissors->x,
|
||||
iscissors->y);
|
||||
|
||||
calculate_segment (iscissors, iscissors->livewire);
|
||||
}
|
||||
|
||||
/* plot the segment */
|
||||
iscissors_draw_segment (draw_tool, iscissors->livewire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! iscissors->curve->first_point)
|
||||
{
|
||||
GimpCanvasItem *item;
|
||||
GList *list;
|
||||
|
||||
/* Draw a point at the init point coordinates */
|
||||
if (! iscissors->curve->connected)
|
||||
/* First, render all segments and lines */
|
||||
if (! iscissors->curve->first_point)
|
||||
{
|
||||
gimp_draw_tool_add_handle (draw_tool,
|
||||
GIMP_HANDLE_FILLED_CIRCLE,
|
||||
iscissors->ix,
|
||||
iscissors->iy,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_HANDLE_ANCHOR_CENTER);
|
||||
}
|
||||
|
||||
/* Go through the list of isegments, and render each one... */
|
||||
for (list = g_queue_peek_head_link (iscissors->curve->segments);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
ISegment *segment = list->data;
|
||||
|
||||
if (iscissors->state == SEED_ADJUSTMENT)
|
||||
/* plot the segment */
|
||||
item = iscissors_draw_segment (draw_tool, segment);
|
||||
|
||||
/* if this segment is currently being added or adjusted */
|
||||
if ((iscissors->state == SEED_PLACEMENT &&
|
||||
! list->next)
|
||||
||
|
||||
(iscissors->state == SEED_ADJUSTMENT &&
|
||||
(segment == iscissors->segment1 ||
|
||||
segment == iscissors->segment2)))
|
||||
{
|
||||
/* don't draw segment1 at all */
|
||||
if (segment == iscissors->segment1)
|
||||
continue;
|
||||
if (! options->interactive)
|
||||
item = gimp_draw_tool_add_line (draw_tool,
|
||||
segment->x1, segment->y1,
|
||||
segment->x2, segment->y2);
|
||||
|
||||
gimp_canvas_item_set_highlight (item, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gimp_draw_tool_add_handle (draw_tool,
|
||||
/* Then, render the handles on top of the segments */
|
||||
for (list = g_queue_peek_head_link (iscissors->curve->segments);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
ISegment *segment = list->data;
|
||||
|
||||
if (! iscissors->curve->first_point)
|
||||
{
|
||||
gboolean adjustment = (iscissors->state == SEED_ADJUSTMENT &&
|
||||
segment == iscissors->segment1);
|
||||
|
||||
item = gimp_draw_tool_add_handle (draw_tool,
|
||||
adjustment ?
|
||||
GIMP_HANDLE_CROSS :
|
||||
GIMP_HANDLE_FILLED_CIRCLE,
|
||||
segment->x1,
|
||||
segment->y1,
|
||||
|
@ -758,60 +839,42 @@ gimp_iscissors_tool_draw (GimpDrawTool *draw_tool)
|
|||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_HANDLE_ANCHOR_CENTER);
|
||||
|
||||
if (iscissors->state == SEED_ADJUSTMENT)
|
||||
{
|
||||
/* draw only the start handle of segment2 */
|
||||
if (segment == iscissors->segment2)
|
||||
continue;
|
||||
if (adjustment)
|
||||
gimp_canvas_item_set_highlight (item, TRUE);
|
||||
}
|
||||
|
||||
/* plot the segment */
|
||||
iscissors_draw_segment (draw_tool, segment);
|
||||
}
|
||||
}
|
||||
|
||||
if (iscissors->state == SEED_ADJUSTMENT)
|
||||
/* Draw the last point if the curve is not connected */
|
||||
if (! list->next && ! iscissors->curve->connected)
|
||||
{
|
||||
/* plot both segments, and the control point between them */
|
||||
if (iscissors->segment1)
|
||||
{
|
||||
gimp_draw_tool_add_line (draw_tool,
|
||||
iscissors->segment1->x2,
|
||||
iscissors->segment1->y2,
|
||||
iscissors->nx,
|
||||
iscissors->ny);
|
||||
}
|
||||
gboolean placement = (iscissors->state == SEED_PLACEMENT);
|
||||
|
||||
if (iscissors->segment2)
|
||||
{
|
||||
gimp_draw_tool_add_line (draw_tool,
|
||||
iscissors->segment2->x1,
|
||||
iscissors->segment2->y1,
|
||||
iscissors->nx,
|
||||
iscissors->ny);
|
||||
}
|
||||
|
||||
gimp_draw_tool_add_handle (draw_tool,
|
||||
item = gimp_draw_tool_add_handle (draw_tool,
|
||||
placement ?
|
||||
GIMP_HANDLE_CROSS :
|
||||
GIMP_HANDLE_FILLED_CIRCLE,
|
||||
iscissors->nx,
|
||||
iscissors->ny,
|
||||
segment->x2,
|
||||
segment->y2,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_HANDLE_ANCHOR_CENTER);
|
||||
|
||||
if (placement)
|
||||
gimp_canvas_item_set_highlight (item, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static GimpCanvasItem *
|
||||
iscissors_draw_segment (GimpDrawTool *draw_tool,
|
||||
ISegment *segment)
|
||||
{
|
||||
GimpCanvasItem *item;
|
||||
GimpVector2 *points;
|
||||
gpointer *point;
|
||||
gint i, len;
|
||||
|
||||
if (! segment->points)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
len = segment->points->len;
|
||||
|
||||
|
@ -825,9 +888,11 @@ iscissors_draw_segment (GimpDrawTool *draw_tool,
|
|||
points[i].y = (coords >> 16);
|
||||
}
|
||||
|
||||
gimp_draw_tool_add_lines (draw_tool, points, len, FALSE);
|
||||
item = gimp_draw_tool_add_lines (draw_tool, points, len, FALSE);
|
||||
|
||||
g_free (points);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -866,14 +931,14 @@ gimp_iscissors_tool_oper_update (GimpTool *tool,
|
|||
GIMP_TOOL_HANDLE_SIZE_CIRCLE,
|
||||
GIMP_HANDLE_ANCHOR_CENTER))
|
||||
{
|
||||
gimp_tool_replace_status (tool, display, _("Click to close the"
|
||||
" curve"));
|
||||
gimp_tool_replace_status (tool, display,
|
||||
_("Click to close the curve"));
|
||||
iscissors->op = ISCISSORS_OP_CONNECT;
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_tool_replace_status (tool, display, _("Click to add a point"
|
||||
" on this segment"));
|
||||
gimp_tool_replace_status (tool, display,
|
||||
_("Click to add a point on this segment"));
|
||||
iscissors->op = ISCISSORS_OP_ADD_POINT;
|
||||
}
|
||||
}
|
||||
|
@ -1021,37 +1086,159 @@ gimp_iscissors_tool_key_press (GimpTool *tool,
|
|||
}
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
gimp_iscissors_tool_get_undo_desc (GimpTool *tool,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
|
||||
|
||||
if (display != tool->display || ! iscissors->undo_stack)
|
||||
return NULL;
|
||||
|
||||
return _("Modify Scissors Curve");
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
gimp_iscissors_tool_get_redo_desc (GimpTool *tool,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
|
||||
|
||||
if (display != tool->display || ! iscissors->redo_stack)
|
||||
return NULL;
|
||||
|
||||
return _("Modify Scissors Curve");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_iscissors_tool_undo (GimpTool *tool,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
|
||||
|
||||
if (! gimp_iscissors_tool_get_undo_desc (tool, display))
|
||||
return FALSE;
|
||||
|
||||
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
||||
|
||||
iscissors->redo_stack = g_list_prepend (iscissors->redo_stack,
|
||||
iscissors->curve);
|
||||
|
||||
iscissors->curve = iscissors->undo_stack->data;
|
||||
|
||||
iscissors->undo_stack = g_list_remove (iscissors->undo_stack,
|
||||
iscissors->curve);
|
||||
|
||||
if (! iscissors->undo_stack)
|
||||
{
|
||||
iscissors->state = NO_ACTION;
|
||||
|
||||
gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
|
||||
}
|
||||
|
||||
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_iscissors_tool_redo (GimpTool *tool,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpIscissorsTool *iscissors = GIMP_ISCISSORS_TOOL (tool);
|
||||
|
||||
if (! gimp_iscissors_tool_get_redo_desc (tool, display))
|
||||
return FALSE;
|
||||
|
||||
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
||||
|
||||
if (! iscissors->undo_stack)
|
||||
{
|
||||
iscissors->state = WAITING;
|
||||
|
||||
gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
|
||||
}
|
||||
|
||||
iscissors->undo_stack = g_list_prepend (iscissors->undo_stack,
|
||||
iscissors->curve);
|
||||
|
||||
iscissors->curve = iscissors->redo_stack->data;
|
||||
|
||||
iscissors->redo_stack = g_list_remove (iscissors->redo_stack,
|
||||
iscissors->curve);
|
||||
|
||||
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_iscissors_tool_push_undo (GimpIscissorsTool *iscissors)
|
||||
{
|
||||
iscissors->undo_stack = g_list_prepend (iscissors->undo_stack,
|
||||
icurve_copy (iscissors->curve));
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_iscissors_tool_pop_undo (GimpIscissorsTool *iscissors)
|
||||
{
|
||||
icurve_free (iscissors->curve);
|
||||
iscissors->curve = iscissors->undo_stack->data;
|
||||
|
||||
iscissors->undo_stack = g_list_remove (iscissors->undo_stack,
|
||||
iscissors->curve);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_iscissors_tool_free_redo (GimpIscissorsTool *iscissors)
|
||||
{
|
||||
g_list_free_full (iscissors->redo_stack,
|
||||
(GDestroyNotify) icurve_free);
|
||||
iscissors->redo_stack = NULL;
|
||||
|
||||
/* update the undo actions / menu items */
|
||||
gimp_image_flush (gimp_display_get_image (GIMP_TOOL (iscissors)->display));
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_iscissors_tool_halt (GimpIscissorsTool *iscissors,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
/* Free and reset the curve */
|
||||
icurve_clear (iscissors->curve);
|
||||
|
||||
/* free mask */
|
||||
if (iscissors->mask)
|
||||
iscissors->segment1 = NULL;
|
||||
iscissors->segment2 = NULL;
|
||||
iscissors->state = NO_ACTION;
|
||||
|
||||
if (iscissors->undo_stack)
|
||||
{
|
||||
g_object_unref (iscissors->mask);
|
||||
iscissors->mask = NULL;
|
||||
g_list_free_full (iscissors->undo_stack, (GDestroyNotify) icurve_free);
|
||||
iscissors->undo_stack = NULL;
|
||||
}
|
||||
|
||||
if (iscissors->redo_stack)
|
||||
{
|
||||
g_list_free_full (iscissors->redo_stack, (GDestroyNotify) icurve_free);
|
||||
iscissors->redo_stack = NULL;
|
||||
}
|
||||
|
||||
/* free the gradient map */
|
||||
if (iscissors->gradient_map)
|
||||
{
|
||||
g_object_unref (iscissors->gradient_map);
|
||||
iscissors->gradient_map = NULL;
|
||||
}
|
||||
|
||||
iscissors->segment1 = NULL;
|
||||
iscissors->segment2 = NULL;
|
||||
iscissors->state = NO_ACTION;
|
||||
|
||||
/* Reset the dp buffers */
|
||||
if (iscissors->dp_buf)
|
||||
{
|
||||
gimp_temp_buf_unref (iscissors->dp_buf);
|
||||
iscissors->dp_buf = NULL;
|
||||
}
|
||||
|
||||
if (iscissors->mask)
|
||||
{
|
||||
g_object_unref (iscissors->mask);
|
||||
iscissors->mask = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1142,7 +1329,11 @@ clicked_on_vertex (GimpIscissorsTool *iscissors,
|
|||
gint segments_found = mouse_over_vertex (iscissors, x, y);
|
||||
|
||||
if (segments_found > 1)
|
||||
{
|
||||
gimp_iscissors_tool_push_undo (iscissors);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* if only one segment was found, the segments are unconnected, and
|
||||
* the user only wants to move either the first or last point
|
||||
|
@ -1173,6 +1364,9 @@ mouse_over_segment (GimpIscissorsTool *iscissors,
|
|||
gpointer *pt;
|
||||
gint len;
|
||||
|
||||
if (! segment->points)
|
||||
continue;
|
||||
|
||||
pt = segment->points->pdata;
|
||||
len = segment->points->len;
|
||||
|
||||
|
@ -1217,6 +1411,8 @@ clicked_on_segment (GimpIscissorsTool *iscissors,
|
|||
ISegment *segment = list->data;
|
||||
ISegment *new_segment;
|
||||
|
||||
gimp_iscissors_tool_push_undo (iscissors);
|
||||
|
||||
/* Create the new segment */
|
||||
new_segment = isegment_new (iscissors->x,
|
||||
iscissors->y,
|
||||
|
@ -1653,8 +1849,9 @@ find_max_gradient (GimpIscissorsTool *iscissors,
|
|||
gint x1, y1, x2, y2;
|
||||
gfloat max_gradient;
|
||||
|
||||
/* Initialise the gradient map tile manager for this image if we
|
||||
* don't already have one. */
|
||||
/* Initialise the gradient map buffer for this image if we don't
|
||||
* already have one.
|
||||
*/
|
||||
if (! iscissors->gradient_map)
|
||||
iscissors->gradient_map = gradient_map_new (image);
|
||||
|
||||
|
@ -1726,6 +1923,31 @@ isegment_new (gint x1,
|
|||
return segment;
|
||||
}
|
||||
|
||||
static ISegment *
|
||||
isegment_copy (ISegment *segment)
|
||||
{
|
||||
ISegment *copy = isegment_new (segment->x1,
|
||||
segment->y1,
|
||||
segment->x2,
|
||||
segment->y2);
|
||||
|
||||
if (segment->points)
|
||||
{
|
||||
gint i;
|
||||
|
||||
copy->points = g_ptr_array_sized_new (segment->points->len);
|
||||
|
||||
for (i = 0; i < segment->points->len; i++)
|
||||
{
|
||||
gpointer value = g_ptr_array_index (segment->points, i);
|
||||
|
||||
g_ptr_array_add (copy->points, value);
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
static void
|
||||
isegment_free (ISegment *segment)
|
||||
{
|
||||
|
@ -1746,6 +1968,25 @@ icurve_new (void)
|
|||
return curve;
|
||||
}
|
||||
|
||||
static ICurve *
|
||||
icurve_copy (ICurve *curve)
|
||||
{
|
||||
ICurve *copy = icurve_new ();
|
||||
GList *link;
|
||||
|
||||
for (link = g_queue_peek_head_link (curve->segments);
|
||||
link;
|
||||
link = g_list_next (link))
|
||||
{
|
||||
g_queue_push_tail (copy->segments, isegment_copy (link->data));
|
||||
}
|
||||
|
||||
copy->first_point = curve->first_point;
|
||||
copy->connected = curve->connected;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
static void
|
||||
icurve_clear (ICurve *curve)
|
||||
{
|
||||
|
|
|
@ -65,24 +65,21 @@ struct _GimpIscissorsTool
|
|||
|
||||
IscissorsOps op;
|
||||
|
||||
gint x, y; /* upper left hand coordinate */
|
||||
gint ix, iy; /* initial coordinates */
|
||||
gint nx, ny; /* new coordinates */
|
||||
|
||||
GimpTempBuf *dp_buf; /* dynamic programming buffer */
|
||||
|
||||
ISegment *livewire; /* livewire boundary segment */
|
||||
gint x, y; /* mouse coordinates */
|
||||
|
||||
ISegment *segment1; /* 1st segment connected to current point */
|
||||
ISegment *segment2; /* 2nd segment connected to current point */
|
||||
|
||||
ICurve *curve; /* the curve */
|
||||
|
||||
GList *undo_stack; /* stack of ICurves for undo */
|
||||
GList *redo_stack; /* stack of ICurves for redo */
|
||||
|
||||
IscissorsState state; /* state of iscissors */
|
||||
|
||||
/* XXX might be useful */
|
||||
GimpChannel *mask; /* selection mask */
|
||||
GeglBuffer *gradient_map; /* lazily filled gradient map */
|
||||
GimpTempBuf *dp_buf; /* dynamic programming buffer */
|
||||
GimpChannel *mask; /* selection mask */
|
||||
};
|
||||
|
||||
struct _GimpIscissorsToolClass
|
||||
|
|
Loading…
Reference in New Issue