From 884b3aa7a30d140ab0f96e787f4cb383b98a4c6f Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Mon, 17 Mar 2003 18:02:41 +0000 Subject: [PATCH] Made drawable/layer properties (visibility, opacity etc.) undoable (fixes 2003-03-17 Michael Natterer Made drawable/layer properties (visibility, opacity etc.) undoable (fixes bug #73893). * app/core/core-enums.[ch]: added undo types/groups for visibility, mode, opacity, linked and preserve_trans. * app/core/Makefile.am * app/core/core-types.h * app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a ref'ed GimpItem pointer so (1) this doesn't need to be done by all undo steps related to an item and (2) the item the undo step is for can be determined from outside the undo system. * app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item() which returns a new GimpItemUndo. * app/core/gimpimage-undo-push.[ch]: use it for all item related undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable and GimpVectors pointers from the private undo structs. Added undo push functions for the new undo types added above. * app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added "gboolean push_undo" parameter. * app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode, _preserve_trans, _linked): added "gboolean push_undo" parameters. * app/core/gimpimage-mask.c * app/core/gimpimage-merge.c * app/core/gimplayer-floating-sel.c * app/tools/gimpmovetool.c * app/xcf/xcf-load.c * app/widgets/gimpdrawablelistitem.c * app/widgets/gimplayerlistitem.c * app/widgets/gimplayerlistview.c: changed accordingly. * tools/pdbgen/pdb/channel.pdb * tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to the foo_accessors() functions. Removed $func from foo_accesors() because we don't manipulate items without using getters/setters any longer. * app/pdb/channel_cmds.c * app/pdb/layer_cmds.c: regenerated. * app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal which carries an additional "GdkModifierType state" parameter as in GimpCellRendererViewable . * app/widgets/gimpcontainertreeview.c: emit "clicked" from the toggle renderer, not "toggled" so the callbacks get the modifier state. * app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive visible by +click" feature as in 1.2. * app/widgets/gimplayertreeview.c: compress layer opacity undos by looking at the top of the undo stack and not pushing an undo if there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active layer. --- ChangeLog | 63 +++ app/core/Makefile.am | 2 + app/core/core-enums.c | 15 +- app/core/core-enums.h | 65 +-- app/core/core-types.h | 1 + app/core/gimpchannel-combine.c | 24 +- app/core/gimpchannel-combine.h | 3 +- app/core/gimpchannel.c | 24 +- app/core/gimpchannel.h | 3 +- app/core/gimpdrawable.c | 15 +- app/core/gimpdrawable.h | 3 +- app/core/gimpimage-mask.c | 2 +- app/core/gimpimage-merge.c | 4 +- app/core/gimpimage-undo-push.c | 623 ++++++++++++++++-------- app/core/gimpimage-undo-push.h | 19 + app/core/gimpimage-undo.c | 42 +- app/core/gimpimage-undo.h | 9 + app/core/gimpitemundo.c | 138 ++++++ app/core/gimpitemundo.h | 62 +++ app/core/gimplayer-floating-sel.c | 19 +- app/core/gimplayer.c | 44 +- app/core/gimplayer.h | 12 +- app/pdb/channel_cmds.c | 8 +- app/pdb/layer_cmds.c | 10 +- app/tools/gimpmovetool.c | 5 + app/widgets/gimpcellrenderertoggle.c | 58 +++ app/widgets/gimpcellrenderertoggle.h | 4 + app/widgets/gimpcontainertreeview.c | 4 +- app/widgets/gimpdrawablelistitem.c | 2 +- app/widgets/gimpdrawabletreeview.c | 53 +- app/widgets/gimplayerlistitem.c | 2 +- app/widgets/gimplayerlistview.c | 6 +- app/widgets/gimplayertreeview.c | 31 +- app/xcf/xcf-load.c | 4 +- libgimpwidgets/gimpcellrenderertoggle.c | 58 +++ libgimpwidgets/gimpcellrenderertoggle.h | 4 + tools/pdbgen/pdb/channel.pdb | 38 +- tools/pdbgen/pdb/layer.pdb | 34 +- 38 files changed, 1171 insertions(+), 342 deletions(-) create mode 100644 app/core/gimpitemundo.c create mode 100644 app/core/gimpitemundo.h diff --git a/ChangeLog b/ChangeLog index 06c31589f5..b24f6cbcac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,66 @@ +2003-03-17 Michael Natterer + + Made drawable/layer properties (visibility, opacity etc.) + undoable (fixes bug #73893). + + * app/core/core-enums.[ch]: added undo types/groups for + visibility, mode, opacity, linked and preserve_trans. + + * app/core/Makefile.am + * app/core/core-types.h + * app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a + ref'ed GimpItem pointer so (1) this doesn't need to be done by all + undo steps related to an item and (2) the item the undo step is + for can be determined from outside the undo system. + + * app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item() + which returns a new GimpItemUndo. + + * app/core/gimpimage-undo-push.[ch]: use it for all item related + undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable + and GimpVectors pointers from the private undo structs. Added + undo push functions for the new undo types added above. + + * app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added + "gboolean push_undo" parameter. + + * app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode, + _preserve_trans, _linked): added "gboolean push_undo" parameters. + + * app/core/gimpimage-mask.c + * app/core/gimpimage-merge.c + * app/core/gimplayer-floating-sel.c + * app/tools/gimpmovetool.c + * app/xcf/xcf-load.c + * app/widgets/gimpdrawablelistitem.c + * app/widgets/gimplayerlistitem.c + * app/widgets/gimplayerlistview.c: changed accordingly. + + * tools/pdbgen/pdb/channel.pdb + * tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to + the foo_accessors() functions. Removed $func from foo_accesors() + because we don't manipulate items without using getters/setters + any longer. + + * app/pdb/channel_cmds.c + * app/pdb/layer_cmds.c: regenerated. + + * app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal + which carries an additional "GdkModifierType state" parameter as + in GimpCellRendererViewable . + + * app/widgets/gimpcontainertreeview.c: emit "clicked" from + the toggle renderer, not "toggled" so the callbacks get the + modifier state. + + * app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive + visible by +click" feature as in 1.2. + + * app/widgets/gimplayertreeview.c: compress layer opacity undos by + looking at the top of the undo stack and not pushing an undo if + there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active + layer. + 2003-03-17 Sven Neumann * plug-ins/ifscompose/ifscompose.c (run): put the actual effect diff --git a/app/core/Makefile.am b/app/core/Makefile.am index a87d5c8005..ca527cdb3a 100644 --- a/app/core/Makefile.am +++ b/app/core/Makefile.am @@ -123,6 +123,8 @@ libappcore_a_sources = \ gimpimagemap.h \ gimpitem.c \ gimpitem.h \ + gimpitemundo.c \ + gimpitemundo.h \ gimplayer.c \ gimplayer.h \ gimplayer-floating-sel.c \ diff --git a/app/core/core-enums.c b/app/core/core-enums.c index c056a7de06..4a6be05693 100644 --- a/app/core/core-enums.c +++ b/app/core/core-enums.c @@ -436,11 +436,13 @@ static const GEnumValue gimp_undo_type_enum_values[] = { GIMP_UNDO_GROUP_IMAGE_QMASK, N_("QuickMask"), "group-image-qmask" }, { GIMP_UNDO_GROUP_IMAGE_GUIDE, N_("Guide"), "group-image-guide" }, { GIMP_UNDO_GROUP_ITEM_PROPERTIES, N_("Item Properties"), "group-item-properties" }, + { GIMP_UNDO_GROUP_DRAWABLE_VISIBILITY, N_("Drawable Visilibity"), "group-drawable-visibility" }, { GIMP_UNDO_GROUP_LAYER_SCALE, N_("Scale Layer"), "group-layer-scale" }, { GIMP_UNDO_GROUP_LAYER_RESIZE, N_("Resize Layer"), "group-layer-resize" }, { GIMP_UNDO_GROUP_LAYER_DISPLACE, N_("Move Layer"), "group-layer-displace" }, { GIMP_UNDO_GROUP_LAYER_LINKED, N_("Linked Layer"), "group-layer-linked" }, { GIMP_UNDO_GROUP_LAYER_APPLY_MASK, N_("Apply Layer Mask"), "group-layer-apply-mask" }, + { GIMP_UNDO_GROUP_FS_TO_LAYER, N_("Floating Selection to Layer"), "group-fs-to-layer" }, { GIMP_UNDO_GROUP_FS_FLOAT, N_("Float Selection"), "group-fs-float" }, { GIMP_UNDO_GROUP_FS_ANCHOR, N_("Anchor Floating Selection"), "group-fs-anchor" }, { GIMP_UNDO_GROUP_EDIT_PASTE, N_("Paste"), "group-edit-paste" }, @@ -461,22 +463,27 @@ static const GEnumValue gimp_undo_type_enum_values[] = { GIMP_UNDO_IMAGE_GUIDE, N_("Guide"), "image-guide" }, { GIMP_UNDO_MASK, N_("Selection Mask"), "mask" }, { GIMP_UNDO_ITEM_RENAME, N_("Rename Item"), "item-rename" }, + { GIMP_UNDO_DRAWABLE_VISIBILITY, N_("Drawable Visibility"), "drawable-visibility" }, { GIMP_UNDO_LAYER_ADD, N_("New Layer"), "layer-add" }, { GIMP_UNDO_LAYER_REMOVE, N_("Delete Layer"), "layer-remove" }, { GIMP_UNDO_LAYER_MOD, N_("Layer Mod"), "layer-mod" }, { GIMP_UNDO_LAYER_MASK_ADD, N_("Add Layer Mask"), "layer-mask-add" }, { GIMP_UNDO_LAYER_MASK_REMOVE, N_("Delete Layer Mask"), "layer-mask-remove" }, - { GIMP_UNDO_LAYER_REPOSITION, N_("Layer Reposition"), "layer-reposition" }, - { GIMP_UNDO_LAYER_DISPLACE, N_("Layer Move"), "layer-displace" }, + { GIMP_UNDO_LAYER_REPOSITION, N_("Reposition Layer"), "layer-reposition" }, + { GIMP_UNDO_LAYER_DISPLACE, N_("Move Layer"), "layer-displace" }, + { GIMP_UNDO_LAYER_MODE, N_("Set Layer Mode"), "layer-mode" }, + { GIMP_UNDO_LAYER_OPACITY, N_("Set Layer Opacity"), "layer-opacity" }, + { GIMP_UNDO_LAYER_PRESERVE_TRANS, N_("Set Preserve Trans"), "layer-preserve-trans" }, + { GIMP_UNDO_LAYER_LINKED, N_("Set Layer Linked"), "layer-linked" }, { GIMP_UNDO_CHANNEL_ADD, N_("New Channel"), "channel-add" }, { GIMP_UNDO_CHANNEL_REMOVE, N_("Delete Channel"), "channel-remove" }, { GIMP_UNDO_CHANNEL_MOD, N_("Channel Mod"), "channel-mod" }, - { GIMP_UNDO_CHANNEL_REPOSITION, N_("Channel Reposition"), "channel-reposition" }, + { GIMP_UNDO_CHANNEL_REPOSITION, N_("Reposition Channel"), "channel-reposition" }, { GIMP_UNDO_CHANNEL_COLOR, N_("Channel Color"), "channel-color" }, { GIMP_UNDO_VECTORS_ADD, N_("New Vectors"), "vectors-add" }, { GIMP_UNDO_VECTORS_REMOVE, N_("Delete Vectors"), "vectors-remove" }, { GIMP_UNDO_VECTORS_MOD, N_("Vectors Mod"), "vectors-mod" }, - { GIMP_UNDO_VECTORS_REPOSITION, N_("Vectors Reposition"), "vectors-reposition" }, + { GIMP_UNDO_VECTORS_REPOSITION, N_("Reposition Vectors"), "vectors-reposition" }, { GIMP_UNDO_FS_TO_LAYER, N_("FS to Layer"), "fs-to-layer" }, { GIMP_UNDO_FS_RIGOR, N_("FS Rigor"), "fs-rigor" }, { GIMP_UNDO_FS_RELAX, N_("FS Relax"), "fs-relax" }, diff --git a/app/core/core-enums.h b/app/core/core-enums.h index e887565abe..c2d6767137 100644 --- a/app/core/core-enums.h +++ b/app/core/core-enums.h @@ -318,34 +318,36 @@ 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. */ - GIMP_UNDO_GROUP_NONE = 0, /*< desc="<>" >*/ + GIMP_UNDO_GROUP_NONE = 0, /*< desc="<>" >*/ GIMP_UNDO_GROUP_FIRST = GIMP_UNDO_GROUP_NONE, /*< skip >*/ - GIMP_UNDO_GROUP_IMAGE_SCALE, /*< desc="Scale Image" >*/ - GIMP_UNDO_GROUP_IMAGE_RESIZE, /*< desc="Resize Image" >*/ - GIMP_UNDO_GROUP_IMAGE_CONVERT, /*< desc="Convert Image" >*/ - GIMP_UNDO_GROUP_IMAGE_CROP, /*< desc="Crop Image" >*/ - GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, /*< desc="Merge Layers" >*/ - GIMP_UNDO_GROUP_IMAGE_QMASK, /*< desc="QuickMask" >*/ - GIMP_UNDO_GROUP_IMAGE_GUIDE, /*< desc="Guide" >*/ - GIMP_UNDO_GROUP_ITEM_PROPERTIES, /*< desc="Item Properties" >*/ - GIMP_UNDO_GROUP_LAYER_SCALE, /*< desc="Scale Layer" >*/ - GIMP_UNDO_GROUP_LAYER_RESIZE, /*< desc="Resize Layer" >*/ - GIMP_UNDO_GROUP_LAYER_DISPLACE, /*< desc="Move Layer" >*/ - GIMP_UNDO_GROUP_LAYER_LINKED, /*< desc="Linked Layer" >*/ - GIMP_UNDO_GROUP_LAYER_APPLY_MASK, /*< desc="Apply Layer Mask" >*/ - GIMP_UNDO_GROUP_FS_FLOAT, /*< desc="Float Selection" >*/ - GIMP_UNDO_GROUP_FS_ANCHOR, /*< desc="Anchor Floating Selection" >*/ - GIMP_UNDO_GROUP_EDIT_PASTE, /*< desc="Paste" >*/ - GIMP_UNDO_GROUP_EDIT_CUT, /*< desc="Cut" >*/ - GIMP_UNDO_GROUP_EDIT_COPY, /*< desc="Copy" >*/ - GIMP_UNDO_GROUP_TEXT, /*< desc="Text" >*/ - GIMP_UNDO_GROUP_TRANSFORM, /*< desc="Transform" >*/ - GIMP_UNDO_GROUP_PAINT, /*< desc="Paint" >*/ - GIMP_UNDO_GROUP_PARASITE_ATTACH, /*< desc="Attach Parasite" >*/ - GIMP_UNDO_GROUP_PARASITE_REMOVE, /*< desc="Remove Parasite" >*/ - GIMP_UNDO_GROUP_MISC, /*< desc="Plug-In" >*/ + GIMP_UNDO_GROUP_IMAGE_SCALE, /*< desc="Scale Image" >*/ + GIMP_UNDO_GROUP_IMAGE_RESIZE, /*< desc="Resize Image" >*/ + GIMP_UNDO_GROUP_IMAGE_CONVERT, /*< desc="Convert Image" >*/ + GIMP_UNDO_GROUP_IMAGE_CROP, /*< desc="Crop Image" >*/ + GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, /*< desc="Merge Layers" >*/ + GIMP_UNDO_GROUP_IMAGE_QMASK, /*< desc="QuickMask" >*/ + GIMP_UNDO_GROUP_IMAGE_GUIDE, /*< desc="Guide" >*/ + GIMP_UNDO_GROUP_ITEM_PROPERTIES, /*< desc="Item Properties" >*/ + GIMP_UNDO_GROUP_DRAWABLE_VISIBILITY,/*< desc="Drawable Visilibity" >*/ + GIMP_UNDO_GROUP_LAYER_SCALE, /*< desc="Scale Layer" >*/ + GIMP_UNDO_GROUP_LAYER_RESIZE, /*< desc="Resize Layer" >*/ + GIMP_UNDO_GROUP_LAYER_DISPLACE, /*< desc="Move Layer" >*/ + GIMP_UNDO_GROUP_LAYER_LINKED, /*< desc="Linked Layer" >*/ + GIMP_UNDO_GROUP_LAYER_APPLY_MASK, /*< desc="Apply Layer Mask" >*/ + GIMP_UNDO_GROUP_FS_TO_LAYER, /*< desc="Floating Selection to Layer" >*/ + GIMP_UNDO_GROUP_FS_FLOAT, /*< desc="Float Selection" >*/ + GIMP_UNDO_GROUP_FS_ANCHOR, /*< desc="Anchor Floating Selection" >*/ + GIMP_UNDO_GROUP_EDIT_PASTE, /*< desc="Paste" >*/ + GIMP_UNDO_GROUP_EDIT_CUT, /*< desc="Cut" >*/ + GIMP_UNDO_GROUP_EDIT_COPY, /*< desc="Copy" >*/ + GIMP_UNDO_GROUP_TEXT, /*< desc="Text" >*/ + GIMP_UNDO_GROUP_TRANSFORM, /*< desc="Transform" >*/ + GIMP_UNDO_GROUP_PAINT, /*< desc="Paint" >*/ + GIMP_UNDO_GROUP_PARASITE_ATTACH, /*< desc="Attach Parasite" >*/ + GIMP_UNDO_GROUP_PARASITE_REMOVE, /*< desc="Remove Parasite" >*/ + GIMP_UNDO_GROUP_MISC, /*< desc="Plug-In" >*/ GIMP_UNDO_GROUP_LAST = GIMP_UNDO_GROUP_MISC, /*< skip >*/ @@ -360,22 +362,27 @@ typedef enum /*< pdb-skip >*/ GIMP_UNDO_IMAGE_GUIDE, /*< desc="Guide" >*/ GIMP_UNDO_MASK, /*< desc="Selection Mask" >*/ GIMP_UNDO_ITEM_RENAME, /*< desc="Rename Item" >*/ + GIMP_UNDO_DRAWABLE_VISIBILITY, /*< desc="Drawable Visibility" >*/ GIMP_UNDO_LAYER_ADD, /*< desc="New Layer" >*/ GIMP_UNDO_LAYER_REMOVE, /*< desc="Delete Layer" >*/ GIMP_UNDO_LAYER_MOD, /*< desc="Layer Mod" >*/ GIMP_UNDO_LAYER_MASK_ADD, /*< desc="Add Layer Mask" >*/ GIMP_UNDO_LAYER_MASK_REMOVE, /*< desc="Delete Layer Mask" >*/ - GIMP_UNDO_LAYER_REPOSITION, /*< desc="Layer Reposition" >*/ - GIMP_UNDO_LAYER_DISPLACE, /*< desc="Layer Move" >*/ + GIMP_UNDO_LAYER_REPOSITION, /*< desc="Reposition Layer" >*/ + GIMP_UNDO_LAYER_DISPLACE, /*< desc="Move Layer" >*/ + GIMP_UNDO_LAYER_MODE, /*< desc="Set Layer Mode" >*/ + GIMP_UNDO_LAYER_OPACITY, /*< desc="Set Layer Opacity" >*/ + GIMP_UNDO_LAYER_PRESERVE_TRANS, /*< desc="Set Preserve Trans" >*/ + GIMP_UNDO_LAYER_LINKED, /*< desc="Set Layer Linked" >*/ GIMP_UNDO_CHANNEL_ADD, /*< desc="New Channel" >*/ GIMP_UNDO_CHANNEL_REMOVE, /*< desc="Delete Channel" >*/ GIMP_UNDO_CHANNEL_MOD, /*< desc="Channel Mod" >*/ - GIMP_UNDO_CHANNEL_REPOSITION, /*< desc="Channel Reposition" >*/ + GIMP_UNDO_CHANNEL_REPOSITION, /*< desc="Reposition Channel" >*/ GIMP_UNDO_CHANNEL_COLOR, /*< desc="Channel Color" >*/ GIMP_UNDO_VECTORS_ADD, /*< desc="New Vectors" >*/ GIMP_UNDO_VECTORS_REMOVE, /*< desc="Delete Vectors" >*/ GIMP_UNDO_VECTORS_MOD, /*< desc="Vectors Mod" >*/ - GIMP_UNDO_VECTORS_REPOSITION, /*< desc="Vectors Reposition" >*/ + GIMP_UNDO_VECTORS_REPOSITION, /*< desc="Reposition Vectors" >*/ GIMP_UNDO_FS_TO_LAYER, /*< desc="FS to Layer" >*/ GIMP_UNDO_FS_RIGOR, /*< desc="FS Rigor" >*/ GIMP_UNDO_FS_RELAX, /*< desc="FS Relax" >*/ diff --git a/app/core/core-types.h b/app/core/core-types.h index b927dbd615..42095180a9 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -111,6 +111,7 @@ typedef struct _GimpEnvironTable GimpEnvironTable; /* undo objects */ typedef struct _GimpUndo GimpUndo; +typedef struct _GimpItemUndo GimpItemUndo; typedef struct _GimpUndoStack GimpUndoStack; typedef struct _GimpUndoAccumulator GimpUndoAccumulator; diff --git a/app/core/gimpchannel-combine.c b/app/core/gimpchannel-combine.c index 57ee381cdc..b69c7f1343 100644 --- a/app/core/gimpchannel-combine.c +++ b/app/core/gimpchannel-combine.c @@ -377,13 +377,33 @@ gimp_channel_get_opacity (const GimpChannel *channel) void gimp_channel_set_opacity (GimpChannel *channel, - gdouble opacity) + gdouble opacity, + gboolean push_undo) { g_return_if_fail (GIMP_IS_CHANNEL (channel)); opacity = CLAMP (opacity, GIMP_OPACITY_TRANSPARENT, GIMP_OPACITY_OPAQUE); - channel->color.a = opacity; + if (channel->color.a != opacity) + { + if (push_undo) + { + GimpImage *gimage; + + gimage = gimp_item_get_image (GIMP_ITEM (channel)); + + if (gimage) + gimp_image_undo_push_channel_color (gimage, _("Set Channel Opacity"), + channel); + } + + channel->color.a = opacity; + + gimp_drawable_update (GIMP_DRAWABLE (channel), + 0, 0, + GIMP_DRAWABLE (channel)->width, + GIMP_DRAWABLE (channel)->height); + } } gboolean diff --git a/app/core/gimpchannel-combine.h b/app/core/gimpchannel-combine.h index e439f19260..6d319ac31a 100644 --- a/app/core/gimpchannel-combine.h +++ b/app/core/gimpchannel-combine.h @@ -85,7 +85,8 @@ GimpChannel * gimp_channel_new_from_component (GimpImage *gimage, gdouble gimp_channel_get_opacity (const GimpChannel *channel); void gimp_channel_set_opacity (GimpChannel *channel, - gdouble opacity); + gdouble opacity, + gboolean push_undo); void gimp_channel_get_color (const GimpChannel *channel, GimpRGB *color); diff --git a/app/core/gimpchannel.c b/app/core/gimpchannel.c index 57ee381cdc..b69c7f1343 100644 --- a/app/core/gimpchannel.c +++ b/app/core/gimpchannel.c @@ -377,13 +377,33 @@ gimp_channel_get_opacity (const GimpChannel *channel) void gimp_channel_set_opacity (GimpChannel *channel, - gdouble opacity) + gdouble opacity, + gboolean push_undo) { g_return_if_fail (GIMP_IS_CHANNEL (channel)); opacity = CLAMP (opacity, GIMP_OPACITY_TRANSPARENT, GIMP_OPACITY_OPAQUE); - channel->color.a = opacity; + if (channel->color.a != opacity) + { + if (push_undo) + { + GimpImage *gimage; + + gimage = gimp_item_get_image (GIMP_ITEM (channel)); + + if (gimage) + gimp_image_undo_push_channel_color (gimage, _("Set Channel Opacity"), + channel); + } + + channel->color.a = opacity; + + gimp_drawable_update (GIMP_DRAWABLE (channel), + 0, 0, + GIMP_DRAWABLE (channel)->width, + GIMP_DRAWABLE (channel)->height); + } } gboolean diff --git a/app/core/gimpchannel.h b/app/core/gimpchannel.h index e439f19260..6d319ac31a 100644 --- a/app/core/gimpchannel.h +++ b/app/core/gimpchannel.h @@ -85,7 +85,8 @@ GimpChannel * gimp_channel_new_from_component (GimpImage *gimage, gdouble gimp_channel_get_opacity (const GimpChannel *channel); void gimp_channel_set_opacity (GimpChannel *channel, - gdouble opacity); + gdouble opacity, + gboolean push_undo); void gimp_channel_get_color (const GimpChannel *channel, GimpRGB *color); diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c index 40b5c2be30..928a096b2d 100644 --- a/app/core/gimpdrawable.c +++ b/app/core/gimpdrawable.c @@ -662,15 +662,22 @@ gimp_drawable_get_visible (const GimpDrawable *drawable) void gimp_drawable_set_visible (GimpDrawable *drawable, - gboolean visible) + gboolean visible, + gboolean push_undo) { g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); - visible = visible ? TRUE : FALSE; - if (drawable->visible != visible) { - drawable->visible = visible; + if (push_undo) + { + GimpImage *gimage = gimp_item_get_image (GIMP_ITEM (drawable)); + + if (gimage) + gimp_image_undo_push_drawable_visibility (gimage, NULL, drawable); + } + + drawable->visible = visible ? TRUE : FALSE; g_signal_emit (drawable, gimp_drawable_signals[VISIBILITY_CHANGED], 0); diff --git a/app/core/gimpdrawable.h b/app/core/gimpdrawable.h index 141f2e6042..db30ab54f7 100644 --- a/app/core/gimpdrawable.h +++ b/app/core/gimpdrawable.h @@ -118,7 +118,8 @@ gint gimp_drawable_height (const GimpDrawable *drawable); gboolean gimp_drawable_get_visible (const GimpDrawable *drawable); void gimp_drawable_set_visible (GimpDrawable *drawable, - gboolean visible); + gboolean visible, + gboolean push_undo); void gimp_drawable_offsets (const GimpDrawable *drawable, gint *offset_x, diff --git a/app/core/gimpimage-mask.c b/app/core/gimpimage-mask.c index 44d8f34566..47b6ed60da 100644 --- a/app/core/gimpimage-mask.c +++ b/app/core/gimpimage-mask.c @@ -643,7 +643,7 @@ gimp_image_mask_save (GimpImage *gimage) FALSE)); /* saved selections are not visible by default */ - gimp_drawable_set_visible (GIMP_DRAWABLE (new_channel), FALSE); + gimp_drawable_set_visible (GIMP_DRAWABLE (new_channel), FALSE, FALSE); gimp_image_add_channel (gimage, new_channel, -1); diff --git a/app/core/gimpimage-merge.c b/app/core/gimpimage-merge.c index 93ec5d6035..e95781444e 100644 --- a/app/core/gimpimage-merge.c +++ b/app/core/gimpimage-merge.c @@ -487,11 +487,11 @@ gimp_image_merge_layers (GimpImage *gimage, gimp_object_set_name (GIMP_OBJECT (merge_layer), name); g_free (name); + gimp_drawable_set_visible (GIMP_DRAWABLE (merge_layer), TRUE, TRUE); + /* End the merge undo group */ gimp_image_undo_group_end (gimage); - gimp_drawable_set_visible (GIMP_DRAWABLE (merge_layer), TRUE); - gimp_drawable_update (GIMP_DRAWABLE (merge_layer), 0, 0, gimp_drawable_width (GIMP_DRAWABLE (merge_layer)), diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index 3d7332a3a7..d76cdc06e0 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -44,12 +44,12 @@ #include "gimpimage-projection.h" #include "gimpimage-undo.h" #include "gimpimage.h" +#include "gimpitemundo.h" #include "gimplayer-floating-sel.h" #include "gimplayer.h" #include "gimplayermask.h" #include "gimplist.h" #include "gimpparasitelist.h" -#include "gimpundo.h" #include "gimpundostack.h" #include "paint/gimppaintcore.h" @@ -915,8 +915,7 @@ typedef struct _ItemRenameUndo ItemRenameUndo; struct _ItemRenameUndo { - GimpItem *item; - gchar *old_name; + gchar *old_name; }; static gboolean undo_pop_item_rename (GimpUndo *undo, @@ -935,19 +934,18 @@ gimp_image_undo_push_item_rename (GimpImage *gimage, g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE); - if ((new = gimp_image_undo_push (gimage, - sizeof (ItemRenameUndo), - sizeof (ItemRenameUndo), - GIMP_UNDO_ITEM_RENAME, undo_desc, - TRUE, - undo_pop_item_rename, - undo_free_item_rename))) + if ((new = gimp_image_undo_push_item (gimage, item, + sizeof (ItemRenameUndo), + sizeof (ItemRenameUndo), + GIMP_UNDO_ITEM_RENAME, undo_desc, + TRUE, + undo_pop_item_rename, + undo_free_item_rename))) { ItemRenameUndo *iru; iru = new->data; - iru->item = item; iru->old_name = g_strdup (gimp_object_get_name (GIMP_OBJECT (item))); return TRUE; @@ -962,12 +960,15 @@ undo_pop_item_rename (GimpUndo *undo, GimpUndoAccumulator *accum) { ItemRenameUndo *iru; + GimpItem *item; gchar *tmp; iru = (ItemRenameUndo *) undo->data; - tmp = g_strdup (gimp_object_get_name (GIMP_OBJECT (iru->item))); - gimp_object_set_name (GIMP_OBJECT (iru->item), iru->old_name); + item = GIMP_ITEM_UNDO (undo)->item; + + tmp = g_strdup (gimp_object_get_name (GIMP_OBJECT (item))); + gimp_object_set_name (GIMP_OBJECT (item), iru->old_name); g_free (iru->old_name); iru->old_name = tmp; @@ -987,6 +988,85 @@ undo_free_item_rename (GimpUndo *undo, } +/******************************/ +/* Drawable Visibility Undo */ +/******************************/ + +typedef struct _DrawableVisibilityUndo DrawableVisibilityUndo; + +struct _DrawableVisibilityUndo +{ + gboolean old_visible; +}; + +static gboolean undo_pop_drawable_visibility (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +static void undo_free_drawable_visibility (GimpUndo *undo, + GimpUndoMode undo_mode); + +gboolean +gimp_image_undo_push_drawable_visibility (GimpImage *gimage, + const gchar *undo_desc, + GimpDrawable *drawable) +{ + GimpUndo *new; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE); + + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (drawable), + sizeof (DrawableVisibilityUndo), + sizeof (DrawableVisibilityUndo), + GIMP_UNDO_DRAWABLE_VISIBILITY, undo_desc, + TRUE, + undo_pop_drawable_visibility, + undo_free_drawable_visibility))) + { + DrawableVisibilityUndo *dvu; + + dvu = new->data; + + dvu->old_visible = gimp_drawable_get_visible (drawable); + + return TRUE; + } + + return FALSE; +} + +static gboolean +undo_pop_drawable_visibility (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum) +{ + DrawableVisibilityUndo *dvu; + GimpDrawable *drawable; + gboolean visible; + + dvu = (DrawableVisibilityUndo *) undo->data; + + drawable = GIMP_DRAWABLE (GIMP_ITEM_UNDO (undo)->item); + + visible = gimp_drawable_get_visible (drawable); + gimp_drawable_set_visible (drawable, dvu->old_visible, FALSE); + dvu->old_visible = visible; + + return TRUE; +} + +static void +undo_free_drawable_visibility (GimpUndo *undo, + GimpUndoMode undo_mode) +{ + DrawableVisibilityUndo *dvu; + + dvu = (DrawableVisibilityUndo *) undo->data; + + g_free (dvu); +} + + /***************************/ /* Layer Add/Remove Undo */ /***************************/ @@ -995,7 +1075,6 @@ typedef struct _LayerUndo LayerUndo; struct _LayerUndo { - GimpLayer *layer; /* the actual layer */ gint prev_position; /* former position in list */ GimpLayer *prev_layer; /* previous active layer */ }; @@ -1054,18 +1133,17 @@ undo_push_layer (GimpImage *gimage, size = sizeof (LayerUndo) + gimp_object_get_memsize (GIMP_OBJECT (layer)); - if ((new = gimp_image_undo_push (gimage, - size, sizeof (LayerUndo), - type, undo_desc, - TRUE, - undo_pop_layer, - undo_free_layer))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (layer), + size, sizeof (LayerUndo), + type, undo_desc, + TRUE, + undo_pop_layer, + undo_free_layer))) { LayerUndo *lu; lu = new->data; - lu->layer = g_object_ref (layer); lu->prev_position = prev_position; lu->prev_layer = prev_layer; @@ -1081,9 +1159,12 @@ undo_pop_layer (GimpUndo *undo, GimpUndoAccumulator *accum) { LayerUndo *lu; + GimpLayer *layer; lu = (LayerUndo *) undo->data; + layer = GIMP_LAYER (GIMP_ITEM_UNDO (undo)->item); + if ((undo_mode == GIMP_UNDO_MODE_UNDO && undo->undo_type == GIMP_UNDO_LAYER_ADD) || (undo_mode == GIMP_UNDO_MODE_REDO && @@ -1092,31 +1173,31 @@ undo_pop_layer (GimpUndo *undo, /* remove layer */ /* record the current position */ - lu->prev_position = gimp_image_get_layer_index (undo->gimage, lu->layer); + lu->prev_position = gimp_image_get_layer_index (undo->gimage, layer); /* if exists, set the previous layer */ if (lu->prev_layer) gimp_image_set_active_layer (undo->gimage, lu->prev_layer); /* remove the layer */ - gimp_container_remove (undo->gimage->layers, GIMP_OBJECT (lu->layer)); + gimp_container_remove (undo->gimage->layers, GIMP_OBJECT (layer)); undo->gimage->layer_stack = g_slist_remove (undo->gimage->layer_stack, - lu->layer); + layer); /* reset the gimage values */ - if (gimp_layer_is_floating_sel (lu->layer)) + if (gimp_layer_is_floating_sel (layer)) { undo->gimage->floating_sel = NULL; /* reset the old drawable */ - floating_sel_reset (lu->layer); + floating_sel_reset (layer); gimp_image_floating_selection_changed (undo->gimage); } - gimp_drawable_update (GIMP_DRAWABLE (lu->layer), + gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, - GIMP_DRAWABLE (lu->layer)->width, - GIMP_DRAWABLE (lu->layer)->height); + GIMP_DRAWABLE (layer)->width, + GIMP_DRAWABLE (layer)->height); if (gimp_container_num_children (undo->gimage->layers) == 1 && ! gimp_drawable_has_alpha (GIMP_LIST (undo->gimage->layers)->list->data)) @@ -1136,8 +1217,8 @@ undo_pop_layer (GimpUndo *undo, gimp_layer_invalidate_boundary (gimp_image_get_active_layer (undo->gimage)); /* if this is a floating selection, set the fs pointer */ - if (gimp_layer_is_floating_sel (lu->layer)) - undo->gimage->floating_sel = lu->layer; + if (gimp_layer_is_floating_sel (layer)) + undo->gimage->floating_sel = layer; if (gimp_container_num_children (undo->gimage->layers) == 1 && ! gimp_drawable_has_alpha (GIMP_LIST (undo->gimage->layers)->list->data)) @@ -1147,16 +1228,16 @@ undo_pop_layer (GimpUndo *undo, /* add the new layer */ gimp_container_insert (undo->gimage->layers, - GIMP_OBJECT (lu->layer), lu->prev_position); - gimp_image_set_active_layer (undo->gimage, lu->layer); + GIMP_OBJECT (layer), lu->prev_position); + gimp_image_set_active_layer (undo->gimage, layer); - if (gimp_layer_is_floating_sel (lu->layer)) + if (gimp_layer_is_floating_sel (layer)) gimp_image_floating_selection_changed (undo->gimage); - gimp_drawable_update (GIMP_DRAWABLE (lu->layer), + gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, - GIMP_DRAWABLE (lu->layer)->width, - GIMP_DRAWABLE (lu->layer)->height); + GIMP_DRAWABLE (layer)->width, + GIMP_DRAWABLE (layer)->height); } return TRUE; @@ -1170,8 +1251,6 @@ undo_free_layer (GimpUndo *undo, lu = (LayerUndo *) undo->data; - g_object_unref (lu->layer); - g_free (lu); } @@ -1184,11 +1263,10 @@ typedef struct _LayerModUndo LayerModUndo; struct _LayerModUndo { - GimpLayer *layer; - TileManager *tiles; - GimpImageType type; - gint offset_x; - gint offset_y; + TileManager *tiles; + GimpImageType type; + gint offset_x; + gint offset_y; }; static gboolean undo_pop_layer_mod (GimpUndo *undo, @@ -1213,22 +1291,21 @@ gimp_image_undo_push_layer_mod (GimpImage *gimage, size = sizeof (LayerModUndo) + tile_manager_get_memsize (tiles); - if ((new = gimp_image_undo_push (gimage, - size, sizeof (LayerModUndo), - GIMP_UNDO_LAYER_MOD, undo_desc, - TRUE, - undo_pop_layer_mod, - undo_free_layer_mod))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (layer), + size, sizeof (LayerModUndo), + GIMP_UNDO_LAYER_MOD, undo_desc, + TRUE, + undo_pop_layer_mod, + undo_free_layer_mod))) { LayerModUndo *lmu; lmu = new->data; - lmu->layer = layer; - lmu->tiles = tiles; - lmu->type = GIMP_DRAWABLE (layer)->type; - lmu->offset_x = GIMP_DRAWABLE (layer)->offset_x; - lmu->offset_y = GIMP_DRAWABLE (layer)->offset_y; + lmu->tiles = tiles; + lmu->type = GIMP_DRAWABLE (layer)->type; + lmu->offset_x = GIMP_DRAWABLE (layer)->offset_x; + lmu->offset_y = GIMP_DRAWABLE (layer)->offset_y; return TRUE; } @@ -1244,14 +1321,14 @@ undo_pop_layer_mod (GimpUndo *undo, GimpUndoAccumulator *accum) { LayerModUndo *lmu; + GimpLayer *layer; GimpImageType layer_type; gint offset_x, offset_y; TileManager *tiles; - GimpLayer *layer; lmu = (LayerModUndo *) undo->data; - layer = lmu->layer; + layer = GIMP_LAYER (GIMP_ITEM_UNDO (undo)->item); /* Issue the first update */ gimp_image_update (undo->gimage, @@ -1328,8 +1405,7 @@ typedef struct _LayerMaskUndo LayerMaskUndo; struct _LayerMaskUndo { - GimpLayer *layer; /* the layer */ - GimpLayerMask *mask; /* the layer mask */ + GimpLayerMask *mask; }; static gboolean undo_push_layer_mask (GimpImage *gimage, @@ -1381,20 +1457,19 @@ undo_push_layer_mask (GimpImage *gimage, size = sizeof (LayerMaskUndo) + gimp_object_get_memsize (GIMP_OBJECT (mask)); - if ((new = gimp_image_undo_push (gimage, - size, - sizeof (LayerMaskUndo), - type, undo_desc, - TRUE, - undo_pop_layer_mask, - undo_free_layer_mask))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (layer), + size, + sizeof (LayerMaskUndo), + type, undo_desc, + TRUE, + undo_pop_layer_mask, + undo_free_layer_mask))) { LayerMaskUndo *lmu; lmu = new->data; - lmu->layer = layer; - lmu->mask = g_object_ref (mask); + lmu->mask = g_object_ref (mask); return TRUE; } @@ -1408,9 +1483,12 @@ undo_pop_layer_mask (GimpUndo *undo, GimpUndoAccumulator *accum) { LayerMaskUndo *lmu; + GimpLayer *layer; lmu = (LayerMaskUndo *) undo->data; + layer = GIMP_LAYER (GIMP_ITEM_UNDO (undo)->item); + if ((undo_mode == GIMP_UNDO_MODE_UNDO && undo->undo_type == GIMP_UNDO_LAYER_MASK_ADD) || (undo_mode == GIMP_UNDO_MODE_REDO && @@ -1418,13 +1496,13 @@ undo_pop_layer_mask (GimpUndo *undo, { /* remove layer mask */ - gimp_layer_apply_mask (lmu->layer, GIMP_MASK_DISCARD, FALSE); + gimp_layer_apply_mask (layer, GIMP_MASK_DISCARD, FALSE); } else { /* restore layer */ - gimp_layer_add_mask (lmu->layer, lmu->mask, FALSE); + gimp_layer_add_mask (layer, lmu->mask, FALSE); } return TRUE; @@ -1452,8 +1530,7 @@ typedef struct _LayerRepositionUndo LayerRepositionUndo; struct _LayerRepositionUndo { - GimpLayer *layer; - gint old_position; + gint old_position; }; static gboolean undo_pop_layer_reposition (GimpUndo *undo, @@ -1472,19 +1549,18 @@ gimp_image_undo_push_layer_reposition (GimpImage *gimage, g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - if ((new = gimp_image_undo_push (gimage, - sizeof (LayerRepositionUndo), - sizeof (LayerRepositionUndo), - GIMP_UNDO_LAYER_REPOSITION, undo_desc, - TRUE, - undo_pop_layer_reposition, - undo_free_layer_reposition))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (layer), + sizeof (LayerRepositionUndo), + sizeof (LayerRepositionUndo), + GIMP_UNDO_LAYER_REPOSITION, undo_desc, + TRUE, + undo_pop_layer_reposition, + undo_free_layer_reposition))) { LayerRepositionUndo *lru; lru = new->data; - lru->layer = layer; lru->old_position = gimp_image_get_layer_index (gimage, layer); return TRUE; @@ -1499,15 +1575,17 @@ undo_pop_layer_reposition (GimpUndo *undo, GimpUndoAccumulator *accum) { LayerRepositionUndo *lru; + GimpLayer *layer; gint pos; lru = (LayerRepositionUndo *) undo->data; - /* what's the layer's current index? */ - pos = gimp_image_get_layer_index (undo->gimage, lru->layer); - gimp_image_position_layer (undo->gimage, lru->layer, lru->old_position, - FALSE, NULL); + layer = GIMP_LAYER (GIMP_ITEM_UNDO (undo)->item); + /* what's the layer's current index? */ + pos = gimp_image_get_layer_index (undo->gimage, layer); + gimp_image_position_layer (undo->gimage, layer, lru->old_position, + FALSE, NULL); lru->old_position = pos; return TRUE; @@ -1529,10 +1607,9 @@ typedef struct _LayerDisplaceUndo LayerDisplaceUndo; struct _LayerDisplaceUndo { - GimpLayer *layer; - gint offset_x; - gint offset_y; - GSList *path_undo; + gint offset_x; + gint offset_y; + GSList *path_undo; }; static gboolean undo_pop_layer_displace (GimpUndo *undo, @@ -1551,19 +1628,18 @@ gimp_image_undo_push_layer_displace (GimpImage *gimage, g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); - if ((new = gimp_image_undo_push (gimage, - sizeof (LayerDisplaceUndo), - sizeof (LayerDisplaceUndo), - GIMP_UNDO_LAYER_DISPLACE, undo_desc, - TRUE, - undo_pop_layer_displace, - undo_free_layer_displace))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (layer), + sizeof (LayerDisplaceUndo), + sizeof (LayerDisplaceUndo), + GIMP_UNDO_LAYER_DISPLACE, undo_desc, + TRUE, + undo_pop_layer_displace, + undo_free_layer_displace))) { LayerDisplaceUndo *ldu; ldu = new->data; - ldu->layer = g_object_ref (layer); ldu->offset_x = GIMP_DRAWABLE (layer)->offset_x; ldu->offset_y = GIMP_DRAWABLE (layer)->offset_y; ldu->path_undo = path_transform_start_undo (gimage); @@ -1586,7 +1662,7 @@ undo_pop_layer_displace (GimpUndo *undo, ldu = (LayerDisplaceUndo *) undo->data; - layer = ldu->layer; + layer = GIMP_LAYER (GIMP_ITEM_UNDO (undo)->item); old_offset_x = GIMP_DRAWABLE (layer)->offset_x; old_offset_y = GIMP_DRAWABLE (layer)->offset_y; @@ -1633,8 +1709,6 @@ undo_free_layer_displace (GimpUndo *undo, ldu = (LayerDisplaceUndo *) undo->data; - g_object_unref (ldu->layer); - if (ldu->path_undo) path_transform_free_undo (ldu->path_undo); @@ -1642,6 +1716,160 @@ undo_free_layer_displace (GimpUndo *undo, } +/***************************/ +/* Layer properties Undo */ +/***************************/ + +typedef struct _LayerPropertiesUndo LayerPropertiesUndo; + +struct _LayerPropertiesUndo +{ + GimpLayerModeEffects old_mode; + gdouble old_opacity; + gboolean old_preserve_trans; + gboolean old_linked; +}; + +static gboolean undo_push_layer_properties (GimpImage *gimage, + GimpUndoType undo_type, + const gchar *undo_desc, + GimpLayer *layer); +static gboolean undo_pop_layer_properties (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum); +static void undo_free_layer_properties (GimpUndo *undo, + GimpUndoMode undo_mode); + +gboolean +gimp_image_undo_push_layer_mode (GimpImage *gimage, + const gchar *undo_desc, + GimpLayer *layer) +{ + return undo_push_layer_properties (gimage, GIMP_UNDO_LAYER_MODE, + undo_desc, layer); +} + +gboolean +gimp_image_undo_push_layer_opacity (GimpImage *gimage, + const gchar *undo_desc, + GimpLayer *layer) +{ + return undo_push_layer_properties (gimage, GIMP_UNDO_LAYER_OPACITY, + undo_desc, layer); +} + +gboolean +gimp_image_undo_push_layer_preserve_trans (GimpImage *gimage, + const gchar *undo_desc, + GimpLayer *layer) +{ + return undo_push_layer_properties (gimage, GIMP_UNDO_LAYER_PRESERVE_TRANS, + undo_desc, layer); +} + +gboolean +gimp_image_undo_push_layer_linked (GimpImage *gimage, + const gchar *undo_desc, + GimpLayer *layer) +{ + return undo_push_layer_properties (gimage, GIMP_UNDO_LAYER_LINKED, + undo_desc, layer); +} + +static gboolean +undo_push_layer_properties (GimpImage *gimage, + GimpUndoType undo_type, + const gchar *undo_desc, + GimpLayer *layer) +{ + GimpUndo *new; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); + g_return_val_if_fail (GIMP_IS_LAYER (layer), FALSE); + + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (layer), + sizeof (LayerPropertiesUndo), + sizeof (LayerPropertiesUndo), + undo_type, undo_desc, + TRUE, + undo_pop_layer_properties, + undo_free_layer_properties))) + { + LayerPropertiesUndo *lpu; + + lpu = new->data; + + lpu->old_mode = gimp_layer_get_mode (layer); + lpu->old_opacity = gimp_layer_get_opacity (layer); + lpu->old_preserve_trans = gimp_layer_get_preserve_trans (layer); + lpu->old_linked = gimp_layer_get_linked (layer); + + return TRUE; + } + + return FALSE; +} + +static gboolean +undo_pop_layer_properties (GimpUndo *undo, + GimpUndoMode undo_mode, + GimpUndoAccumulator *accum) +{ + LayerPropertiesUndo *lpu; + GimpLayer *layer; + + lpu = (LayerPropertiesUndo *) undo->data; + + layer = GIMP_LAYER (GIMP_ITEM_UNDO (undo)->item); + + if (undo->undo_type == GIMP_UNDO_LAYER_MODE) + { + GimpLayerModeEffects mode; + + mode = gimp_layer_get_mode (layer); + gimp_layer_set_mode (layer, lpu->old_mode, FALSE); + lpu->old_mode = mode; + } + else if (undo->undo_type == GIMP_UNDO_LAYER_OPACITY) + { + gdouble opacity; + + opacity = gimp_layer_get_opacity (layer); + gimp_layer_set_opacity (layer, lpu->old_opacity, FALSE); + lpu->old_opacity = opacity; + } + else if (undo->undo_type == GIMP_UNDO_LAYER_PRESERVE_TRANS) + { + gboolean preserve_trans; + + preserve_trans = gimp_layer_get_preserve_trans (layer); + gimp_layer_set_preserve_trans (layer, lpu->old_preserve_trans, FALSE); + lpu->old_preserve_trans = preserve_trans; + } + else if (undo->undo_type == GIMP_UNDO_LAYER_LINKED) + { + gboolean linked; + + linked = gimp_layer_get_linked (layer); + gimp_layer_set_linked (layer, lpu->old_linked, FALSE); + lpu->old_linked = linked; + } + + return TRUE; +} + +static void +undo_free_layer_properties (GimpUndo *undo, + GimpUndoMode undo_mode) +{ + LayerPropertiesUndo *lpu; + + lpu = (LayerPropertiesUndo *) undo->data; + + g_free (lpu); +} + + /*****************************/ /* Add/Remove Channel Undo */ /*****************************/ @@ -1650,7 +1878,6 @@ typedef struct _ChannelUndo ChannelUndo; struct _ChannelUndo { - GimpChannel *channel; /* the actual channel */ gint prev_position; /* former position in list */ GimpChannel *prev_channel; /* previous active channel */ }; @@ -1709,19 +1936,18 @@ undo_push_channel (GimpImage *gimage, size = sizeof (ChannelUndo) + gimp_object_get_memsize (GIMP_OBJECT (channel)); - if ((new = gimp_image_undo_push (gimage, - size, - sizeof (ChannelUndo), - type, undo_desc, - TRUE, - undo_pop_channel, - undo_free_channel))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (channel), + size, + sizeof (ChannelUndo), + type, undo_desc, + TRUE, + undo_pop_channel, + undo_free_channel))) { ChannelUndo *cu; cu = new->data; - cu->channel = g_object_ref (channel); cu->prev_position = prev_position; cu->prev_channel = prev_channel; @@ -1737,9 +1963,12 @@ undo_pop_channel (GimpUndo *undo, GimpUndoAccumulator *accum) { ChannelUndo *cu; + GimpChannel *channel; cu = (ChannelUndo *) undo->data; + channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (undo)->item); + if ((undo_mode == GIMP_UNDO_MODE_UNDO && undo->undo_type == GIMP_UNDO_CHANNEL_ADD) || (undo_mode == GIMP_UNDO_MODE_REDO && @@ -1749,20 +1978,20 @@ undo_pop_channel (GimpUndo *undo, /* record the current position */ cu->prev_position = gimp_image_get_channel_index (undo->gimage, - cu->channel); + channel); /* remove the channel */ - gimp_container_remove (undo->gimage->channels, GIMP_OBJECT (cu->channel)); + gimp_container_remove (undo->gimage->channels, GIMP_OBJECT (channel)); /* if exists, set the previous channel */ if (cu->prev_channel) gimp_image_set_active_channel (undo->gimage, cu->prev_channel); /* update the area */ - gimp_drawable_update (GIMP_DRAWABLE (cu->channel), + gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, - GIMP_DRAWABLE (cu->channel)->width, - GIMP_DRAWABLE (cu->channel)->height); + GIMP_DRAWABLE (channel)->width, + GIMP_DRAWABLE (channel)->height); } else { @@ -1773,16 +2002,16 @@ undo_pop_channel (GimpUndo *undo, /* add the new channel */ gimp_container_insert (undo->gimage->channels, - GIMP_OBJECT (cu->channel), cu->prev_position); + GIMP_OBJECT (channel), cu->prev_position); /* set the new channel */ - gimp_image_set_active_channel (undo->gimage, cu->channel); + gimp_image_set_active_channel (undo->gimage, channel); /* update the area */ - gimp_drawable_update (GIMP_DRAWABLE (cu->channel), + gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, - GIMP_DRAWABLE (cu->channel)->width, - GIMP_DRAWABLE (cu->channel)->height); + GIMP_DRAWABLE (channel)->width, + GIMP_DRAWABLE (channel)->height); } return TRUE; @@ -1796,8 +2025,6 @@ undo_free_channel (GimpUndo *undo, cu = (ChannelUndo *) undo->data; - g_object_unref (cu->channel); - g_free (cu); } @@ -1810,7 +2037,6 @@ typedef struct _ChannelModUndo ChannelModUndo; struct _ChannelModUndo { - GimpChannel *channel; TileManager *tiles; }; @@ -1836,20 +2062,19 @@ gimp_image_undo_push_channel_mod (GimpImage *gimage, size = sizeof (ChannelModUndo) + tile_manager_get_memsize (tiles); - if ((new = gimp_image_undo_push (gimage, - size, - sizeof (ChannelModUndo), - GIMP_UNDO_CHANNEL_MOD, undo_desc, - TRUE, - undo_pop_channel_mod, - undo_free_channel_mod))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (channel), + size, + sizeof (ChannelModUndo), + GIMP_UNDO_CHANNEL_MOD, undo_desc, + TRUE, + undo_pop_channel_mod, + undo_free_channel_mod))) { ChannelModUndo *cmu; cmu = new->data; - cmu->channel = channel; - cmu->tiles = tiles; + cmu->tiles = tiles; return TRUE; } @@ -1865,12 +2090,12 @@ undo_pop_channel_mod (GimpUndo *undo, GimpUndoAccumulator *accum) { ChannelModUndo *cmu; - TileManager *tiles; GimpChannel *channel; + TileManager *tiles; cmu = (ChannelModUndo *) undo->data; - channel = cmu->channel; + channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (undo)->item); /* Issue the first update */ gimp_drawable_update (GIMP_DRAWABLE (channel), @@ -1924,8 +2149,7 @@ typedef struct _ChannelRepositionUndo ChannelRepositionUndo; struct _ChannelRepositionUndo { - GimpChannel *channel; - gint old_position; + gint old_position; }; static gboolean undo_pop_channel_reposition (GimpUndo *undo, @@ -1944,19 +2168,18 @@ gimp_image_undo_push_channel_reposition (GimpImage *gimage, g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - if ((new = gimp_image_undo_push (gimage, - sizeof (ChannelRepositionUndo), - sizeof (ChannelRepositionUndo), - GIMP_UNDO_CHANNEL_REPOSITION, undo_desc, - TRUE, - undo_pop_channel_reposition, - undo_free_channel_reposition))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (channel), + sizeof (ChannelRepositionUndo), + sizeof (ChannelRepositionUndo), + GIMP_UNDO_CHANNEL_REPOSITION, undo_desc, + TRUE, + undo_pop_channel_reposition, + undo_free_channel_reposition))) { ChannelRepositionUndo *cru; cru = new->data; - cru->channel = channel; cru->old_position = gimp_image_get_channel_index (gimage, channel); return TRUE; @@ -1971,15 +2194,16 @@ undo_pop_channel_reposition (GimpUndo *undo, GimpUndoAccumulator *accum) { ChannelRepositionUndo *cru; + GimpChannel *channel; gint pos; cru = (ChannelRepositionUndo *) undo->data; - /* what's the channel's current index? */ - pos = gimp_image_get_channel_index (undo->gimage, cru->channel); - gimp_image_position_channel (undo->gimage, cru->channel, cru->old_position, - FALSE, NULL); + channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (undo)->item); + pos = gimp_image_get_channel_index (undo->gimage, channel); + gimp_image_position_channel (undo->gimage, channel, cru->old_position, + FALSE, NULL); cru->old_position = pos; return TRUE; @@ -2001,8 +2225,7 @@ typedef struct _ChannelColorUndo ChannelColorUndo; struct _ChannelColorUndo { - GimpChannel *channel; - GimpRGB old_color; + GimpRGB old_color; }; static gboolean undo_pop_channel_color (GimpUndo *undo, @@ -2021,19 +2244,18 @@ gimp_image_undo_push_channel_color (GimpImage *gimage, g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); g_return_val_if_fail (GIMP_IS_CHANNEL (channel), FALSE); - if ((new = gimp_image_undo_push (gimage, - sizeof (ChannelColorUndo), - sizeof (ChannelColorUndo), - GIMP_UNDO_CHANNEL_COLOR, undo_desc, - TRUE, - undo_pop_channel_color, - undo_free_channel_color))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (channel), + sizeof (ChannelColorUndo), + sizeof (ChannelColorUndo), + GIMP_UNDO_CHANNEL_COLOR, undo_desc, + TRUE, + undo_pop_channel_color, + undo_free_channel_color))) { ChannelColorUndo *ccu; ccu = new->data; - ccu->channel = channel; gimp_channel_get_color (channel , &ccu->old_color); return TRUE; @@ -2048,12 +2270,15 @@ undo_pop_channel_color (GimpUndo *undo, GimpUndoAccumulator *accum) { ChannelColorUndo *ccu; + GimpChannel *channel; GimpRGB color; ccu = (ChannelColorUndo *) undo->data; - gimp_channel_get_color (ccu->channel, &color); - gimp_channel_set_color (ccu->channel, &ccu->old_color, FALSE); + channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (undo)->item); + + gimp_channel_get_color (channel, &color); + gimp_channel_set_color (channel, &ccu->old_color, FALSE); ccu->old_color = color; return TRUE; @@ -2075,7 +2300,6 @@ typedef struct _VectorsUndo VectorsUndo; struct _VectorsUndo { - GimpVectors *vectors; /* the actual vectors */ gint prev_position; /* former position in list */ GimpVectors *prev_vectors; /* previous active vectors */ }; @@ -2134,19 +2358,18 @@ undo_push_vectors (GimpImage *gimage, size = sizeof (VectorsUndo) + gimp_object_get_memsize (GIMP_OBJECT (vectors)); - if ((new = gimp_image_undo_push (gimage, - size, - sizeof (VectorsUndo), - type, undo_desc, - TRUE, - undo_pop_vectors, - undo_free_vectors))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (vectors), + size, + sizeof (VectorsUndo), + type, undo_desc, + TRUE, + undo_pop_vectors, + undo_free_vectors))) { VectorsUndo *vu; vu = new->data; - vu->vectors = g_object_ref (vectors); vu->prev_position = prev_position; vu->prev_vectors = prev_vectors; @@ -2162,9 +2385,12 @@ undo_pop_vectors (GimpUndo *undo, GimpUndoAccumulator *accum) { VectorsUndo *vu; + GimpVectors *vectors; vu = (VectorsUndo *) undo->data; + vectors = GIMP_VECTORS (GIMP_ITEM_UNDO (undo)->item); + if ((undo_mode == GIMP_UNDO_MODE_UNDO && undo->undo_type == GIMP_UNDO_VECTORS_ADD) || (undo_mode == GIMP_UNDO_MODE_REDO && @@ -2174,10 +2400,10 @@ undo_pop_vectors (GimpUndo *undo, /* record the current position */ vu->prev_position = gimp_image_get_vectors_index (undo->gimage, - vu->vectors); + vectors); /* remove the vectors */ - gimp_container_remove (undo->gimage->vectors, GIMP_OBJECT (vu->vectors)); + gimp_container_remove (undo->gimage->vectors, GIMP_OBJECT (vectors)); /* if exists, set the previous vectors */ if (vu->prev_vectors) @@ -2192,10 +2418,10 @@ undo_pop_vectors (GimpUndo *undo, /* add the new vectors */ gimp_container_insert (undo->gimage->vectors, - GIMP_OBJECT (vu->vectors), vu->prev_position); + GIMP_OBJECT (vectors), vu->prev_position); /* set the new vectors */ - gimp_image_set_active_vectors (undo->gimage, vu->vectors); + gimp_image_set_active_vectors (undo->gimage, vectors); } return TRUE; @@ -2209,8 +2435,6 @@ undo_free_vectors (GimpUndo *undo, vu = (VectorsUndo *) undo->data; - g_object_unref (vu->vectors); - g_free (vu); } @@ -2223,7 +2447,6 @@ typedef struct _VectorsModUndo VectorsModUndo; struct _VectorsModUndo { - GimpVectors *vectors; GimpVectors *undo_vectors; }; @@ -2247,19 +2470,18 @@ gimp_image_undo_push_vectors_mod (GimpImage *gimage, size = (sizeof (VectorsModUndo) + gimp_object_get_memsize (GIMP_OBJECT (vectors))); - if ((new = gimp_image_undo_push (gimage, - size, - sizeof (VectorsModUndo), - GIMP_UNDO_VECTORS_MOD, undo_desc, - TRUE, - undo_pop_vectors_mod, - undo_free_vectors_mod))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (vectors), + size, + sizeof (VectorsModUndo), + GIMP_UNDO_VECTORS_MOD, undo_desc, + TRUE, + undo_pop_vectors_mod, + undo_free_vectors_mod))) { VectorsModUndo *vmu; vmu = new->data; - vmu->vectors = vectors; vmu->undo_vectors = GIMP_VECTORS (gimp_item_duplicate (GIMP_ITEM (vectors), G_TYPE_FROM_INSTANCE (vectors), FALSE)); @@ -2276,18 +2498,21 @@ undo_pop_vectors_mod (GimpUndo *undo, GimpUndoAccumulator *accum) { VectorsModUndo *vmu; + GimpVectors *vectors; GimpVectors *temp; vmu = (VectorsModUndo *) undo->data; + vectors = GIMP_VECTORS (GIMP_ITEM_UNDO (undo)->item); + temp = vmu->undo_vectors; vmu->undo_vectors = - GIMP_VECTORS (gimp_item_duplicate (GIMP_ITEM (vmu->vectors), - G_TYPE_FROM_INSTANCE (vmu->vectors), + GIMP_VECTORS (gimp_item_duplicate (GIMP_ITEM (vectors), + G_TYPE_FROM_INSTANCE (vectors), FALSE)); - gimp_vectors_copy_strokes (temp, vmu->vectors); + gimp_vectors_copy_strokes (temp, vectors); g_object_unref (temp); @@ -2316,8 +2541,7 @@ typedef struct _VectorsRepositionUndo VectorsRepositionUndo; struct _VectorsRepositionUndo { - GimpVectors *vectors; - gint old_position; + gint old_position; }; static gboolean undo_pop_vectors_reposition (GimpUndo *undo, @@ -2336,19 +2560,18 @@ gimp_image_undo_push_vectors_reposition (GimpImage *gimage, g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); g_return_val_if_fail (GIMP_IS_VECTORS (vectors), FALSE); - if ((new = gimp_image_undo_push (gimage, - sizeof (VectorsRepositionUndo), - sizeof (VectorsRepositionUndo), - GIMP_UNDO_VECTORS_REPOSITION, undo_desc, - TRUE, - undo_pop_vectors_reposition, - undo_free_vectors_reposition))) + if ((new = gimp_image_undo_push_item (gimage, GIMP_ITEM (vectors), + sizeof (VectorsRepositionUndo), + sizeof (VectorsRepositionUndo), + GIMP_UNDO_VECTORS_REPOSITION, undo_desc, + TRUE, + undo_pop_vectors_reposition, + undo_free_vectors_reposition))) { VectorsRepositionUndo *vru; vru = new->data; - vru->vectors = vectors; vru->old_position = gimp_image_get_vectors_index (gimage, vectors); return TRUE; @@ -2363,15 +2586,17 @@ undo_pop_vectors_reposition (GimpUndo *undo, GimpUndoAccumulator *accum) { VectorsRepositionUndo *vru; + GimpVectors *vectors; gint pos; vru = (VectorsRepositionUndo *) undo->data; - /* what's the vectors's current index? */ - pos = gimp_image_get_vectors_index (undo->gimage, vru->vectors); - gimp_image_position_vectors (undo->gimage, vru->vectors, vru->old_position, - FALSE, NULL); + vectors = GIMP_VECTORS (GIMP_ITEM_UNDO (undo)->item); + /* what's the vectors's current index? */ + pos = gimp_image_get_vectors_index (undo->gimage, vectors); + gimp_image_position_vectors (undo->gimage, vectors, vru->old_position, + FALSE, NULL); vru->old_position = pos; return TRUE; diff --git a/app/core/gimpimage-undo-push.h b/app/core/gimpimage-undo-push.h index f5d098fe27..81fcc64646 100644 --- a/app/core/gimpimage-undo-push.h +++ b/app/core/gimpimage-undo-push.h @@ -65,6 +65,13 @@ gboolean gimp_image_undo_push_item_rename (GimpImage *gimage, GimpItem *item); +/* drawable undos */ + +gboolean gimp_image_undo_push_drawable_visibility (GimpImage *gimage, + const gchar *undo_desc, + GimpDrawable *drawable); + + /* layer undos */ gboolean gimp_image_undo_push_layer_add (GimpImage *gimage, @@ -94,6 +101,18 @@ gboolean gimp_image_undo_push_layer_reposition (GimpImage *gimage, gboolean gimp_image_undo_push_layer_displace (GimpImage *gimage, const gchar *undo_desc, GimpLayer *layer); +gboolean gimp_image_undo_push_layer_mode (GimpImage *gimage, + const gchar *undo_desc, + GimpLayer *layer); +gboolean gimp_image_undo_push_layer_opacity (GimpImage *gimage, + const gchar *undo_desc, + GimpLayer *layer); +gboolean gimp_image_undo_push_layer_preserve_trans (GimpImage *gimage, + const gchar *undo_desc, + GimpLayer *layer); +gboolean gimp_image_undo_push_layer_linked (GimpImage *gimage, + const gchar *undo_desc, + GimpLayer *layer); /* channel undos */ diff --git a/app/core/gimpimage-undo.c b/app/core/gimpimage-undo.c index b6895079a9..9f2596fe91 100644 --- a/app/core/gimpimage-undo.c +++ b/app/core/gimpimage-undo.c @@ -27,6 +27,8 @@ #include "gimp.h" #include "gimpimage.h" #include "gimpimage-undo.h" +#include "gimpitem.h" +#include "gimpitemundo.h" #include "gimplist.h" #include "gimpundostack.h" @@ -190,11 +192,29 @@ gimp_image_undo_push (GimpImage *gimage, gboolean dirties_image, GimpUndoPopFunc pop_func, GimpUndoFreeFunc free_func) +{ + return gimp_image_undo_push_item (gimage, NULL, + size, struct_size, + type, name, dirties_image, + pop_func, free_func); +} + +GimpUndo * +gimp_image_undo_push_item (GimpImage *gimage, + GimpItem *item, + 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 (item == NULL || GIMP_IS_ITEM (item), NULL); g_return_val_if_fail (type > GIMP_UNDO_GROUP_LAST, NULL); if (! name) @@ -224,12 +244,22 @@ gimp_image_undo_push (GimpImage *gimage, if (struct_size > 0) undo_struct = g_malloc0 (struct_size); - new = gimp_undo_new (gimage, - type, - name, - undo_struct, size, - dirties_image, - pop_func, free_func); + if (item) + { + new = gimp_item_undo_new (gimage, item, + type, name, + undo_struct, size, + dirties_image, + pop_func, free_func); + } + else + { + new = gimp_undo_new (gimage, + type, name, + undo_struct, size, + dirties_image, + pop_func, free_func); + } if (gimage->pushing_undo_group == GIMP_UNDO_GROUP_NONE) { diff --git a/app/core/gimpimage-undo.h b/app/core/gimpimage-undo.h index ea6379ff89..a21307f925 100644 --- a/app/core/gimpimage-undo.h +++ b/app/core/gimpimage-undo.h @@ -38,6 +38,15 @@ GimpUndo * gimp_image_undo_push (GimpImage *gimage, gboolean dirties_image, GimpUndoPopFunc pop_func, GimpUndoFreeFunc free_func); +GimpUndo * gimp_image_undo_push_item (GimpImage *gimage, + GimpItem *item, + gsize size, + gsize struct_size, + GimpUndoType type, + const gchar *name, + gboolean dirties_image, + GimpUndoPopFunc pop_func, + GimpUndoFreeFunc free_func); #endif /* __GIMP_IMAGE_UNDO_H__ */ diff --git a/app/core/gimpitemundo.c b/app/core/gimpitemundo.c new file mode 100644 index 0000000000..15832fa31d --- /dev/null +++ b/app/core/gimpitemundo.c @@ -0,0 +1,138 @@ +/* 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. + */ + +#include "config.h" + +#include + +#include "core-types.h" + +#include "gimpimage.h" +#include "gimpitem.h" +#include "gimpitemundo.h" + + +static void gimp_item_undo_class_init (GimpItemUndoClass *klass); +static void gimp_item_undo_init (GimpItemUndo *undo); + +static void gimp_item_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode); + + +static GimpUndoClass *parent_class = NULL; + + +GType +gimp_item_undo_get_type (void) +{ + static GType undo_type = 0; + + if (! undo_type) + { + static const GTypeInfo undo_info = + { + sizeof (GimpItemUndoClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gimp_item_undo_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GimpItemUndo), + 0, /* n_preallocs */ + (GInstanceInitFunc) gimp_item_undo_init, + }; + + undo_type = g_type_register_static (GIMP_TYPE_UNDO, + "GimpItemUndo", + &undo_info, 0); + } + + return undo_type; +} + +static void +gimp_item_undo_class_init (GimpItemUndoClass *klass) +{ + GObjectClass *object_class; + GimpUndoClass *undo_class; + + object_class = G_OBJECT_CLASS (klass); + undo_class = GIMP_UNDO_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + undo_class->free = gimp_item_undo_free; +} + +static void +gimp_item_undo_init (GimpItemUndo *undo) +{ + undo->item = NULL; +} + +static void +gimp_item_undo_free (GimpUndo *undo, + GimpUndoMode undo_mode) +{ + GimpItemUndo *item_undo; + + item_undo = GIMP_ITEM_UNDO (undo); + + GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode); + + if (item_undo->item) + { + g_object_unref (item_undo->item); + item_undo->item = NULL; + } +} + +GimpUndo * +gimp_item_undo_new (GimpImage *gimage, + GimpItem *item, + GimpUndoType undo_type, + const gchar *name, + gpointer data, + gsize size, + gboolean dirties_image, + GimpUndoPopFunc pop_func, + GimpUndoFreeFunc free_func) +{ + GimpUndo *undo; + + g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL); + g_return_val_if_fail (GIMP_IS_ITEM (item), 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_ITEM_UNDO, + "name", name, + NULL); + + undo->gimage = gimage; + 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; + + GIMP_ITEM_UNDO (undo)->item = g_object_ref (item); + + return undo; +} diff --git a/app/core/gimpitemundo.h b/app/core/gimpitemundo.h new file mode 100644 index 0000000000..73cacde7e3 --- /dev/null +++ b/app/core/gimpitemundo.h @@ -0,0 +1,62 @@ +/* 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 __GIMP_ITEM_UNDO_H__ +#define __GIMP_ITEM_UNDO_H__ + + +#include "gimpundo.h" + + +#define GIMP_TYPE_ITEM_UNDO (gimp_item_undo_get_type ()) +#define GIMP_ITEM_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_ITEM_UNDO, GimpItemUndo)) +#define GIMP_ITEM_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_ITEM_UNDO, GimpItemUndoClass)) +#define GIMP_IS_ITEM_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_ITEM_UNDO)) +#define GIMP_IS_ITEM_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_ITEM_UNDO)) +#define GIMP_ITEM_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_ITEM_UNDO, GimpItemUndoClass)) + + +typedef struct _GimpItemUndoClass GimpItemUndoClass; + +struct _GimpItemUndo +{ + GimpUndo parent_instance; + + GimpItem *item; /* the item this undo is for */ +}; + +struct _GimpItemUndoClass +{ + GimpUndoClass parent_class; +}; + + +GType gimp_item_undo_get_type (void) G_GNUC_CONST; + +GimpUndo * gimp_item_undo_new (GimpImage *gimage, + GimpItem *item, + GimpUndoType undo_type, + const gchar *name, + gpointer data, + gsize size, + gboolean dirties_image, + GimpUndoPopFunc pop_func, + GimpUndoFreeFunc free_func); + + +#endif /* __GIMP_ITEM_UNDO_H__ */ diff --git a/app/core/gimplayer-floating-sel.c b/app/core/gimplayer-floating-sel.c index 18e6dd0e15..4702fe0935 100644 --- a/app/core/gimplayer-floating-sel.c +++ b/app/core/gimplayer-floating-sel.c @@ -65,7 +65,7 @@ floating_sel_attach (GimpLayer *layer, } /* set the drawable and allocate a backing store */ - gimp_layer_set_preserve_trans (layer, TRUE); + gimp_layer_set_preserve_trans (layer, TRUE, FALSE); layer->fs.drawable = drawable; layer->fs.backing_store = tile_manager_new (GIMP_DRAWABLE (layer)->width, @@ -214,10 +214,11 @@ floating_sel_to_layer (GimpLayer *layer) width = gimp_drawable_width (layer->fs.drawable); height = gimp_drawable_height (layer->fs.drawable); - gimp_image_undo_push_fs_to_layer (gimage, - _("Floating Selection to Layer"), - layer, - layer->fs.drawable); + gimp_image_undo_group_start (gimage, GIMP_UNDO_GROUP_FS_TO_LAYER, + _("Floating Selection to Layer")); + + gimp_image_undo_push_fs_to_layer (gimage, NULL, + layer, layer->fs.drawable); /* clear the selection */ gimp_layer_invalidate_boundary (layer); @@ -225,7 +226,9 @@ floating_sel_to_layer (GimpLayer *layer) /* Set pointers */ layer->fs.drawable = NULL; gimage->floating_sel = NULL; - gimp_drawable_set_visible (GIMP_DRAWABLE (layer), TRUE); + gimp_drawable_set_visible (GIMP_DRAWABLE (layer), TRUE, TRUE); + + gimp_image_undo_group_end (gimage); gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, @@ -447,7 +450,7 @@ floating_sel_composite (GimpLayer *layer, { d_layer = GIMP_LAYER (layer->fs.drawable); if ((preserve_trans = gimp_layer_get_preserve_trans (d_layer))) - gimp_layer_set_preserve_trans (d_layer, FALSE); + gimp_layer_set_preserve_trans (d_layer, FALSE, FALSE); } else preserve_trans = FALSE; @@ -475,7 +478,7 @@ floating_sel_composite (GimpLayer *layer, /* restore preserve transparency */ if (preserve_trans) - gimp_layer_set_preserve_trans (d_layer, TRUE); + gimp_layer_set_preserve_trans (d_layer, TRUE, FALSE); /* restore gimage active channels */ for (i = 0; i < MAX_CHANNELS; i++) diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c index 739a2c7286..8d9bb2a19d 100644 --- a/app/core/gimplayer.c +++ b/app/core/gimplayer.c @@ -1546,7 +1546,8 @@ gimp_layer_is_floating_sel (const GimpLayer *layer) void gimp_layer_set_opacity (GimpLayer *layer, - gdouble opacity) + gdouble opacity, + gboolean push_undo) { g_return_if_fail (GIMP_IS_LAYER (layer)); @@ -1554,6 +1555,14 @@ gimp_layer_set_opacity (GimpLayer *layer, if (layer->opacity != opacity) { + if (push_undo) + { + GimpImage *gimage = gimp_item_get_image (GIMP_ITEM (layer)); + + if (gimage) + gimp_image_undo_push_layer_opacity (gimage, NULL, layer); + } + layer->opacity = opacity; g_signal_emit (layer, layer_signals[OPACITY_CHANGED], 0); @@ -1575,12 +1584,21 @@ gimp_layer_get_opacity (const GimpLayer *layer) void gimp_layer_set_mode (GimpLayer *layer, - GimpLayerModeEffects mode) + GimpLayerModeEffects mode, + gboolean push_undo) { g_return_if_fail (GIMP_IS_LAYER (layer)); if (layer->mode != mode) { + if (push_undo) + { + GimpImage *gimage = gimp_item_get_image (GIMP_ITEM (layer)); + + if (gimage) + gimp_image_undo_push_layer_mode (gimage, NULL, layer); + } + layer->mode = mode; g_signal_emit (layer, layer_signals[MODE_CHANGED], 0); @@ -1602,12 +1620,21 @@ gimp_layer_get_mode (const GimpLayer *layer) void gimp_layer_set_preserve_trans (GimpLayer *layer, - gboolean preserve) + gboolean preserve, + gboolean push_undo) { g_return_if_fail (GIMP_IS_LAYER (layer)); if (layer->preserve_trans != preserve) { + if (push_undo) + { + GimpImage *gimage = gimp_item_get_image (GIMP_ITEM (layer)); + + if (gimage) + gimp_image_undo_push_layer_preserve_trans (gimage, NULL, layer); + } + layer->preserve_trans = preserve ? TRUE : FALSE; g_signal_emit (layer, layer_signals[PRESERVE_TRANS_CHANGED], 0); @@ -1624,12 +1651,21 @@ gimp_layer_get_preserve_trans (const GimpLayer *layer) void gimp_layer_set_linked (GimpLayer *layer, - gboolean linked) + gboolean linked, + gboolean push_undo) { g_return_if_fail (GIMP_IS_LAYER (layer)); if (layer->linked != linked) { + if (push_undo) + { + GimpImage *gimage = gimp_item_get_image (GIMP_ITEM (layer)); + + if (gimage) + gimp_image_undo_push_layer_linked (gimage, NULL, layer); + } + layer->linked = linked ? TRUE : FALSE; g_signal_emit (layer, layer_signals[LINKED_CHANGED], 0); diff --git a/app/core/gimplayer.h b/app/core/gimplayer.h index e9b1ca23fe..4b1bbbb704 100644 --- a/app/core/gimplayer.h +++ b/app/core/gimplayer.h @@ -133,19 +133,23 @@ GimpLayerMask * gimp_layer_get_mask (const GimpLayer *layer); gboolean gimp_layer_is_floating_sel (const GimpLayer *layer); void gimp_layer_set_opacity (GimpLayer *layer, - gdouble opacity); + gdouble opacity, + gboolean push_undo); gdouble gimp_layer_get_opacity (const GimpLayer *layer); void gimp_layer_set_mode (GimpLayer *layer, - GimpLayerModeEffects mode); + GimpLayerModeEffects mode, + gboolean push_undo); GimpLayerModeEffects gimp_layer_get_mode (const GimpLayer *layer); void gimp_layer_set_preserve_trans (GimpLayer *layer, - gboolean preserve); + gboolean preserve, + gboolean push_undo); gboolean gimp_layer_get_preserve_trans (const GimpLayer *layer); void gimp_layer_set_linked (GimpLayer *layer, - gboolean linked); + gboolean linked, + gboolean push_undo); gboolean gimp_layer_get_linked (const GimpLayer *layer); diff --git a/app/pdb/channel_cmds.c b/app/pdb/channel_cmds.c index 55361c6793..7743e43a02 100644 --- a/app/pdb/channel_cmds.c +++ b/app/pdb/channel_cmds.c @@ -546,7 +546,7 @@ channel_set_visible_invoker (Gimp *gimp, visible = args[1].value.pdb_int ? TRUE : FALSE; if (success) - gimp_drawable_set_visible (GIMP_DRAWABLE (channel), visible); + gimp_drawable_set_visible (GIMP_DRAWABLE (channel), visible, TRUE); return procedural_db_return_args (&channel_set_visible_proc, success); } @@ -700,7 +700,7 @@ channel_get_opacity_invoker (Gimp *gimp, return_args = procedural_db_return_args (&channel_get_opacity_proc, success); if (success) - return_args[1].value.pdb_float = channel->color.a * 100.0; + return_args[1].value.pdb_float = gimp_channel_get_opacity (channel) * 100.0; return return_args; } @@ -756,7 +756,7 @@ channel_set_opacity_invoker (Gimp *gimp, success = FALSE; if (success) - channel->color.a = opacity / 100.0; + gimp_channel_set_opacity (channel, opacity / 100.0, TRUE); return procedural_db_return_args (&channel_set_opacity_proc, success); } @@ -806,7 +806,7 @@ channel_get_color_invoker (Gimp *gimp, if (success) { - color = channel->color; + gimp_channel_get_color (channel, &color); } return_args = procedural_db_return_args (&channel_get_color_proc, success); diff --git a/app/pdb/layer_cmds.c b/app/pdb/layer_cmds.c index b018140412..815a385264 100644 --- a/app/pdb/layer_cmds.c +++ b/app/pdb/layer_cmds.c @@ -1186,7 +1186,7 @@ layer_set_visible_invoker (Gimp *gimp, visible = args[1].value.pdb_int ? TRUE : FALSE; if (success) - gimp_drawable_set_visible (GIMP_DRAWABLE (layer), visible); + gimp_drawable_set_visible (GIMP_DRAWABLE (layer), visible, TRUE); return procedural_db_return_args (&layer_set_visible_proc, success); } @@ -1290,7 +1290,7 @@ layer_set_preserve_trans_invoker (Gimp *gimp, preserve_trans = args[1].value.pdb_int ? TRUE : FALSE; if (success) - gimp_layer_set_preserve_trans (layer, preserve_trans); + gimp_layer_set_preserve_trans (layer, preserve_trans, TRUE); return procedural_db_return_args (&layer_set_preserve_trans_proc, success); } @@ -1708,7 +1708,7 @@ layer_set_opacity_invoker (Gimp *gimp, success = FALSE; if (success) - gimp_layer_set_opacity (layer, opacity / 100.0); + gimp_layer_set_opacity (layer, opacity / 100.0, TRUE); return procedural_db_return_args (&layer_set_opacity_proc, success); } @@ -1814,7 +1814,7 @@ layer_set_mode_invoker (Gimp *gimp, success = FALSE; if (success) - gimp_layer_set_mode (layer, mode); + gimp_layer_set_mode (layer, mode, TRUE); return procedural_db_return_args (&layer_set_mode_proc, success); } @@ -1918,7 +1918,7 @@ layer_set_linked_invoker (Gimp *gimp, linked = args[1].value.pdb_int ? TRUE : FALSE; if (success) - gimp_layer_set_linked (layer, linked); + gimp_layer_set_linked (layer, linked, TRUE); return procedural_db_return_args (&layer_set_linked_proc, success); } diff --git a/app/tools/gimpmovetool.c b/app/tools/gimpmovetool.c index c70093cd54..7d4941f17a 100644 --- a/app/tools/gimpmovetool.c +++ b/app/tools/gimpmovetool.c @@ -278,8 +278,13 @@ gimp_move_tool_button_press (GimpTool *tool, { gimp_image_set_active_layer (gdisp->gimage, layer); +#ifdef __GNUC__ +#warning FIXME: gimp_layer_set_linked() +#endif +#if 0 if (state & GDK_SHIFT_MASK) gimp_layer_set_linked (layer, ! gimp_layer_get_linked (layer)); +#endif init_edit_selection (tool, gdisp, coords, EDIT_LAYER_TRANSLATE); } diff --git a/app/widgets/gimpcellrenderertoggle.c b/app/widgets/gimpcellrenderertoggle.c index e059cb040f..ff5e223544 100644 --- a/app/widgets/gimpcellrenderertoggle.c +++ b/app/widgets/gimpcellrenderertoggle.c @@ -25,11 +25,20 @@ #include "widgets-types.h" +#include "core/gimpmarshal.h" + #include "gimpcellrenderertoggle.h" #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON + +enum +{ + CLICKED, + LAST_SIGNAL +}; + enum { PROP_0, @@ -64,10 +73,19 @@ static void gimp_cell_renderer_toggle_render (GtkCellRenderer *cell, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags); +static gboolean gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags); static void gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle, GtkWidget *widget); +static guint toggle_cell_signals[LAST_SIGNAL] = { 0 }; + static GtkCellRendererToggleClass *parent_class = NULL; @@ -110,6 +128,17 @@ gimp_cell_renderer_toggle_class_init (GimpCellRendererToggleClass *klass) parent_class = g_type_class_peek_parent (klass); + toggle_cell_signals[CLICKED] = + g_signal_new ("clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GimpCellRendererToggleClass, clicked), + NULL, NULL, + gimp_marshal_VOID__STRING_UINT, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_UINT); + object_class->finalize = gimp_cell_renderer_toggle_finalize; object_class->get_property = gimp_cell_renderer_toggle_get_property; object_class->set_property = gimp_cell_renderer_toggle_set_property; @@ -374,6 +403,35 @@ gimp_cell_renderer_toggle_render (GtkCellRenderer *cell, } } +static gboolean +gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + GtkCellRendererToggle *celltoggle; + + celltoggle = GTK_CELL_RENDERER_TOGGLE (cell); + + if (celltoggle->activatable) + { + GdkModifierType state = 0; + + if (((GdkEventAny *) event)->type == GDK_BUTTON_PRESS) + state = ((GdkEventButton *) event)->state; + + g_signal_emit (cell, toggle_cell_signals[CLICKED], 0, + path, state); + + return TRUE; + } + + return FALSE; +} + static void gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle, GtkWidget *widget) diff --git a/app/widgets/gimpcellrenderertoggle.h b/app/widgets/gimpcellrenderertoggle.h index 3705a39c1c..be0aa31270 100644 --- a/app/widgets/gimpcellrenderertoggle.h +++ b/app/widgets/gimpcellrenderertoggle.h @@ -48,6 +48,10 @@ struct _GimpCellRendererToggle struct _GimpCellRendererToggleClass { GtkCellRendererToggleClass parent_class; + + void (* clicked) (GimpCellRendererViewable *cell, + const gchar *path, + GdkModifierType state); }; diff --git a/app/widgets/gimpcontainertreeview.c b/app/widgets/gimpcontainertreeview.c index 36bc739604..5d6be3bac7 100644 --- a/app/widgets/gimpcontainertreeview.c +++ b/app/widgets/gimpcontainertreeview.c @@ -749,8 +749,8 @@ gimp_container_tree_view_button_press (GtkWidget *widget, if (toggled_cell) { /* don't select path */ - g_signal_emit_by_name (toggled_cell, "toggled", - path_str); + g_signal_emit_by_name (toggled_cell, "clicked", + path_str, bevent->state); } else if (clicked_cell) { diff --git a/app/widgets/gimpdrawablelistitem.c b/app/widgets/gimpdrawablelistitem.c index 8612c7ff25..9788b89998 100644 --- a/app/widgets/gimpdrawablelistitem.c +++ b/app/widgets/gimpdrawablelistitem.c @@ -201,7 +201,7 @@ gimp_drawable_list_item_eye_toggled (GtkWidget *widget, gimp_drawable_list_item_visibility_changed, list_item); - gimp_drawable_set_visible (drawable, visible); + gimp_drawable_set_visible (drawable, visible, TRUE); g_signal_handlers_unblock_by_func (drawable, gimp_drawable_list_item_visibility_changed, diff --git a/app/widgets/gimpdrawabletreeview.c b/app/widgets/gimpdrawabletreeview.c index 432278bc26..179a9dad8f 100644 --- a/app/widgets/gimpdrawabletreeview.c +++ b/app/widgets/gimpdrawabletreeview.c @@ -88,8 +88,9 @@ static void gimp_drawable_tree_view_new_color_dropped static void gimp_drawable_tree_view_visibility_changed (GimpDrawable *drawable, GimpDrawableTreeView *view); -static void gimp_drawable_tree_view_eye_toggled(GtkCellRendererToggle *toggle, +static void gimp_drawable_tree_view_eye_clicked(GtkCellRendererToggle *toggle, gchar *path, + GdkModifierType state, GimpDrawableTreeView *view); @@ -194,8 +195,8 @@ gimp_drawable_tree_view_constructor (GType type, tree_view->toggle_cells = g_list_prepend (tree_view->toggle_cells, drawable_view->eye_cell); - g_signal_connect (drawable_view->eye_cell, "toggled", - G_CALLBACK (gimp_drawable_tree_view_eye_toggled), + g_signal_connect (drawable_view->eye_cell, "clicked", + G_CALLBACK (gimp_drawable_tree_view_eye_clicked), drawable_view); gtk_tree_selection_set_select_function (tree_view->selection, @@ -446,8 +447,9 @@ gimp_drawable_tree_view_visibility_changed (GimpDrawable *drawable, } static void -gimp_drawable_tree_view_eye_toggled (GtkCellRendererToggle *toggle, +gimp_drawable_tree_view_eye_clicked (GtkCellRendererToggle *toggle, gchar *path_str, + GdkModifierType state, GimpDrawableTreeView *view) { GimpContainerTreeView *tree_view; @@ -473,12 +475,45 @@ gimp_drawable_tree_view_eye_toggled (GtkCellRendererToggle *toggle, NULL); drawable = GIMP_DRAWABLE (renderer->viewable); - gimage = gimp_item_get_image (GIMP_ITEM (drawable)); - - gimp_drawable_set_visible (drawable, !active); - gimp_image_flush (gimage); - g_object_unref (renderer); + + gimage = gimp_item_get_image (GIMP_ITEM (drawable)); + + if (state & GDK_SHIFT_MASK) + { + gboolean iter_valid; + + gimp_image_undo_group_start (gimage, + GIMP_UNDO_GROUP_DRAWABLE_VISIBILITY, + _("Set Drawable Exclusive Visible")); + + for (iter_valid = gtk_tree_model_get_iter_first (tree_view->model, + &iter); + iter_valid; + iter_valid = gtk_tree_model_iter_next (tree_view->model, + &iter)) + { + gtk_tree_model_get (tree_view->model, &iter, + tree_view->model_column_renderer, &renderer, + -1); + + if (renderer->viewable != (GimpViewable *) drawable) + gimp_drawable_set_visible (GIMP_DRAWABLE (renderer->viewable), + FALSE, TRUE); + + g_object_unref (renderer); + } + + gimp_drawable_set_visible (drawable, TRUE, TRUE); + + gimp_image_undo_group_end (gimage); + } + else + { + gimp_drawable_set_visible (drawable, !active, TRUE); + } + + gimp_image_flush (gimage); } gtk_tree_path_free (path); diff --git a/app/widgets/gimplayerlistitem.c b/app/widgets/gimplayerlistitem.c index 15132dff1c..93b2815131 100644 --- a/app/widgets/gimplayerlistitem.c +++ b/app/widgets/gimplayerlistitem.c @@ -389,7 +389,7 @@ gimp_layer_list_item_linked_toggled (GtkWidget *widget, gimp_layer_list_item_linked_changed, list_item); - gimp_layer_set_linked (layer, linked); + gimp_layer_set_linked (layer, linked, TRUE); g_signal_handlers_unblock_by_func (layer, gimp_layer_list_item_linked_changed, diff --git a/app/widgets/gimplayerlistview.c b/app/widgets/gimplayerlistview.c index b126f2c4c4..c02a9f0dc6 100644 --- a/app/widgets/gimplayerlistview.c +++ b/app/widgets/gimplayerlistview.c @@ -404,7 +404,7 @@ gimp_layer_list_view_paint_mode_menu_callback (GtkWidget *widget, if (gimp_layer_get_mode (layer) != mode) { BLOCK(); - gimp_layer_set_mode (layer, mode); + gimp_layer_set_mode (layer, mode, TRUE); UNBLOCK(); gimp_image_flush (gimage); @@ -433,7 +433,7 @@ gimp_layer_list_view_preserve_button_toggled (GtkWidget *widget, if (gimp_layer_get_preserve_trans (layer) != preserve_trans) { BLOCK(); - gimp_layer_set_preserve_trans (layer, preserve_trans); + gimp_layer_set_preserve_trans (layer, preserve_trans, TRUE); UNBLOCK(); } } @@ -460,7 +460,7 @@ gimp_layer_list_view_opacity_scale_changed (GtkAdjustment *adjustment, if (gimp_layer_get_opacity (layer) != opacity) { BLOCK(); - gimp_layer_set_opacity (layer, opacity); + gimp_layer_set_opacity (layer, opacity, TRUE); UNBLOCK(); gimp_image_flush (gimage); diff --git a/app/widgets/gimplayertreeview.c b/app/widgets/gimplayertreeview.c index 7c185f4973..f2d1881933 100644 --- a/app/widgets/gimplayertreeview.c +++ b/app/widgets/gimplayertreeview.c @@ -34,6 +34,8 @@ #include "core/gimplayermask.h" #include "core/gimplayer-floating-sel.h" #include "core/gimpimage.h" +#include "core/gimpitemundo.h" +#include "core/gimpundostack.h" #include "gimpcellrenderertoggle.h" #include "gimpcellrendererviewable.h" @@ -88,8 +90,9 @@ static void gimp_layer_tree_view_update_options (GimpLayerTreeView *view, static void gimp_layer_tree_view_linked_changed (GimpLayer *layer, GimpLayerTreeView *view); -static void gimp_layer_tree_view_chain_toggled (GtkCellRendererToggle *toggle, +static void gimp_layer_tree_view_chain_clicked (GtkCellRendererToggle *toggle, gchar *path, + GdkModifierType state, GimpLayerTreeView *view); static void gimp_layer_tree_view_mask_update (GimpLayerTreeView *view, @@ -343,8 +346,8 @@ gimp_layer_tree_view_constructor (GType type, tree_view->renderer_cells = g_list_prepend (tree_view->renderer_cells, layer_view->mask_cell); - g_signal_connect (layer_view->chain_cell, "toggled", - G_CALLBACK (gimp_layer_tree_view_chain_toggled), + g_signal_connect (layer_view->chain_cell, "clicked", + G_CALLBACK (gimp_layer_tree_view_chain_clicked), layer_view); g_signal_connect (tree_view->renderer_cell, "clicked", @@ -612,7 +615,7 @@ gimp_layer_tree_view_paint_mode_menu_callback (GtkWidget *widget, if (gimp_layer_get_mode (layer) != mode) { BLOCK(); - gimp_layer_set_mode (layer, mode); + gimp_layer_set_mode (layer, mode, TRUE); UNBLOCK(); gimp_image_flush (gimage); @@ -641,7 +644,7 @@ gimp_layer_tree_view_preserve_button_toggled (GtkWidget *widget, if (gimp_layer_get_preserve_trans (layer) != preserve_trans) { BLOCK(); - gimp_layer_set_preserve_trans (layer, preserve_trans); + gimp_layer_set_preserve_trans (layer, preserve_trans, TRUE); UNBLOCK(); } } @@ -667,8 +670,19 @@ gimp_layer_tree_view_opacity_scale_changed (GtkAdjustment *adjustment, if (gimp_layer_get_opacity (layer) != opacity) { + GimpUndo *undo; + gboolean push_undo = TRUE; + + undo = gimp_undo_stack_peek (gimage->undo_stack); + + /* compress opacity undos */ + if (GIMP_IS_ITEM_UNDO (undo) && + undo->undo_type == GIMP_UNDO_LAYER_OPACITY && + GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layer)) + push_undo = FALSE; + BLOCK(); - gimp_layer_set_opacity (layer, opacity); + gimp_layer_set_opacity (layer, opacity, push_undo); UNBLOCK(); gimp_image_flush (gimage); @@ -763,8 +777,9 @@ gimp_layer_tree_view_linked_changed (GimpLayer *layer, } static void -gimp_layer_tree_view_chain_toggled (GtkCellRendererToggle *toggle, +gimp_layer_tree_view_chain_clicked (GtkCellRendererToggle *toggle, gchar *path_str, + GdkModifierType state, GimpLayerTreeView *view) { GimpContainerTreeView *tree_view; @@ -790,7 +805,7 @@ gimp_layer_tree_view_chain_toggled (GtkCellRendererToggle *toggle, layer = GIMP_LAYER (renderer->viewable); - gimp_layer_set_linked (layer, !linked); + gimp_layer_set_linked (layer, !linked, TRUE); g_object_unref (renderer); } diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c index e7071a222a..2160208faf 100644 --- a/app/xcf/xcf-load.c +++ b/app/xcf/xcf-load.c @@ -666,7 +666,7 @@ xcf_load_layer_props (XcfInfo *info, info->cp += xcf_read_int32 (info->fp, (guint32 *) &visible, 1); gimp_drawable_set_visible (GIMP_DRAWABLE (layer), - visible ? TRUE : FALSE); + visible ? TRUE : FALSE, FALSE); } break; case PROP_LINKED: @@ -778,7 +778,7 @@ xcf_load_channel_props (XcfInfo *info, info->cp += xcf_read_int32 (info->fp, (guint32 *) &visible, 1); gimp_drawable_set_visible (GIMP_DRAWABLE (channel), - visible ? TRUE : FALSE); + visible ? TRUE : FALSE, FALSE); } break; case PROP_SHOW_MASKED: diff --git a/libgimpwidgets/gimpcellrenderertoggle.c b/libgimpwidgets/gimpcellrenderertoggle.c index e059cb040f..ff5e223544 100644 --- a/libgimpwidgets/gimpcellrenderertoggle.c +++ b/libgimpwidgets/gimpcellrenderertoggle.c @@ -25,11 +25,20 @@ #include "widgets-types.h" +#include "core/gimpmarshal.h" + #include "gimpcellrenderertoggle.h" #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON + +enum +{ + CLICKED, + LAST_SIGNAL +}; + enum { PROP_0, @@ -64,10 +73,19 @@ static void gimp_cell_renderer_toggle_render (GtkCellRenderer *cell, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags); +static gboolean gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags); static void gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle, GtkWidget *widget); +static guint toggle_cell_signals[LAST_SIGNAL] = { 0 }; + static GtkCellRendererToggleClass *parent_class = NULL; @@ -110,6 +128,17 @@ gimp_cell_renderer_toggle_class_init (GimpCellRendererToggleClass *klass) parent_class = g_type_class_peek_parent (klass); + toggle_cell_signals[CLICKED] = + g_signal_new ("clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GimpCellRendererToggleClass, clicked), + NULL, NULL, + gimp_marshal_VOID__STRING_UINT, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_UINT); + object_class->finalize = gimp_cell_renderer_toggle_finalize; object_class->get_property = gimp_cell_renderer_toggle_get_property; object_class->set_property = gimp_cell_renderer_toggle_set_property; @@ -374,6 +403,35 @@ gimp_cell_renderer_toggle_render (GtkCellRenderer *cell, } } +static gboolean +gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + GtkCellRendererToggle *celltoggle; + + celltoggle = GTK_CELL_RENDERER_TOGGLE (cell); + + if (celltoggle->activatable) + { + GdkModifierType state = 0; + + if (((GdkEventAny *) event)->type == GDK_BUTTON_PRESS) + state = ((GdkEventButton *) event)->state; + + g_signal_emit (cell, toggle_cell_signals[CLICKED], 0, + path, state); + + return TRUE; + } + + return FALSE; +} + static void gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle, GtkWidget *widget) diff --git a/libgimpwidgets/gimpcellrenderertoggle.h b/libgimpwidgets/gimpcellrenderertoggle.h index 3705a39c1c..be0aa31270 100644 --- a/libgimpwidgets/gimpcellrenderertoggle.h +++ b/libgimpwidgets/gimpcellrenderertoggle.h @@ -48,6 +48,10 @@ struct _GimpCellRendererToggle struct _GimpCellRendererToggleClass { GtkCellRendererToggleClass parent_class; + + void (* clicked) (GimpCellRendererViewable *cell, + const gchar *path, + GdkModifierType state); }; diff --git a/tools/pdbgen/pdb/channel.pdb b/tools/pdbgen/pdb/channel.pdb index 9873668477..6478ab6a10 100644 --- a/tools/pdbgen/pdb/channel.pdb +++ b/tools/pdbgen/pdb/channel.pdb @@ -30,7 +30,7 @@ sub operation_arg () {{ }} sub channel_get_prop_proc { - my ($prop, $type, $desc, $func, $core_type, $core_var) = @_; + my ($prop, $type, $desc, $undo, $core_type, $core_var) = @_; $core_type = 'channel' unless $core_type; $core_var = 'channel' unless $core_var; @@ -48,7 +48,7 @@ sub channel_get_prop_proc { desc => "The channel $desc", no_declare => 1 } ); - my $alias = $func ? "gimp_${core_type}_get_$prop ($core_var)" : "$core_var->$prop"; + my $alias = "gimp_${core_type}_get_$prop ($core_var)"; $alias = "g_strdup ($alias)" if $type eq 'string'; $outargs[0]->{alias} .= "$alias"; @@ -60,14 +60,14 @@ sub channel_get_prop_proc { $invoke{code} = <<'CODE' { - color = channel->color; + gimp_channel_get_color (channel, &color); } CODE } } sub channel_set_prop_proc { - my ($prop, $type, $desc, $func, $core_type, $core_var) = @_; + my ($prop, $type, $desc, $undo, $core_type, $core_var) = @_; $core_type = 'channel' unless $core_type; $core_var = 'channel' unless $core_var; @@ -88,8 +88,8 @@ sub channel_set_prop_proc { $inargs[1]->{desc} .= ' (%%desc%%)'; } - $invoke{code} = $func ? "gimp_${core_type}_set_$prop ($core_var, $prop);" - : "$core_var->$prop = $prop;"; + $invoke{code} = $undo ? "gimp_${core_type}_set_$prop ($core_var, $prop, TRUE);" + : "gimp_${core_type}_set_$prop ($core_var, $prop);"; if ($type eq 'color') { %invoke = ( @@ -103,16 +103,10 @@ sub channel_set_prop_proc { CODE ); } - - if ($prop eq 'opacity') { - %invoke = ( - code => "channel->color.a = $prop / 100.0;" - ); - } } sub channel_accessors { - my ($prop, $type, $desc, $func, $extra, $core_type, $core_var) = @_; + my ($prop, $type, $desc, $undo, $extra, $core_type, $core_var) = @_; $core_type = 'channel' unless $core_type; $core_var = 'channel' unless $core_var; @@ -129,7 +123,7 @@ sub channel_accessors { eval <{alias} = - "channel->color.a * 100.0"', - '$invoke{code} =~ - s%(color.a);$%(($1 / 100.0);%' ]); +&channel_accessors('opacity', '0 <= float <= 100', 'opacity', 1, + [ '$outargs[0]->{alias} = + "gimp_channel_get_opacity (channel) * 100.0"', + '$invoke{code} =~ + s%opacity, %opacity / 100.0, %' ]); &channel_accessors('color', 'color', 'compositing color', 0, [ '$outargs[0]->{void_ret} = 1', '' ]); -&channel_accessors('tattoo', 'tattoo', 'tattoo', 1, +&channel_accessors('tattoo', 'tattoo', 'tattoo', 0, <<'CODE', 'item', 'GIMP_ITEM (channel)'); $help .= <<'HELP'; A tattoo is a unique and permanent identifier attached to a channel that can be diff --git a/tools/pdbgen/pdb/layer.pdb b/tools/pdbgen/pdb/layer.pdb index 2c69e6e100..89023bb1cd 100644 --- a/tools/pdbgen/pdb/layer.pdb +++ b/tools/pdbgen/pdb/layer.pdb @@ -108,7 +108,7 @@ HELP } sub layer_get_prop_proc { - my ($prop, $type, $desc, $func, $core_type, $core_var) = @_; + my ($prop, $type, $desc, $undo, $core_type, $core_var) = @_; $core_type = 'layer' unless $core_type; $core_var = 'layer' unless $core_var; @@ -126,7 +126,7 @@ sub layer_get_prop_proc { desc => "The layer $desc", no_declare => 1 } ); - my $alias = $func ? "gimp_${core_type}_get_$prop ($core_var)" : "$core_var->$prop"; + my $alias = "gimp_${core_type}_get_$prop ($core_var)"; $alias = "g_strdup ($alias)" if $type eq 'string'; $outargs[0]->{alias} .= "$alias"; @@ -145,7 +145,7 @@ sub layer_get_prop_proc { } sub layer_set_prop_proc { - my ($prop, $type, $desc, $func, $core_type, $core_var) = @_; + my ($prop, $type, $desc, $undo, $core_type, $core_var) = @_; $core_type = 'layer' unless $core_type; $core_var = 'layer' unless $core_var; @@ -166,8 +166,8 @@ sub layer_set_prop_proc { $inargs[1]->{desc} .= ' (%%desc%%)'; } - $invoke{code} = $func ? "gimp_${core_type}_set_$prop ($core_var, $prop);" - : "$core_var->$prop = $prop;"; + $invoke{code} = $undo ? "gimp_${core_type}_set_$prop ($core_var, $prop, TRUE);" + : "gimp_${core_type}_set_$prop ($core_var, $prop);"; if ($type eq 'color') { %invoke = ( @@ -181,7 +181,7 @@ CODE } sub layer_accessors { - my ($prop, $type, $desc, $func, $setting, $extra, $core_type, $core_var) = @_; + my ($prop, $type, $desc, $setting, $undo, $extra, $core_type, $core_var) = @_; $core_type = 'layer' unless $core_type; $core_var = 'layer' unless $core_var; @@ -206,7 +206,7 @@ sub layer_accessors { eval <{alias} = "gimp_layer_get_opacity (layer) * 100.0"', '$invoke{code} =~ - s%opacity\);%opacity / 100.0\);%' ]); + s%opacity, %opacity / 100.0, %' ]); -&layer_accessors('mode', 'enum GimpLayerModeEffects', 'combination mode', 1, 0); +&layer_accessors('mode', 'enum GimpLayerModeEffects', 'combination mode', 0, 1); -&layer_accessors('linked', 'boolean', 'linked state', 1, 0, +&layer_accessors('linked', 'boolean', 'linked state', 0, 1, <<'CODE'); $author = $copyright = 'Wolfgang Hofer'; $date = '1998'; @@ -595,7 +595,7 @@ CODE2 } CODE -&layer_accessors('tattoo', 'tattoo', 'tattoo', 1, 0, +&layer_accessors('tattoo', 'tattoo', 'tattoo', 0, 0, <<'CODE', 'item', 'GIMP_ITEM (layer)'); $help .= <<'HELP'; A tattoo is a unique and permanent identifier attached to a