[gimp/wip/gradient-edit: 1/2] app: implement tool undo for gradient editing in the blend tool
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/gradient-edit: 1/2] app: implement tool undo for gradient editing in the blend tool
- Date: Fri, 4 Aug 2017 14:01:18 +0000 (UTC)
commit 159d6748a8c3d814bba2cc8e026cdd1c2a352c97
Author: Ell <ell_se yahoo com>
Date: Thu Aug 3 19:59:21 2017 -0400
app: implement tool undo for gradient editing in the blend tool
Move the tool undo functionality of the blend tool to the editor,
and add support for undoing gradient edit operations. Each undo
step that is the result of an operation that changes the gradient
holds, in addition to the line endpoint poisitions and the selected
handle, a copy of the gradient at the beginning of the operation;
when undoing the operation, the saved gradient is copied back to
the active gradient.
To avoid all kinds of complex scenarios, when the active gradient
changes, or when the gradient is modified externally (e.g., by the
(old) gradient editor), all undo steps that affect the gradient are
deleted from the history, while those that affect only the endpoint
positions are kept.
app/tools/gimpblendtool-editor.c | 550 +++++++++++++++++++++++++++++++-------
app/tools/gimpblendtool-editor.h | 26 ++-
app/tools/gimpblendtool.c | 197 ++++----------
app/tools/gimpblendtool.h | 9 +-
4 files changed, 523 insertions(+), 259 deletions(-)
---
diff --git a/app/tools/gimpblendtool-editor.c b/app/tools/gimpblendtool-editor.c
index 95d925d..533e4a5 100644
--- a/app/tools/gimpblendtool-editor.c
+++ b/app/tools/gimpblendtool-editor.c
@@ -61,97 +61,131 @@ typedef enum
} Direction;
+typedef struct
+{
+ /* line endpoints */
+ gdouble start_x;
+ gdouble start_y;
+ gdouble end_x;
+ gdouble end_y;
+
+ /* copy of the gradient, owned by the blend info, or NULL, if the gradient
+ * isn't affected
+ */
+ GimpGradient *gradient;
+
+ /* selected handle, when gradient != NULL */
+ gint selection;
+} BlendInfo;
+
+
/* local function prototypes */
-static gboolean gimp_blend_tool_editor_line_can_add_slider (GimpToolLine
*line,
- gdouble
value,
- GimpBlendTool
*blend_tool);
-static gint gimp_blend_tool_editor_line_add_slider (GimpToolLine
*line,
- gdouble
value,
- GimpBlendTool
*blend_tool);
-static void gimp_blend_tool_editor_line_remove_slider (GimpToolLine
*line,
- gint
slider,
- GimpBlendTool
*blend_tool);
-static void gimp_blend_tool_editor_line_selection_changed (GimpToolLine
*line,
- GimpBlendTool
*blend_tool);
-static gboolean gimp_blend_tool_editor_line_handle_clicked (GimpToolLine
*line,
- gint
handle,
- GdkModifierType
state,
- GimpButtonPressType
press_type,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_gui_response (GimpToolGui
*gui,
- gint
response_id,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_color_entry_color_changed (GimpColorButton
*button,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_color_entry_type_changed (GtkComboBox
*combo,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_endpoint_se_value_changed (GimpSizeEntry
*se,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_stop_spinbutton_value_changed (GtkAdjustment
*adjustment,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_stop_delete_clicked (GtkWidget
*button,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_midpoint_spinbutton_value_changed (GtkAdjustment
*adjustment,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_midpoint_type_changed (GtkComboBox
*combo,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_midpoint_color_changed (GtkComboBox
*combo,
- GimpBlendTool
*blend_tool);
-
-static void gimp_blend_tool_editor_midpoint_new_stop_clicked (GtkWidget
*button,
- GimpBlendTool
*blend_tool);
-static void gimp_blend_tool_editor_midpoint_center_clicked (GtkWidget
*button,
- GimpBlendTool
*blend_tool);
-
-static gboolean gimp_blend_tool_editor_is_gradient_editable (GimpBlendTool
*blend_tool);
-
-static gboolean gimp_blend_tool_editor_handle_is_endpoint (GimpBlendTool
*blend_tool,
- gint
handle);
-static gboolean gimp_blend_tool_editor_handle_is_stop (GimpBlendTool
*blend_tool,
- gint
handle);
-static gboolean gimp_blend_tool_editor_handle_is_midpoint (GimpBlendTool
*blend_tool,
- gint
handle);
-static GimpGradientSegment * gimp_blend_tool_editor_handle_get_segment (GimpBlendTool
*blend_tool,
- gint
handle);
-
-static void gimp_blend_tool_editor_freeze_gradient (GimpBlendTool
*blend_tool);
-static void gimp_blend_tool_editor_thaw_gradient (GimpBlendTool
*blend_tool);
-
-static gint gimp_blend_tool_editor_add_stop (GimpBlendTool
*blend_tool,
- gdouble
value);
-static void gimp_blend_tool_editor_delete_stop (GimpBlendTool
*blend_tool,
- gint
slider);
-static gint gimp_blend_tool_editor_midpoint_to_stop (GimpBlendTool
*blend_tool,
- gint
slider);
-
-static void gimp_blend_tool_editor_update_sliders (GimpBlendTool
*blend_tool);
-
-static GtkWidget * gimp_blend_tool_editor_color_entry_new (GimpBlendTool
*blend_tool,
- const gchar
*title,
- Direction
direction,
- GtkWidget
*chain_button,
- GtkWidget
**color_panel,
- GtkWidget
**type_combo);
-static void gimp_blend_tool_editor_init_endpoint_gui (GimpBlendTool
*blend_tool);
-static void gimp_blend_tool_editor_init_stop_gui (GimpBlendTool
*blend_tool);
-static void gimp_blend_tool_editor_init_midpoint_gui (GimpBlendTool
*blend_tool);
-static void gimp_blend_tool_editor_update_endpoint_gui (GimpBlendTool
*blend_tool,
- gint
selection);
-static void gimp_blend_tool_editor_update_stop_gui (GimpBlendTool
*blend_tool,
- gint
selection);
-static void gimp_blend_tool_editor_update_midpoint_gui (GimpBlendTool
*blend_tool,
- gint
selection);
-static void gimp_blend_tool_editor_update_gui (GimpBlendTool
*blend_tool);
+static gboolean gimp_blend_tool_editor_line_can_add_slider (GimpToolLine
*line,
+ gdouble
value,
+ GimpBlendTool
*blend_tool);
+static gint gimp_blend_tool_editor_line_add_slider (GimpToolLine
*line,
+ gdouble
value,
+ GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_line_remove_slider (GimpToolLine
*line,
+ gint
slider,
+ GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_line_selection_changed (GimpToolLine
*line,
+ GimpBlendTool
*blend_tool);
+static gboolean gimp_blend_tool_editor_line_handle_clicked (GimpToolLine
*line,
+ gint
handle,
+ GdkModifierType
state,
+ GimpButtonPressType
press_type,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_gui_response (GimpToolGui
*gui,
+ gint
response_id,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_color_entry_color_clicked (GimpColorButton
*button,
+ GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_color_entry_color_changed (GimpColorButton
*button,
+ GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_color_entry_color_response (GimpColorButton
*button,
+ GimpColorDialogState
state,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_color_entry_type_changed (GtkComboBox
*combo,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_endpoint_se_value_changed (GimpSizeEntry
*se,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_stop_spinbutton_value_changed (GtkAdjustment
*adjustment,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_stop_delete_clicked (GtkWidget
*button,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_midpoint_spinbutton_value_changed (GtkAdjustment
*adjustment,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_midpoint_type_changed (GtkComboBox
*combo,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_midpoint_color_changed (GtkComboBox
*combo,
+ GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_midpoint_new_stop_clicked (GtkWidget
*button,
+ GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_midpoint_center_clicked (GtkWidget
*button,
+ GimpBlendTool
*blend_tool);
+
+static gboolean gimp_blend_tool_editor_flush_idle (GimpBlendTool
*blend_tool);
+
+static gboolean gimp_blend_tool_editor_is_gradient_editable (GimpBlendTool
*blend_tool);
+
+static gboolean gimp_blend_tool_editor_handle_is_endpoint (GimpBlendTool
*blend_tool,
+ gint
handle);
+static gboolean gimp_blend_tool_editor_handle_is_stop (GimpBlendTool
*blend_tool,
+ gint
handle);
+static gboolean gimp_blend_tool_editor_handle_is_midpoint (GimpBlendTool
*blend_tool,
+ gint
handle);
+static GimpGradientSegment * gimp_blend_tool_editor_handle_get_segment (GimpBlendTool
*blend_tool,
+ gint
handle);
+
+static void gimp_blend_tool_editor_freeze_gradient (GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_thaw_gradient (GimpBlendTool
*blend_tool);
+
+static gint gimp_blend_tool_editor_add_stop (GimpBlendTool
*blend_tool,
+ gdouble
value);
+static void gimp_blend_tool_editor_delete_stop (GimpBlendTool
*blend_tool,
+ gint
slider);
+static gint gimp_blend_tool_editor_midpoint_to_stop (GimpBlendTool
*blend_tool,
+ gint
slider);
+
+static void gimp_blend_tool_editor_update_sliders (GimpBlendTool
*blend_tool);
+
+static void gimp_blend_tool_editor_purge_gradient_history (GSList
**stack);
+static void gimp_blend_tool_editor_purge_gradient (GimpBlendTool
*blend_tool);
+
+static GtkWidget * gimp_blend_tool_editor_color_entry_new (GimpBlendTool
*blend_tool,
+ const gchar
*title,
+ Direction
direction,
+ GtkWidget
*chain_button,
+ GtkWidget
**color_panel,
+ GtkWidget
**type_combo);
+static void gimp_blend_tool_editor_init_endpoint_gui (GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_init_stop_gui (GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_init_midpoint_gui (GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_update_endpoint_gui (GimpBlendTool
*blend_tool,
+ gint
selection);
+static void gimp_blend_tool_editor_update_stop_gui (GimpBlendTool
*blend_tool,
+ gint
selection);
+static void gimp_blend_tool_editor_update_midpoint_gui (GimpBlendTool
*blend_tool,
+ gint
selection);
+static void gimp_blend_tool_editor_update_gui (GimpBlendTool
*blend_tool);
+
+static BlendInfo * gimp_blend_tool_editor_blend_info_new (GimpBlendTool
*blend_tool);
+static void gimp_blend_tool_editor_blend_info_free (BlendInfo
*info);
+static void gimp_blend_tool_editor_blend_info_apply (GimpBlendTool
*blend_tool,
+ const BlendInfo
*info,
+ gboolean
set_selection);
/* private functions */
@@ -283,6 +317,13 @@ gimp_blend_tool_editor_gui_response (GimpToolGui *gui,
}
static void
+gimp_blend_tool_editor_color_entry_color_clicked (GimpColorButton *button,
+ GimpBlendTool *blend_tool)
+{
+ gimp_blend_tool_editor_start_edit (blend_tool);
+}
+
+static void
gimp_blend_tool_editor_color_entry_color_changed (GimpColorButton *button,
GimpBlendTool *blend_tool)
{
@@ -367,6 +408,14 @@ gimp_blend_tool_editor_color_entry_color_changed (GimpColorButton *button,
}
static void
+gimp_blend_tool_editor_color_entry_color_response (GimpColorButton *button,
+ GimpColorDialogState state,
+ GimpBlendTool *blend_tool)
+{
+ gimp_blend_tool_editor_end_edit (blend_tool, FALSE);
+}
+
+static void
gimp_blend_tool_editor_color_entry_type_changed (GtkComboBox *combo,
GimpBlendTool *blend_tool)
{
@@ -444,7 +493,7 @@ gimp_blend_tool_editor_color_entry_type_changed (GtkComboBox *combo,
blend_tool->modifying = FALSE;
- gimp_blend_tool_editor_update_gui (blend_tool)
+ gimp_blend_tool_editor_update_gui (blend_tool);
}
static void
@@ -466,6 +515,8 @@ gimp_blend_tool_editor_endpoint_se_value_changed (GimpSizeEntry *se,
blend_tool->modifying = TRUE;
+ gimp_blend_tool_editor_start_edit (blend_tool);
+
switch (selection)
{
case GIMP_TOOL_LINE_HANDLE_START:
@@ -486,6 +537,8 @@ gimp_blend_tool_editor_endpoint_se_value_changed (GimpSizeEntry *se,
g_assert_not_reached ();
}
+ gimp_blend_tool_editor_end_edit (blend_tool, FALSE);
+
blend_tool->modifying = FALSE;
}
@@ -676,6 +729,18 @@ gimp_blend_tool_editor_midpoint_center_clicked (GtkWidget *button,
}
static gboolean
+gimp_blend_tool_editor_flush_idle (GimpBlendTool *blend_tool)
+{
+ GimpDisplay *display = GIMP_TOOL (blend_tool)->display;
+
+ gimp_image_flush (gimp_display_get_image (display));
+
+ blend_tool->flush_idle_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean
gimp_blend_tool_editor_is_gradient_editable (GimpBlendTool *blend_tool)
{
GimpBlendOptions *options = GIMP_BLEND_TOOL_GET_OPTIONS (blend_tool);
@@ -750,6 +815,7 @@ static void
gimp_blend_tool_editor_freeze_gradient (GimpBlendTool *blend_tool)
{
GimpBlendOptions *options = GIMP_BLEND_TOOL_GET_OPTIONS (blend_tool);
+ BlendInfo *info;
if (options->modify_active)
{
@@ -775,11 +841,26 @@ gimp_blend_tool_editor_freeze_gradient (GimpBlendTool *blend_tool)
g_assert (blend_tool->gradient == custom);
g_assert (gimp_blend_tool_editor_is_gradient_editable (blend_tool));
}
+
+ gimp_blend_tool_editor_start_edit (blend_tool);
+
+ info = blend_tool->undo_stack->data;
+
+ if (! info->gradient)
+ {
+ info->gradient =
+ GIMP_GRADIENT (gimp_data_duplicate (GIMP_DATA (blend_tool->gradient)));
+
+ info->selection =
+ gimp_tool_line_get_selection (GIMP_TOOL_LINE (blend_tool->widget));
+ }
}
static void
gimp_blend_tool_editor_thaw_gradient(GimpBlendTool *blend_tool)
{
+ gimp_blend_tool_editor_end_edit (blend_tool, FALSE);
+
gimp_data_thaw (GIMP_DATA (blend_tool->gradient));
}
@@ -957,6 +1038,41 @@ gimp_blend_tool_editor_update_sliders (GimpBlendTool *blend_tool)
blend_tool->modifying = FALSE;
}
+static void
+gimp_blend_tool_editor_purge_gradient_history (GSList **stack)
+{
+ GSList *link;
+
+ /* eliminate all history steps that modify the gradient */
+ while ((link = *stack))
+ {
+ BlendInfo *info = link->data;
+
+ if (info->gradient)
+ {
+ gimp_blend_tool_editor_blend_info_free (info);
+
+ *stack = g_slist_delete_link (*stack, link);
+ }
+ else
+ {
+ stack = &link->next;
+ }
+ }
+}
+
+static void
+gimp_blend_tool_editor_purge_gradient (GimpBlendTool *blend_tool)
+{
+ gimp_blend_tool_editor_update_sliders (blend_tool);
+
+ gimp_tool_line_set_selection (GIMP_TOOL_LINE (blend_tool->widget),
+ GIMP_TOOL_LINE_HANDLE_NONE);
+
+ gimp_blend_tool_editor_purge_gradient_history (&blend_tool->undo_stack);
+ gimp_blend_tool_editor_purge_gradient_history (&blend_tool->redo_stack);
+}
+
static GtkWidget *
gimp_blend_tool_editor_color_entry_new (GimpBlendTool *blend_tool,
const gchar *title,
@@ -989,9 +1105,15 @@ gimp_blend_tool_editor_color_entry_new (GimpBlendTool *blend_tool,
"gimp-blend-tool-editor-chain-button",
chain_button);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (gimp_blend_tool_editor_color_entry_color_clicked),
+ blend_tool);
g_signal_connect (button, "color-changed",
G_CALLBACK (gimp_blend_tool_editor_color_entry_color_changed),
blend_tool);
+ g_signal_connect (button, "response",
+ G_CALLBACK (gimp_blend_tool_editor_color_entry_color_response),
+ blend_tool);
/* the color type combo */
*type_combo = combo = gimp_enum_combo_box_new (GIMP_TYPE_GRADIENT_COLOR);
@@ -1663,6 +1785,91 @@ gimp_blend_tool_editor_update_gui (GimpBlendTool *blend_tool)
gimp_tool_gui_hide (blend_tool->gui);
}
+static BlendInfo *
+gimp_blend_tool_editor_blend_info_new (GimpBlendTool *blend_tool)
+{
+ BlendInfo *info = g_slice_new0 (BlendInfo);
+
+ info->start_x = blend_tool->start_x;
+ info->start_y = blend_tool->start_y;
+ info->end_x = blend_tool->end_x;
+ info->end_y = blend_tool->end_y;
+
+ return info;
+}
+
+static void
+gimp_blend_tool_editor_blend_info_free (BlendInfo *info)
+{
+ if (info->gradient)
+ g_object_unref (info->gradient);
+
+ g_slice_free (BlendInfo, info);
+}
+
+static void
+gimp_blend_tool_editor_blend_info_apply (GimpBlendTool *blend_tool,
+ const BlendInfo *info,
+ gboolean set_selection)
+{
+ gint selection;
+
+ g_assert (blend_tool->widget != NULL);
+ g_assert (blend_tool->gradient != NULL);
+ g_assert (! blend_tool->modifying);
+
+ blend_tool->modifying = TRUE;
+
+ /* pick the handle to select */
+ if (info->gradient)
+ {
+ selection = info->selection;
+ }
+ else if ((info->start_x != blend_tool->start_x ||
+ info->start_y != blend_tool->start_y) &&
+ (info->end_x == blend_tool->end_x &&
+ info->end_y == blend_tool->end_y))
+ {
+ selection = GIMP_TOOL_LINE_HANDLE_START;
+ }
+ else if ((info->end_x != blend_tool->end_x ||
+ info->end_y != blend_tool->end_y) &&
+ (info->start_x == blend_tool->start_x &&
+ info->start_y == blend_tool->start_y))
+
+ {
+ selection = GIMP_TOOL_LINE_HANDLE_END;
+ }
+ else
+ {
+ set_selection = FALSE;
+ }
+
+ g_object_set (blend_tool->widget,
+ "x1", info->start_x,
+ "y1", info->start_y,
+ "x2", info->end_x,
+ "y2", info->end_y,
+ NULL);
+
+ if (info->gradient)
+ {
+ gimp_data_copy (GIMP_DATA (blend_tool->gradient),
+ GIMP_DATA (info->gradient));
+ }
+
+ blend_tool->modifying = FALSE;
+
+ gimp_blend_tool_editor_update_sliders (blend_tool);
+ gimp_blend_tool_editor_update_gui (blend_tool);
+
+ if (set_selection)
+ {
+ gimp_tool_line_set_selection (GIMP_TOOL_LINE (blend_tool->widget),
+ selection);
+ }
+}
+
/* public functions */
@@ -1734,6 +1941,28 @@ void
gimp_blend_tool_editor_halt (GimpBlendTool *blend_tool)
{
g_clear_object (&blend_tool->gui);
+
+ blend_tool->edit_count = 0;
+
+ if (blend_tool->undo_stack)
+ {
+ g_slist_free_full (blend_tool->undo_stack,
+ (GDestroyNotify) gimp_blend_tool_editor_blend_info_free);
+ blend_tool->undo_stack = NULL;
+ }
+
+ if (blend_tool->redo_stack)
+ {
+ g_slist_free_full (blend_tool->redo_stack,
+ (GDestroyNotify) gimp_blend_tool_editor_blend_info_free);
+ blend_tool->redo_stack = NULL;
+ }
+
+ if (blend_tool->flush_idle_id)
+ {
+ g_source_remove (blend_tool->flush_idle_id);
+ blend_tool->flush_idle_id = 0;
+ }
}
void
@@ -1844,12 +2073,7 @@ void
gimp_blend_tool_editor_gradient_dirty (GimpBlendTool *blend_tool)
{
if (blend_tool->widget && ! blend_tool->modifying)
- {
- gimp_blend_tool_editor_update_sliders (blend_tool);
-
- gimp_tool_line_set_selection (GIMP_TOOL_LINE (blend_tool->widget),
- GIMP_TOOL_LINE_HANDLE_NONE);
- }
+ gimp_blend_tool_editor_purge_gradient (blend_tool);
}
void
@@ -1873,10 +2097,138 @@ gimp_blend_tool_editor_gradient_changed (GimpBlendTool *blend_tool)
}
if (blend_tool->widget && ! blend_tool->modifying)
+ gimp_blend_tool_editor_purge_gradient (blend_tool);
+}
+
+const gchar *
+gimp_blend_tool_editor_can_undo (GimpBlendTool *blend_tool)
+{
+ if (! blend_tool->undo_stack || blend_tool->edit_count > 0)
+ return NULL;
+
+ return _("Blend Step");
+}
+
+const gchar *
+gimp_blend_tool_editor_can_redo (GimpBlendTool *blend_tool)
+{
+ if (! blend_tool->redo_stack || blend_tool->edit_count > 0)
+ return NULL;
+
+ return _("Blend Step");
+}
+
+gboolean
+gimp_blend_tool_editor_undo (GimpBlendTool *blend_tool)
+{
+ BlendInfo *info;
+ BlendInfo *new_info;
+
+ g_assert (blend_tool->undo_stack != NULL);
+ g_assert (blend_tool->edit_count == 0);
+
+ info = blend_tool->undo_stack->data;
+
+ new_info = gimp_blend_tool_editor_blend_info_new (blend_tool);
+
+ if (info->gradient)
{
- gimp_blend_tool_editor_update_sliders (blend_tool);
+ new_info->gradient =
+ GIMP_GRADIENT (gimp_data_duplicate (GIMP_DATA (blend_tool->gradient)));
+ }
- gimp_tool_line_set_selection (GIMP_TOOL_LINE (blend_tool->widget),
- GIMP_TOOL_LINE_HANDLE_NONE);
+ blend_tool->undo_stack = g_slist_remove (blend_tool->undo_stack, info);
+ blend_tool->redo_stack = g_slist_prepend (blend_tool->redo_stack, new_info);
+
+ gimp_blend_tool_editor_blend_info_apply (blend_tool, info, TRUE);
+ gimp_blend_tool_editor_blend_info_free (info);
+
+ return TRUE;
+}
+
+gboolean
+gimp_blend_tool_editor_redo (GimpBlendTool *blend_tool)
+{
+ BlendInfo *info;
+ BlendInfo *new_info;
+
+ g_assert (blend_tool->redo_stack != NULL);
+ g_assert (blend_tool->edit_count == 0);
+
+ info = blend_tool->redo_stack->data;
+
+ new_info = gimp_blend_tool_editor_blend_info_new (blend_tool);
+
+ if (info->gradient)
+ {
+ new_info->gradient =
+ GIMP_GRADIENT (gimp_data_duplicate (GIMP_DATA (blend_tool->gradient)));
+ }
+
+ blend_tool->redo_stack = g_slist_remove (blend_tool->redo_stack, info);
+ blend_tool->undo_stack = g_slist_prepend (blend_tool->undo_stack, new_info);
+
+ gimp_blend_tool_editor_blend_info_apply (blend_tool, info, TRUE);
+ gimp_blend_tool_editor_blend_info_free (info);
+
+ return TRUE;
+}
+
+void
+gimp_blend_tool_editor_start_edit (GimpBlendTool *blend_tool)
+{
+ if (blend_tool->edit_count++ == 0)
+ {
+ BlendInfo *info;
+
+ info = gimp_blend_tool_editor_blend_info_new (blend_tool);
+
+ blend_tool->undo_stack = g_slist_prepend (blend_tool->undo_stack, info);
+ }
+}
+
+void
+gimp_blend_tool_editor_end_edit (GimpBlendTool *blend_tool,
+ gboolean cancel)
+{
+ /* can happen when halting using esc */
+ if (blend_tool->edit_count == 0)
+ return;
+
+ if (--blend_tool->edit_count == 0)
+ {
+ BlendInfo *info = blend_tool->undo_stack->data;
+
+ if (cancel ||
+ (info->start_x == blend_tool->start_x &&
+ info->start_y == blend_tool->start_y &&
+ info->end_x == blend_tool->end_x &&
+ info->end_y == blend_tool->end_y &&
+ ! info->gradient))
+ {
+ /* if the edit is canceled, or if nothing changed, undo the last
+ * step
+ */
+ gimp_blend_tool_editor_blend_info_apply (blend_tool, info, FALSE);
+
+ blend_tool->undo_stack = g_slist_remove (blend_tool->undo_stack,
+ info);
+ gimp_blend_tool_editor_blend_info_free (info);
+ }
+ else
+ {
+ /* otherwise, blow the redo stack */
+ g_slist_free_full (blend_tool->redo_stack,
+ (GDestroyNotify) gimp_blend_tool_editor_blend_info_free);
+ blend_tool->redo_stack = NULL;
+ }
+
+ /* update the undo actions / menu items */
+ if (! blend_tool->flush_idle_id)
+ {
+ blend_tool->flush_idle_id =
+ g_idle_add ((GSourceFunc) gimp_blend_tool_editor_flush_idle,
+ blend_tool);
+ }
}
}
diff --git a/app/tools/gimpblendtool-editor.h b/app/tools/gimpblendtool-editor.h
index fc7bcf2..c72fa47 100644
--- a/app/tools/gimpblendtool-editor.h
+++ b/app/tools/gimpblendtool-editor.h
@@ -19,18 +19,28 @@
#define __GIMP_BLEND_TOOL_EDITOR_H__
-void gimp_blend_tool_editor_options_notify (GimpBlendTool *blend_tool,
- GimpToolOptions *options,
- const GParamSpec *pspec);
+void gimp_blend_tool_editor_options_notify (GimpBlendTool *blend_tool,
+ GimpToolOptions *options,
+ const GParamSpec *pspec);
-void gimp_blend_tool_editor_start (GimpBlendTool *blend_tool);
-void gimp_blend_tool_editor_halt (GimpBlendTool *blend_tool);
+void gimp_blend_tool_editor_start (GimpBlendTool *blend_tool);
+void gimp_blend_tool_editor_halt (GimpBlendTool *blend_tool);
-void gimp_blend_tool_editor_line_changed (GimpBlendTool *blend_tool);
+void gimp_blend_tool_editor_line_changed (GimpBlendTool *blend_tool);
-void gimp_blend_tool_editor_gradient_dirty (GimpBlendTool *blend_tool);
+void gimp_blend_tool_editor_gradient_dirty (GimpBlendTool *blend_tool);
-void gimp_blend_tool_editor_gradient_changed (GimpBlendTool *blend_tool);
+void gimp_blend_tool_editor_gradient_changed (GimpBlendTool *blend_tool);
+
+const gchar * gimp_blend_tool_editor_can_undo (GimpBlendTool *blend_tool);
+const gchar * gimp_blend_tool_editor_can_redo (GimpBlendTool *blend_tool);
+
+gboolean gimp_blend_tool_editor_undo (GimpBlendTool *blend_tool);
+gboolean gimp_blend_tool_editor_redo (GimpBlendTool *blend_tool);
+
+void gimp_blend_tool_editor_start_edit (GimpBlendTool *blend_tool);
+void gimp_blend_tool_editor_end_edit (GimpBlendTool *blend_tool,
+ gboolean cancel);
#endif /* __GIMP_BLEND_TOOL_EDITOR_H__ */
diff --git a/app/tools/gimpblendtool.c b/app/tools/gimpblendtool.c
index b225ef1..3c6f6b4 100644
--- a/app/tools/gimpblendtool.c
+++ b/app/tools/gimpblendtool.c
@@ -53,17 +53,6 @@
#include "gimp-intl.h"
-typedef struct _BlendInfo BlendInfo;
-
-struct _BlendInfo
-{
- gdouble start_x;
- gdouble start_y;
- gdouble end_x;
- gdouble end_y;
-};
-
-
/* local function prototypes */
static void gimp_blend_tool_dispose (GObject *object);
@@ -91,6 +80,9 @@ static void gimp_blend_tool_motion (GimpTool *tool,
guint32 time,
GdkModifierType state,
GimpDisplay *display);
+static gboolean gimp_blend_tool_key_press (GimpTool *tool,
+ GdkEventKey *kevent,
+ GimpDisplay *display);
static void gimp_blend_tool_modifier_key (GimpTool *tool,
GdkModifierType key,
gboolean press,
@@ -140,12 +132,6 @@ static void gimp_blend_tool_create_filter (GimpBlendTool *blend_
static void gimp_blend_tool_filter_flush (GimpDrawableFilter *filter,
GimpTool *tool);
-static BlendInfo * blend_info_new (gdouble start_x,
- gdouble start_y,
- gdouble end_x,
- gdouble end_y);
-static void blend_info_free (BlendInfo *info);
-
G_DEFINE_TYPE (GimpBlendTool, gimp_blend_tool, GIMP_TYPE_DRAW_TOOL)
@@ -186,6 +172,7 @@ gimp_blend_tool_class_init (GimpBlendToolClass *klass)
tool_class->button_press = gimp_blend_tool_button_press;
tool_class->button_release = gimp_blend_tool_button_release;
tool_class->motion = gimp_blend_tool_motion;
+ tool_class->key_press = gimp_blend_tool_key_press;
tool_class->modifier_key = gimp_blend_tool_modifier_key;
tool_class->cursor_update = gimp_blend_tool_cursor_update;
tool_class->can_undo = gimp_blend_tool_can_undo;
@@ -310,11 +297,8 @@ gimp_blend_tool_button_press (GimpTool *tool,
GimpButtonPressType press_type,
GimpDisplay *display)
{
- GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);
- gdouble start_x;
- gdouble start_y;
- gdouble end_x;
- gdouble end_y;
+ GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);
+ GimpBlendOptions *options = GIMP_BLEND_TOOL_GET_OPTIONS (tool);
if (tool->display && display != tool->display)
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);
@@ -326,21 +310,18 @@ gimp_blend_tool_button_press (GimpTool *tool,
gimp_tool_widget_hover (blend_tool->widget, coords, state, TRUE);
}
- /* save the current line for undo, widget_button_press() might change it
+ /* call start_edit() before widget_button_press(), because we need to record
+ * the undo state before widget_button_press() potentially changes it. note
+ * that if widget_button_press() return FALSE, nothing changes and no undo
+ * step is created.
*/
- start_x = blend_tool->start_x;
- start_y = blend_tool->start_y;
- end_x = blend_tool->end_x;
- end_y = blend_tool->end_y;
+ if (press_type == GIMP_BUTTON_PRESS_NORMAL)
+ gimp_blend_tool_editor_start_edit (blend_tool);
if (gimp_tool_widget_button_press (blend_tool->widget, coords, time, state,
press_type))
{
blend_tool->grab_widget = blend_tool->widget;
-
- blend_tool->undo_stack =
- g_list_prepend (blend_tool->undo_stack,
- blend_info_new (start_x, start_y, end_x, end_y));
}
if (press_type == GIMP_BUTTON_PRESS_NORMAL)
@@ -375,32 +356,13 @@ gimp_blend_tool_button_release (GimpTool *tool,
else
gimp_tool_control (tool, GIMP_TOOL_ACTION_COMMIT, display);
}
- else
- {
- if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
- {
- /* simply destroy the undo step we pushed in button_press(),
- * the tool widget restored the old position by itself
- */
- blend_info_free (blend_tool->undo_stack->data);
- blend_tool->undo_stack = g_list_remove (blend_tool->undo_stack,
- blend_tool->undo_stack->data);
- }
- else
- {
- /* blow the redo stack, we had an actual undoable movement
- */
- if (blend_tool->redo_stack)
- {
- g_list_free_full (blend_tool->redo_stack,
- (GDestroyNotify) blend_info_free);
- blend_tool->redo_stack = NULL;
- }
- }
-
- /* update the undo actions / menu items */
- gimp_image_flush (gimp_display_get_image (display));
- }
+ }
+
+ if (! options->instant)
+ {
+ gimp_blend_tool_editor_end_edit (blend_tool,
+ release_type ==
+ GIMP_BUTTON_RELEASE_CANCEL);
}
}
@@ -419,6 +381,31 @@ gimp_blend_tool_motion (GimpTool *tool,
}
}
+static gboolean
+gimp_blend_tool_key_press (GimpTool *tool,
+ GdkEventKey *kevent,
+ GimpDisplay *display)
+{
+ GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);
+ GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
+ gboolean result;
+
+ /* call start_edit() before widget_key_press(), because we need to record the
+ * undo state before widget_key_press() potentially changes it. note that if
+ * widget_key_press() return FALSE, nothing changes and no undo step is
+ * created.
+ */
+ if (display == draw_tool->display)
+ gimp_blend_tool_editor_start_edit (blend_tool);
+
+ result = GIMP_TOOL_CLASS (parent_class)->key_press (tool, kevent, display);
+
+ if (display == draw_tool->display)
+ gimp_blend_tool_editor_end_edit (blend_tool, FALSE);
+
+ return result;
+}
+
static void
gimp_blend_tool_modifier_key (GimpTool *tool,
GdkModifierType key,
@@ -466,80 +453,28 @@ static const gchar *
gimp_blend_tool_can_undo (GimpTool *tool,
GimpDisplay *display)
{
- GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);
-
- if (! blend_tool->undo_stack)
- return NULL;
-
- return _("Blend Step");
+ return gimp_blend_tool_editor_can_undo (GIMP_BLEND_TOOL (tool));
}
static const gchar *
gimp_blend_tool_can_redo (GimpTool *tool,
GimpDisplay *display)
{
- GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);
-
- if (! blend_tool->redo_stack)
- return NULL;
-
- return _("Blend Step");
+ return gimp_blend_tool_editor_can_redo (GIMP_BLEND_TOOL (tool));
}
static gboolean
gimp_blend_tool_undo (GimpTool *tool,
GimpDisplay *display)
{
- GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);
- BlendInfo *info;
-
- info = blend_info_new (blend_tool->start_x,
- blend_tool->start_y,
- blend_tool->end_x,
- blend_tool->end_y);
- blend_tool->redo_stack = g_list_prepend (blend_tool->redo_stack, info);
-
- info = blend_tool->undo_stack->data;
-
- g_object_set (blend_tool->widget,
- "x1", info->start_x,
- "y1", info->start_y,
- "x2", info->end_x,
- "y2", info->end_y,
- NULL);
-
- blend_tool->undo_stack = g_list_remove (blend_tool->undo_stack, info);
- blend_info_free (info);
-
- return TRUE;
+ return gimp_blend_tool_editor_undo (GIMP_BLEND_TOOL (tool));
}
static gboolean
gimp_blend_tool_redo (GimpTool *tool,
GimpDisplay *display)
{
- GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);
- BlendInfo *info;
-
- info = blend_info_new (blend_tool->start_x,
- blend_tool->start_y,
- blend_tool->end_x,
- blend_tool->end_y);
- blend_tool->undo_stack = g_list_prepend (blend_tool->undo_stack, info);
-
- info = blend_tool->redo_stack->data;
-
- g_object_set (blend_tool->widget,
- "x1", info->start_x,
- "y1", info->start_y,
- "x2", info->end_x,
- "y2", info->end_y,
- NULL);
-
- blend_tool->redo_stack = g_list_remove (blend_tool->redo_stack, info);
- blend_info_free (info);
-
- return TRUE;
+ return gimp_blend_tool_editor_redo (GIMP_BLEND_TOOL (tool));
}
static void
@@ -691,20 +626,6 @@ gimp_blend_tool_halt (GimpBlendTool *blend_tool)
gimp_image_flush (gimp_display_get_image (tool->display));
}
- if (blend_tool->undo_stack)
- {
- g_list_free_full (blend_tool->undo_stack,
- (GDestroyNotify) blend_info_free);
- blend_tool->undo_stack = NULL;
- }
-
- if (blend_tool->redo_stack)
- {
- g_list_free_full (blend_tool->redo_stack,
- (GDestroyNotify) blend_info_free);
- blend_tool->redo_stack = NULL;
- }
-
if (tool->display)
gimp_tool_pop_status (tool, tool->display);
@@ -1018,25 +939,3 @@ gimp_blend_tool_filter_flush (GimpDrawableFilter *filter,
gimp_projection_flush (gimp_image_get_projection (image));
}
-
-static BlendInfo *
-blend_info_new (gdouble start_x,
- gdouble start_y,
- gdouble end_x,
- gdouble end_y)
-{
- BlendInfo *info = g_slice_new0 (BlendInfo);
-
- info->start_x = start_x;
- info->start_y = start_y;
- info->end_x = end_x;
- info->end_y = end_y;
-
- return info;
-}
-
-static void
-blend_info_free (BlendInfo *info)
-{
- g_slice_free (BlendInfo, info);
-}
diff --git a/app/tools/gimpblendtool.h b/app/tools/gimpblendtool.h
index 28b58fa..25d58ef 100644
--- a/app/tools/gimpblendtool.h
+++ b/app/tools/gimpblendtool.h
@@ -46,9 +46,6 @@ struct _GimpBlendTool
gdouble end_x; /* ending x coord */
gdouble end_y; /* ending y coord */
- GList *undo_stack;
- GList *redo_stack;
-
GimpToolWidget *widget;
GimpToolWidget *grab_widget;
@@ -66,6 +63,12 @@ struct _GimpBlendTool
gboolean modifying;
+ gint edit_count;
+ GSList *undo_stack;
+ GSList *redo_stack;
+
+ guint flush_idle_id;
+
GimpToolGui *gui;
GtkWidget *endpoint_editor;
GtkWidget *endpoint_se;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]