diff --git a/app/core/gimpdrawable-filters.c b/app/core/gimpdrawable-filters.c index dabb92414b..b1438bcc3f 100644 --- a/app/core/gimpdrawable-filters.c +++ b/app/core/gimpdrawable-filters.c @@ -90,6 +90,63 @@ gimp_drawable_has_visible_filters (GimpDrawable *drawable) return FALSE; } +gint +gimp_drawable_n_editable_filters (GimpDrawable *drawable, + gint *first, + gint *last) +{ + GList *list; + gint index = 0; + gint n_editable = 0; + gint first_editable = -1; + gint last_editable = -1; + + g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE); + + for (list = GIMP_LIST (drawable->private->filter_stack)->queue->head; + list; + list = g_list_next (list), index++) + { + GimpFilter *filter = list->data; + gboolean editable = FALSE; + + if (GIMP_IS_DRAWABLE_FILTER (filter)) + { + gboolean temporary; + + g_object_get (filter, + "temporary", &temporary, + NULL); + + if (temporary) + { + n_editable = 0; + first_editable = -1; + last_editable = -1; + + break; + } + + editable = TRUE; + } + + if (editable) + { + n_editable++; + + if (first_editable == -1) + first_editable = index; + + last_editable = index; + } + } + + if (first) *first = first_editable; + if (last) *last = last_editable; + + return n_editable; +} + void gimp_drawable_add_filter (GimpDrawable *drawable, GimpFilter *filter) @@ -170,7 +227,7 @@ gimp_drawable_raise_filter (GimpDrawable *drawable, gimp_container_reorder (drawable->private->filter_stack, GIMP_OBJECT (filter), index); - gimp_item_refresh_filters (GIMP_ITEM (drawable)); + gimp_drawable_update (drawable, 0, 0, -1, -1); return TRUE; } @@ -210,7 +267,7 @@ gimp_drawable_lower_filter (GimpDrawable *drawable, gimp_container_reorder (drawable->private->filter_stack, GIMP_OBJECT (filter), index); - gimp_item_refresh_filters (GIMP_ITEM (drawable)); + gimp_drawable_update (drawable, 0, 0, -1, -1); return TRUE; } diff --git a/app/core/gimpdrawable-filters.h b/app/core/gimpdrawable-filters.h index 434bcc7dc0..039121d7d4 100644 --- a/app/core/gimpdrawable-filters.h +++ b/app/core/gimpdrawable-filters.h @@ -33,6 +33,10 @@ GimpContainer * gimp_drawable_get_filters (GimpDrawable *drawable); gboolean gimp_drawable_has_visible_filters (GimpDrawable *drawable); +gint gimp_drawable_n_editable_filters (GimpDrawable *drawable, + gint *first, + gint *last); + void gimp_drawable_add_filter (GimpDrawable *drawable, GimpFilter *filter); void gimp_drawable_remove_filter (GimpDrawable *drawable, diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c index a221df4128..2033c4a7ac 100644 --- a/app/core/gimpdrawable.c +++ b/app/core/gimpdrawable.c @@ -2107,7 +2107,7 @@ gimp_drawable_end_paint (GimpDrawable *drawable) if (gimp_drawable_has_visible_filters (drawable) && drawable->private->paint_count == 0) { - gimp_item_refresh_filters (GIMP_ITEM (drawable)); + gimp_drawable_update (drawable, 0, 0, -1, -1); } return result; diff --git a/app/core/gimpdrawablefilterundo.c b/app/core/gimpdrawablefilterundo.c index cc76e64439..7b4d3ef735 100644 --- a/app/core/gimpdrawablefilterundo.c +++ b/app/core/gimpdrawablefilterundo.c @@ -242,7 +242,7 @@ gimp_drawable_filter_undo_pop (GimpUndo *undo, { gimp_drawable_remove_filter (drawable, GIMP_FILTER (filter)); - gimp_item_refresh_filters (GIMP_ITEM (drawable)); + gimp_drawable_update (drawable, 0, 0, -1, -1); } } if ((undo_mode == GIMP_UNDO_MODE_UNDO && diff --git a/app/core/gimpitem.c b/app/core/gimpitem.c index 44b469cfbe..3d4fb97313 100644 --- a/app/core/gimpitem.c +++ b/app/core/gimpitem.c @@ -2786,20 +2786,3 @@ gimp_item_is_in_set (GimpItem *item, return FALSE; } - -/* Hack to make the effects visibly change */ -void -gimp_item_refresh_filters (GimpItem *item) -{ - g_return_if_fail (GIMP_IS_ITEM (item)); - - if (gimp_item_is_visible (item)) - { - GimpImage *image = gimp_item_get_image (item); - - gimp_item_set_visible (item, FALSE, FALSE); - gimp_image_flush (image); - gimp_item_set_visible (item, TRUE, FALSE); - gimp_image_flush (image); - } -} diff --git a/app/core/gimpitem.h b/app/core/gimpitem.h index a47bdea8db..2be9a355bf 100644 --- a/app/core/gimpitem.h +++ b/app/core/gimpitem.h @@ -410,7 +410,5 @@ gboolean gimp_item_mask_intersect (GimpItem *item, gboolean gimp_item_is_in_set (GimpItem *item, GimpItemSet set); -void gimp_item_refresh_filters (GimpItem *item); - #endif /* __GIMP_ITEM_H__ */ diff --git a/app/tools/gimpfiltertool.c b/app/tools/gimpfiltertool.c index bc2927e6f7..4ebe04bada 100644 --- a/app/tools/gimpfiltertool.c +++ b/app/tools/gimpfiltertool.c @@ -924,7 +924,8 @@ gimp_filter_tool_options_notify (GimpTool *tool, gimp_container_reorder (filters, GIMP_OBJECT (filter_tool->filter), 0); - gimp_item_refresh_filters (GIMP_ITEM (drawable)); + gimp_drawable_update (drawable, 0, 0, -1, -1); + gimp_image_flush (gimp_item_get_image (GIMP_ITEM (drawable))); } g_object_set (filter_tool->filter, @@ -1196,7 +1197,8 @@ gimp_filter_tool_halt (GimpFilterTool *filter_tool) gimp_filter_set_active (GIMP_FILTER (filter_tool->existing_filter), TRUE); - gimp_item_refresh_filters (GIMP_ITEM (drawable)); + gimp_drawable_update (drawable, 0, 0, -1, -1); + gimp_image_flush (gimp_item_get_image (GIMP_ITEM (drawable))); /* Restore buttons in layer tree view */ gimp_drawable_filters_changed (gimp_drawable_filter_get_drawable (filter_tool->existing_filter)); @@ -1249,7 +1251,7 @@ gimp_filter_tool_commit (GimpFilterTool *filter_tool, gimp_drawable_filter_get_drawable (filter_tool->existing_filter); image = gimp_item_get_image (GIMP_ITEM (drawable)); - gimp_image_undo_push_filter_modified (image, _("Edited filter"), + gimp_image_undo_push_filter_modified (image, _("Edit filter"), drawable, filter_tool->existing_filter); /* If the filter was changed, we need to update the original filter's @@ -1354,9 +1356,8 @@ gimp_filter_tool_commit (GimpFilterTool *filter_tool, /* TODO: Review when we can apply NDE filters to channels/layer masks */ if (GIMP_IS_LAYER (drawable)) - { - gimp_item_refresh_filters (GIMP_ITEM (drawable)); - } + gimp_drawable_update (drawable, 0, 0, -1, -1); + gimp_image_flush (gimp_display_get_image (tool->display)); if (filter_tool->config && filter_tool->has_settings) @@ -1375,7 +1376,8 @@ gimp_filter_tool_commit (GimpFilterTool *filter_tool, gimp_filter_set_active (GIMP_FILTER (filter_tool->existing_filter), TRUE); - gimp_item_refresh_filters (GIMP_ITEM (drawable)); + gimp_drawable_update (drawable, 0, 0, -1, -1); + gimp_image_flush (gimp_display_get_image (tool->display)); } filter_tool->existing_filter = NULL; @@ -1558,7 +1560,9 @@ gimp_filter_tool_create_filter (GimpFilterTool *filter_tool) { gimp_container_reorder (filters, GIMP_OBJECT (filter_tool->filter), count - 1); - gimp_item_refresh_filters ((GIMP_ITEM (drawable))); + + gimp_drawable_update (drawable, 0, 0, -1, -1); + gimp_image_flush (gimp_display_get_image (tool->display)); } } } @@ -2171,7 +2175,7 @@ gimp_filter_tool_set_config (GimpFilterTool *filter_tool, GimpDrawableFilterMask *mask; GimpDrawable *existing_drawable; gint index; - const gchar *name = _("Editing filter..."); + gchar *name; /* Get drawable from existing filter, as we might have a different * drawable selected in the layer tree */ @@ -2196,11 +2200,15 @@ gimp_filter_tool_set_config (GimpFilterTool *filter_tool, index); } + name = g_strdup_printf (_("Editing '%s'..."), + gimp_object_get_name (filter_tool->existing_filter)); g_object_set (filter_tool->filter, "name", name, "mask", mask, "temporary", TRUE, NULL); + + g_free (name); } } diff --git a/app/tools/gimpgradienttool.c b/app/tools/gimpgradienttool.c index f478cebd39..b919a89d6a 100644 --- a/app/tools/gimpgradienttool.c +++ b/app/tools/gimpgradienttool.c @@ -1102,9 +1102,9 @@ gimp_gradient_tool_create_filter (GimpGradientTool *gradient_tool, gimp_gradient_tool_create_graph (gradient_tool); gradient_tool->filter = gimp_drawable_filter_new (drawable, - C_("undo-type", "Gradient"), - gradient_tool->graph, - GIMP_ICON_TOOL_GRADIENT); + C_("undo-type", "Gradient"), + gradient_tool->graph, + GIMP_ICON_TOOL_GRADIENT); g_object_set (gradient_tool->filter, "temporary", TRUE, NULL); gimp_drawable_filter_set_region (gradient_tool->filter, diff --git a/app/widgets/gimpdrawabletreeview-filters.c b/app/widgets/gimpdrawabletreeview-filters.c new file mode 100644 index 0000000000..6bc7d52280 --- /dev/null +++ b/app/widgets/gimpdrawabletreeview-filters.c @@ -0,0 +1,855 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpdrawabletreeview-filters.c + * + * 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 . + */ + +#include "config.h" + +#include +#include + +#include "libgimpwidgets/gimpwidgets.h" + +#include "gimphelp-ids.h" +#include "widgets-types.h" +#include "tools/tools-types.h" /* FIXME */ + +#include "actions/gimpgeglprocedure.h" +#include "actions/filters-commands.h" + +#include "config/gimpguiconfig.h" + +#include "core/gimp.h" +#include "core/gimpcontext.h" +#include "core/gimpdrawable.h" +#include "core/gimpdrawable-filters.h" +#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 "gimpcontainerview.h" +#include "gimpdrawabletreeview.h" +#include "gimpdrawabletreeview-filters.h" +#include "gimpviewrenderer.h" + +#include "gimp-intl.h" + + +#define COLUMN_FILTERS_ACTIVE 3 + + +struct _GimpDrawableTreeViewFiltersEditor +{ + GimpDrawable *drawable; + GimpDrawableFilter *filter; + + GtkWidget *popover; + GtkWidget *vbox; + GtkWidget *view; + GtkWidget *options; + + GtkWidget *visible_button; + GtkWidget *edit_button; + GtkWidget *raise_button; + GtkWidget *lower_button; + GtkWidget *merge_button; + GtkWidget *remove_button; + + GimpTreeHandler *active_changed_handler; + GimpTreeHandler *notify_temporary_handler; +}; + + +static void gimp_drawable_filters_editor_set_sensitive + (GimpDrawableTreeView *view); + +static gboolean + gimp_drawable_filters_editor_view_select_items + (GimpContainerView *view, + GList *filters, + GList *paths, + GimpDrawableTreeView *drawable_view); +static void gimp_drawable_filters_editor_view_activate_item + (GtkWidget *widget, + GimpViewable *viewable, + gpointer insert_data, + 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, + GimpDrawableTreeView *view); +static void gimp_drawable_filters_editor_filters_changed + (GimpDrawable *drawable, + GimpDrawableTreeView *view); + +static void gimp_drawable_filters_editor_visible_all_toggled + (GtkWidget *widget, + GimpDrawableTreeView *view); +static void gimp_drawable_filters_editor_edit_clicked + (GtkWidget *widget, + GimpDrawableTreeView *view); +static void gimp_drawable_filters_editor_raise_clicked + (GtkWidget *widget, + GimpDrawableTreeView *view); +static void gimp_drawable_filters_editor_lower_clicked + (GtkWidget *widget, + GimpDrawableTreeView *view); +static void gimp_drawable_filters_editor_merge_clicked + (GtkWidget *widget, + GimpDrawableTreeView *view); +static void gimp_drawable_filters_editor_remove_clicked + (GtkWidget *widget, + GimpDrawableTreeView *view); + + +gboolean +_gimp_drawable_tree_view_filter_editor_show (GimpDrawableTreeView *view, + GimpDrawable *drawable, + GdkRectangle *rect) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view); + GimpContainer *filters; + GList *list; + gint n_children = 0; + gboolean visible = FALSE; + + if (! editor) + { + GtkWidget *vbox; + GtkWidget *image; + GtkWidget *label; + gchar *text; + GtkIconSize button_icon_size = GTK_ICON_SIZE_SMALL_TOOLBAR; + gint pixel_icon_size = 16; + gint button_spacing; + + view->editor = editor = g_new0 (GimpDrawableTreeViewFiltersEditor, 1); + + gtk_widget_style_get (GTK_WIDGET (view), + "button-icon-size", &button_icon_size, + "button-spacing", &button_spacing, + NULL); + gtk_icon_size_lookup (button_icon_size, &pixel_icon_size, NULL); + + /* filters popover */ + editor->popover = gtk_popover_new (GTK_WIDGET (tree_view->view)); + gtk_popover_set_modal (GTK_POPOVER (editor->popover), TRUE); + + g_signal_connect_swapped (editor->popover, "closed", + G_CALLBACK (_gimp_drawable_tree_view_filter_editor_hide), + view); + + /* main vbox */ + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, button_spacing); + gtk_container_add (GTK_CONTAINER (editor->popover), vbox); + gtk_widget_show (vbox); + + gimp_help_connect (vbox, NULL, gimp_standard_help_func, + GIMP_HELP_LAYER_EFFECTS, NULL, NULL); + + /* top label */ + label = gtk_label_new (NULL); + text = g_strdup_printf ("%s", + _("Layer Effects")); + gtk_label_set_markup (GTK_LABEL (label), text); + g_free (text); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + /* main vbox within */ + editor->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, button_spacing); + gtk_box_pack_end (GTK_BOX (vbox), editor->vbox, TRUE, TRUE, 0); + gtk_widget_show (editor->vbox); + + /* bottom buttons */ + editor->options = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, button_spacing); + gtk_box_pack_end (GTK_BOX (editor->vbox), editor->options, FALSE, FALSE, 0); + gtk_widget_show (editor->options); + + /* "visible" button */ + editor->visible_button = gtk_toggle_button_new (); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (editor->visible_button), + TRUE); + image = gtk_image_new_from_icon_name (GIMP_ICON_VISIBLE, + GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_container_add (GTK_CONTAINER (editor->visible_button), image); + gtk_widget_show (image); + + gtk_box_pack_start (GTK_BOX (editor->options), + editor->visible_button, TRUE, TRUE, 0); + gtk_widget_show (editor->visible_button); + + gimp_help_set_help_data (editor->visible_button, + _("Toggle the visibility of all filters."), + GIMP_HELP_LAYER_EFFECTS); + + g_signal_connect (editor->visible_button, "toggled", + G_CALLBACK (gimp_drawable_filters_editor_visible_all_toggled), + view); + + /* "edit" button */ + editor->edit_button = + gtk_button_new_from_icon_name (GIMP_ICON_EDIT, + GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_box_pack_start (GTK_BOX (editor->options), + editor->edit_button, TRUE, TRUE, 0); + gtk_widget_show (editor->edit_button); + + gimp_help_set_help_data (editor->edit_button, + _("Edit the selected filter."), + GIMP_HELP_LAYER_EFFECTS); + + g_signal_connect (editor->edit_button, "clicked", + G_CALLBACK (gimp_drawable_filters_editor_edit_clicked), + view); + + /* "raide" button */ + editor->raise_button = + gtk_button_new_from_icon_name (GIMP_ICON_GO_UP, + GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_box_pack_start (GTK_BOX (editor->options), + editor->raise_button, TRUE, TRUE, 0); + gtk_widget_show (editor->raise_button); + + gimp_help_set_help_data (editor->raise_button, + _("Raise filter one step up in the stack."), + GIMP_HELP_LAYER_EFFECTS); + g_signal_connect (editor->raise_button, "clicked", + G_CALLBACK (gimp_drawable_filters_editor_raise_clicked), + view); + + /* "lower" button */ + editor->lower_button = + gtk_button_new_from_icon_name (GIMP_ICON_GO_DOWN, + GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_box_pack_start (GTK_BOX (editor->options), + editor->lower_button, TRUE, TRUE, 0); + gtk_widget_show (editor->lower_button); + + gimp_help_set_help_data (editor->lower_button, + _("Lower filter one step down in the stack."), + GIMP_HELP_LAYER_EFFECTS); + + g_signal_connect (editor->lower_button, "clicked", + G_CALLBACK (gimp_drawable_filters_editor_lower_clicked), + view); + + /* "merge" button */ + editor->merge_button = + gtk_button_new_from_icon_name (GIMP_ICON_LAYER_MERGE_DOWN, + GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_box_pack_start (GTK_BOX (editor->options), + editor->merge_button, TRUE, TRUE, 0); + gtk_widget_show (editor->merge_button); + + gimp_help_set_help_data (editor->merge_button, + _("Merge all active filters down."), + GIMP_HELP_LAYER_EFFECTS); + + g_signal_connect (editor->merge_button, "clicked", + G_CALLBACK (gimp_drawable_filters_editor_merge_clicked), + view); + + /* "remove" button */ + editor->remove_button = + gtk_button_new_from_icon_name (GIMP_ICON_EDIT_DELETE, + GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_box_pack_start (GTK_BOX (editor->options), + editor->remove_button, TRUE, TRUE, 0); + gtk_widget_show (editor->remove_button); + + gimp_help_set_help_data (editor->remove_button, + _("Remove the selected filter."), + GIMP_HELP_LAYER_EFFECTS); + + g_signal_connect (editor->remove_button, "clicked", + G_CALLBACK (gimp_drawable_filters_editor_remove_clicked), + view); + } + + filters = gimp_drawable_get_filters (drawable); + + for (list = GIMP_LIST (filters)->queue->tail; + list; + list = g_list_previous (list)) + { + if (GIMP_IS_DRAWABLE_FILTER (list->data)) + { + if (gimp_filter_get_active (list->data)) + visible = TRUE; + + n_children++; + } + } + + /* Set the initial value for the effect visibility toggle */ + g_signal_handlers_block_by_func (editor->visible_button, + gimp_drawable_filters_editor_visible_all_toggled, + view); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (editor->visible_button), + visible); + g_signal_handlers_unblock_by_func (editor->visible_button, + gimp_drawable_filters_editor_visible_all_toggled, + view); + + /* Only show if we have at least one active filter */ + if (n_children > 0) + { + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GimpContainerTreeView *filter_tree_view; + GtkWidget *scrolled_window; + + editor->drawable = drawable; + + editor->view = gimp_container_tree_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); + + 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, "select-items", + G_CALLBACK (gimp_drawable_filters_editor_view_select_items), + view); + g_signal_connect_object (filter_tree_view, "activate-item", + G_CALLBACK (gimp_drawable_filters_editor_view_activate_item), + view, 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)); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_NEVER, + GTK_POLICY_NEVER); + gtk_widget_set_size_request (editor->vbox, -1, 24 * (n_children + 1)); + + gimp_drawable_filters_editor_set_sensitive (view); + + gtk_popover_set_pointing_to (GTK_POPOVER (editor->popover), rect); + gtk_widget_show (editor->popover); + + return TRUE; + } + + return FALSE; +} + +void +_gimp_drawable_tree_view_filter_editor_hide (GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + + if (! editor) + return; + + gtk_widget_hide (editor->popover); + + if (editor->active_changed_handler) + { + g_signal_handlers_disconnect_by_func (editor->drawable, + 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); + } + + if (editor->view) + { + g_signal_handlers_disconnect_by_func (editor->view, + gimp_drawable_filters_editor_view_select_items, + view); + g_signal_handlers_disconnect_by_func (editor->view, + gimp_drawable_filters_editor_view_activate_item, + view); + + g_clear_pointer (&editor->view, gtk_widget_destroy); + } + + editor->drawable = NULL; + editor->filter = NULL; +} + +void +_gimp_drawable_tree_view_filter_editor_destroy (GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + + if (! editor) + return; + + _gimp_drawable_tree_view_filter_editor_hide (view); + + g_signal_handlers_disconnect_by_func (editor->popover, + _gimp_drawable_tree_view_filter_editor_hide, + view); + + g_clear_pointer (&editor->popover, gtk_widget_destroy); + g_clear_pointer (&view->editor, g_free); +} + +static void +gimp_drawable_filters_editor_set_sensitive (GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor= view->editor; + gint n_editable; + gint first_editable; + gint last_editable; + + n_editable = gimp_drawable_n_editable_filters (editor->drawable, + &first_editable, + &last_editable); + + gtk_widget_set_sensitive (editor->vbox, n_editable > 0); + + /* lock filter options if none is editable */ + if (n_editable == 0) + return; + + gtk_widget_set_sensitive (editor->options, + GIMP_IS_DRAWABLE_FILTER (editor->filter)); + + if (GIMP_IS_DRAWABLE_FILTER (editor->filter)) + { + GimpContainer *filters; + gboolean is_group = FALSE; + gboolean is_editable = FALSE; + gint index; + + filters = gimp_drawable_get_filters (editor->drawable); + + index = gimp_container_get_child_index (filters, + GIMP_OBJECT (editor->filter)); + + /* do not allow merging down effects on group layers */ + if (gimp_viewable_get_children (GIMP_VIEWABLE (editor->drawable))) + is_group = TRUE; + + is_editable = (index >= first_editable && + index <= last_editable); + + gtk_widget_set_sensitive (editor->visible_button, + TRUE); + gtk_widget_set_sensitive (editor->edit_button, + is_editable); + gtk_widget_set_sensitive (editor->raise_button, + index > first_editable); + gtk_widget_set_sensitive (editor->lower_button, + index < last_editable); + gtk_widget_set_sensitive (editor->merge_button, + ! is_group); + gtk_widget_set_sensitive (editor->remove_button, + is_editable); + } +} + +static gboolean +gimp_drawable_filters_editor_view_select_items (GimpContainerView *view, + GList *filters, + GList *paths, + GimpDrawableTreeView *drawable_view) +{ + GimpDrawableTreeViewFiltersEditor *editor = drawable_view->editor; + + g_return_val_if_fail (g_list_length (filters) <= 1, FALSE); + + editor->filter = NULL; + + if (filters) + { + /* Don't set floating selection as active filter */ + if (GIMP_IS_DRAWABLE_FILTER (filters->data)) + { + editor->filter = filters->data; + } + } + + gimp_drawable_filters_editor_set_sensitive (drawable_view); + + return FALSE; +} + +static void +gimp_drawable_filters_editor_view_activate_item (GtkWidget *widget, + GimpViewable *viewable, + gpointer insert_data, + GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + + if (gtk_widget_is_sensitive (editor->edit_button)) + 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)) + { + GimpViewRenderer *renderer; + GimpContainerTreeStore *store; + GimpDrawableFilter *filter; + + /* Update the filter state. */ + 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 visible; + + drawable = gimp_drawable_filter_get_drawable (filter); + + visible = gimp_filter_get_active (GIMP_FILTER (filter)); + gimp_filter_set_active (GIMP_FILTER (filter), ! visible); + + 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, + GimpDrawableTreeView *view) +{ + gimp_drawable_filters_editor_set_sensitive (view); +} + +static void +gimp_drawable_filters_editor_filters_changed (GimpDrawable *drawable, + GimpDrawableTreeView *view) +{ + gimp_drawable_filters_editor_set_sensitive (view); +} + +static void +gimp_drawable_filters_editor_visible_all_toggled (GtkWidget *widget, + GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + GimpContainer *filters; + GList *list; + gboolean visible; + + visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + filters = gimp_drawable_get_filters (editor->drawable); + + for (list = GIMP_LIST (filters)->queue->head; + list; + list = g_list_next (list)) + { + if (GIMP_IS_DRAWABLE_FILTER (list->data)) + { + GimpFilter *filter = list->data; + + gimp_filter_set_active (filter, visible); + } + } + + gimp_drawable_update (editor->drawable, 0, 0, -1, -1); + gimp_image_flush (gimp_item_get_image (GIMP_ITEM (editor->drawable))); +} + +static void +gimp_drawable_filters_editor_edit_clicked (GtkWidget *widget, + GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + GimpImage *image; + GeglNode *op; + + if (! GIMP_IS_DRAWABLE_FILTER (editor->filter)) + return; + + image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); + + if (! gimp_item_is_visible (GIMP_ITEM (editor->drawable)) && + ! GIMP_GUI_CONFIG (image->gimp->config)->edit_non_visible) + { + gimp_message_literal (image->gimp, G_OBJECT (view), + GIMP_MESSAGE_ERROR, + _("A selected layer is not visible.")); + return; + } + else if (gimp_item_get_lock_content (GIMP_ITEM (editor->drawable))) + { + gimp_message_literal (image->gimp, G_OBJECT (view), + GIMP_MESSAGE_WARNING, + _("A selected layer's pixels are locked.")); + return; + } + + op = gimp_drawable_filter_get_operation (editor->filter); + if (op) + { + GimpProcedure *procedure; + GVariant *variant; + gchar *operation; + gchar *name; + + g_object_get (editor->filter, + "name", &name, + NULL); + g_object_get (op, + "operation", &operation, + NULL); + + if (operation) + { + procedure = gimp_gegl_procedure_new (image->gimp, + editor->filter, + GIMP_RUN_INTERACTIVE, NULL, + operation, + name, + name, + NULL, NULL, NULL); + + variant = g_variant_new_uint64 (GPOINTER_TO_SIZE (procedure)); + g_variant_take_ref (variant); + filters_run_procedure (image->gimp, + gimp_context_get_display (gimp_get_user_context (image->gimp)), + procedure, GIMP_RUN_INTERACTIVE); + + g_variant_unref (variant); + g_object_unref (procedure); + } + + g_free (name); + g_free (operation); + } +} + +static void +gimp_drawable_filters_editor_raise_clicked (GtkWidget *widget, + GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + GimpImage *image; + + if (! GIMP_IS_DRAWABLE_FILTER (editor->filter)) + return; + + image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); + + if (gimp_drawable_filter_get_mask (editor->filter) == NULL) + { + gimp_message_literal (image->gimp, G_OBJECT (view), GIMP_MESSAGE_ERROR, + _("Cannot reorder a filter that is being edited.")); + return; + } + + if (gimp_drawable_raise_filter (editor->drawable, + GIMP_FILTER (editor->filter))) + { + gimp_image_flush (image); + } +} + +static void +gimp_drawable_filters_editor_lower_clicked (GtkWidget *widget, + GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + GimpImage *image; + + if (! GIMP_IS_DRAWABLE_FILTER (editor->filter)) + return; + + image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); + + if (gimp_drawable_filter_get_mask (editor->filter) == NULL) + { + gimp_message_literal (image->gimp, G_OBJECT (view), GIMP_MESSAGE_ERROR, + _("Cannot reorder a filter that is being edited.")); + return; + } + + if (gimp_drawable_lower_filter (editor->drawable, + GIMP_FILTER (editor->filter))) + { + gimp_image_flush (image); + } +} + +static void +gimp_drawable_filters_editor_merge_clicked (GtkWidget *widget, + GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + GimpContext *context; + GimpToolInfo *active_tool; + + if (! GIMP_IS_DRAWABLE_FILTER (editor->filter)) + return; + + /* Commit GEGL-based tools before trying to merge filters */ + context = gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view)); + active_tool = gimp_context_get_tool (context); + + if (! strcmp (gimp_object_get_name (active_tool), "gimp-cage-tool") || + ! strcmp (gimp_object_get_name (active_tool), "gimp-gradient-tool") || + ! strcmp (gimp_object_get_name (active_tool), "gimp-warp-tool")) + { + tool_manager_control_active (context->gimp, GIMP_TOOL_ACTION_COMMIT, + gimp_context_get_display (context)); + } + + if (! gimp_viewable_get_children (GIMP_VIEWABLE (editor->drawable))) + { + GimpImage *image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); + + /* Don't merge if the layer is currently locked */ + if (gimp_item_get_lock_content (GIMP_ITEM (editor->drawable))) + { + gimp_message_literal (image->gimp, G_OBJECT (view), + GIMP_MESSAGE_WARNING, + _("The layer to merge down to is locked.")); + return; + } + + gimp_drawable_merge_filters (GIMP_DRAWABLE (editor->drawable)); + + _gimp_drawable_tree_view_filter_editor_hide (view); + + gimp_image_flush (image); + } +} + +static void +gimp_drawable_filters_editor_remove_clicked (GtkWidget *widget, + GimpDrawableTreeView *view) +{ + GimpDrawableTreeViewFiltersEditor *editor = view->editor; + GimpContainer *filters; + GimpImage *image; + + if (! GIMP_IS_DRAWABLE_FILTER (editor->filter)) + return; + + filters = gimp_drawable_get_filters (editor->drawable); + image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); + + gimp_image_undo_push_filter_remove (image, _("Remove filter"), + editor->drawable, + editor->filter); + + gimp_drawable_filter_abort (editor->filter); + + /* close the popover if all effects are deleted */ + if (gimp_container_get_n_children (filters) == 0) + _gimp_drawable_tree_view_filter_editor_hide (view); + + gimp_image_flush (image); +} diff --git a/app/widgets/gimpdrawabletreeview-filters.h b/app/widgets/gimpdrawabletreeview-filters.h new file mode 100644 index 0000000000..32c967b836 --- /dev/null +++ b/app/widgets/gimpdrawabletreeview-filters.h @@ -0,0 +1,32 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpdrawabletreeview-filters.h + * + * 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 . + */ + +#ifndef __GIMP_DRAWABLE_TREE_VIEW_FILTERS_H__ +#define __GIMP_DRAWABLE_TREE_VIEW_FILTERS_H__ + + +gboolean _gimp_drawable_tree_view_filter_editor_show (GimpDrawableTreeView *view, + GimpDrawable *drawable, + GdkRectangle *rect); +void _gimp_drawable_tree_view_filter_editor_hide (GimpDrawableTreeView *view); + +void _gimp_drawable_tree_view_filter_editor_destroy (GimpDrawableTreeView *view); + + +#endif /* __GIMP_DRAWABLE_TREE_VIEW_FILTERS_H__ */ diff --git a/app/widgets/gimpdrawabletreeview.c b/app/widgets/gimpdrawabletreeview.c index 2185b6929f..958d3dc5ed 100644 --- a/app/widgets/gimpdrawabletreeview.c +++ b/app/widgets/gimpdrawabletreeview.c @@ -28,10 +28,6 @@ #include "gimphelp-ids.h" #include "widgets-types.h" -#include "tools/tools-types.h" /* FIXME */ - -#include "actions/gimpgeglprocedure.h" -#include "actions/filters-commands.h" #include "config/gimpguiconfig.h" @@ -49,12 +45,11 @@ #include "core/gimppattern.h" #include "core/gimptreehandler.h" -#include "tools/tool_manager.h" /* FIXME */ - #include "gimpcontainertreestore.h" #include "gimpcontainerview.h" #include "gimpdnd.h" #include "gimpdrawabletreeview.h" +#include "gimpdrawabletreeview-filters.h" #include "gimplayertreeview.h" /* FIXME */ #include "gimpviewrenderer.h" @@ -71,23 +66,7 @@ struct _GimpDrawableTreeViewPrivate gint model_column_filters; GtkCellRenderer *filters_cell; - GtkWidget *filters_popover; - GtkWidget *filters_vbox; - GtkWidget *filters_view; - GtkWidget *filters_options; - - GtkWidget *filters_visible_button; - GtkWidget *filters_edit_button; - GtkWidget *filters_raise_button; - GtkWidget *filters_lower_button; - GtkWidget *filters_merge_button; - GtkWidget *filters_remove_button; - - GimpDrawable *filter_drawable; - GimpDrawableFilter *filter; - GimpTreeHandler *filters_changed_handler; - GimpTreeHandler *filters_active_changed_handler; }; @@ -136,54 +115,11 @@ static void gimp_drawable_tree_view_floating_selection_changed static void gimp_drawable_tree_view_filters_changed (GimpDrawable *drawable, GimpDrawableTreeView *view); -static void gimp_drawable_tree_view_filters_set_sensitive - (GimpDrawableTreeView *view, - gboolean is_sensitive); - static void gimp_drawable_tree_view_filters_cell_clicked (GtkCellRendererToggle *toggle, gchar *path, GdkModifierType state, GimpDrawableTreeView *view); -static gboolean - gimp_drawable_tree_view_filters_view_select_items - (GimpContainerView *view, - GList *filters, - GList *paths, - GimpDrawableTreeView *drawable_view); -static void gimp_drawable_tree_view_filters_view_activate_item - (GtkWidget *widget, - GimpViewable *viewable, - gpointer insert_data, - GimpDrawableTreeView *view); -static void gimp_drawable_tree_view_filters_view_visible_cell_toggled - (GtkCellRendererToggle *toggle, - gchar *path_str, - GdkModifierType state, - GimpContainerTreeView *view); - -static void gimp_drawable_tree_view_filters_active_changed - (GimpFilter *item, - GimpContainerTreeView *view); - -static void gimp_drawable_tree_view_filters_visible_all_toggled - (GtkWidget *widget, - GimpDrawableTreeView *view); -static void gimp_drawable_tree_view_filters_edit_clicked - (GtkWidget *widget, - GimpDrawableTreeView *view); -static void gimp_drawable_tree_view_filters_raise_clicked - (GtkWidget *widget, - GimpDrawableTreeView *view); -static void gimp_drawable_tree_view_filters_lower_clicked - (GtkWidget *widget, - GimpDrawableTreeView *view); -static void gimp_drawable_tree_view_filters_merge_clicked - (GtkWidget *widget, - GimpDrawableTreeView *view); -static void gimp_drawable_tree_view_filters_remove_clicked - (GtkWidget *widget, - GimpDrawableTreeView *view); static void gimp_drawable_tree_view_new_pattern_dropped (GtkWidget *widget, @@ -317,144 +253,6 @@ gimp_drawable_tree_view_constructed (GObject *object) item_view); } - /* Effects box. */ - if (GIMP_IS_LAYER_TREE_VIEW (object)) - { - GtkWidget *image; - GtkWidget *label; - gchar *text; - - /* filters popover */ - view->priv->filters_popover = gtk_popover_new (GTK_WIDGET (tree_view->view)); - gtk_popover_set_modal (GTK_POPOVER (view->priv->filters_popover), TRUE); - - /* main vbox within */ - view->priv->filters_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, - button_spacing); - gtk_container_add (GTK_CONTAINER (view->priv->filters_popover), - view->priv->filters_vbox); - gtk_widget_show (view->priv->filters_vbox); - - gimp_help_connect (view->priv->filters_vbox, NULL, gimp_standard_help_func, - GIMP_HELP_LAYER_EFFECTS, NULL, NULL); - - /* top label */ - label = gtk_label_new (NULL); - text = g_strdup_printf ("%s", - _("Layer Effects")); - gtk_label_set_markup (GTK_LABEL (label), text); - g_free (text); - gtk_box_pack_start (GTK_BOX (view->priv->filters_vbox), label, - FALSE, FALSE, 0); - gtk_widget_show (label); - - /* bottom buttons */ - view->priv->filters_options = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, button_spacing); - gtk_box_pack_end (GTK_BOX (view->priv->filters_vbox), - view->priv->filters_options, FALSE, FALSE, 0); - gtk_widget_show (view->priv->filters_options); - - /* "visible" button */ - view->priv->filters_visible_button = gtk_toggle_button_new (); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (view->priv->filters_visible_button), - TRUE); - image = gtk_image_new_from_icon_name (GIMP_ICON_VISIBLE, - GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_container_add (GTK_CONTAINER (view->priv->filters_visible_button), image); - gtk_widget_show (image); - - gtk_box_pack_start (GTK_BOX (view->priv->filters_options), - view->priv->filters_visible_button, TRUE, TRUE, 0); - gtk_widget_show (view->priv->filters_visible_button); - - gimp_help_set_help_data (view->priv->filters_visible_button, - _("Toggle the visibility of all filters."), - GIMP_HELP_LAYER_EFFECTS); - - g_signal_connect (view->priv->filters_visible_button, "toggled", - G_CALLBACK (gimp_drawable_tree_view_filters_visible_all_toggled), - view); - - /* "edit" button */ - view->priv->filters_edit_button = - gtk_button_new_from_icon_name (GIMP_ICON_EDIT, - GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_box_pack_start (GTK_BOX (view->priv->filters_options), - view->priv->filters_edit_button, TRUE, TRUE, 0); - gtk_widget_show (view->priv->filters_edit_button); - - gimp_help_set_help_data (view->priv->filters_edit_button, - _("Edit the selected filter."), - GIMP_HELP_LAYER_EFFECTS); - - g_signal_connect (view->priv->filters_edit_button, "clicked", - G_CALLBACK (gimp_drawable_tree_view_filters_edit_clicked), - view); - - /* "raide" button */ - view->priv->filters_raise_button = - gtk_button_new_from_icon_name (GIMP_ICON_GO_UP, - GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_box_pack_start (GTK_BOX (view->priv->filters_options), - view->priv->filters_raise_button, TRUE, TRUE, 0); - gtk_widget_show (view->priv->filters_raise_button); - - gimp_help_set_help_data (view->priv->filters_raise_button, - _("Raise filter one step up in the stack."), - GIMP_HELP_LAYER_EFFECTS); - g_signal_connect (view->priv->filters_raise_button, "clicked", - G_CALLBACK (gimp_drawable_tree_view_filters_raise_clicked), - view); - - /* "lower" button */ - view->priv->filters_lower_button = - gtk_button_new_from_icon_name (GIMP_ICON_GO_DOWN, - GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_box_pack_start (GTK_BOX (view->priv->filters_options), - view->priv->filters_lower_button, TRUE, TRUE, 0); - gtk_widget_show (view->priv->filters_lower_button); - - gimp_help_set_help_data (view->priv->filters_lower_button, - _("Lower filter one step down in the stack."), - GIMP_HELP_LAYER_EFFECTS); - - g_signal_connect (view->priv->filters_lower_button, "clicked", - G_CALLBACK (gimp_drawable_tree_view_filters_lower_clicked), - view); - - /* "merge" button */ - view->priv->filters_merge_button = - gtk_button_new_from_icon_name (GIMP_ICON_LAYER_MERGE_DOWN, - GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_box_pack_start (GTK_BOX (view->priv->filters_options), - view->priv->filters_merge_button, TRUE, TRUE, 0); - gtk_widget_show (view->priv->filters_merge_button); - - gimp_help_set_help_data (view->priv->filters_merge_button, - _("Merge all active filters down."), - GIMP_HELP_LAYER_EFFECTS); - - g_signal_connect (view->priv->filters_merge_button, "clicked", - G_CALLBACK (gimp_drawable_tree_view_filters_merge_clicked), - view); - - /* "remove" button */ - view->priv->filters_remove_button = - gtk_button_new_from_icon_name (GIMP_ICON_EDIT_DELETE, - GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_box_pack_start (GTK_BOX (view->priv->filters_options), - view->priv->filters_remove_button, TRUE, TRUE, 0); - gtk_widget_show (view->priv->filters_remove_button); - - gimp_help_set_help_data (view->priv->filters_remove_button, - _("Remove the selected filter."), - GIMP_HELP_LAYER_EFFECTS); - - g_signal_connect (view->priv->filters_remove_button, "clicked", - G_CALLBACK (gimp_drawable_tree_view_filters_remove_clicked), - view); - } - gimp_dnd_viewable_dest_add (gimp_item_tree_view_get_new_button (item_view), GIMP_TYPE_PATTERN, gimp_drawable_tree_view_new_pattern_dropped, @@ -474,7 +272,7 @@ gimp_drawable_tree_view_dispose (GObject *object) { GimpDrawableTreeView *view = GIMP_DRAWABLE_TREE_VIEW (object); - g_clear_pointer (&view->priv->filters_popover, gtk_widget_destroy); + _gimp_drawable_tree_view_filter_editor_destroy (view); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -531,8 +329,6 @@ gimp_drawable_tree_view_set_container (GimpContainerView *view, { g_clear_pointer (&drawable_view->priv->filters_changed_handler, gimp_tree_handler_disconnect); - g_clear_pointer (&drawable_view->priv->filters_active_changed_handler, - gimp_tree_handler_disconnect); } } @@ -726,22 +522,11 @@ static void gimp_drawable_tree_view_set_image (GimpItemTreeView *view, GimpImage *image) { - GimpDrawableTreeView *drawable_view = GIMP_DRAWABLE_TREE_VIEW (view); - if (gimp_item_tree_view_get_image (view)) { g_signal_handlers_disconnect_by_func (gimp_item_tree_view_get_image (view), gimp_drawable_tree_view_floating_selection_changed, view); - - if (GIMP_IS_LAYER_TREE_VIEW (view)) - { - drawable_view->priv->filter_drawable = NULL; - drawable_view->priv->filter = NULL; - - if (drawable_view->priv->filters_popover) - gtk_widget_hide (drawable_view->priv->filters_popover); - } } GIMP_ITEM_TREE_VIEW_CLASS (parent_class)->set_image (view, image); @@ -780,97 +565,23 @@ static void gimp_drawable_tree_view_filters_changed (GimpDrawable *drawable, GimpDrawableTreeView *view) { - GimpContainerView *container_view = GIMP_CONTAINER_VIEW (view); - GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view); + GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view); GtkTreeIter *iter; - GimpContainer *filters; - GList *list; - gint n_filters = 0; - gboolean fs_disabled = FALSE; - gboolean temporary_only = TRUE; - iter = gimp_container_view_lookup (container_view, + iter = gimp_container_view_lookup (GIMP_CONTAINER_VIEW (view), (GimpViewable *) drawable); - filters = gimp_drawable_get_filters (drawable); - - /* Since floating selections are also stored in the filter stack, - * we need to verify what's in there to get the correct count - */ - for (list = GIMP_LIST (filters)->queue->tail; - list; - list = g_list_previous (list)) - { - if (GIMP_IS_DRAWABLE_FILTER (list->data)) - { - n_filters++; - - if (temporary_only) - g_object_get (list->data, - "temporary", &temporary_only, - NULL); - } - else - { - fs_disabled = TRUE; - } - } - - /* Don't show icon if we only have a temporary filter - * like a tool-based filter */ - if (temporary_only) - n_filters = 0; - - if (n_filters == 0 || fs_disabled) - view->priv->filter = NULL; - if (iter) - gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter, - view->priv->model_column_filters, - n_filters > 0, - -1); - - /* Re-enable buttons after editing */ - gimp_drawable_tree_view_filters_set_sensitive (view, ! fs_disabled); - - if (view->priv->filters_popover && - view->priv->filter && - ! fs_disabled) { - if (GIMP_IS_DRAWABLE_FILTER (view->priv->filter)) - { - gint index = gimp_container_get_child_index (filters, - GIMP_OBJECT (view->priv->filter)); + gint n_filters = gimp_drawable_n_editable_filters (drawable, NULL, NULL); - if (index == 0) - gtk_widget_set_sensitive (view->priv->filters_raise_button, FALSE); - else if (index == (n_filters - 1)) - gtk_widget_set_sensitive (view->priv->filters_lower_button, FALSE); - } + gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter, + view->priv->model_column_filters, + n_filters > 0, + -1); } } -static void -gimp_drawable_tree_view_filters_set_sensitive (GimpDrawableTreeView *view, - gboolean is_sensitive) -{ - gboolean is_group = FALSE; - - /* Do not allow merging down effects on group layers */ - if (view->priv->filter_drawable && - gimp_viewable_get_children (GIMP_VIEWABLE (view->priv->filter_drawable))) - is_group = TRUE; - - gtk_widget_set_sensitive (view->priv->filters_vbox, is_sensitive); - gtk_widget_set_sensitive (view->priv->filters_visible_button, is_sensitive); - gtk_widget_set_sensitive (view->priv->filters_edit_button, is_sensitive); - gtk_widget_set_sensitive (view->priv->filters_raise_button, is_sensitive); - gtk_widget_set_sensitive (view->priv->filters_lower_button, is_sensitive); - gtk_widget_set_sensitive (view->priv->filters_merge_button, (is_sensitive && - ! is_group)); - gtk_widget_set_sensitive (view->priv->filters_remove_button, is_sensitive); -} - static void gimp_drawable_tree_view_filters_cell_clicked (GtkCellRendererToggle *toggle, gchar *path_str, @@ -888,11 +599,7 @@ gimp_drawable_tree_view_filters_cell_clicked (GtkCellRendererToggle *toggle, GimpViewRenderer *renderer; GimpContainerTreeStore *store; GimpDrawable *drawable; - GimpContainer *filters; GdkRectangle rect; - GList *list; - gint n_children = 0; - gboolean visible = TRUE; /* Update the filter state. */ store = GIMP_CONTAINER_TREE_STORE (GIMP_CONTAINER_TREE_VIEW (view)->model); @@ -900,521 +607,15 @@ gimp_drawable_tree_view_filters_cell_clicked (GtkCellRendererToggle *toggle, drawable = GIMP_DRAWABLE (renderer->viewable); g_object_unref (renderer); - /* Get filters */ - if (view->priv->filters_view) - { - g_signal_handlers_disconnect_by_func (view->priv->filters_view, - gimp_drawable_tree_view_filters_view_select_items, - view); - g_signal_handlers_disconnect_by_func (view->priv->filters_view, - gimp_drawable_tree_view_filters_view_activate_item, - view); + gtk_tree_view_get_cell_area (GIMP_CONTAINER_TREE_VIEW (view)->view, path, + gtk_tree_view_get_column (GIMP_CONTAINER_TREE_VIEW (view)->view, 2), + &rect); + gtk_tree_view_convert_bin_window_to_widget_coords (GIMP_CONTAINER_TREE_VIEW (view)->view, + rect.x, rect.y, &rect.x, &rect.y); - g_clear_pointer (&view->priv->filters_active_changed_handler, - gimp_tree_handler_disconnect); - g_clear_pointer (&view->priv->filters_view, - gtk_widget_destroy); - } + gimp_drawable_tree_view_filters_changed (drawable, view); - view->priv->filter_drawable = drawable; - - filters = gimp_drawable_get_filters (drawable); - - for (list = GIMP_LIST (filters)->queue->tail; - list; - list = g_list_previous (list)) - { - if (GIMP_IS_DRAWABLE_FILTER (list->data)) - { - if (! gimp_filter_get_active (GIMP_FILTER (list->data))) - visible = FALSE; - - n_children++; - } - } - - /* Set the initial value for the effect visibility toggle */ - g_signal_handlers_block_by_func (view->priv->filters_visible_button, - gimp_drawable_tree_view_filters_visible_all_toggled, - view); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (view->priv->filters_visible_button), - visible); - g_signal_handlers_unblock_by_func (view->priv->filters_visible_button, - gimp_drawable_tree_view_filters_visible_all_toggled, - view); - - /* Only show if we have at least one active filter */ - if (n_children > 0) - { - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - GimpContainerTreeView *filter_tree_view; - GtkWidget *scrolled_window = NULL; - gboolean is_editing = FALSE; - - view->priv->filters_view = gimp_container_tree_view_new (filters, - gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view)), - GIMP_VIEW_SIZE_SMALL, 0); - filter_tree_view = GIMP_CONTAINER_TREE_VIEW (view->priv->filters_view); - - /* Connect filter active signal */ - view->priv->filters_active_changed_handler = - gimp_tree_handler_connect (filters, "active-changed", - G_CALLBACK (gimp_drawable_tree_view_filters_active_changed), - view->priv->filters_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_tree_view_filters_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)) - { - gboolean is_temporary; - - gimp_drawable_tree_view_filters_active_changed (GIMP_FILTER (list->data), - filter_tree_view); - - g_object_get (list->data, - "temporary", &is_temporary, - NULL); - if (is_temporary) - is_editing = TRUE; - } - } - - g_signal_connect (filter_tree_view, "select-items", - G_CALLBACK (gimp_drawable_tree_view_filters_view_select_items), - view); - g_signal_connect_object (filter_tree_view, "activate-item", - G_CALLBACK (gimp_drawable_tree_view_filters_view_activate_item), - view, 0); - - gtk_box_pack_start (GTK_BOX (view->priv->filters_vbox), - view->priv->filters_view, TRUE, TRUE, 0); - gtk_widget_show (view->priv->filters_view); - - scrolled_window = gtk_widget_get_parent (GTK_WIDGET (filter_tree_view->view)); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), - GTK_POLICY_NEVER, - GTK_POLICY_NEVER); - gtk_widget_set_size_request (view->priv->filters_vbox, -1, 24 * (n_children + 1)); - - /* Change popover position. */ - gtk_tree_view_get_cell_area (GIMP_CONTAINER_TREE_VIEW (view)->view, path, - gtk_tree_view_get_column (GIMP_CONTAINER_TREE_VIEW (view)->view, 2), - &rect); - gtk_tree_view_convert_bin_window_to_widget_coords (GIMP_CONTAINER_TREE_VIEW (view)->view, - rect.x, rect.y, &rect.x, &rect.y); - gtk_popover_set_pointing_to (GTK_POPOVER (view->priv->filters_popover), &rect); - - gimp_drawable_tree_view_filters_changed (drawable, view); - gtk_widget_show (view->priv->filters_popover); - - /* Lock filter options if we're actively editing a filter */ - gimp_drawable_tree_view_filters_set_sensitive (view, ! is_editing); - } - } -} - -static gboolean -gimp_drawable_tree_view_filters_view_select_items (GimpContainerView *view, - GList *filters, - GList *paths, - GimpDrawableTreeView *drawable_view) -{ - g_return_val_if_fail (g_list_length (filters) <= 1, FALSE); - - if (filters && GIMP_IS_DRAWABLE (drawable_view->priv->filter_drawable)) - { - gint index = -1; - gint n_children = 0; - gboolean is_blocked_op = FALSE; - - /* Don't set floating selection as active filter */ - if (GIMP_IS_DRAWABLE_FILTER (filters->data)) - { - GimpContainer *container; - GeglNode *op_node; - - drawable_view->priv->filter = filters->data; - - container = - gimp_drawable_get_filters (GIMP_DRAWABLE (drawable_view->priv->filter_drawable)); - - index = gimp_container_get_child_index (container, - GIMP_OBJECT (drawable_view->priv->filter)); - - n_children = gimp_container_get_n_children (container); - - /* TODO: For now, prevent raising/lowering tool operations like Warp. */ - op_node = gimp_drawable_filter_get_operation (drawable_view->priv->filter); - if (op_node && - ! strcmp (gegl_node_get_operation (op_node), "GraphNode")) - is_blocked_op = TRUE; - } - else - { - is_blocked_op = TRUE; - } - - gtk_widget_set_sensitive (drawable_view->priv->filters_remove_button, - ! is_blocked_op); - gtk_widget_set_sensitive (drawable_view->priv->filters_raise_button, - (index != 0) && ! is_blocked_op); - gtk_widget_set_sensitive (drawable_view->priv->filters_lower_button, - (index != n_children - 1) && ! is_blocked_op); - } - - return TRUE; -} - -static void -gimp_drawable_tree_view_filters_view_activate_item (GtkWidget *widget, - GimpViewable *viewable, - gpointer insert_data, - GimpDrawableTreeView *view) -{ - if (gtk_widget_get_sensitive (view->priv->filters_edit_button)) - gimp_drawable_tree_view_filters_edit_clicked (widget, view); -} - -static void -gimp_drawable_tree_view_filters_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)) - { - GimpViewRenderer *renderer; - GimpContainerTreeStore *store; - GimpDrawableFilter *filter; - gboolean visible; - - /* Update the filter state. */ - 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; - - drawable = gimp_drawable_filter_get_drawable (filter); - - if (drawable) - { - visible = gimp_filter_get_active (GIMP_FILTER (filter)); - - gimp_filter_set_active (GIMP_FILTER (filter), ! visible); - - gimp_item_refresh_filters (GIMP_ITEM (drawable)); - } - } - } -} - -static void -gimp_drawable_tree_view_filters_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_tree_view_filters_visible_all_toggled (GtkWidget *widget, - GimpDrawableTreeView *view) -{ - if (view->priv->filter_drawable) - { - GimpContainer *filters; - GList *list; - gboolean visible; - - visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - filters = gimp_drawable_get_filters (GIMP_DRAWABLE (view->priv->filter_drawable)); - - for (list = GIMP_LIST (filters)->queue->head; - list; - list = g_list_next (list)) - { - if (GIMP_IS_DRAWABLE_FILTER (list->data)) - { - GimpFilter *filter = list->data; - - gimp_filter_set_active (filter, visible); - } - } - - gimp_item_refresh_filters (GIMP_ITEM (view->priv->filter_drawable)); - } -} - -static void -gimp_drawable_tree_view_filters_edit_clicked (GtkWidget *widget, - GimpDrawableTreeView *view) -{ - GimpImage *image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); - GimpDrawable *drawable; - GeglNode *op; - - if (! GIMP_IS_DRAWABLE_FILTER (view->priv->filter)) - return; - - drawable = gimp_drawable_filter_get_drawable (view->priv->filter); - - if (drawable && GIMP_IS_DRAWABLE (drawable)) - { - if (! gimp_item_is_visible (GIMP_ITEM (drawable)) && - ! GIMP_GUI_CONFIG (image->gimp->config)->edit_non_visible) - { - gimp_message_literal (image->gimp, G_OBJECT (view), - GIMP_MESSAGE_ERROR, - _("A selected layer is not visible.")); - return; - } - else if (gimp_item_get_lock_content (GIMP_ITEM (drawable))) - { - gimp_message_literal (image->gimp, G_OBJECT (view), - GIMP_MESSAGE_WARNING, - _("A selected layer's pixels are locked.")); - return; - } - - op = gimp_drawable_filter_get_operation (view->priv->filter); - if (op) - { - GimpProcedure *procedure; - GVariant *variant; - gchar *operation; - gchar *name; - - g_object_get (view->priv->filter, - "name", &name, - NULL); - g_object_get (op, - "operation", &operation, - NULL); - - if (operation) - { - procedure = gimp_gegl_procedure_new (image->gimp, - view->priv->filter, - GIMP_RUN_INTERACTIVE, NULL, - operation, - name, - name, - NULL, NULL, NULL); - - variant = g_variant_new_uint64 (GPOINTER_TO_SIZE (procedure)); - g_variant_take_ref (variant); - filters_run_procedure (image->gimp, - gimp_context_get_display (gimp_get_user_context (image->gimp)), - procedure, GIMP_RUN_INTERACTIVE); - - g_variant_unref (variant); - g_object_unref (procedure); - - /* Disable buttons until we're done editing */ - gimp_drawable_tree_view_filters_set_sensitive (view, FALSE); - } - - g_free (name); - g_free (operation); - } - } -} - -static void -gimp_drawable_tree_view_filters_raise_clicked (GtkWidget *widget, - GimpDrawableTreeView *view) -{ - GimpImage *image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); - - if (! GIMP_IS_DRAWABLE_FILTER (view->priv->filter)) - return; - - if (gimp_drawable_filter_get_mask (view->priv->filter) == NULL) - { - gimp_message_literal (image->gimp, G_OBJECT (view), GIMP_MESSAGE_ERROR, - _("Cannot reorder a filter that is being edited.")); - return; - } - - if (gimp_drawable_raise_filter (view->priv->filter_drawable, - GIMP_FILTER (view->priv->filter))) - { - if (gtk_widget_get_sensitive (view->priv->filters_edit_button)) - { - GimpContainer *filters; - gint index; - - filters = - gimp_drawable_get_filters (GIMP_DRAWABLE (view->priv->filter_drawable)); - - index = gimp_container_get_child_index (filters, - GIMP_OBJECT (view->priv->filter)); - - gtk_widget_set_sensitive (view->priv->filters_lower_button, TRUE); - if (index == 0) - gtk_widget_set_sensitive (view->priv->filters_raise_button, FALSE); - } - } -} - -static void -gimp_drawable_tree_view_filters_lower_clicked (GtkWidget *widget, - GimpDrawableTreeView *view) -{ - GimpImage *image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); - - if (! GIMP_IS_DRAWABLE_FILTER (view->priv->filter)) - return; - - if (gimp_drawable_filter_get_mask (view->priv->filter) == NULL) - { - gimp_message_literal (image->gimp, G_OBJECT (view), GIMP_MESSAGE_ERROR, - _("Cannot reorder a filter that is being edited.")); - return; - } - - if (gimp_drawable_lower_filter (view->priv->filter_drawable, - GIMP_FILTER (view->priv->filter))) - { - if (gtk_widget_get_sensitive (view->priv->filters_edit_button)) - { - GimpContainer *filters; - gint index; - - filters = - gimp_drawable_get_filters (GIMP_DRAWABLE (view->priv->filter_drawable)); - - index = gimp_container_get_child_index (filters, - GIMP_OBJECT (view->priv->filter)); - - gtk_widget_set_sensitive (view->priv->filters_raise_button, TRUE); - if (index == gimp_container_get_n_children (filters) - 1) - gtk_widget_set_sensitive (view->priv->filters_lower_button, FALSE); - } - } -} - -static void -gimp_drawable_tree_view_filters_merge_clicked (GtkWidget *widget, - GimpDrawableTreeView *view) -{ - GimpContext *context; - GimpToolInfo *active_tool; - - if (! GIMP_IS_DRAWABLE_FILTER (view->priv->filter)) - return; - - /* Commit GEGL-based tools before trying to merge filters */ - context = gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view)); - active_tool = gimp_context_get_tool (context); - - if (! strcmp (gimp_object_get_name (active_tool), "gimp-cage-tool") || - ! strcmp (gimp_object_get_name (active_tool), "gimp-gradient-tool") || - ! strcmp (gimp_object_get_name (active_tool), "gimp-warp-tool")) - { - tool_manager_control_active (context->gimp, GIMP_TOOL_ACTION_COMMIT, - gimp_context_get_display (context)); - } - - if (view->priv->filter_drawable && - ! gimp_viewable_get_children (GIMP_VIEWABLE (view->priv->filter_drawable))) - { - GimpImage *image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); - - /* Don't merge if the layer is currently locked */ - if (gimp_item_get_lock_content (GIMP_ITEM (view->priv->filter_drawable))) - { - gimp_message_literal (image->gimp, G_OBJECT (view), - GIMP_MESSAGE_WARNING, - _("The layer to merge down to is locked.")); - return; - } - - gimp_drawable_merge_filters (GIMP_DRAWABLE (view->priv->filter_drawable)); - gimp_drawable_clear_filters (GIMP_DRAWABLE (view->priv->filter_drawable)); - - view->priv->filter = NULL; - - /* Close NDE pop-over on successful merge */ - gtk_widget_hide (view->priv->filters_popover); - - gimp_item_refresh_filters (GIMP_ITEM (view->priv->filter_drawable)); - } -} - -static void -gimp_drawable_tree_view_filters_remove_clicked (GtkWidget *widget, - GimpDrawableTreeView *view) -{ - if (view->priv->filter_drawable) - { - GimpImage *image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)); - GimpContainer *filters; - - filters = gimp_drawable_get_filters (view->priv->filter_drawable); - - if (gimp_container_have (filters, - GIMP_OBJECT (view->priv->filter))) - { - gimp_image_undo_push_filter_remove (image, _("Remove filter"), - view->priv->filter_drawable, - view->priv->filter); - - gimp_drawable_filter_abort (view->priv->filter); - - /* Toggle the popover off if all effects are deleted */ - if (gimp_container_get_n_children (filters) == 0) - gtk_widget_hide (view->priv->filters_popover); - } - - gimp_item_refresh_filters (GIMP_ITEM (view->priv->filter_drawable)); + _gimp_drawable_tree_view_filter_editor_show (view, drawable, &rect); } } diff --git a/app/widgets/gimpdrawabletreeview.h b/app/widgets/gimpdrawabletreeview.h index 57f2e6aa5c..a225f83235 100644 --- a/app/widgets/gimpdrawabletreeview.h +++ b/app/widgets/gimpdrawabletreeview.h @@ -33,14 +33,16 @@ #define GIMP_DRAWABLE_TREE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_DRAWABLE_TREE_VIEW, GimpDrawableTreeViewClass)) -typedef struct _GimpDrawableTreeViewClass GimpDrawableTreeViewClass; -typedef struct _GimpDrawableTreeViewPrivate GimpDrawableTreeViewPrivate; +typedef struct _GimpDrawableTreeViewClass GimpDrawableTreeViewClass; +typedef struct _GimpDrawableTreeViewPrivate GimpDrawableTreeViewPrivate; +typedef struct _GimpDrawableTreeViewFiltersEditor GimpDrawableTreeViewFiltersEditor; struct _GimpDrawableTreeView { - GimpItemTreeView parent_instance; + GimpItemTreeView parent_instance; - GimpDrawableTreeViewPrivate *priv; + GimpDrawableTreeViewPrivate *priv; + GimpDrawableTreeViewFiltersEditor *editor; }; struct _GimpDrawableTreeViewClass diff --git a/app/widgets/meson.build b/app/widgets/meson.build index fbd996805a..aee43824d9 100644 --- a/app/widgets/meson.build +++ b/app/widgets/meson.build @@ -105,6 +105,7 @@ libappwidgets_sources = [ 'gimpdocumentview.c', 'gimpdoubleaction.c', 'gimpdrawabletreeview.c', + 'gimpdrawabletreeview-filters.c', 'gimpdynamicseditor.c', 'gimpdynamicsfactoryview.c', 'gimpdynamicsoutputeditor.c',