Merge branch 'wip/estecka/filter_undo_visibility' into 'master'

core,widgets: Undo actions for filter visibility.

See merge request GNOME/gimp!2290
This commit is contained in:
Estecka 2025-07-02 08:31:13 +00:00
commit f0460816c9
9 changed files with 185 additions and 6 deletions

View file

@ -1229,6 +1229,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_GROUP_PARASITE_ATTACH, "GIMP_UNDO_GROUP_PARASITE_ATTACH", "group-parasite-attach" }, { GIMP_UNDO_GROUP_PARASITE_ATTACH, "GIMP_UNDO_GROUP_PARASITE_ATTACH", "group-parasite-attach" },
{ GIMP_UNDO_GROUP_PARASITE_REMOVE, "GIMP_UNDO_GROUP_PARASITE_REMOVE", "group-parasite-remove" }, { GIMP_UNDO_GROUP_PARASITE_REMOVE, "GIMP_UNDO_GROUP_PARASITE_REMOVE", "group-parasite-remove" },
{ GIMP_UNDO_GROUP_PATHS_IMPORT, "GIMP_UNDO_GROUP_PATHS_IMPORT", "group-paths-import" }, { GIMP_UNDO_GROUP_PATHS_IMPORT, "GIMP_UNDO_GROUP_PATHS_IMPORT", "group-paths-import" },
{ GIMP_UNDO_GROUP_FILTER_VISIBILITY, "GIMP_UNDO_GROUP_FILTER_VISIBILITY", "group-filter-visibility" },
{ GIMP_UNDO_GROUP_MISC, "GIMP_UNDO_GROUP_MISC", "group-misc" }, { GIMP_UNDO_GROUP_MISC, "GIMP_UNDO_GROUP_MISC", "group-misc" },
{ GIMP_UNDO_IMAGE_TYPE, "GIMP_UNDO_IMAGE_TYPE", "image-type" }, { GIMP_UNDO_IMAGE_TYPE, "GIMP_UNDO_IMAGE_TYPE", "image-type" },
{ GIMP_UNDO_IMAGE_PRECISION, "GIMP_UNDO_IMAGE_PRECISION", "image-precision" }, { GIMP_UNDO_IMAGE_PRECISION, "GIMP_UNDO_IMAGE_PRECISION", "image-precision" },
@ -1288,6 +1289,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_FILTER_REMOVE, "GIMP_UNDO_FILTER_REMOVE", "filter-remove" }, { GIMP_UNDO_FILTER_REMOVE, "GIMP_UNDO_FILTER_REMOVE", "filter-remove" },
{ GIMP_UNDO_FILTER_REORDER, "GIMP_UNDO_FILTER_REORDER", "filter-reorder" }, { GIMP_UNDO_FILTER_REORDER, "GIMP_UNDO_FILTER_REORDER", "filter-reorder" },
{ GIMP_UNDO_FILTER_MODIFIED, "GIMP_UNDO_FILTER_MODIFIED", "filter-modified" }, { GIMP_UNDO_FILTER_MODIFIED, "GIMP_UNDO_FILTER_MODIFIED", "filter-modified" },
{ GIMP_UNDO_FILTER_VISIBILITY, "GIMP_UNDO_FILTER_VISIBILITY", "filter-visibility" },
{ GIMP_UNDO_CANT, "GIMP_UNDO_CANT", "cant" }, { GIMP_UNDO_CANT, "GIMP_UNDO_CANT", "cant" },
{ 0, NULL, NULL } { 0, NULL, NULL }
}; };
@ -1342,6 +1344,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_GROUP_PARASITE_ATTACH, NC_("undo-type", "Attach parasite"), NULL }, { GIMP_UNDO_GROUP_PARASITE_ATTACH, NC_("undo-type", "Attach parasite"), NULL },
{ GIMP_UNDO_GROUP_PARASITE_REMOVE, NC_("undo-type", "Remove parasite"), NULL }, { GIMP_UNDO_GROUP_PARASITE_REMOVE, NC_("undo-type", "Remove parasite"), NULL },
{ GIMP_UNDO_GROUP_PATHS_IMPORT, NC_("undo-type", "Import paths"), NULL }, { GIMP_UNDO_GROUP_PATHS_IMPORT, NC_("undo-type", "Import paths"), NULL },
{ GIMP_UNDO_GROUP_FILTER_VISIBILITY, NC_("undo-type", "Effects visibility"), NULL },
{ GIMP_UNDO_GROUP_MISC, NC_("undo-type", "Plug-In"), NULL }, { GIMP_UNDO_GROUP_MISC, NC_("undo-type", "Plug-In"), NULL },
{ GIMP_UNDO_IMAGE_TYPE, NC_("undo-type", "Image type"), NULL }, { GIMP_UNDO_IMAGE_TYPE, NC_("undo-type", "Image type"), NULL },
{ GIMP_UNDO_IMAGE_PRECISION, NC_("undo-type", "Image precision"), NULL }, { GIMP_UNDO_IMAGE_PRECISION, NC_("undo-type", "Image precision"), NULL },
@ -1401,6 +1404,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_FILTER_REMOVE, NC_("undo-type", "Remove effect"), NULL }, { GIMP_UNDO_FILTER_REMOVE, NC_("undo-type", "Remove effect"), NULL },
{ GIMP_UNDO_FILTER_REORDER, NC_("undo-type", "Reorder effect"), NULL }, { GIMP_UNDO_FILTER_REORDER, NC_("undo-type", "Reorder effect"), NULL },
{ GIMP_UNDO_FILTER_MODIFIED, NC_("undo-type", "Effect modification"), NULL }, { GIMP_UNDO_FILTER_MODIFIED, NC_("undo-type", "Effect modification"), NULL },
{ GIMP_UNDO_FILTER_VISIBILITY, NC_("undo-type", "Effect visibility"), NULL },
{ GIMP_UNDO_CANT, NC_("undo-type", "Not undoable"), NULL }, { GIMP_UNDO_CANT, NC_("undo-type", "Not undoable"), NULL },
{ 0, NULL, NULL } { 0, NULL, NULL }
}; };

View file

@ -578,6 +578,7 @@ typedef enum /*< pdb-skip >*/
GIMP_UNDO_GROUP_PARASITE_ATTACH, /*< desc="Attach parasite" >*/ GIMP_UNDO_GROUP_PARASITE_ATTACH, /*< desc="Attach parasite" >*/
GIMP_UNDO_GROUP_PARASITE_REMOVE, /*< desc="Remove parasite" >*/ GIMP_UNDO_GROUP_PARASITE_REMOVE, /*< desc="Remove parasite" >*/
GIMP_UNDO_GROUP_PATHS_IMPORT, /*< desc="Import paths" >*/ GIMP_UNDO_GROUP_PATHS_IMPORT, /*< desc="Import paths" >*/
GIMP_UNDO_GROUP_FILTER_VISIBILITY, /*< desc="Effects visibility" >*/
GIMP_UNDO_GROUP_MISC, /*< desc="Plug-In" >*/ GIMP_UNDO_GROUP_MISC, /*< desc="Plug-In" >*/
GIMP_UNDO_GROUP_LAST = GIMP_UNDO_GROUP_MISC, /*< skip >*/ GIMP_UNDO_GROUP_LAST = GIMP_UNDO_GROUP_MISC, /*< skip >*/
@ -642,6 +643,7 @@ typedef enum /*< pdb-skip >*/
GIMP_UNDO_FILTER_REMOVE, /*< desc="Remove effect" >*/ GIMP_UNDO_FILTER_REMOVE, /*< desc="Remove effect" >*/
GIMP_UNDO_FILTER_REORDER, /*< desc="Reorder effect" >*/ GIMP_UNDO_FILTER_REORDER, /*< desc="Reorder effect" >*/
GIMP_UNDO_FILTER_MODIFIED, /*< desc="Effect modification" >*/ GIMP_UNDO_FILTER_MODIFIED, /*< desc="Effect modification" >*/
GIMP_UNDO_FILTER_VISIBILITY, /*< desc="Effect visibility" >*/
GIMP_UNDO_CANT /*< desc="Not undoable" >*/ GIMP_UNDO_CANT /*< desc="Not undoable" >*/
} GimpUndoType; } GimpUndoType;

View file

@ -32,7 +32,9 @@
#include "gimpdrawablefilter.h" #include "gimpdrawablefilter.h"
#include "gimpdrawablefilterundo.h" #include "gimpdrawablefilterundo.h"
#include "gimpimage.h" #include "gimpimage.h"
#include "gimpimage-undo.h"
#include "gimpitem.h" #include "gimpitem.h"
#include "gimpundostack.h"
enum enum
@ -140,6 +142,7 @@ gimp_drawable_filter_undo_constructed (GObject *object)
g_value_unset (&value); g_value_unset (&value);
} }
df_undo->active = gimp_filter_get_active (GIMP_FILTER (df_undo->filter));
df_undo->opacity = gimp_drawable_filter_get_opacity (df_undo->filter); df_undo->opacity = gimp_drawable_filter_get_opacity (df_undo->filter);
df_undo->paint_mode = gimp_drawable_filter_get_paint_mode (df_undo->filter); df_undo->paint_mode = gimp_drawable_filter_get_paint_mode (df_undo->filter);
df_undo->blend_space = gimp_drawable_filter_get_blend_space (df_undo->filter); df_undo->blend_space = gimp_drawable_filter_get_blend_space (df_undo->filter);
@ -267,6 +270,19 @@ gimp_drawable_filter_undo_pop (GimpUndo *undo,
df_undo->row_index); df_undo->row_index);
gimp_drawable_update (drawable, 0, 0, -1, -1); gimp_drawable_update (drawable, 0, 0, -1, -1);
} }
else if (undo->undo_type == GIMP_UNDO_FILTER_VISIBILITY)
{
GimpFilter *gfilter;
gboolean active;
gfilter = GIMP_FILTER (filter);
active = gimp_filter_get_active (gfilter);
gimp_filter_set_active (gfilter, df_undo->active);
gimp_drawable_filter_apply (filter, NULL);
df_undo->active = active;
}
else if (undo->undo_type == GIMP_UNDO_FILTER_MODIFIED) else if (undo->undo_type == GIMP_UNDO_FILTER_MODIFIED)
{ {
GeglNode *op; GeglNode *op;
@ -357,3 +373,52 @@ gimp_drawable_filter_undo_free (GimpUndo *undo,
GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode); GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode);
} }
/**
* Checks whether the undo step of toggling all filters in @filter_list can be
* compressed. It will be compressed if:
* - The previous undo is a group of filter visibility changes
* - The group has changes for every filters in the list
* - The group only has changes for filters from the list
*/
GimpUndo *
gimp_drawable_filter_undo_can_compress_visibility (GimpImage *image,
GList *filter_list)
{
GimpUndo *undo;
GimpUndoStack *undo_stack;
gint n_items;
g_return_val_if_fail (image != NULL, NULL);
g_return_val_if_fail (filter_list != NULL, NULL);
undo = gimp_image_undo_can_compress (image,
GIMP_TYPE_UNDO_STACK,
GIMP_UNDO_GROUP_FILTER_VISIBILITY);
if (undo == NULL)
return NULL;
undo_stack = GIMP_UNDO_STACK (undo);
n_items = gimp_container_get_n_children (undo_stack->undos);
if (n_items != g_list_length (filter_list))
return NULL;
for (int i = 0; i < n_items; i++)
{
const GimpObject *sub_undo;
const GimpDrawableFilterUndo *sub_filter_undo;
sub_undo = gimp_container_get_child_by_index (undo_stack->undos, i);
sub_filter_undo = GIMP_DRAWABLE_FILTER_UNDO (sub_undo);
if (sub_filter_undo == NULL ||
GIMP_UNDO (sub_undo)->undo_type != GIMP_UNDO_FILTER_VISIBILITY ||
! g_list_find (filter_list, sub_filter_undo->filter))
{
return NULL;
}
}
return undo;
}

View file

@ -39,6 +39,7 @@ struct _GimpDrawableFilterUndo
GimpDrawableFilter *filter; GimpDrawableFilter *filter;
gint row_index; gint row_index;
gboolean active;
GeglNode *node; GeglNode *node;
gdouble opacity; gdouble opacity;
@ -57,5 +58,8 @@ struct _GimpDrawableFilterUndoClass
GType gimp_drawable_filter_undo_get_type (void) G_GNUC_CONST; GType gimp_drawable_filter_undo_get_type (void) G_GNUC_CONST;
GimpUndo * gimp_drawable_filter_undo_can_compress_visibility (GimpImage *image,
GList *filter_list);
#endif /* __GIMP_DRAWABLE_FILTER_UNDO_H__ */ #endif /* __GIMP_DRAWABLE_FILTER_UNDO_H__ */

View file

@ -384,6 +384,22 @@ gimp_image_undo_push_filter_modified (GimpImage *image,
NULL); NULL);
} }
GimpUndo *
gimp_image_undo_push_filter_visibility (GimpImage *image,
const gchar *undo_desc,
GimpDrawable *drawable,
GimpDrawableFilter *filter)
{
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
return gimp_image_undo_push (image, GIMP_TYPE_DRAWABLE_FILTER_UNDO,
GIMP_UNDO_FILTER_VISIBILITY, undo_desc,
GIMP_DIRTY_DRAWABLE,
"filter", filter,
NULL);
}
/****************/ /****************/
/* Mask Undos */ /* Mask Undos */

View file

@ -101,6 +101,11 @@ GimpUndo * gimp_image_undo_push_filter_modified (GimpImage *image,
GimpDrawable *drawable, GimpDrawable *drawable,
GimpDrawableFilter GimpDrawableFilter
*filter); *filter);
GimpUndo * gimp_image_undo_push_filter_visibility (GimpImage *image,
const gchar *undo_desc,
GimpDrawable *drawable,
GimpDrawableFilter
*filter);
/* mask undos */ /* mask undos */

View file

@ -686,6 +686,9 @@ gimp_image_undo_dirty_from_type (GimpUndoType undo_type)
case GIMP_UNDO_GROUP_PATHS_IMPORT: case GIMP_UNDO_GROUP_PATHS_IMPORT:
return GIMP_DIRTY_IMAGE_STRUCTURE | GIMP_DIRTY_PATH; return GIMP_DIRTY_IMAGE_STRUCTURE | GIMP_DIRTY_PATH;
case GIMP_UNDO_GROUP_FILTER_VISIBILITY:
return GIMP_DIRTY_DRAWABLE;
case GIMP_UNDO_GROUP_MISC: case GIMP_UNDO_GROUP_MISC:
return GIMP_DIRTY_ALL; return GIMP_DIRTY_ALL;

View file

@ -539,11 +539,13 @@ gimp_undo_is_weak (GimpUndo *undo)
case GIMP_UNDO_GROUP_ITEM_VISIBILITY: case GIMP_UNDO_GROUP_ITEM_VISIBILITY:
case GIMP_UNDO_GROUP_ITEM_PROPERTIES: case GIMP_UNDO_GROUP_ITEM_PROPERTIES:
case GIMP_UNDO_GROUP_LAYER_APPLY_MASK: case GIMP_UNDO_GROUP_LAYER_APPLY_MASK:
case GIMP_UNDO_GROUP_FILTER_VISIBILITY:
case GIMP_UNDO_ITEM_VISIBILITY: case GIMP_UNDO_ITEM_VISIBILITY:
case GIMP_UNDO_LAYER_MODE: case GIMP_UNDO_LAYER_MODE:
case GIMP_UNDO_LAYER_OPACITY: case GIMP_UNDO_LAYER_OPACITY:
case GIMP_UNDO_LAYER_MASK_APPLY: case GIMP_UNDO_LAYER_MASK_APPLY:
case GIMP_UNDO_LAYER_MASK_SHOW: case GIMP_UNDO_LAYER_MASK_SHOW:
case GIMP_UNDO_FILTER_VISIBILITY:
return TRUE; return TRUE;
break; break;

View file

@ -38,6 +38,7 @@
#include "core/gimpdrawable.h" #include "core/gimpdrawable.h"
#include "core/gimpdrawable-filters.h" #include "core/gimpdrawable-filters.h"
#include "core/gimpdrawablefilter.h" #include "core/gimpdrawablefilter.h"
#include "core/gimpdrawablefilterundo.h"
#include "core/gimplist.h" #include "core/gimplist.h"
#include "core/gimpimage.h" #include "core/gimpimage.h"
#include "core/gimpimage-undo.h" #include "core/gimpimage-undo.h"
@ -593,15 +594,41 @@ gimp_drawable_filters_editor_view_visible_cell_toggled (GtkCellRendererToggle *t
if (GIMP_IS_DRAWABLE_FILTER (filter)) if (GIMP_IS_DRAWABLE_FILTER (filter))
{ {
GimpDrawable *drawable; GimpDrawable *drawable;
GimpImage *image;
GimpContext *context;
gboolean active; gboolean active;
GimpUndo *undo;
gboolean push_undo = TRUE;
g_object_get (toggle, g_object_get (toggle,
"active", &active, "active", &active,
NULL); NULL);
drawable = gimp_drawable_filter_get_drawable (filter); drawable = gimp_drawable_filter_get_drawable (filter);
image = gimp_item_get_image (GIMP_ITEM (drawable));
context = gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view));
undo = gimp_image_undo_can_compress(image,
GIMP_TYPE_DRAWABLE_FILTER_UNDO,
GIMP_UNDO_FILTER_VISIBILITY);
if (undo != NULL && GIMP_DRAWABLE_FILTER_UNDO (undo)->filter == filter)
{
push_undo = FALSE;
}
else
{
gimp_image_undo_push_filter_visibility (image,
_("Effect visibility"),
drawable,
filter);
}
gimp_filter_set_active (GIMP_FILTER (filter), ! active); gimp_filter_set_active (GIMP_FILTER (filter), ! active);
if (! push_undo)
gimp_undo_refresh_preview (undo, context);
gimp_drawable_update (drawable, 0, 0, -1, -1); gimp_drawable_update (drawable, 0, 0, -1, -1);
gimp_image_flush (gimp_item_get_image (GIMP_ITEM (drawable))); gimp_image_flush (gimp_item_get_image (GIMP_ITEM (drawable)));
} }
@ -657,26 +684,77 @@ gimp_drawable_filters_editor_visible_all_toggled (GtkWidget *widget,
GimpDrawableTreeView *view) GimpDrawableTreeView *view)
{ {
GimpDrawableTreeViewFiltersEditor *editor = view->editor; GimpDrawableTreeViewFiltersEditor *editor = view->editor;
GimpImage *image;
GimpContainer *filters; GimpContainer *filters;
GList *list; GList *list;
GList *iter;
gint n_filters = 0;
gboolean visible; gboolean visible;
GimpUndo *undo;
visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view));
filters = gimp_drawable_get_filters (editor->drawable); filters = gimp_drawable_get_filters (editor->drawable);
list = GIMP_LIST (filters)->queue->head;
for (list = GIMP_LIST (filters)->queue->head; undo = gimp_drawable_filter_undo_can_compress_visibility (image, list);
list;
list = g_list_next (list)) for (iter = list; iter; iter = g_list_next (iter))
{ {
if (GIMP_IS_DRAWABLE_FILTER (list->data)) if (GIMP_IS_DRAWABLE_FILTER (iter->data) &&
visible != gimp_filter_get_active (GIMP_FILTER (iter->data)))
{ {
GimpFilter *filter = list->data; n_filters++;
}
}
if (n_filters <= 0)
return;
if (undo == NULL)
{
gimp_image_undo_group_start (image,
GIMP_UNDO_GROUP_FILTER_VISIBILITY,
"Effects visibility");
}
for (iter = list; iter; iter = g_list_next (iter))
{
if (GIMP_IS_DRAWABLE_FILTER (iter->data))
{
GimpFilter *filter = iter->data;
GimpDrawableFilter *dfilter = iter->data;
/**
* Undos are pushed for every filters, even if they weren't
* actually toggled, so that the undo group can be compressed with
* subsequent toggles.
*/
if (undo == NULL)
{
gimp_image_undo_push_filter_visibility (image,
_("Effect visibility"),
editor->drawable,
dfilter);
}
gimp_filter_set_active (filter, visible); gimp_filter_set_active (filter, visible);
} }
} }
if (undo == NULL)
{
gimp_image_undo_group_end (image);
}
else
{
GimpContext *context;
context = gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view));
gimp_undo_refresh_preview (undo, context);
}
gimp_drawable_update (editor->drawable, 0, 0, -1, -1); gimp_drawable_update (editor->drawable, 0, 0, -1, -1);
gimp_image_flush (gimp_item_get_image (GIMP_ITEM (editor->drawable))); gimp_image_flush (gimp_item_get_image (GIMP_ITEM (editor->drawable)));
} }