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_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_FILTER_VISIBILITY, "GIMP_UNDO_GROUP_FILTER_VISIBILITY", "group-filter-visibility" },
{ GIMP_UNDO_GROUP_MISC, "GIMP_UNDO_GROUP_MISC", "group-misc" },
{ GIMP_UNDO_IMAGE_TYPE, "GIMP_UNDO_IMAGE_TYPE", "image-type" },
{ 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_REORDER, "GIMP_UNDO_FILTER_REORDER", "filter-reorder" },
{ 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" },
{ 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_REMOVE, NC_("undo-type", "Remove parasite"), 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_IMAGE_TYPE, NC_("undo-type", "Image type"), 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_REORDER, NC_("undo-type", "Reorder effect"), 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 },
{ 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_REMOVE, /*< desc="Remove parasite" >*/
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_LAST = GIMP_UNDO_GROUP_MISC, /*< skip >*/
@ -642,6 +643,7 @@ typedef enum /*< pdb-skip >*/
GIMP_UNDO_FILTER_REMOVE, /*< desc="Remove effect" >*/
GIMP_UNDO_FILTER_REORDER, /*< desc="Reorder effect" >*/
GIMP_UNDO_FILTER_MODIFIED, /*< desc="Effect modification" >*/
GIMP_UNDO_FILTER_VISIBILITY, /*< desc="Effect visibility" >*/
GIMP_UNDO_CANT /*< desc="Not undoable" >*/
} GimpUndoType;

View file

@ -32,7 +32,9 @@
#include "gimpdrawablefilter.h"
#include "gimpdrawablefilterundo.h"
#include "gimpimage.h"
#include "gimpimage-undo.h"
#include "gimpitem.h"
#include "gimpundostack.h"
enum
@ -140,6 +142,7 @@ gimp_drawable_filter_undo_constructed (GObject *object)
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->paint_mode = gimp_drawable_filter_get_paint_mode (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);
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)
{
GeglNode *op;
@ -357,3 +373,52 @@ gimp_drawable_filter_undo_free (GimpUndo *undo,
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;
gint row_index;
gboolean active;
GeglNode *node;
gdouble opacity;
@ -57,5 +58,8 @@ struct _GimpDrawableFilterUndoClass
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__ */

View file

@ -384,6 +384,22 @@ gimp_image_undo_push_filter_modified (GimpImage *image,
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 */

View file

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

View file

@ -686,6 +686,9 @@ gimp_image_undo_dirty_from_type (GimpUndoType undo_type)
case GIMP_UNDO_GROUP_PATHS_IMPORT:
return GIMP_DIRTY_IMAGE_STRUCTURE | GIMP_DIRTY_PATH;
case GIMP_UNDO_GROUP_FILTER_VISIBILITY:
return GIMP_DIRTY_DRAWABLE;
case GIMP_UNDO_GROUP_MISC:
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_PROPERTIES:
case GIMP_UNDO_GROUP_LAYER_APPLY_MASK:
case GIMP_UNDO_GROUP_FILTER_VISIBILITY:
case GIMP_UNDO_ITEM_VISIBILITY:
case GIMP_UNDO_LAYER_MODE:
case GIMP_UNDO_LAYER_OPACITY:
case GIMP_UNDO_LAYER_MASK_APPLY:
case GIMP_UNDO_LAYER_MASK_SHOW:
case GIMP_UNDO_FILTER_VISIBILITY:
return TRUE;
break;

View file

@ -38,6 +38,7 @@
#include "core/gimpdrawable.h"
#include "core/gimpdrawable-filters.h"
#include "core/gimpdrawablefilter.h"
#include "core/gimpdrawablefilterundo.h"
#include "core/gimplist.h"
#include "core/gimpimage.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))
{
GimpDrawable *drawable;
GimpImage *image;
GimpContext *context;
gboolean active;
GimpUndo *undo;
gboolean push_undo = TRUE;
g_object_get (toggle,
"active", &active,
NULL);
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);
if (! push_undo)
gimp_undo_refresh_preview (undo, context);
gimp_drawable_update (drawable, 0, 0, -1, -1);
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)
{
GimpDrawableTreeViewFiltersEditor *editor = view->editor;
GimpImage *image;
GimpContainer *filters;
GList *list;
GList *iter;
gint n_filters = 0;
gboolean visible;
GimpUndo *undo;
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);
list = GIMP_LIST (filters)->queue->head;
for (list = GIMP_LIST (filters)->queue->head;
list;
list = g_list_next (list))
undo = gimp_drawable_filter_undo_can_compress_visibility (image, 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);
}
}
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_image_flush (gimp_item_get_image (GIMP_ITEM (editor->drawable)));
}