[gimp/soc-2012-unified-transformation: 4/25] transformtool: Infinite undo
- From: Mikael Magnusson <mikachu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/soc-2012-unified-transformation: 4/25] transformtool: Infinite undo
- Date: Tue, 10 Jul 2012 20:34:08 +0000 (UTC)
commit f163442e5e4d33f7a624407e53b5355befc57ba3
Author: Mikael Magnusson <mikachu src gnome org>
Date: Sat Aug 13 17:42:41 2011 +0200
transformtool: Infinite undo
add undo and redo buttons, can undo all interactions. The reset button
is equivalent to undoing all operations and lets you press redo to get
back to before you reset. Doing something after undo will of course
clear all redo events.
app/tools/gimprotatetool.c | 4 +
app/tools/gimpscaletool.c | 2 +
app/tools/gimpsheartool.c | 4 +
app/tools/gimptransformtool.c | 143 ++++++++++++++++++++++++++++++------
app/tools/gimptransformtool.h | 10 ++-
app/tools/gimptransformtoolundo.c | 2 +-
6 files changed, 138 insertions(+), 27 deletions(-)
---
diff --git a/app/tools/gimprotatetool.c b/app/tools/gimprotatetool.c
index 8ac7294..2d2f704 100644
--- a/app/tools/gimprotatetool.c
+++ b/app/tools/gimprotatetool.c
@@ -391,6 +391,8 @@ rotate_angle_changed (GtkAdjustment *adj,
tr_tool->trans_info[REAL_ANGLE] = tr_tool->trans_info[ANGLE] = value;
+ gimp_transform_tool_push_internal_undo (tr_tool);
+
gimp_transform_tool_recalc_matrix (tr_tool);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
@@ -416,6 +418,8 @@ rotate_center_changed (GtkWidget *widget,
tr_tool->px = px;
tr_tool->py = py;
+ gimp_transform_tool_push_internal_undo (tr_tool);
+
gimp_transform_tool_recalc_matrix (tr_tool);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
diff --git a/app/tools/gimpscaletool.c b/app/tools/gimpscaletool.c
index 6120265..66be2b2 100644
--- a/app/tools/gimpscaletool.c
+++ b/app/tools/gimpscaletool.c
@@ -369,6 +369,8 @@ gimp_scale_tool_size_notify (GtkWidget *box,
tr_tool->trans_info[X1] = tr_tool->trans_info[X0] + width;
tr_tool->trans_info[Y1] = tr_tool->trans_info[Y0] + height;
+ gimp_transform_tool_push_internal_undo (tr_tool);
+
gimp_transform_tool_recalc_matrix (tr_tool);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
diff --git a/app/tools/gimpsheartool.c b/app/tools/gimpsheartool.c
index 1eae0e3..2d9aa88 100644
--- a/app/tools/gimpsheartool.c
+++ b/app/tools/gimpsheartool.c
@@ -282,6 +282,8 @@ shear_x_mag_changed (GtkAdjustment *adj,
tr_tool->trans_info[XSHEAR] = value;
+ gimp_transform_tool_push_internal_undo (tr_tool);
+
gimp_transform_tool_recalc_matrix (tr_tool);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
@@ -303,6 +305,8 @@ shear_y_mag_changed (GtkAdjustment *adj,
tr_tool->trans_info[YSHEAR] = value;
+ gimp_transform_tool_push_internal_undo (tr_tool);
+
gimp_transform_tool_recalc_matrix (tr_tool);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
diff --git a/app/tools/gimptransformtool.c b/app/tools/gimptransformtool.c
index 9220b88..06a2007 100644
--- a/app/tools/gimptransformtool.c
+++ b/app/tools/gimptransformtool.c
@@ -67,6 +67,8 @@
#define RESPONSE_RESET 1
+#define RESPONSE_UNDO 2
+#define RESPONSE_REDO 3
#define MIN_HANDLE_SIZE 6
@@ -147,6 +149,8 @@ static void gimp_transform_tool_handles_recalc (GimpTransformTool
static void gimp_transform_tool_response (GtkWidget *widget,
gint response_id,
GimpTransformTool *tr_tool);
+static void free_trans(gpointer data);
+static void update_sensitivity(GimpTransformTool *tr_tool);
G_DEFINE_TYPE (GimpTransformTool, gimp_transform_tool, GIMP_TYPE_DRAW_TOOL)
@@ -221,6 +225,9 @@ gimp_transform_tool_finalize (GObject *object)
tr_tool->dialog = NULL;
}
+ g_list_free_full(tr_tool->redo_list, free_trans);
+ g_list_free_full(tr_tool->undo_list, free_trans);
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -275,11 +282,16 @@ gimp_transform_tool_initialize (GimpTool *tool,
tr_tool->function = TRANSFORM_CREATING;
+ /* Initialize undo and redo lists */
+ tr_tool->undo_list = g_list_prepend(NULL, g_slice_new(TransInfo));
+ tr_tool->redo_list = NULL;
+ tr_tool->old_trans_info = g_list_last(tr_tool->undo_list)->data;
+ tr_tool->prev_trans_info = g_list_first(tr_tool->undo_list)->data;
+ update_sensitivity(tr_tool);
/* Save the current transformation info */
for (i = 0; i < TRANS_INFO_SIZE; i++)
{
- tr_tool->old_trans_info[i] = tr_tool->trans_info[i];
- tr_tool->prev_trans_info[i] = tr_tool->trans_info[i];
+ (*tr_tool->prev_trans_info)[i] = tr_tool->trans_info[i];
}
}
@@ -325,7 +337,6 @@ gimp_transform_tool_button_press (GimpTool *tool,
GimpDisplay *display)
{
GimpTransformTool *tr_tool = GIMP_TRANSFORM_TOOL (tool);
- gint i;
if (tr_tool->function == TRANSFORM_CREATING)
gimp_transform_tool_oper_update (tool, coords, state, TRUE, display);
@@ -333,11 +344,33 @@ gimp_transform_tool_button_press (GimpTool *tool,
tr_tool->lastx = tr_tool->mousex = coords->x;
tr_tool->lasty = tr_tool->mousey = coords->y;
- /* Store current trans_info */
+ gimp_tool_control_activate (tool->control);
+}
+
+void gimp_transform_tool_push_internal_undo (GimpTransformTool *tr_tool)
+{
+ gint i;
+
+ /* push current state on the undo list and set this
+ * state as the current state, but avoid doing this if there were no changes */
for (i = 0; i < TRANS_INFO_SIZE; i++)
- tr_tool->prev_trans_info[i] = tr_tool->trans_info[i];
+ if ((*tr_tool->prev_trans_info)[i] != tr_tool->trans_info[i])
+ break;
- gimp_tool_control_activate (tool->control);
+ if (i < TRANS_INFO_SIZE)
+ {
+ tr_tool->prev_trans_info = g_slice_new(TransInfo);
+ for (i = 0; i < TRANS_INFO_SIZE; i++)
+ (*tr_tool->prev_trans_info)[i] = tr_tool->trans_info[i];
+ tr_tool->undo_list = g_list_prepend(tr_tool->undo_list, tr_tool->prev_trans_info);
+
+ /* If we undid anything and started interacting, we have to discard
+ * the redo history */
+ g_list_free_full(tr_tool->redo_list, free_trans);
+ tr_tool->redo_list = NULL;
+
+ update_sensitivity(tr_tool);
+ }
}
static void
@@ -364,14 +397,17 @@ gimp_transform_tool_button_release (GimpTool *tool,
{
gimp_transform_tool_response (NULL, GTK_RESPONSE_OK, tr_tool);
}
+
+ /* We're done with an interaction, save it on the undo list */
+ gimp_transform_tool_push_internal_undo(tr_tool);
}
else
{
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
- /* Restore the previous trans_info */
+ /* Restore the last saved state */
for (i = 0; i < TRANS_INFO_SIZE; i++)
- tr_tool->trans_info[i] = tr_tool->prev_trans_info[i];
+ tr_tool->trans_info[i] = (*tr_tool->prev_trans_info)[i];
/* reget the selection bounds */
gimp_transform_tool_bounds (tr_tool, display);
@@ -434,7 +470,11 @@ gimp_transform_tool_key_press (GimpTool *tool,
return TRUE;
case GDK_KEY_BackSpace:
- gimp_transform_tool_response (NULL, RESPONSE_RESET, trans_tool);
+ gimp_transform_tool_response (NULL, RESPONSE_UNDO, trans_tool);
+ return TRUE;
+
+ case GDK_KEY_space:
+ gimp_transform_tool_response (NULL, RESPONSE_REDO, trans_tool);
return TRUE;
case GDK_KEY_Escape:
@@ -1382,6 +1422,8 @@ gimp_transform_tool_dialog (GimpTransformTool *tr_tool)
gimp_display_get_shell (tool->display),
tool_info->blurb,
GIMP_STOCK_RESET, RESPONSE_RESET,
+ GTK_STOCK_UNDO, RESPONSE_UNDO,
+ GTK_STOCK_REDO, RESPONSE_REDO,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
stock_id, GTK_RESPONSE_OK,
NULL);
@@ -1389,6 +1431,8 @@ gimp_transform_tool_dialog (GimpTransformTool *tr_tool)
GTK_RESPONSE_OK);
gtk_dialog_set_alternative_button_order (GTK_DIALOG (tr_tool->dialog),
RESPONSE_RESET,
+ RESPONSE_UNDO,
+ RESPONSE_REDO,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
@@ -1443,26 +1487,59 @@ gimp_transform_tool_response (GtkWidget *widget,
GimpTransformTool *tr_tool)
{
GimpTool *tool = GIMP_TOOL (tr_tool);
+ GList *it = tr_tool->redo_list;
+ gint i;
switch (response_id)
{
- case RESPONSE_RESET:
+ case RESPONSE_UNDO:
{
- gint i;
-
- gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
-
- /* Restore the previous transformation info */
- for (i = 0; i < TRANS_INFO_SIZE; i++)
- tr_tool->trans_info[i] = tr_tool->old_trans_info[i];
-
- /* reget the selection bounds */
- gimp_transform_tool_bounds (tr_tool, tool->display);
+ it = g_list_next(tr_tool->undo_list);
- /* recalculate the tool's transformation matrix */
- gimp_transform_tool_recalc_matrix (tr_tool);
-
- gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+ case RESPONSE_REDO:
+ if (it)
+ {
+ case RESPONSE_RESET:
+ if (response_id == RESPONSE_UNDO)
+ {
+ /* Move prev_trans_info from undo_list to redo_list */
+ tr_tool->redo_list = g_list_prepend(tr_tool->redo_list, tr_tool->prev_trans_info);
+ tr_tool->undo_list = g_list_remove(tr_tool->undo_list, tr_tool->prev_trans_info);
+ tr_tool->prev_trans_info = it->data;
+ }
+ else if (response_id == RESPONSE_REDO)
+ {
+ /* And the opposite */
+ tr_tool->prev_trans_info = it->data;
+ tr_tool->undo_list = g_list_prepend(tr_tool->undo_list, tr_tool->prev_trans_info);
+ tr_tool->redo_list = g_list_remove(tr_tool->redo_list, tr_tool->prev_trans_info);
+ }
+ else if (response_id == RESPONSE_RESET)
+ {
+ /* Move all undo events to redo, and pop off the first one as that's the current one,
+ * which always sits on the undo_list */
+ tr_tool->redo_list = g_list_remove(g_list_concat(g_list_reverse(tr_tool->undo_list), tr_tool->redo_list), tr_tool->old_trans_info);
+ tr_tool->prev_trans_info = tr_tool->old_trans_info;
+ tr_tool->undo_list = g_list_prepend(NULL, tr_tool->prev_trans_info);
+ }
+ update_sensitivity(tr_tool);
+
+ gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+
+ /* Restore the previous transformation info */
+ for (i = 0; i < TRANS_INFO_SIZE; i++)
+ {
+ tr_tool->trans_info[i] = (*tr_tool->prev_trans_info)[i];
+ }
+
+ /* reget the selection bounds */
+ gimp_transform_tool_bounds (tr_tool, tool->display);
+
+ /* recalculate the tool's transformation matrix */
+ gimp_transform_tool_recalc_matrix (tr_tool);
+
+ gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+ }
}
break;
@@ -1476,3 +1553,21 @@ gimp_transform_tool_response (GtkWidget *widget,
break;
}
}
+
+static void free_trans(gpointer data)
+{
+ g_slice_free(TransInfo, data);
+}
+
+static void update_sensitivity(GimpTransformTool *tr_tool)
+{
+ if (!tr_tool->dialog)
+ return;
+
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(tr_tool->dialog), RESPONSE_UNDO,
+ g_list_next(tr_tool->undo_list) != NULL);
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(tr_tool->dialog), RESPONSE_REDO,
+ tr_tool->redo_list != NULL);
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(tr_tool->dialog), RESPONSE_RESET,
+ g_list_next(tr_tool->undo_list) != NULL);
+}
diff --git a/app/tools/gimptransformtool.h b/app/tools/gimptransformtool.h
index 95a4a45..d8dacf1 100644
--- a/app/tools/gimptransformtool.h
+++ b/app/tools/gimptransformtool.h
@@ -80,8 +80,13 @@ struct _GimpTransformTool
GimpMatrix3 transform; /* transformation matrix */
TransInfo trans_info; /* transformation info */
- TransInfo old_trans_info; /* for resetting everything */
- TransInfo prev_trans_info; /* for cancelling a drag operation */
+ TransInfo *old_trans_info; /* for resetting everything */
+ TransInfo *prev_trans_info; /* the current finished state */
+ GList *undo_list; /* list of all states,
+ head is current == prev_trans_info,
+ tail is original == old_trans_info*/
+ GList *redo_list; /* list of all undone states,
+ NULL when nothing undone */
TransformAction function; /* current tool activity */
@@ -122,6 +127,7 @@ struct _GimpTransformToolClass
GType gimp_transform_tool_get_type (void) G_GNUC_CONST;
void gimp_transform_tool_recalc_matrix (GimpTransformTool *tr_tool);
+void gimp_transform_tool_push_internal_undo (GimpTransformTool *tr_tool);
#endif /* __GIMP_TRANSFORM_TOOL_H__ */
diff --git a/app/tools/gimptransformtoolundo.c b/app/tools/gimptransformtoolundo.c
index 17a8ddc..98a8b3b 100644
--- a/app/tools/gimptransformtoolundo.c
+++ b/app/tools/gimptransformtoolundo.c
@@ -97,7 +97,7 @@ gimp_transform_tool_undo_constructed (GObject *object)
transform_tool = transform_tool_undo->transform_tool;
for (i = 0; i < TRANS_INFO_SIZE; i++)
- transform_tool_undo->trans_info[i] = transform_tool->old_trans_info[i];
+ transform_tool_undo->trans_info[i] = (*transform_tool->old_trans_info)[i];
#if 0
if (transform_tool->original)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]