Moved the undo system to the core: Keep GimpUndoStack objects as undo and

2003-02-12  Michael Natterer  <mitch@gimp.org>

	Moved the undo system to the core: Keep GimpUndoStack objects as
	undo and redo stack. Use GimpUndo objects as members of the
	stacks. GimpUndoStack is derived from GimpUndo and keeps undo
	groups, so undo group handling is much simpler than before
	(the whole group is just a single GimpUndo object on the
	stack and not everything between group boundary markers).

	* app/Makefile.am
	* app/undo_types.h: removed.

	* app/config/gimpcoreconfig.[ch]: added "gulong undo_size".
	* app/config/gimprc-blurbs.h: and its blurb.

	* app/core/core-enums.[ch]: added GimpUndoMode and GimpUndoType.

	* app/core/core-types.h: removed UndoType, added GimpUndoAccumulator,
	GimpUndoPopFunc and GimpUndoFreeFunc.

	* app/core/gimpundo.[ch]: do everything the old "Undo" struct did.
	Removed the virtual push() function and added free().

	* app/core/gimpundostack.[ch]: keeps the new undo/redo stacks
	and also acts as undo group.

	* app/core/gimpimage-undo.[ch]: moved the undo apparatus here.

	* app/core/gimpimage.[ch]: removed the old stuff.

	* app/core/gimpmarshal.list: added marshaller needed for GimpUndo.

	* app/undo.[ch]: removed the whole undo mechanism. Only the
	actual undo pushing functions are left.

	* app/undo_history.c
	* app/gui/edit-commands.c
	* app/gui/file-commands.c
	* app/gui/image-menu.c
	* app/gui/preferences-dialog.c
	* app/tools/gimpeditselectiontool.c: changed accordingly.
This commit is contained in:
Michael Natterer 2003-02-12 17:11:34 +00:00 committed by Michael Natterer
parent 4858a3750b
commit be70105d3b
32 changed files with 2677 additions and 3249 deletions

View File

@ -1,3 +1,37 @@
2003-02-12 Michael Natterer <mitch@gimp.org>
Undo chopping:
* app/Makefile.am
* app/undo_types.h: removed.
* app/config/gimpcoreconfig.[ch]: added "gulong undo_size".
* app/config/gimprc-blurbs.h: and its blurb.
* app/undo.[ch]
* app/core/core-enums.[ch]: added GimpUndoMode and GimpUndoType.
* app/core/core-types.h: removed UndoType, added GimpUndoAccumulator,
GimpUndoPopFunc and GimpUndoFreeFunc.
* app/core/gimpundo.[ch]: do everything the old "Undo" struct did.
Removed the virtual push() function and added free().
* app/core/gimpundostack.[ch]: keeps the new undo/redo stacks
and also acts as undo group.
* app/core/gimpimage-undo.[ch]
* app/core/gimpimage.[ch]
* app/core/gimpmarshal.list
* app/undo_history.c
* app/gui/edit-commands.c
* app/gui/file-commands.c
* app/gui/image-menu.c
* app/gui/preferences-dialog.c
* app/tools/gimpeditselectiontool.c: changed accordingly.
2003-02-12 Sven Neumann <sven@gimp.org>
* app/Makefile.am

View File

@ -53,8 +53,7 @@ bye_sources = \
pathP.h \
path_transform.h \
undo.c \
undo.h \
undo_types.h
undo.h
##
## stuff

View File

@ -34,6 +34,7 @@
#include "core/gimpedit.h"
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
#include "core/gimpimage-undo.h"
#include "display/gimpdisplay.h"
@ -42,8 +43,6 @@
#include "dialogs.h"
#include "edit-commands.h"
#include "undo.h"
#include "libgimp/gimpintl.h"
@ -87,7 +86,7 @@ edit_undo_cmd_callback (GtkWidget *widget,
GimpImage *gimage;
return_if_no_image (gimage, data);
if (undo_pop (gimage))
if (gimp_image_undo (gimage))
gimp_image_flush (gimage);
}
@ -98,7 +97,7 @@ edit_redo_cmd_callback (GtkWidget *widget,
GimpImage *gimage;
return_if_no_image (gimage, data);
if (undo_redo (gimage))
if (gimp_image_redo (gimage))
gimp_image_flush (gimage);
}

View File

@ -30,6 +30,7 @@
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
#include "core/gimpimage-undo.h"
#include "core/gimpobject.h"
#include "file/file-open.h"
@ -365,7 +366,7 @@ file_revert_confirm_callback (GtkWidget *widget,
if (new_gimage)
{
undo_free (new_gimage);
gimp_image_undo_free (new_gimage);
gimp_displays_reconnect (old_gimage->gimp, old_gimage, new_gimage);

View File

@ -80,6 +80,7 @@ enum
PROP_DEFAULT_YRESOLUTION,
PROP_DEFAULT_RESOLUTION_UNIT,
PROP_UNDO_LEVELS,
PROP_UNDO_SIZE,
PROP_PLUGINRC_PATH,
PROP_MODULE_LOAD_INHIBIT,
PROP_PREVIEW_SIZE,
@ -239,6 +240,10 @@ gimp_core_config_class_init (GimpCoreConfigClass *klass)
"undo-levels", UNDO_LEVELS_BLURB,
0, G_MAXINT, 5,
GIMP_PARAM_CONFIRM);
GIMP_CONFIG_INSTALL_PROP_MEMSIZE (object_class, PROP_UNDO_SIZE,
"undo-size", UNDO_SIZE_BLURB,
0, G_MAXULONG, 1 << 20,
GIMP_PARAM_CONFIRM);
GIMP_CONFIG_INSTALL_PROP_PATH (object_class,
PROP_PLUGINRC_PATH,
"pluginrc-path", PLUGINRC_PATH_BLURB,
@ -392,6 +397,9 @@ gimp_core_config_set_property (GObject *object,
case PROP_UNDO_LEVELS:
core_config->levels_of_undo = g_value_get_int (value);
break;
case PROP_UNDO_SIZE:
core_config->undo_size = g_value_get_ulong (value);
break;
case PROP_PLUGINRC_PATH:
g_free (core_config->plug_in_rc_path);
core_config->plug_in_rc_path = g_value_dup_string (value);
@ -500,6 +508,9 @@ gimp_core_config_get_property (GObject *object,
case PROP_UNDO_LEVELS:
g_value_set_int (value, core_config->levels_of_undo);
break;
case PROP_UNDO_SIZE:
g_value_set_ulong (value, core_config->undo_size);
break;
case PROP_PLUGINRC_PATH:
g_value_set_string (value, core_config->plug_in_rc_path);
break;

View File

@ -62,6 +62,7 @@ struct _GimpCoreConfig
gdouble default_yresolution;
GimpUnit default_resolution_unit;
gint levels_of_undo;
gulong undo_size;
gchar *plug_in_rc_path;
gchar *module_load_inhibit;
GimpPreviewSize preview_size;

View File

@ -299,6 +299,9 @@ N_("When set to yes, the GIMP will not save if the image is unchanged since " \
#define UNDO_LEVELS_BLURB \
N_("Sets the number of operations kept on the undo stack.")
#define UNDO_SIZE_BLURB \
N_("Sets the maximum memory used by operations kept on the undo stack.")
#define USE_HELP_BLURB \
N_("When set to no the F1 help binding will be disabled.")

View File

@ -362,6 +362,101 @@ gimp_channel_ops_get_type (void)
}
static const GEnumValue gimp_undo_mode_enum_values[] =
{
{ GIMP_UNDO_MODE_UNDO, "GIMP_UNDO_MODE_UNDO", "undo" },
{ GIMP_UNDO_MODE_REDO, "GIMP_UNDO_MODE_REDO", "redo" },
{ 0, NULL, NULL }
};
GType
gimp_undo_mode_get_type (void)
{
static GType enum_type = 0;
if (!enum_type)
enum_type = g_enum_register_static ("GimpUndoMode", gimp_undo_mode_enum_values);
return enum_type;
}
static const GEnumValue gimp_undo_type_enum_values[] =
{
{ NO_UNDO_GROUP, N_("<<invalid>>"), "no-undo-group" },
{ FIRST_UNDO_GROUP, "FIRST_UNDO_GROUP", "first-undo-group" },
{ IMAGE_SCALE_UNDO_GROUP, N_("Scale Image"), "image-scale-undo-group" },
{ IMAGE_RESIZE_UNDO_GROUP, N_("Resize Image"), "image-resize-undo-group" },
{ IMAGE_CONVERT_UNDO_GROUP, N_("Convert Image"), "image-convert-undo-group" },
{ IMAGE_CROP_UNDO_GROUP, N_("Crop Image"), "image-crop-undo-group" },
{ IMAGE_LAYERS_MERGE_UNDO_GROUP, N_("Merge Layers"), "image-layers-merge-undo-group" },
{ IMAGE_QMASK_UNDO_GROUP, N_("QuickMask"), "image-qmask-undo-group" },
{ IMAGE_GUIDE_UNDO_GROUP, N_("Guide"), "image-guide-undo-group" },
{ LAYER_PROPERTIES_UNDO_GROUP, N_("Layer Properties"), "layer-properties-undo-group" },
{ LAYER_SCALE_UNDO_GROUP, N_("Scale Layer"), "layer-scale-undo-group" },
{ LAYER_RESIZE_UNDO_GROUP, N_("Resize Layer"), "layer-resize-undo-group" },
{ LAYER_DISPLACE_UNDO_GROUP, N_("Move Layer"), "layer-displace-undo-group" },
{ LAYER_LINKED_UNDO_GROUP, N_("Linked Layer"), "layer-linked-undo-group" },
{ LAYER_APPLY_MASK_UNDO_GROUP, N_("Apply Layer Mask"), "layer-apply-mask-undo-group" },
{ FS_FLOAT_UNDO_GROUP, N_("Float Selection"), "fs-float-undo-group" },
{ FS_ANCHOR_UNDO_GROUP, N_("Anchor Floating Selection"), "fs-anchor-undo-group" },
{ EDIT_PASTE_UNDO_GROUP, N_("Paste"), "edit-paste-undo-group" },
{ EDIT_CUT_UNDO_GROUP, N_("Cut"), "edit-cut-undo-group" },
{ EDIT_COPY_UNDO_GROUP, N_("Copy"), "edit-copy-undo-group" },
{ TEXT_UNDO_GROUP, N_("Text"), "text-undo-group" },
{ TRANSFORM_UNDO_GROUP, N_("Transform"), "transform-undo-group" },
{ PAINT_UNDO_GROUP, N_("Paint"), "paint-undo-group" },
{ PARASITE_ATTACH_UNDO_GROUP, N_("Attach Parasite"), "parasite-attach-undo-group" },
{ PARASITE_REMOVE_UNDO_GROUP, N_("Remove Parasite"), "parasite-remove-undo-group" },
{ MISC_UNDO_GROUP, N_("Plug-In"), "misc-undo-group" },
{ LAST_UNDO_GROUP, "LAST_UNDO_GROUP", "last-undo-group" },
{ IMAGE_UNDO, N_("Image"), "image-undo" },
{ IMAGE_MOD_UNDO, N_("Image Mod"), "image-mod-undo" },
{ IMAGE_TYPE_UNDO, N_("Image Type"), "image-type-undo" },
{ IMAGE_SIZE_UNDO, N_("Image Size"), "image-size-undo" },
{ IMAGE_RESOLUTION_UNDO, N_("Resolution Change"), "image-resolution-undo" },
{ IMAGE_QMASK_UNDO, N_("QuickMask"), "image-qmask-undo" },
{ IMAGE_GUIDE_UNDO, N_("Guide"), "image-guide-undo" },
{ MASK_UNDO, N_("Selection Mask"), "mask-undo" },
{ ITEM_RENAME_UNDO, N_("Rename Item"), "item-rename-undo" },
{ LAYER_ADD_UNDO, N_("New Layer"), "layer-add-undo" },
{ LAYER_REMOVE_UNDO, N_("Delete Layer"), "layer-remove-undo" },
{ LAYER_MOD_UNDO, N_("Layer Mod"), "layer-mod-undo" },
{ LAYER_MASK_ADD_UNDO, N_("Add Layer Mask"), "layer-mask-add-undo" },
{ LAYER_MASK_REMOVE_UNDO, N_("Delete Layer Mask"), "layer-mask-remove-undo" },
{ LAYER_REPOSITION_UNDO, N_("Layer Reposition"), "layer-reposition-undo" },
{ LAYER_DISPLACE_UNDO, N_("Layer Move"), "layer-displace-undo" },
{ CHANNEL_ADD_UNDO, N_("New Channel"), "channel-add-undo" },
{ CHANNEL_REMOVE_UNDO, N_("Delete Channel"), "channel-remove-undo" },
{ CHANNEL_MOD_UNDO, N_("Channel Mod"), "channel-mod-undo" },
{ CHANNEL_REPOSITION_UNDO, N_("Channel Reposition"), "channel-reposition-undo" },
{ VECTORS_ADD_UNDO, N_("New Vectors"), "vectors-add-undo" },
{ VECTORS_REMOVE_UNDO, N_("Delete Vectors"), "vectors-remove-undo" },
{ VECTORS_MOD_UNDO, N_("Vectors Mod"), "vectors-mod-undo" },
{ VECTORS_REPOSITION_UNDO, N_("Vectors Reposition"), "vectors-reposition-undo" },
{ FS_TO_LAYER_UNDO, N_("FS to Layer"), "fs-to-layer-undo" },
{ FS_RIGOR_UNDO, N_("FS Rigor"), "fs-rigor-undo" },
{ FS_RELAX_UNDO, N_("FS Relax"), "fs-relax-undo" },
{ TRANSFORM_UNDO, N_("Transform"), "transform-undo" },
{ PAINT_UNDO, N_("Paint"), "paint-undo" },
{ PARASITE_ATTACH_UNDO, N_("Attach Parasite"), "parasite-attach-undo" },
{ PARASITE_REMOVE_UNDO, N_("Remove Parasite"), "parasite-remove-undo" },
{ CANT_UNDO, N_("EEK: can't undo"), "cant-undo" },
{ 0, NULL, NULL }
};
GType
gimp_undo_type_get_type (void)
{
static GType enum_type = 0;
if (!enum_type)
enum_type = g_enum_register_static ("GimpUndoType", gimp_undo_type_enum_values);
return enum_type;
}
static const GEnumValue gimp_convert_palette_type_enum_values[] =
{
{ GIMP_MAKE_PALETTE, "GIMP_MAKE_PALETTE", "make-palette" },

View File

@ -267,6 +267,95 @@ typedef enum /*< proxy-resume >*/
} GimpChannelOps;
#define GIMP_TYPE_UNDO_MODE (gimp_undo_mode_get_type ())
GType gimp_undo_mode_get_type (void) G_GNUC_CONST;
typedef enum /*< proxy-skip >*/ /*< pdb-skip >*/
{
GIMP_UNDO_MODE_UNDO,
GIMP_UNDO_MODE_REDO
} GimpUndoMode;
#define GIMP_TYPE_UNDO_TYPE (gimp_undo_type_get_type ())
GType gimp_undo_type_get_type (void) G_GNUC_CONST;
typedef enum /*< pdb-skip >*/
{
/* Type NO_UNDO_GROUP (0) is special - in the gimpimage structure it
* means there is no undo group currently being added to.
*/
NO_UNDO_GROUP = 0, /*< desc="<<invalid>>" >*/
FIRST_UNDO_GROUP = NO_UNDO_GROUP,
IMAGE_SCALE_UNDO_GROUP, /*< desc="Scale Image" >*/
IMAGE_RESIZE_UNDO_GROUP, /*< desc="Resize Image" >*/
IMAGE_CONVERT_UNDO_GROUP, /*< desc="Convert Image" >*/
IMAGE_CROP_UNDO_GROUP, /*< desc="Crop Image" >*/
IMAGE_LAYERS_MERGE_UNDO_GROUP, /*< desc="Merge Layers" >*/
IMAGE_QMASK_UNDO_GROUP, /*< desc="QuickMask" >*/
IMAGE_GUIDE_UNDO_GROUP, /*< desc="Guide" >*/
LAYER_PROPERTIES_UNDO_GROUP, /*< desc="Layer Properties" >*/
LAYER_SCALE_UNDO_GROUP, /*< desc="Scale Layer" >*/
LAYER_RESIZE_UNDO_GROUP, /*< desc="Resize Layer" >*/
LAYER_DISPLACE_UNDO_GROUP, /*< desc="Move Layer" >*/
LAYER_LINKED_UNDO_GROUP, /*< desc="Linked Layer" >*/
LAYER_APPLY_MASK_UNDO_GROUP, /*< desc="Apply Layer Mask" >*/
FS_FLOAT_UNDO_GROUP, /*< desc="Float Selection" >*/
FS_ANCHOR_UNDO_GROUP, /*< desc="Anchor Floating Selection" >*/
EDIT_PASTE_UNDO_GROUP, /*< desc="Paste" >*/
EDIT_CUT_UNDO_GROUP, /*< desc="Cut" >*/
EDIT_COPY_UNDO_GROUP, /*< desc="Copy" >*/
TEXT_UNDO_GROUP, /*< desc="Text" >*/
TRANSFORM_UNDO_GROUP, /*< desc="Transform" >*/
PAINT_UNDO_GROUP, /*< desc="Paint" >*/
PARASITE_ATTACH_UNDO_GROUP, /*< desc="Attach Parasite" >*/
PARASITE_REMOVE_UNDO_GROUP, /*< desc="Remove Parasite" >*/
MISC_UNDO_GROUP, /*< desc="Plug-In" >*/
LAST_UNDO_GROUP = MISC_UNDO_GROUP,
/* Undo types which actually do something */
IMAGE_UNDO, /*< desc="Image" >*/
IMAGE_MOD_UNDO, /*< desc="Image Mod" >*/
IMAGE_TYPE_UNDO, /*< desc="Image Type" >*/
IMAGE_SIZE_UNDO, /*< desc="Image Size" >*/
IMAGE_RESOLUTION_UNDO, /*< desc="Resolution Change" >*/
IMAGE_QMASK_UNDO, /*< desc="QuickMask" >*/
IMAGE_GUIDE_UNDO, /*< desc="Guide" >*/
MASK_UNDO, /*< desc="Selection Mask" >*/
ITEM_RENAME_UNDO, /*< desc="Rename Item" >*/
LAYER_ADD_UNDO, /*< desc="New Layer" >*/
LAYER_REMOVE_UNDO, /*< desc="Delete Layer" >*/
LAYER_MOD_UNDO, /*< desc="Layer Mod" >*/
LAYER_MASK_ADD_UNDO, /*< desc="Add Layer Mask" >*/
LAYER_MASK_REMOVE_UNDO, /*< desc="Delete Layer Mask" >*/
LAYER_REPOSITION_UNDO, /*< desc="Layer Reposition" >*/
LAYER_DISPLACE_UNDO, /*< desc="Layer Move" >*/
CHANNEL_ADD_UNDO, /*< desc="New Channel" >*/
CHANNEL_REMOVE_UNDO, /*< desc="Delete Channel" >*/
CHANNEL_MOD_UNDO, /*< desc="Channel Mod" >*/
CHANNEL_REPOSITION_UNDO, /*< desc="Channel Reposition" >*/
VECTORS_ADD_UNDO, /*< desc="New Vectors" >*/
VECTORS_REMOVE_UNDO, /*< desc="Delete Vectors" >*/
VECTORS_MOD_UNDO, /*< desc="Vectors Mod" >*/
VECTORS_REPOSITION_UNDO, /*< desc="Vectors Reposition" >*/
FS_TO_LAYER_UNDO, /*< desc="FS to Layer" >*/
FS_RIGOR_UNDO, /*< desc="FS Rigor" >*/
FS_RELAX_UNDO, /*< desc="FS Relax" >*/
TRANSFORM_UNDO, /*< desc="Transform" >*/
PAINT_UNDO, /*< desc="Paint" >*/
PARASITE_ATTACH_UNDO, /*< desc="Attach Parasite" >*/
PARASITE_REMOVE_UNDO, /*< desc="Remove Parasite" >*/
CANT_UNDO, /*< desc="EEK: can't undo" >*/
} GimpUndoType;
/*
* non-registered enums; register them if needed
*/

View File

@ -44,46 +44,17 @@ typedef enum
GIMP_POINTS
} SizeType;
typedef enum /*< pdb-skip >*/ /*< skip >*/
/* Argument to undo_event signal emitted by images */
typedef enum /*< pdb-skip >*/ /*< skip >*/
{
/* NOTE: If you change this list, please update the textual mapping at
* the bottom of undo.c as well.
*/
UNDO_PUSHED, /* a new undo has been added to the undo stack */
UNDO_EXPIRED, /* an undo has been freed from the undo stack */
UNDO_POPPED, /* an undo has been executed and moved to redo stack */
UNDO_REDO, /* a redo has been executed and moved to undo stack */
UNDO_FREE /* all undo and redo info has been cleared */
} undo_event_t;
/* Type NO_UNDO_GROUP (0) is special - in the gimpimage structure it
* means there is no undo group currently being added to.
*/
NO_UNDO_GROUP = 0,
FIRST_UNDO_GROUP = NO_UNDO_GROUP,
IMAGE_SCALE_UNDO_GROUP,
IMAGE_RESIZE_UNDO_GROUP,
IMAGE_CONVERT_UNDO_GROUP,
IMAGE_CROP_UNDO_GROUP,
IMAGE_LAYERS_MERGE_UNDO_GROUP,
IMAGE_QMASK_UNDO_GROUP,
IMAGE_GUIDE_UNDO_GROUP,
LAYER_PROPERTIES_UNDO_GROUP,
LAYER_SCALE_UNDO_GROUP,
LAYER_RESIZE_UNDO_GROUP,
LAYER_DISPLACE_UNDO_GROUP,
LAYER_LINKED_UNDO_GROUP,
LAYER_APPLY_MASK_UNDO_GROUP,
FS_FLOAT_UNDO_GROUP,
FS_ANCHOR_UNDO_GROUP,
EDIT_PASTE_UNDO_GROUP,
EDIT_CUT_UNDO_GROUP,
EDIT_COPY_UNDO_GROUP,
TEXT_UNDO_GROUP,
TRANSFORM_UNDO_GROUP,
PAINT_UNDO_GROUP,
PARASITE_ATTACH_UNDO_GROUP,
PARASITE_REMOVE_UNDO_GROUP,
MISC_UNDO_GROUP,
LAST_UNDO_GROUP = MISC_UNDO_GROUP
} UndoType;
/* base objects */
@ -153,6 +124,7 @@ typedef struct _GimpEnvironTable GimpEnvironTable;
typedef struct _GimpUndo GimpUndo;
typedef struct _GimpUndoStack GimpUndoStack;
typedef struct _GimpUndoAccumulator GimpUndoAccumulator;
/* non-object types */
@ -181,10 +153,19 @@ typedef struct _PathList PathList;
/* functions */
typedef void (* GimpInitStatusFunc) (const gchar *text1,
const gchar *text2,
gdouble percentage);
typedef GimpData * (* GimpDataObjectLoaderFunc) (const gchar *filename);
typedef void (* GimpInitStatusFunc) (const gchar *text1,
const gchar *text2,
gdouble percentage);
typedef GimpData * (* GimpDataObjectLoaderFunc) (const gchar *filename);
typedef gboolean (* GimpUndoPopFunc) (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
typedef void (* GimpUndoFreeFunc) (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode);
/* structs */

File diff suppressed because it is too large Load Diff

View File

@ -20,48 +20,10 @@
#define __UNDO_H__
/* Argument to undo_event signal emitted by images */
typedef enum
{
UNDO_PUSHED, /* a new undo has been added to the undo stack */
UNDO_EXPIRED, /* an undo has been freed from the undo stack */
UNDO_POPPED, /* an undo has been executed and moved to redo stack */
UNDO_REDO, /* a redo has been executed and moved to undo stack */
UNDO_FREE /* all undo and redo info has been cleared */
} undo_event_t;
/* Stack peeking functions */
typedef gint (*undo_map_fn) (const gchar *undoitemname,
gpointer data);
/* main undo functions */
gboolean undo_pop (GimpImage *gimage);
gboolean undo_redo (GimpImage *gimage);
void undo_free (GimpImage *gimage);
const gchar * undo_get_undo_name (GimpImage *gimage);
const gchar * undo_get_redo_name (GimpImage *gimage);
void undo_map_over_undo_stack (GimpImage *gimage,
undo_map_fn fn,
gpointer data);
void undo_map_over_redo_stack (GimpImage *gimage,
undo_map_fn fn,
gpointer data);
UndoType undo_get_undo_top_type (GimpImage *gimage);
/* undo groups */
gboolean undo_push_group_start (GimpImage *gimage,
UndoType type);
GimpUndoType undo_type);
gboolean undo_push_group_end (GimpImage *gimage);

View File

@ -22,30 +22,319 @@
#include "core-types.h"
#include "config/gimpcoreconfig.h"
#include "gimp.h"
#include "gimpimage.h"
#include "gimpimage-undo.h"
#include "gimplist.h"
#include "gimpundostack.h"
void
/* local function prototypes */
static void gimp_image_undo_pop_stack (GimpImage *gimage,
GimpUndoStack *undo_stack,
GimpUndoStack *redo_stack,
GimpUndoMode undo_mode);
static void gimp_image_undo_free_space (GimpImage *gimage);
static const gchar * gimp_image_undo_type_to_name (GimpUndoType type);
/* public functions */
gboolean
gimp_image_undo (GimpImage *gimage)
{
GimpUndo *undo;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (gimage->pushing_undo_group == NO_UNDO_GROUP, FALSE);
undo = GIMP_UNDO (gimp_undo_stack_pop (gimage->new_undo_stack));
if (undo)
gimp_undo_stack_push (gimage->new_redo_stack, undo);
gimp_image_undo_pop_stack (gimage,
gimage->undo_stack,
gimage->redo_stack,
GIMP_UNDO_MODE_UNDO);
return TRUE;
}
void
gboolean
gimp_image_redo (GimpImage *gimage)
{
GimpUndo *redo;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (gimage->pushing_undo_group == NO_UNDO_GROUP, FALSE);
redo = GIMP_UNDO (gimp_undo_stack_pop (gimage->new_redo_stack));
if (redo)
gimp_undo_stack_push (gimage->new_undo_stack, redo);
gimp_image_undo_pop_stack (gimage,
gimage->redo_stack,
gimage->undo_stack,
GIMP_UNDO_MODE_REDO);
return TRUE;
}
void
gimp_image_undo_free (GimpImage *gimage)
{
g_return_if_fail (GIMP_IS_IMAGE (gimage));
gimp_undo_free (GIMP_UNDO (gimage->undo_stack), gimage, GIMP_UNDO_MODE_UNDO);
gimp_undo_free (GIMP_UNDO (gimage->redo_stack), gimage, GIMP_UNDO_MODE_REDO);
/* If the image was dirty, but could become clean by redo-ing
* some actions, then it should now become 'infinitely' dirty.
* This is because we've just nuked the actions that would allow
* the image to become clean again. The only hope for salvation
* is to save the image now! -- austin
*/
if (gimage->dirty < 0)
gimage->dirty = 10000;
/* The same applies to the case where the image would become clean
* due to undo actions, but since user can't undo without an undo
* stack, that's not so much a problem.
*/
gimp_image_undo_event (gimage, UNDO_FREE);
}
gboolean
gimp_image_undo_group_start (GimpImage *gimage,
GimpUndoType type,
const gchar *name)
{
GimpUndoStack *undo_group;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (type > FIRST_UNDO_GROUP &&
type <= LAST_UNDO_GROUP, FALSE);
if (! name)
name = gimp_image_undo_type_to_name (type);
/* Notify listeners that the image will be modified */
gimp_image_undo_start (gimage);
if (! gimage->undo_on)
return FALSE;
gimage->group_count++;
/* If we're already in a group...ignore */
if (gimage->group_count > 1)
return TRUE;
/* nuke the redo stack */
gimp_undo_free (GIMP_UNDO (gimage->redo_stack), gimage,
GIMP_UNDO_MODE_REDO);
/* If the image was dirty, but could become clean by redo-ing
* some actions, then it should now become 'infinitely' dirty.
* This is because we've just nuked the actions that would allow
* the image to become clean again. The only hope for salvation
* is to save the image now! -- austin
*/
if (gimage->dirty < 0)
gimage->dirty = 10000;
undo_group = gimp_undo_stack_new (gimage);
gimp_object_set_name (GIMP_OBJECT (undo_group), name);
GIMP_UNDO (undo_group)->undo_type = type;
gimp_undo_stack_push_undo (gimage->undo_stack,
GIMP_UNDO (undo_group));
gimage->pushing_undo_group = type;
return TRUE;
}
gboolean
gimp_image_undo_group_end (GimpImage *gimage)
{
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
g_return_val_if_fail (gimage->group_count > 0, FALSE);
if (! gimage->undo_on)
return FALSE;
gimage->group_count--;
if (gimage->group_count == 0)
{
gimage->pushing_undo_group = NO_UNDO_GROUP;
gimp_image_undo_free_space (gimage);
/* Do it here, since undo_push doesn't emit this event while in
* the middle of a group
*/
gimp_image_undo_event (gimage, UNDO_PUSHED);
}
return TRUE;
}
GimpUndo *
gimp_image_undo_push (GimpImage *gimage,
gsize size,
gsize struct_size,
GimpUndoType type,
const gchar *name,
gboolean dirties_image,
GimpUndoPopFunc pop_func,
GimpUndoFreeFunc free_func)
{
GimpUndo *new;
gpointer undo_struct = NULL;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
g_return_val_if_fail (type > LAST_UNDO_GROUP, NULL);
if (! name)
name = gimp_image_undo_type_to_name (type);
/* Does this undo dirty the image? If so, we always want to mark
* image dirty, even if we can't actually push the undo.
*/
if (dirties_image)
gimp_image_dirty (gimage);
if (! gimage->undo_on)
return NULL;
/* nuke the redo stack */
gimp_undo_free (GIMP_UNDO (gimage->redo_stack), gimage,
GIMP_UNDO_MODE_REDO);
/* If the image was dirty, but could become clean by redo-ing
* some actions, then it should now become 'infinitely' dirty.
* This is because we've just nuked the actions that would allow
* the image to become clean again. The only hope for salvation
* is to save the image now! -- austin
*/
if (gimage->dirty < 0)
gimage->dirty = 10000;
if (struct_size > 0)
undo_struct = g_malloc0 (struct_size);
new = gimp_undo_new (type,
name,
undo_struct, size,
dirties_image,
pop_func, free_func);
if (gimage->pushing_undo_group == NO_UNDO_GROUP)
{
gimp_undo_stack_push_undo (gimage->undo_stack, new);
gimp_image_undo_free_space (gimage);
gimp_image_undo_event (gimage, UNDO_PUSHED);
}
else
{
GimpUndoStack *undo_group;
undo_group = GIMP_UNDO_STACK (gimp_undo_stack_peek (gimage->undo_stack));
gimp_undo_stack_push_undo (undo_group, new);
}
return new;
}
/* private functions */
static void
gimp_image_undo_pop_stack (GimpImage *gimage,
GimpUndoStack *undo_stack,
GimpUndoStack *redo_stack,
GimpUndoMode undo_mode)
{
GimpUndo *undo;
GimpUndoAccumulator accum = { 0, };
undo = gimp_undo_stack_pop_undo (undo_stack, undo_mode, &accum);
if (! undo)
return;
if (GIMP_IS_UNDO_STACK (undo))
gimp_list_reverse (GIMP_LIST (GIMP_UNDO_STACK (undo)->undos));
gimp_undo_stack_push_undo (redo_stack, undo);
if (accum.mode_changed)
gimp_image_mode_changed (gimage);
if (accum.size_changed)
gimp_viewable_size_changed (GIMP_VIEWABLE (gimage));
if (accum.resolution_changed)
gimp_image_resolution_changed (gimage);
if (accum.unit_changed)
gimp_image_unit_changed (gimage);
if (accum.mask_changed)
gimp_image_mask_changed (gimage);
if (accum.qmask_changed)
gimp_image_qmask_changed (gimage);
if (accum.alpha_changed)
gimp_image_alpha_changed (gimage);
/* let others know that we just popped an action */
gimp_image_undo_event (gimage,
(undo_mode == GIMP_UNDO_MODE_UNDO) ?
UNDO_POPPED : UNDO_REDO);
}
static void
gimp_image_undo_free_space (GimpImage *gimage)
{
GimpContainer *container;
gint min_undo_levels;
gint max_undo_levels;
gulong undo_size;
container = gimage->undo_stack->undos;
min_undo_levels = gimage->gimp->config->levels_of_undo;
max_undo_levels = 1024; /* FIXME */
undo_size = gimage->gimp->config->undo_size;
/* keep at least undo_levels undo steps */
if (gimp_container_num_children (container) <= min_undo_levels)
return;
while ((gimp_object_get_memsize (GIMP_OBJECT (container)) > undo_size) ||
(gimp_container_num_children (container) > max_undo_levels))
{
gimp_undo_stack_free_bottom (gimage->undo_stack, GIMP_UNDO_MODE_UNDO);
gimp_image_undo_event (gimage, UNDO_EXPIRED);
if (gimp_container_num_children (container) <= min_undo_levels)
return;
}
}
static const gchar *
gimp_image_undo_type_to_name (GimpUndoType type)
{
static GEnumClass *enum_class = NULL;
GEnumValue *value;
if (! enum_class)
enum_class = g_type_class_ref (GIMP_TYPE_UNDO_TYPE);
value = g_enum_get_value (enum_class, type);
if (value)
return value->value_name;
return "";
}

View File

@ -20,8 +20,24 @@
#define __GIMP_IMAGE_UNDO_H__
void gimp_image_undo (GimpImage *gimage);
void gimp_image_redo (GimpImage *gimage);
gboolean gimp_image_undo (GimpImage *gimage);
gboolean gimp_image_redo (GimpImage *gimage);
void gimp_image_undo_free (GimpImage *gimage);
gboolean gimp_image_undo_group_start (GimpImage *gimage,
GimpUndoType type,
const gchar *name);
gboolean gimp_image_undo_group_end (GimpImage *gimage);
GimpUndo * gimp_image_undo_push (GimpImage *gimage,
gsize size,
gsize struct_size,
GimpUndoType type,
const gchar *name,
gboolean dirties_image,
GimpUndoPopFunc pop_func,
GimpUndoFreeFunc free_func);
#endif /* __GIMP_IMAGE_UNDO_H__ */

View File

@ -414,9 +414,6 @@ gimp_image_class_init (GimpImageClass *klass)
klass->undo_event = NULL;
klass->flush = NULL;
klass->undo = gimp_image_undo;
klass->redo = gimp_image_redo;
gimp_image_color_hash_init ();
}
@ -479,15 +476,11 @@ gimp_image_init (GimpImage *gimage)
gimage->qmask_color.b = 0.0;
gimage->qmask_color.a = 0.5;
gimage->undo_stack = NULL;
gimage->redo_stack = NULL;
gimage->undo_bytes = 0;
gimage->undo_levels = 0;
gimage->undo_stack = gimp_undo_stack_new (gimage);
gimage->redo_stack = gimp_undo_stack_new (gimage);
gimage->group_count = 0;
gimage->pushing_undo_group = NO_UNDO_GROUP;
gimage->new_undo_stack = gimp_undo_stack_new (gimage);
gimage->new_redo_stack = gimp_undo_stack_new (gimage);
gimage->comp_preview = NULL;
gimage->comp_preview_valid = FALSE;
@ -500,7 +493,7 @@ gimp_image_dispose (GObject *object)
gimage = GIMP_IMAGE (object);
undo_free (gimage);
gimp_image_undo_free (gimage);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@ -577,15 +570,15 @@ gimp_image_finalize (GObject *object)
gimage->guides = NULL;
}
if (gimage->new_undo_stack)
if (gimage->undo_stack)
{
g_object_unref (gimage->new_undo_stack);
gimage->new_undo_stack = NULL;
g_object_unref (gimage->undo_stack);
gimage->undo_stack = NULL;
}
if (gimage->new_redo_stack)
if (gimage->redo_stack)
{
g_object_unref (gimage->new_redo_stack);
gimage->new_redo_stack = NULL;
g_object_unref (gimage->redo_stack);
gimage->redo_stack = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
@ -643,13 +636,8 @@ gimp_image_get_memsize (GimpObject *object)
/* FIXME paths */
memsize += g_slist_length (gimage->undo_stack) * (3 * sizeof (gint) +
4 * sizeof (gpointer)); /* FIXME */
memsize += g_slist_length (gimage->redo_stack) * (3 * sizeof (gint) +
4 * sizeof (gpointer)); /* FIXME */
memsize += gimp_object_get_memsize (GIMP_OBJECT (gimage->new_undo_stack));
memsize += gimp_object_get_memsize (GIMP_OBJECT (gimage->new_redo_stack));
memsize += gimp_object_get_memsize (GIMP_OBJECT (gimage->undo_stack));
memsize += gimp_object_get_memsize (GIMP_OBJECT (gimage->redo_stack));
if (gimage->comp_preview)
memsize += temp_buf_get_memsize (gimage->comp_preview);
@ -1538,7 +1526,7 @@ gimp_image_undo_enable (GimpImage *gimage)
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
/* Free all undo steps as they are now invalidated */
undo_free (gimage);
gimp_image_undo_free (gimage);
return gimp_image_undo_thaw (gimage);
}

View File

@ -151,17 +151,12 @@ struct _GimpImage
gboolean qmask_inverted; /* TRUE if qmask is inverted */
GimpRGB qmask_color; /* rgba triplet of the color */
/* Old undo apparatus */
GSList *undo_stack; /* stack for undo operations */
GSList *redo_stack; /* stack for redo operations */
gint undo_bytes; /* bytes in undo stack */
gint undo_levels; /* levels in undo stack */
GimpUndoStack *undo_stack; /* stack for undo operations */
GimpUndoStack *redo_stack; /* stack for redo operations */
gint group_count; /* nested undo groups */
UndoType pushing_undo_group; /* undo group status flag */
GimpUndoType pushing_undo_group; /* undo group status flag */
/* New undo apparatus */
GimpUndoStack *new_undo_stack; /* stack for undo operations */
GimpUndoStack *new_redo_stack; /* stack for redo operations */
/* Composite preview */
TempBuf *comp_preview; /* the composite preview */
@ -206,10 +201,6 @@ struct _GimpImageClass
gint event);
void (* flush) (GimpImage *gimage);
/* virtual functions */
void (* undo) (GimpImage *gimage);
void (* redo) (GimpImage *gimage);
};

View File

@ -24,6 +24,7 @@
BOOLEAN: BOOLEAN
BOOLEAN: OBJECT
BOOLEAN: OBJECT, ENUM
BOOLEAN: POINTER
BOOLEAN: VOID
@ -54,6 +55,8 @@ VOID: INT, OBJECT
VOID: INT, POINTER
VOID: INT, POINTER, POINTER
VOID: OBJECT
VOID: OBJECT, ENUM
VOID: OBJECT, ENUM, POINTER
VOID: OBJECT, INT
VOID: OBJECT, INT, POINTER
VOID: OBJECT, POINTER

View File

@ -31,27 +31,30 @@
enum
{
PUSH,
POP,
FREE,
LAST_SIGNAL
};
static void gimp_undo_class_init (GimpUndoClass *klass);
static void gimp_undo_init (GimpUndo *undo);
static void gimp_undo_class_init (GimpUndoClass *klass);
static void gimp_undo_init (GimpUndo *undo);
static void gimp_undo_finalize (GObject *object);
static void gimp_undo_finalize (GObject *object);
static gsize gimp_undo_get_memsize (GimpObject *object);
static gsize gimp_undo_get_memsize (GimpObject *object);
static TempBuf * gimp_undo_get_preview (GimpViewable *viewable,
gint width,
gint height);
static TempBuf * gimp_undo_get_preview (GimpViewable *viewable,
gint width,
gint height);
static void gimp_undo_real_push (GimpUndo *undo,
GimpImage *gimage);
static void gimp_undo_real_pop (GimpUndo *undo,
GimpImage *gimage);
static void gimp_undo_real_pop (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
static void gimp_undo_real_free (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode);
static guint undo_signals[LAST_SIGNAL] = { 0 };
@ -100,25 +103,28 @@ gimp_undo_class_init (GimpUndoClass *klass)
parent_class = g_type_class_peek_parent (klass);
undo_signals[PUSH] =
g_signal_new ("push",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpUndoClass, push),
NULL, NULL,
gimp_marshal_VOID__POINTER,
G_TYPE_NONE, 1,
G_TYPE_POINTER);
undo_signals[POP] =
g_signal_new ("pop",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpUndoClass, pop),
NULL, NULL,
gimp_marshal_VOID__POINTER,
G_TYPE_NONE, 1,
G_TYPE_POINTER);
gimp_marshal_VOID__OBJECT_ENUM_POINTER,
G_TYPE_NONE, 3,
GIMP_TYPE_IMAGE,
GIMP_TYPE_UNDO_MODE,
G_TYPE_POINTER);
undo_signals[FREE] =
g_signal_new ("free",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpUndoClass, free),
NULL, NULL,
gimp_marshal_VOID__OBJECT_ENUM,
G_TYPE_NONE, 2,
GIMP_TYPE_IMAGE,
GIMP_TYPE_UNDO_MODE);
object_class->finalize = gimp_undo_finalize;
@ -126,8 +132,8 @@ gimp_undo_class_init (GimpUndoClass *klass)
viewable_class->get_preview = gimp_undo_get_preview;
klass->push = gimp_undo_real_push;
klass->pop = gimp_undo_real_pop;
klass->free = gimp_undo_real_free;
}
static void
@ -147,12 +153,6 @@ gimp_undo_finalize (GObject *object)
undo = GIMP_UNDO (object);
if (undo->free_func)
{
undo->free_func (undo);
undo->free_func = NULL;
}
if (undo->preview)
{
temp_buf_free (undo->preview);
@ -170,6 +170,8 @@ gimp_undo_get_memsize (GimpObject *object)
undo = GIMP_UNDO (object);
memsize += undo->size;
if (undo->preview)
memsize += temp_buf_get_memsize (undo->preview);
@ -185,61 +187,86 @@ gimp_undo_get_preview (GimpViewable *viewable,
}
GimpUndo *
gimp_undo_new (const gchar *name,
gimp_undo_new (GimpUndoType undo_type,
const gchar *name,
gpointer data,
gsize size,
gboolean dirties_image,
GimpUndoPopFunc pop_func,
GimpUndoFreeFunc free_func)
{
GimpUndo *undo;
undo = GIMP_UNDO (g_object_new (GIMP_TYPE_UNDO, NULL));
g_return_val_if_fail (name != NULL, NULL);
//g_return_val_if_fail (size == 0 || data != NULL, NULL);
undo = g_object_new (GIMP_TYPE_UNDO,
"name", name,
NULL);
gimp_object_set_name (GIMP_OBJECT (undo), name);
undo->data = data;
undo->pop_func = pop_func;
undo->free_func = free_func;
undo->undo_type = undo_type;
undo->data = data;
undo->size = size;
undo->dirties_image = dirties_image ? TRUE : FALSE;
undo->pop_func = pop_func;
undo->free_func = free_func;
return undo;
}
void
gimp_undo_push (GimpUndo *undo,
GimpImage *gimage)
gimp_undo_pop (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum)
{
g_return_if_fail (GIMP_IS_UNDO (undo));
g_return_if_fail (GIMP_IS_IMAGE (gimage));
g_return_if_fail (accum != NULL);
g_signal_emit (undo, undo_signals[PUSH], 0, gimage);
g_signal_emit (undo, undo_signals[POP], 0, gimage, undo_mode, accum);
if (undo->dirties_image)
{
switch (undo_mode)
{
case GIMP_UNDO_MODE_UNDO:
gimp_image_clean (gimage);
break;
case GIMP_UNDO_MODE_REDO:
gimp_image_dirty (gimage);
break;
}
}
}
void
gimp_undo_pop (GimpUndo *undo,
GimpImage *gimage)
gimp_undo_free (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode)
{
g_return_if_fail (GIMP_IS_UNDO (undo));
g_return_if_fail (GIMP_IS_IMAGE (gimage));
g_signal_emit (undo, undo_signals[POP], 0, gimage);
g_signal_emit (undo, undo_signals[FREE], 0, gimage, undo_mode);
}
static void
gimp_undo_real_push (GimpUndo *undo,
GimpImage *gimage)
{
/* FIXME: need core_config->undo_preview_size */
undo->preview = gimp_viewable_get_preview (GIMP_VIEWABLE (gimage),
24,
24);
}
static void
gimp_undo_real_pop (GimpUndo *undo,
GimpImage *gimage)
gimp_undo_real_pop (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum)
{
if (undo->pop_func)
undo->pop_func (undo, gimage);
undo->pop_func (undo, gimage, undo_mode, accum);
}
static void
gimp_undo_real_free (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode)
{
if (undo->free_func)
undo->free_func (undo, gimage, undo_mode);
}

View File

@ -23,6 +23,18 @@
#include "gimpviewable.h"
struct _GimpUndoAccumulator
{
gboolean mode_changed;
gboolean size_changed;
gboolean resolution_changed;
gboolean unit_changed;
gboolean mask_changed;
gboolean qmask_changed;
gboolean alpha_changed;
};
#define GIMP_TYPE_UNDO (gimp_undo_get_type ())
#define GIMP_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_UNDO, GimpUndo))
#define GIMP_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_UNDO, GimpUndoClass))
@ -31,18 +43,16 @@
#define GIMP_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_UNDO, GimpUndoClass))
typedef gboolean (* GimpUndoPopFunc) (GimpUndo *undo, GimpImage *gimage);
typedef void (* GimpUndoFreeFunc) (GimpUndo *undo);
typedef struct _GimpUndoClass GimpUndoClass;
struct _GimpUndo
{
GimpViewable parent_instance;
gpointer data; /* data to implement the undo */
gboolean dirties_image; /* TRUE if undo mutates image */
GimpUndoType undo_type; /* undo type */
gpointer data; /* data to implement the undo */
gsize size; /* size of undo item */
gboolean dirties_image; /* TRUE if undo mutates image */
GimpUndoPopFunc pop_func; /* function pointer to undo pop proc */
GimpUndoFreeFunc free_func; /* function pointer to free undo data */
@ -54,23 +64,33 @@ struct _GimpUndoClass
{
GimpViewableClass parent_class;
void (* push) (GimpUndo *undo,
GimpImage *gimage);
void (* pop) (GimpUndo *undo,
GimpImage *gimage);
void (* pop) (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
void (* free) (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode);
};
GType gimp_undo_get_type (void) G_GNUC_CONST;
GimpUndo * gimp_undo_new (const gchar *name,
gpointer data,
gboolean dirties_image,
GimpUndoPopFunc pop_func,
GimpUndoFreeFunc free_func);
void gimp_undo_push (GimpUndo *undo,
GimpImage *gimage);
void gimp_undo_pop (GimpUndo *undo,
GimpImage *gimage);
GimpUndo * gimp_undo_new (GimpUndoType undo_type,
const gchar *name,
gpointer data,
gsize size,
gboolean dirties_image,
GimpUndoPopFunc pop_func,
GimpUndoFreeFunc free_func);
void gimp_undo_pop (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
void gimp_undo_free (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode);
#endif /* __GIMP_UNDO_H__ */

View File

@ -28,19 +28,27 @@
#include "gimpundostack.h"
static void gimp_undo_stack_class_init (GimpUndoStackClass *klass);
static void gimp_undo_stack_init (GimpUndoStack *stack);
static void gimp_undo_stack_class_init (GimpUndoStackClass *klass);
static void gimp_undo_stack_init (GimpUndoStack *stack);
static void gimp_undo_stack_finalize (GObject *object);
static void gimp_undo_stack_finalize (GObject *object);
static gsize gimp_undo_stack_get_memsize (GimpObject *object);
static gsize gimp_undo_stack_get_memsize (GimpObject *object);
static void gimp_undo_stack_add_callback (GimpContainer *container,
GimpObject *object,
gpointer data);
static void gimp_undo_stack_remove_callback (GimpContainer *container,
GimpObject *object,
gpointer data);
static void gimp_undo_stack_pop (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
static void gimp_undo_stack_free (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode);
static void gimp_undo_stack_add_callback (GimpContainer *container,
GimpObject *object,
gpointer data);
static void gimp_undo_stack_remove_callback (GimpContainer *container,
GimpObject *object,
gpointer data);
static GimpUndoClass *parent_class = NULL;
@ -79,15 +87,20 @@ gimp_undo_stack_class_init (GimpUndoStackClass *klass)
{
GObjectClass *object_class;
GimpObjectClass *gimp_object_class;
GimpUndoClass *undo_class;
object_class = G_OBJECT_CLASS (klass);
gimp_object_class = GIMP_OBJECT_CLASS (klass);
undo_class = GIMP_UNDO_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gimp_undo_stack_finalize;
gimp_object_class->get_memsize = gimp_undo_stack_get_memsize;
undo_class->pop = gimp_undo_stack_pop;
undo_class->free = gimp_undo_stack_free;
}
static void
@ -140,6 +153,56 @@ gimp_undo_stack_get_memsize (GimpObject *object)
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object);
}
static void
gimp_undo_stack_pop (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum)
{
GimpUndoStack *stack;
GList *list;
stack = GIMP_UNDO_STACK (undo);
for (list = GIMP_LIST (stack->undos)->list;
list;
list = g_list_next (list))
{
GimpUndo *child;
child = GIMP_UNDO (list->data);
gimp_undo_pop (child, gimage, undo_mode, accum);
}
}
static void
gimp_undo_stack_free (GimpUndo *undo,
GimpImage *gimage,
GimpUndoMode undo_mode)
{
GimpUndoStack *stack;
GList *list;
stack = GIMP_UNDO_STACK (undo);
for (list = GIMP_LIST (stack->undos)->list;
list;
list = g_list_next (list))
{
GimpUndo *child;
child = GIMP_UNDO (list->data);
gimp_undo_free (child, gimage, undo_mode);
g_object_unref (child);
}
while (GIMP_LIST (stack->undos)->list)
gimp_container_remove (GIMP_CONTAINER (stack->undos),
GIMP_OBJECT (GIMP_LIST (stack->undos)->list->data));
}
GimpUndoStack *
gimp_undo_stack_new (GimpImage *gimage)
{
@ -155,30 +218,31 @@ gimp_undo_stack_new (GimpImage *gimage)
}
void
gimp_undo_stack_push (GimpUndoStack *stack,
GimpUndo *undo)
gimp_undo_stack_push_undo (GimpUndoStack *stack,
GimpUndo *undo)
{
g_return_if_fail (GIMP_IS_UNDO_STACK (stack));
g_return_if_fail (GIMP_IS_UNDO (undo));
gimp_undo_push (undo, stack->gimage);
gimp_container_add (GIMP_CONTAINER (stack->undos), GIMP_OBJECT (undo));
g_object_unref (undo);
}
GimpUndo *
gimp_undo_stack_pop (GimpUndoStack *stack)
gimp_undo_stack_pop_undo (GimpUndoStack *stack,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum)
{
GimpObject *object;
g_return_val_if_fail (GIMP_IS_UNDO_STACK (stack), NULL);
g_return_val_if_fail (accum != NULL, NULL);
object = gimp_container_get_child_by_index (GIMP_CONTAINER (stack->undos),0);
if (object)
{
gimp_container_remove (GIMP_CONTAINER (stack->undos), object);
gimp_undo_pop (GIMP_UNDO (object), stack->gimage);
gimp_undo_pop (GIMP_UNDO (object), stack->gimage, undo_mode, accum);
return GIMP_UNDO (object);
}
@ -186,6 +250,29 @@ gimp_undo_stack_pop (GimpUndoStack *stack)
return NULL;
}
void
gimp_undo_stack_free_bottom (GimpUndoStack *stack,
GimpUndoMode undo_mode)
{
GimpObject *object;
gint n_children;
g_return_if_fail (GIMP_IS_UNDO_STACK (stack));
n_children = gimp_container_num_children (GIMP_CONTAINER (stack->undos));
object = gimp_container_get_child_by_index (GIMP_CONTAINER (stack->undos),
n_children - 1);
if (object)
{
gimp_container_remove (GIMP_CONTAINER (stack->undos), object);
gimp_undo_free (GIMP_UNDO (object), stack->gimage, undo_mode);
g_object_unref (object);
}
}
GimpUndo *
gimp_undo_stack_peek (GimpUndoStack *stack)
{

View File

@ -47,14 +47,19 @@ struct _GimpUndoStackClass
};
GType gimp_undo_stack_get_type (void) G_GNUC_CONST;
GType gimp_undo_stack_get_type (void) G_GNUC_CONST;
GimpUndoStack * gimp_undo_stack_new (GimpImage *gimage);
GimpUndoStack * gimp_undo_stack_new (GimpImage *gimage);
void gimp_undo_stack_push (GimpUndoStack *stack,
GimpUndo *undo);
GimpUndo * gimp_undo_stack_pop (GimpUndoStack *stack);
GimpUndo * gimp_undo_stack_peek (GimpUndoStack *stack);
void gimp_undo_stack_push_undo (GimpUndoStack *stack,
GimpUndo *undo);
GimpUndo * gimp_undo_stack_pop_undo (GimpUndoStack *stack,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
void gimp_undo_stack_free_bottom (GimpUndoStack *stack,
GimpUndoMode undo_mode);
GimpUndo * gimp_undo_stack_peek (GimpUndoStack *stack);
#endif /* __GIMP_UNDO_STACK_H__ */

View File

@ -1673,22 +1673,25 @@ prefs_dialog_new (Gimp *gimp,
GTK_BOX (vbox2));
#ifdef ENABLE_MP
table = prefs_table_new (3, GTK_CONTAINER (vbox2), FALSE);
table = prefs_table_new (4, GTK_CONTAINER (vbox2), FALSE);
#else
table = prefs_table_new (2, GTK_CONTAINER (vbox2), FALSE);
table = prefs_table_new (3, GTK_CONTAINER (vbox2), FALSE);
#endif /* ENABLE_MP */
prefs_spin_button_add (config, "undo-levels", 1.0, 5.0, 0,
_("Levels of Undo:"),
GTK_TABLE (table), 0);
prefs_memsize_entry_add (config, "undo-size",
_("Maximum Undo Memory:"),
GTK_TABLE (table), 1);
prefs_memsize_entry_add (config, "tile-cache-size",
_("Tile Cache Size:"),
GTK_TABLE (table), 1);
GTK_TABLE (table), 2);
#ifdef ENABLE_MP
prefs_spin_button_add (config, "num-processors", 1.0, 4.0, 0,
_("Number of Processors to Use:"),
GTK_TABLE (table), 2);
GTK_TABLE (table), 3);
#endif /* ENABLE_MP */
/* File Saving */

View File

@ -34,6 +34,7 @@
#include "core/gimpedit.h"
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
#include "core/gimpimage-undo.h"
#include "display/gimpdisplay.h"
@ -42,8 +43,6 @@
#include "dialogs.h"
#include "edit-commands.h"
#include "undo.h"
#include "libgimp/gimpintl.h"
@ -87,7 +86,7 @@ edit_undo_cmd_callback (GtkWidget *widget,
GimpImage *gimage;
return_if_no_image (gimage, data);
if (undo_pop (gimage))
if (gimp_image_undo (gimage))
gimp_image_flush (gimage);
}
@ -98,7 +97,7 @@ edit_redo_cmd_callback (GtkWidget *widget,
GimpImage *gimage;
return_if_no_image (gimage, data);
if (undo_redo (gimage))
if (gimp_image_redo (gimage))
gimp_image_flush (gimage);
}

View File

@ -30,6 +30,7 @@
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
#include "core/gimpimage-undo.h"
#include "core/gimpobject.h"
#include "file/file-open.h"
@ -365,7 +366,7 @@ file_revert_confirm_callback (GtkWidget *widget,
if (new_gimage)
{
undo_free (new_gimage);
gimp_image_undo_free (new_gimage);
gimp_displays_reconnect (old_gimage->gimp, old_gimage, new_gimage);

View File

@ -31,6 +31,7 @@
#include "core/gimplayer.h"
#include "core/gimplist.h"
#include "core/gimptoolinfo.h"
#include "core/gimpundostack.h"
#include "plug-in/plug-ins.h"
@ -54,8 +55,6 @@
#include "tools-commands.h"
#include "view-commands.h"
#include "undo.h"
#include "libgimp/gimpintl.h"
@ -1163,16 +1162,23 @@ image_menu_update (GtkItemFactory *item_factory,
if (gdisp && gimp_image_undo_is_enabled (gimage))
{
undo_name = (gchar *) undo_get_undo_name (gimage);
redo_name = (gchar *) undo_get_redo_name (gimage);
GimpUndo *undo;
GimpUndo *redo;
undo = gimp_undo_stack_peek (gimage->undo_stack);
redo = gimp_undo_stack_peek (gimage->redo_stack);
if (undo)
undo_name =
g_strdup_printf (_("Undo %s"),
gimp_object_get_name (GIMP_OBJECT (undo)));
if (redo)
redo_name =
g_strdup_printf (_("Redo %s"),
gimp_object_get_name (GIMP_OBJECT (redo)));
}
if (undo_name)
undo_name = g_strdup_printf (_("Undo %s"), gettext (undo_name));
if (redo_name)
redo_name = g_strdup_printf (_("Redo %s"), gettext (redo_name));
SET_LABEL ("/Edit/Undo", undo_name ? undo_name : _("Undo"));
SET_LABEL ("/Edit/Redo", redo_name ? redo_name : _("Redo"));

View File

@ -1673,22 +1673,25 @@ prefs_dialog_new (Gimp *gimp,
GTK_BOX (vbox2));
#ifdef ENABLE_MP
table = prefs_table_new (3, GTK_CONTAINER (vbox2), FALSE);
table = prefs_table_new (4, GTK_CONTAINER (vbox2), FALSE);
#else
table = prefs_table_new (2, GTK_CONTAINER (vbox2), FALSE);
table = prefs_table_new (3, GTK_CONTAINER (vbox2), FALSE);
#endif /* ENABLE_MP */
prefs_spin_button_add (config, "undo-levels", 1.0, 5.0, 0,
_("Levels of Undo:"),
GTK_TABLE (table), 0);
prefs_memsize_entry_add (config, "undo-size",
_("Maximum Undo Memory:"),
GTK_TABLE (table), 1);
prefs_memsize_entry_add (config, "tile-cache-size",
_("Tile Cache Size:"),
GTK_TABLE (table), 1);
GTK_TABLE (table), 2);
#ifdef ENABLE_MP
prefs_spin_button_add (config, "num-processors", 1.0, 4.0, 0,
_("Number of Processors to Use:"),
GTK_TABLE (table), 2);
GTK_TABLE (table), 3);
#endif /* ENABLE_MP */
/* File Saving */

View File

@ -31,6 +31,7 @@
#include "core/gimplayer.h"
#include "core/gimplist.h"
#include "core/gimptoolinfo.h"
#include "core/gimpundostack.h"
#include "plug-in/plug-ins.h"
@ -54,8 +55,6 @@
#include "tools-commands.h"
#include "view-commands.h"
#include "undo.h"
#include "libgimp/gimpintl.h"
@ -1163,16 +1162,23 @@ image_menu_update (GtkItemFactory *item_factory,
if (gdisp && gimp_image_undo_is_enabled (gimage))
{
undo_name = (gchar *) undo_get_undo_name (gimage);
redo_name = (gchar *) undo_get_redo_name (gimage);
GimpUndo *undo;
GimpUndo *redo;
undo = gimp_undo_stack_peek (gimage->undo_stack);
redo = gimp_undo_stack_peek (gimage->redo_stack);
if (undo)
undo_name =
g_strdup_printf (_("Undo %s"),
gimp_object_get_name (GIMP_OBJECT (undo)));
if (redo)
redo_name =
g_strdup_printf (_("Redo %s"),
gimp_object_get_name (GIMP_OBJECT (redo)));
}
if (undo_name)
undo_name = g_strdup_printf (_("Undo %s"), gettext (undo_name));
if (redo_name)
redo_name = g_strdup_printf (_("Redo %s"), gettext (redo_name));
SET_LABEL ("/Edit/Undo", undo_name ? undo_name : _("Undo"));
SET_LABEL ("/Edit/Redo", redo_name ? redo_name : _("Redo"));

View File

@ -35,6 +35,7 @@
#include "core/gimpimage.h"
#include "core/gimpimage-guides.h"
#include "core/gimpimage-mask.h"
#include "core/gimpimage-undo.h"
#include "core/gimplayer.h"
#include "core/gimplayer-floating-sel.h"
#include "core/gimplist.h"
@ -387,7 +388,7 @@ gimp_edit_selection_tool_button_release (GimpTool *tool,
if (state & GDK_BUTTON3_MASK) /* OPERATION CANCELLED */
{
/* Operation cancelled - undo the undo-group! */
undo_pop (gdisp->gimage);
gimp_image_undo (gdisp->gimage);
}
gimp_image_flush (gdisp->gimage);

2302
app/undo.c

File diff suppressed because it is too large Load Diff

View File

@ -20,48 +20,10 @@
#define __UNDO_H__
/* Argument to undo_event signal emitted by images */
typedef enum
{
UNDO_PUSHED, /* a new undo has been added to the undo stack */
UNDO_EXPIRED, /* an undo has been freed from the undo stack */
UNDO_POPPED, /* an undo has been executed and moved to redo stack */
UNDO_REDO, /* a redo has been executed and moved to undo stack */
UNDO_FREE /* all undo and redo info has been cleared */
} undo_event_t;
/* Stack peeking functions */
typedef gint (*undo_map_fn) (const gchar *undoitemname,
gpointer data);
/* main undo functions */
gboolean undo_pop (GimpImage *gimage);
gboolean undo_redo (GimpImage *gimage);
void undo_free (GimpImage *gimage);
const gchar * undo_get_undo_name (GimpImage *gimage);
const gchar * undo_get_redo_name (GimpImage *gimage);
void undo_map_over_undo_stack (GimpImage *gimage,
undo_map_fn fn,
gpointer data);
void undo_map_over_redo_stack (GimpImage *gimage,
undo_map_fn fn,
gpointer data);
UndoType undo_get_undo_top_type (GimpImage *gimage);
/* undo groups */
gboolean undo_push_group_start (GimpImage *gimage,
UndoType type);
GimpUndoType undo_type);
gboolean undo_push_group_end (GimpImage *gimage);

View File

@ -63,16 +63,18 @@
#include "paint-funcs/paint-funcs.h"
#include "core/gimp.h"
#include "core/gimpcontainer.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
#include "core/gimpimage-undo.h"
#include "core/gimpundostack.h"
#include "file/file-utils.h"
#include "widgets/gimpviewabledialog.h"
#include "undo.h"
#include "undo_types.h"
#include "libgimp/gimpintl.h"
@ -276,7 +278,7 @@ undo_history_set_pixmap_idle (gpointer data)
static GdkGC *gc = NULL;
TempBuf *buf = NULL;
GdkPixmap *pixmap;
UndoType utype;
GimpUndoType utype;
MaskBuf *mbuf = NULL;
guchar *src;
gdouble r, g, b, a;
@ -303,7 +305,7 @@ undo_history_set_pixmap_idle (gpointer data)
height = (gint)(((gdouble)height * (gdouble)width ) /(gdouble) idle->gimage->width + 0.5);
}
utype = undo_get_undo_top_type (idle->gimage);
utype = gimp_undo_stack_peek (idle->gimage->undo_stack)->undo_type;
if ((utype != MASK_UNDO && utype != IMAGE_QMASK_UNDO) ||
(mbuf = mask_render_preview (idle->gimage, &width, &height)) == NULL)
@ -507,7 +509,7 @@ undo_history_undo_callback (GtkWidget *widget,
{
undo_history_st *st = data;
if (undo_pop (st->gimage))
if (gimp_image_undo (st->gimage))
gimp_image_flush (st->gimage);
}
@ -518,7 +520,7 @@ undo_history_redo_callback (GtkWidget *widget,
{
undo_history_st *st = data;
if (undo_redo (st->gimage))
if (gimp_image_redo (st->gimage))
gimp_image_flush (st->gimage);
}
@ -589,7 +591,7 @@ undo_history_undo_event (GtkWidget *widget,
gtk_clist_remove (clist, cur_selection + 1);
/* find out what's new */
name = undo_get_undo_name (st->gimage);
name = gimp_object_get_name (GIMP_OBJECT (gimp_undo_stack_peek (st->gimage->undo_stack)));
namelist[0] = NULL;
namelist[1] = NULL;
namelist[2] = (char *) name;
@ -677,12 +679,12 @@ undo_history_select_row_callback (GtkWidget *widget,
while (cur_selection < st->old_selection)
{
undo_pop (st->gimage);
gimp_image_undo (st->gimage);
st->old_selection--;
}
while (cur_selection > st->old_selection)
{
undo_redo (st->gimage);
gimp_image_redo (st->gimage);
st->old_selection++;
}
@ -735,9 +737,9 @@ undo_history_clean_callback (GtkWidget *widget,
/* Used to build up initial contents of clist */
static gboolean
undo_history_init_undo (const gchar *undoitemname,
void *data)
static void
undo_history_init_undo (gpointer undo,
gpointer data)
{
undo_history_st *st = data;
gchar *namelist[3];
@ -745,30 +747,26 @@ undo_history_init_undo (const gchar *undoitemname,
namelist[0] = NULL;
namelist[1] = NULL;
namelist[2] = (gchar *) undoitemname;
namelist[2] = (gchar *) gimp_object_get_name (GIMP_OBJECT (undo));
row = gtk_clist_prepend (GTK_CLIST (st->clist), namelist);
gtk_clist_set_pixmap (GTK_CLIST (st->clist), row, 0,
clear_pixmap, clear_mask);
return FALSE;
}
/* Ditto */
static gboolean
undo_history_init_redo (const char *undoitemname,
void *data)
static void
undo_history_init_redo (gpointer undo,
gpointer data)
{
undo_history_st *st = data;
gchar *namelist[3];
gint row;
namelist[0] = NULL; namelist[1] = NULL;
namelist[2] = (gchar *) undoitemname;
namelist[1] = NULL;
namelist[2] = (gchar *) gimp_object_get_name (GIMP_OBJECT (undo));
row = gtk_clist_append (GTK_CLIST (st->clist), namelist);
gtk_clist_set_pixmap (GTK_CLIST (st->clist), row, 0,
clear_pixmap, clear_mask);
return FALSE;
}
@ -859,11 +857,16 @@ undo_history_new (GimpImage *gimage)
}
/* work out the initial contents */
undo_map_over_undo_stack (st->gimage, undo_history_init_undo, st);
gimp_container_foreach (GIMP_CONTAINER (st->gimage->undo_stack->undos),
undo_history_init_undo, st);
/* force selection to bottom */
gtk_clist_select_row (GTK_CLIST (st->clist),
GTK_CLIST (st->clist)->rows - 1, -1);
undo_map_over_redo_stack (st->gimage, undo_history_init_redo, st);
gimp_container_foreach (GIMP_CONTAINER (st->gimage->redo_stack->undos),
undo_history_init_redo, st);
undo_history_prepend_special (GTK_CLIST (st->clist));
st->old_selection = GPOINTER_TO_INT(GTK_CLIST(st->clist)->selection->data);

View File

@ -1,65 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __UNDO_TYPES_H__
#define __UNDO_TYPES_H__
/* Undo types which actually do something, unlike the ones in
* core/core-types.h, which are only for pushing groups
*/
typedef enum
{
IMAGE_UNDO = LAST_UNDO_GROUP + 1,
IMAGE_MOD_UNDO,
IMAGE_TYPE_UNDO,
IMAGE_SIZE_UNDO,
IMAGE_RESOLUTION_UNDO,
IMAGE_QMASK_UNDO,
IMAGE_GUIDE_UNDO,
MASK_UNDO,
ITEM_RENAME_UNDO,
LAYER_ADD_UNDO,
LAYER_REMOVE_UNDO,
LAYER_MOD_UNDO,
LAYER_MASK_ADD_UNDO,
LAYER_MASK_REMOVE_UNDO,
LAYER_REPOSITION_UNDO,
LAYER_DISPLACE_UNDO,
CHANNEL_ADD_UNDO,
CHANNEL_REMOVE_UNDO,
CHANNEL_MOD_UNDO,
CHANNEL_REPOSITION_UNDO,
VECTORS_ADD_UNDO,
VECTORS_REMOVE_UNDO,
VECTORS_MOD_UNDO,
VECTORS_REPOSITION_UNDO,
FS_TO_LAYER_UNDO,
FS_RIGOR_UNDO,
FS_RELAX_UNDO,
TRANSFORM_UNDO,
PAINT_UNDO,
PARASITE_ATTACH_UNDO,
PARASITE_REMOVE_UNDO,
CANT_UNDO
} UndoImplType;
#endif /* __UNDO_TYPES_H__ */