app: add GimpRowFilter and GimpRowDrawableFilter and port the filters

popover to GimpContainerListView.
This commit is contained in:
Michael Natterer 2025-08-12 11:53:26 +02:00
parent d4aac4a3e5
commit f96a7192cd
7 changed files with 392 additions and 146 deletions

View file

@ -40,25 +40,18 @@
#include "core/gimpdrawablefilter.h"
#include "core/gimplist.h"
#include "core/gimpimage.h"
#include "core/gimpimage-undo.h"
#include "core/gimpimage-undo-push.h"
#include "core/gimptreehandler.h"
#include "tools/tool_manager.h" /* FIXME */
#include "gimpcontainertreestore.h"
#include "gimpcontainerlistview.h"
#include "gimpcontainerview.h"
#include "gimpcontainerview-cruft.h"
#include "gimpdrawabletreeview.h"
#include "gimpdrawabletreeview-filters.h"
#include "gimpviewrenderer.h"
#include "gimp-intl.h"
#define COLUMN_FILTERS_ACTIVE 3
struct _GimpDrawableTreeViewFiltersEditor
{
GimpDrawable *drawable;
@ -67,8 +60,8 @@ struct _GimpDrawableTreeViewFiltersEditor
GtkWidget *popover;
GtkWidget *vbox;
GtkWidget *view;
GtkWidget *options;
GtkWidget *options;
GtkWidget *visible_button;
GtkWidget *edit_button;
GtkWidget *raise_button;
@ -76,8 +69,7 @@ struct _GimpDrawableTreeViewFiltersEditor
GtkWidget *merge_button;
GtkWidget *remove_button;
GimpTreeHandler *active_changed_handler;
GimpTreeHandler *notify_temporary_handler;
GQuark notify_temporary_handler;
};
@ -91,15 +83,7 @@ static void gimp_drawable_filters_editor_view_item_activated
(GtkWidget *widget,
GimpViewable *viewable,
GimpDrawableTreeView *view);
static void gimp_drawable_filters_editor_view_visible_cell_toggled
(GtkCellRendererToggle *toggle,
gchar *path_str,
GdkModifierType state,
GimpContainerTreeView *view);
static void gimp_drawable_filters_editor_active_changed
(GimpFilter *filter,
GimpContainerTreeView *view);
static void gimp_drawable_filters_editor_temporary_changed
(GimpFilter *filter,
const GParamSpec *pspec,
@ -322,79 +306,35 @@ _gimp_drawable_tree_view_filter_editor_show (GimpDrawableTreeView *view,
/* only show if we have at least one editable filter */
if (n_editable > 0)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GimpContainerTreeView *filter_tree_view;
GtkWidget *scrolled_window;
GtkWidget *scrolled_window;
editor->drawable = drawable;
editor->view = gimp_container_tree_view_new (filters,
editor->view = gimp_container_list_view_new (filters,
gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view)),
GIMP_VIEW_SIZE_SMALL, 0);
filter_tree_view = GIMP_CONTAINER_TREE_VIEW (editor->view);
/* Connect filter active signal */
editor->active_changed_handler =
gimp_tree_handler_connect (filters, "active-changed",
G_CALLBACK (gimp_drawable_filters_editor_active_changed),
editor->view);
editor->notify_temporary_handler =
gimp_tree_handler_connect (filters, "notify::temporary",
G_CALLBACK (gimp_drawable_filters_editor_temporary_changed),
view);
gimp_container_add_handler (filters, "notify::temporary",
G_CALLBACK (gimp_drawable_filters_editor_temporary_changed),
view);
g_signal_connect (drawable, "filters-changed",
G_CALLBACK (gimp_drawable_filters_editor_filters_changed),
view);
gimp_container_tree_store_columns_add (filter_tree_view->model_columns,
&filter_tree_view->n_model_columns,
G_TYPE_BOOLEAN);
/* Set up individual visibility toggles */
column = gtk_tree_view_column_new ();
renderer = gimp_cell_renderer_toggle_new (GIMP_ICON_VISIBLE);
gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (renderer), TRUE);
gtk_tree_view_column_pack_end (column, renderer, FALSE);
gtk_tree_view_column_set_attributes (column, renderer,
"active",
COLUMN_FILTERS_ACTIVE,
NULL);
gtk_tree_view_append_column (filter_tree_view->view, column);
gtk_tree_view_move_column_after (filter_tree_view->view, column, NULL);
gimp_container_tree_view_add_toggle_cell (filter_tree_view, renderer);
g_signal_connect_object (renderer, "clicked",
G_CALLBACK (gimp_drawable_filters_editor_view_visible_cell_toggled),
filter_tree_view, 0);
/* Update filter visible icon */
for (list = GIMP_LIST (filters)->queue->tail;
list;
list = g_list_previous (list))
{
if (GIMP_IS_DRAWABLE_FILTER (list->data))
{
gimp_drawable_filters_editor_active_changed (list->data,
filter_tree_view);
}
}
g_signal_connect (filter_tree_view, "selection-changed",
g_signal_connect (editor->view, "selection-changed",
G_CALLBACK (gimp_drawable_filters_editor_view_selection_changed),
view);
g_signal_connect_object (filter_tree_view, "item-activated",
g_signal_connect_object (editor->view, "item-activated",
G_CALLBACK (gimp_drawable_filters_editor_view_item_activated),
view, 0);
gtk_box_pack_start (GTK_BOX (editor->vbox),
editor->view, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (editor->vbox), editor->view,
TRUE, TRUE, 0);
gtk_widget_show (editor->view);
scrolled_window = gtk_widget_get_parent (GTK_WIDGET (filter_tree_view->view));
scrolled_window = GIMP_CONTAINER_BOX (editor->view)->scrolled_win;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_NEVER,
GTK_POLICY_NEVER);
@ -422,8 +362,10 @@ _gimp_drawable_tree_view_filter_editor_hide (GimpDrawableTreeView *view)
if (! editor)
return;
if (editor->active_changed_handler)
if (editor->notify_temporary_handler)
{
GimpContainer *filters = gimp_drawable_get_filters (editor->drawable);
g_signal_handlers_disconnect_by_func (editor->popover,
_gimp_drawable_tree_view_filter_editor_hide,
view);
@ -432,10 +374,9 @@ _gimp_drawable_tree_view_filter_editor_hide (GimpDrawableTreeView *view)
gimp_drawable_filters_editor_filters_changed,
view);
g_clear_pointer (&editor->notify_temporary_handler,
gimp_tree_handler_disconnect);
g_clear_pointer (&editor->active_changed_handler,
gimp_tree_handler_disconnect);
gimp_container_remove_handler (filters,
editor->notify_temporary_handler);
editor->notify_temporary_handler = 0;
}
gtk_popover_popdown (GTK_POPOVER (editor->popover));
@ -531,27 +472,22 @@ gimp_drawable_filters_editor_view_selection_changed (GimpContainerView *view,
GimpDrawableTreeView *drawable_view)
{
GimpDrawableTreeViewFiltersEditor *editor = drawable_view->editor;
GList *items;
gint n_items;
GimpViewable *viewable;
n_items = gimp_container_view_get_selected (view, &items);
g_warn_if_fail (n_items <= 1);
viewable = gimp_container_view_get_1_selected (view);
editor->filter = NULL;
if (items)
if (viewable)
{
/* Don't set floating selection as active filter */
if (GIMP_IS_DRAWABLE_FILTER (items->data))
if (GIMP_IS_DRAWABLE_FILTER (viewable))
{
editor->filter = items->data;
editor->filter = GIMP_DRAWABLE_FILTER (viewable);
}
}
gimp_drawable_filters_editor_set_sensitive (drawable_view);
g_list_free (items);
}
static void
@ -565,63 +501,6 @@ gimp_drawable_filters_editor_view_item_activated (GtkWidget *widget,
gimp_drawable_filters_editor_edit_clicked (widget, view);
}
static void
gimp_drawable_filters_editor_view_visible_cell_toggled (GtkCellRendererToggle *toggle,
gchar *path_str,
GdkModifierType state,
GimpContainerTreeView *view)
{
GtkTreePath *path;
GtkTreeIter iter;
path = gtk_tree_path_new_from_string (path_str);
if (gtk_tree_model_get_iter (view->model, &iter, path))
{
GimpContainerTreeStore *store;
GimpViewRenderer *renderer;
GimpDrawableFilter *filter;
store = GIMP_CONTAINER_TREE_STORE (view->model);
renderer = gimp_container_tree_store_get_renderer (store, &iter);
filter = GIMP_DRAWABLE_FILTER (renderer->viewable);
g_object_unref (renderer);
if (GIMP_IS_DRAWABLE_FILTER (filter))
{
GimpDrawable *drawable;
gboolean active;
g_object_get (toggle,
"active", &active,
NULL);
drawable = gimp_drawable_filter_get_drawable (filter);
gimp_filter_set_active (GIMP_FILTER (filter), ! active);
gimp_drawable_update (drawable, 0, 0, -1, -1);
gimp_image_flush (gimp_item_get_image (GIMP_ITEM (drawable)));
}
}
}
static void
gimp_drawable_filters_editor_active_changed (GimpFilter *filter,
GimpContainerTreeView *view)
{
GtkTreeIter *iter;
iter = _gimp_container_view_lookup (GIMP_CONTAINER_VIEW (view),
(GimpViewable *) filter);
if (iter)
gtk_tree_store_set (GTK_TREE_STORE (view->model), iter,
COLUMN_FILTERS_ACTIVE,
gimp_filter_get_active (filter),
-1);
}
static void
gimp_drawable_filters_editor_temporary_changed (GimpFilter *filter,
const GParamSpec *pspec,

View file

@ -26,6 +26,7 @@
#include "widgets-types.h"
#include "core/gimpcontext.h"
#include "core/gimpdrawablefilter.h"
#include "core/gimpsettings.h"
#include "gimpcontainerview.h"
@ -33,6 +34,7 @@
#include "gimprow.h"
#include "gimprow-utils.h"
#include "gimprowdeviceinfo.h"
#include "gimprowdrawablefilter.h"
#include "gimprowseparator.h"
#include "gimprowsettings.h"
@ -44,7 +46,15 @@ gimp_row_type_from_viewable (GimpViewable *viewable)
g_return_val_if_fail (GIMP_IS_VIEWABLE (viewable), G_TYPE_NONE);
if (GIMP_IS_SETTINGS (viewable))
if (GIMP_IS_DRAWABLE_FILTER (viewable))
{
row_type = GIMP_TYPE_ROW_DRAWABLE_FILTER;
}
else if (GIMP_IS_FILTER (viewable))
{
row_type = GIMP_TYPE_ROW_FILTER;
}
else if (GIMP_IS_SETTINGS (viewable))
{
if (gimp_object_get_name (viewable))
row_type = GIMP_TYPE_ROW_SETTINGS;
@ -56,6 +66,12 @@ gimp_row_type_from_viewable (GimpViewable *viewable)
row_type = GIMP_TYPE_ROW_DEVICE_INFO;
}
#if 0
g_printerr ("viewable/row type: %s/%s\n",
g_type_name (G_OBJECT_TYPE (viewable)),
g_type_name (row_type));
#endif
return row_type;
}

View file

@ -0,0 +1,81 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimprowdrawablefilter.c
* Copyright (C) 2025 Michael Natterer <mitch@gimp.org>
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "widgets-types.h"
#include "core/gimpdrawable.h"
#include "core/gimpdrawablefilter.h"
#include "core/gimpimage.h"
#include "gimprowdrawablefilter.h"
struct _GimpRowDrawableFilter
{
GimpRowFilter parent_instance;
};
static void gimp_row_filter_drawable_active_toggled (GimpRowFilter *row,
gboolean active);
G_DEFINE_TYPE (GimpRowDrawableFilter,
gimp_row_drawable_filter,
GIMP_TYPE_ROW_FILTER)
#define parent_class gimp_row_drawable_filter_parent_class
static void
gimp_row_drawable_filter_class_init (GimpRowDrawableFilterClass *klass)
{
GimpRowFilterClass *row_filter_class = GIMP_ROW_FILTER_CLASS (klass);
row_filter_class->active_toggled = gimp_row_filter_drawable_active_toggled;
}
static void
gimp_row_drawable_filter_init (GimpRowDrawableFilter *row)
{
}
static void
gimp_row_filter_drawable_active_toggled (GimpRowFilter *row,
gboolean active)
{
GimpViewable *viewable = gimp_row_get_viewable (GIMP_ROW (row));
GIMP_ROW_FILTER_CLASS (parent_class)->active_toggled (row, active);
if (viewable)
{
GimpDrawable *drawable =
gimp_drawable_filter_get_drawable (GIMP_DRAWABLE_FILTER (viewable));
gimp_drawable_update (drawable, 0, 0, -1, -1);
gimp_image_flush (gimp_item_get_image (GIMP_ITEM (drawable)));
}
}

View file

@ -0,0 +1,30 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimprowdrawablefilter.h
* Copyright (C) 2025 Michael Natterer <mitch@gimp.org>
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "gimprowfilter.h"
#define GIMP_TYPE_ROW_DRAWABLE_FILTER (gimp_row_drawable_filter_get_type ())
G_DECLARE_FINAL_TYPE (GimpRowDrawableFilter,
gimp_row_drawable_filter,
GIMP, ROW_DRAWABLE_FILTER,
GimpRowFilter)

196
app/widgets/gimprowfilter.c Normal file
View file

@ -0,0 +1,196 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimprowfilter.c
* Copyright (C) 2025 Michael Natterer <mitch@gimp.org>
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libgimpwidgets/gimpwidgets.h"
#include "widgets-types.h"
#include "core/gimp-utils.h"
#include "core/gimpfilter.h"
#include "gimprowfilter.h"
typedef struct _GimpRowFilterPrivate GimpRowFilterPrivate;
struct _GimpRowFilterPrivate
{
GtkWidget *active_toggle;
GtkWidget *active_icon;
};
#define GET_PRIVATE(obj) \
((GimpRowFilterPrivate *) \
gimp_row_filter_get_instance_private ((GimpRowFilter *) obj))
static void gimp_row_filter_set_viewable (GimpRow *row,
GimpViewable *viewable);
static void gimp_row_filter_set_view_size (GimpRow *row);
static void gimp_row_filter_real_active_toggled (GimpRowFilter *row,
gboolean active);
static void gimp_row_filter_active_changed (GimpFilter *filter,
GimpRowFilter *row);
static void gimp_row_filter_active_toggled (GtkToggleButton *button,
GimpRowFilter *row);
G_DEFINE_TYPE_WITH_PRIVATE (GimpRowFilter,
gimp_row_filter,
GIMP_TYPE_ROW)
#define parent_class gimp_row_filter_parent_class
static void
gimp_row_filter_class_init (GimpRowFilterClass *klass)
{
GimpRowClass *row_class = GIMP_ROW_CLASS (klass);
row_class->set_viewable = gimp_row_filter_set_viewable;
row_class->set_view_size = gimp_row_filter_set_view_size;
klass->active_property = "active";
klass->active_changed_signal = "active-changed";
klass->active_toggled = gimp_row_filter_real_active_toggled;
}
static void
gimp_row_filter_init (GimpRowFilter *row)
{
GimpRowFilterPrivate *priv = GET_PRIVATE (row);
GtkWidget *box;
box = _gimp_row_get_box (GIMP_ROW (row));
priv->active_toggle = gtk_toggle_button_new ();
gtk_box_pack_start (GTK_BOX (box), priv->active_toggle, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (box), priv->active_toggle, 0);
gtk_widget_set_visible (priv->active_toggle, TRUE);
g_signal_connect (priv->active_toggle, "toggled",
G_CALLBACK (gimp_row_filter_active_toggled),
row);
priv->active_icon = gtk_image_new_from_icon_name (GIMP_ICON_VISIBLE,
GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (priv->active_toggle),
priv->active_icon);
gtk_widget_set_visible (priv->active_icon, TRUE);
}
static void
gimp_row_filter_set_viewable (GimpRow *row,
GimpViewable *viewable)
{
GimpViewable *old_viewable = gimp_row_get_viewable (row);
if (old_viewable)
{
g_signal_handlers_disconnect_by_func (old_viewable,
gimp_row_filter_active_changed,
row);
}
GIMP_ROW_CLASS (parent_class)->set_viewable (row, viewable);
if (viewable)
{
g_signal_connect (viewable,
GIMP_ROW_FILTER_GET_CLASS (row)->active_changed_signal,
G_CALLBACK (gimp_row_filter_active_changed),
row);
gimp_row_filter_active_changed (GIMP_FILTER (viewable),
GIMP_ROW_FILTER (row));
}
}
static void
gimp_row_filter_set_view_size (GimpRow *row)
{
GimpRowFilterPrivate *priv = GET_PRIVATE (row);
gint view_size;
GIMP_ROW_CLASS (parent_class)->set_view_size (row);
view_size = gimp_row_get_view_size (row, NULL);
view_size = gimp_view_size_get_smaller (view_size);
gtk_image_set_pixel_size (GTK_IMAGE (priv->active_icon),
view_size);
}
static void
gimp_row_filter_real_active_toggled (GimpRowFilter *row,
gboolean active)
{
GimpViewable *viewable = gimp_row_get_viewable (GIMP_ROW (row));
if (viewable)
g_object_set (viewable,
GIMP_ROW_FILTER_GET_CLASS (row)->active_property, active,
NULL);
}
static void
gimp_row_filter_active_changed (GimpFilter *filter,
GimpRowFilter *row)
{
GimpRowFilterPrivate *priv = GET_PRIVATE (row);
gboolean active;
g_signal_handlers_block_by_func (priv->active_toggle,
gimp_row_filter_active_toggled,
row);
g_object_get (filter,
GIMP_ROW_FILTER_GET_CLASS (row)->active_property, &active,
NULL);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->active_toggle),
active);
gtk_widget_set_opacity (priv->active_icon, active ? 1.0 : 0.0);
g_signal_handlers_unblock_by_func (priv->active_toggle,
gimp_row_filter_active_toggled,
row);
}
static void
gimp_row_filter_active_toggled (GtkToggleButton *button,
GimpRowFilter *row)
{
GimpRowFilterPrivate *priv = GET_PRIVATE (row);
gboolean active;
active =
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->active_toggle));
GIMP_ROW_FILTER_GET_CLASS (row)->active_toggled (row, active);
}

View file

@ -0,0 +1,42 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimprowfilter.h
* Copyright (C) 2025 Michael Natterer <mitch@gimp.org>
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "gimprow.h"
#define GIMP_TYPE_ROW_FILTER (gimp_row_filter_get_type ())
G_DECLARE_DERIVABLE_TYPE (GimpRowFilter,
gimp_row_filter,
GIMP, ROW_FILTER,
GimpRow)
struct _GimpRowFilterClass
{
GimpRowClass parent_class;
const gchar *active_property;
const gchar *active_changed_signal;
void (* active_toggled) (GimpRowFilter *row,
gboolean active);
};

View file

@ -193,6 +193,8 @@ libappwidgets_sources = [
'gimprow.c',
'gimprow-utils.c',
'gimprowdeviceinfo.c',
'gimprowdrawablefilter.c',
'gimprowfilter.c',
'gimprowseparator.c',
'gimprowsettings.c',
'gimpsamplepointeditor.c',