summaryrefslogtreecommitdiffstats
path: root/app/widgets/gimplayertreeview.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/widgets/gimplayertreeview.c')
-rw-r--r--app/widgets/gimplayertreeview.c1555
1 files changed, 1555 insertions, 0 deletions
diff --git a/app/widgets/gimplayertreeview.c b/app/widgets/gimplayertreeview.c
new file mode 100644
index 0000000..9b61504
--- /dev/null
+++ b/app/widgets/gimplayertreeview.c
@@ -0,0 +1,1555 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimplayertreeview.c
+ * Copyright (C) 2001-2009 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 <string.h>
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpmath/gimpmath.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "core/gimp.h"
+#include "core/gimpchannel.h"
+#include "core/gimpcontainer.h"
+#include "core/gimpimage-undo.h"
+#include "core/gimpimage.h"
+#include "core/gimpitemundo.h"
+#include "core/gimplayer.h"
+#include "core/gimplayer-floating-selection.h"
+#include "core/gimplayer-new.h"
+#include "core/gimplayermask.h"
+#include "core/gimptreehandler.h"
+
+#include "text/gimptextlayer.h"
+
+#include "file/file-open.h"
+
+#include "gimpactiongroup.h"
+#include "gimpcellrendererviewable.h"
+#include "gimpcontainertreestore.h"
+#include "gimpcontainerview.h"
+#include "gimpdnd.h"
+#include "gimphelp-ids.h"
+#include "gimphighlightablebutton.h"
+#include "gimplayermodebox.h"
+#include "gimplayertreeview.h"
+#include "gimpspinscale.h"
+#include "gimpuimanager.h"
+#include "gimpviewrenderer.h"
+#include "gimpwidgets-utils.h"
+
+#include "gimp-intl.h"
+
+
+struct _GimpLayerTreeViewPrivate
+{
+ GtkWidget *layer_mode_box;
+ GtkAdjustment *opacity_adjustment;
+ GtkWidget *lock_alpha_toggle;
+ GtkWidget *anchor_button;
+
+ gint model_column_mask;
+ gint model_column_mask_visible;
+
+ GtkCellRenderer *mask_cell;
+
+ PangoAttrList *italic_attrs;
+ PangoAttrList *bold_attrs;
+
+ GimpTreeHandler *mode_changed_handler;
+ GimpTreeHandler *opacity_changed_handler;
+ GimpTreeHandler *lock_alpha_changed_handler;
+ GimpTreeHandler *mask_changed_handler;
+ GimpTreeHandler *alpha_changed_handler;
+};
+
+
+static void gimp_layer_tree_view_view_iface_init (GimpContainerViewInterface *iface);
+
+static void gimp_layer_tree_view_constructed (GObject *object);
+static void gimp_layer_tree_view_finalize (GObject *object);
+
+static void gimp_layer_tree_view_set_container (GimpContainerView *view,
+ GimpContainer *container);
+static void gimp_layer_tree_view_set_context (GimpContainerView *view,
+ GimpContext *context);
+static gpointer gimp_layer_tree_view_insert_item (GimpContainerView *view,
+ GimpViewable *viewable,
+ gpointer parent_insert_data,
+ gint index);
+static gboolean gimp_layer_tree_view_select_item (GimpContainerView *view,
+ GimpViewable *item,
+ gpointer insert_data);
+static void gimp_layer_tree_view_set_view_size (GimpContainerView *view);
+static gboolean gimp_layer_tree_view_drop_possible (GimpContainerTreeView *view,
+ GimpDndType src_type,
+ GimpViewable *src_viewable,
+ GimpViewable *dest_viewable,
+ GtkTreePath *drop_path,
+ GtkTreeViewDropPosition drop_pos,
+ GtkTreeViewDropPosition *return_drop_pos,
+ GdkDragAction *return_drag_action);
+static void gimp_layer_tree_view_drop_color (GimpContainerTreeView *view,
+ const GimpRGB *color,
+ GimpViewable *dest_viewable,
+ GtkTreeViewDropPosition drop_pos);
+static void gimp_layer_tree_view_drop_uri_list (GimpContainerTreeView *view,
+ GList *uri_list,
+ GimpViewable *dest_viewable,
+ GtkTreeViewDropPosition drop_pos);
+static void gimp_layer_tree_view_drop_component (GimpContainerTreeView *tree_view,
+ GimpImage *image,
+ GimpChannelType component,
+ GimpViewable *dest_viewable,
+ GtkTreeViewDropPosition drop_pos);
+static void gimp_layer_tree_view_drop_pixbuf (GimpContainerTreeView *tree_view,
+ GdkPixbuf *pixbuf,
+ GimpViewable *dest_viewable,
+ GtkTreeViewDropPosition drop_pos);
+static void gimp_layer_tree_view_set_image (GimpItemTreeView *view,
+ GimpImage *image);
+static GimpItem * gimp_layer_tree_view_item_new (GimpImage *image);
+static void gimp_layer_tree_view_floating_selection_changed (GimpImage *image,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_layer_mode_box_callback (GtkWidget *widget,
+ const GParamSpec *pspec,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_opacity_scale_changed (GtkAdjustment *adj,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_lock_alpha_button_toggled (GtkWidget *widget,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_layer_signal_handler (GimpLayer *layer,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_update_options (GimpLayerTreeView *view,
+ GimpLayer *layer);
+static void gimp_layer_tree_view_update_menu (GimpLayerTreeView *view,
+ GimpLayer *layer);
+static void gimp_layer_tree_view_update_highlight (GimpLayerTreeView *view);
+static void gimp_layer_tree_view_mask_update (GimpLayerTreeView *view,
+ GtkTreeIter *iter,
+ GimpLayer *layer);
+static void gimp_layer_tree_view_mask_changed (GimpLayer *layer,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_renderer_update (GimpViewRenderer *renderer,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_update_borders (GimpLayerTreeView *view,
+ GtkTreeIter *iter);
+static void gimp_layer_tree_view_mask_callback (GimpLayer *mask,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_layer_clicked (GimpCellRendererViewable *cell,
+ const gchar *path,
+ GdkModifierType state,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_mask_clicked (GimpCellRendererViewable *cell,
+ const gchar *path,
+ GdkModifierType state,
+ GimpLayerTreeView *view);
+static void gimp_layer_tree_view_alpha_update (GimpLayerTreeView *view,
+ GtkTreeIter *iter,
+ GimpLayer *layer);
+static void gimp_layer_tree_view_alpha_changed (GimpLayer *layer,
+ GimpLayerTreeView *view);
+
+
+G_DEFINE_TYPE_WITH_CODE (GimpLayerTreeView, gimp_layer_tree_view,
+ GIMP_TYPE_DRAWABLE_TREE_VIEW,
+ G_ADD_PRIVATE (GimpLayerTreeView)
+ G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONTAINER_VIEW,
+ gimp_layer_tree_view_view_iface_init))
+
+#define parent_class gimp_layer_tree_view_parent_class
+
+static GimpContainerViewInterface *parent_view_iface = NULL;
+
+
+static void
+gimp_layer_tree_view_class_init (GimpLayerTreeViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GimpContainerTreeViewClass *tree_view_class;
+ GimpItemTreeViewClass *item_view_class;
+
+ tree_view_class = GIMP_CONTAINER_TREE_VIEW_CLASS (klass);
+ item_view_class = GIMP_ITEM_TREE_VIEW_CLASS (klass);
+
+ object_class->constructed = gimp_layer_tree_view_constructed;
+ object_class->finalize = gimp_layer_tree_view_finalize;
+
+ tree_view_class->drop_possible = gimp_layer_tree_view_drop_possible;
+ tree_view_class->drop_color = gimp_layer_tree_view_drop_color;
+ tree_view_class->drop_uri_list = gimp_layer_tree_view_drop_uri_list;
+ tree_view_class->drop_component = gimp_layer_tree_view_drop_component;
+ tree_view_class->drop_pixbuf = gimp_layer_tree_view_drop_pixbuf;
+
+ item_view_class->item_type = GIMP_TYPE_LAYER;
+ item_view_class->signal_name = "active-layer-changed";
+
+ item_view_class->set_image = gimp_layer_tree_view_set_image;
+ item_view_class->get_container = gimp_image_get_layers;
+ item_view_class->get_active_item = (GimpGetItemFunc) gimp_image_get_active_layer;
+ item_view_class->set_active_item = (GimpSetItemFunc) gimp_image_set_active_layer;
+ item_view_class->add_item = (GimpAddItemFunc) gimp_image_add_layer;
+ item_view_class->remove_item = (GimpRemoveItemFunc) gimp_image_remove_layer;
+ item_view_class->new_item = gimp_layer_tree_view_item_new;
+
+ item_view_class->action_group = "layers";
+ item_view_class->activate_action = "layers-edit";
+ item_view_class->new_action = "layers-new";
+ item_view_class->new_default_action = "layers-new-last-values";
+ item_view_class->raise_action = "layers-raise";
+ item_view_class->raise_top_action = "layers-raise-to-top";
+ item_view_class->lower_action = "layers-lower";
+ item_view_class->lower_bottom_action = "layers-lower-to-bottom";
+ item_view_class->duplicate_action = "layers-duplicate";
+ item_view_class->delete_action = "layers-delete";
+ item_view_class->lock_content_help_id = GIMP_HELP_LAYER_LOCK_PIXELS;
+ item_view_class->lock_position_help_id = GIMP_HELP_LAYER_LOCK_POSITION;
+}
+
+static void
+gimp_layer_tree_view_view_iface_init (GimpContainerViewInterface *iface)
+{
+ parent_view_iface = g_type_interface_peek_parent (iface);
+
+ iface->set_container = gimp_layer_tree_view_set_container;
+ iface->set_context = gimp_layer_tree_view_set_context;
+ iface->insert_item = gimp_layer_tree_view_insert_item;
+ iface->select_item = gimp_layer_tree_view_select_item;
+ iface->set_view_size = gimp_layer_tree_view_set_view_size;
+
+ iface->model_is_tree = TRUE;
+}
+
+static void
+gimp_layer_tree_view_init (GimpLayerTreeView *view)
+{
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
+ GtkWidget *scale;
+ GtkWidget *hbox;
+ GtkWidget *image;
+ GtkIconSize icon_size;
+ PangoAttribute *attr;
+
+ view->priv = gimp_layer_tree_view_get_instance_private (view);
+
+ view->priv->model_column_mask =
+ gimp_container_tree_store_columns_add (tree_view->model_columns,
+ &tree_view->n_model_columns,
+ GIMP_TYPE_VIEW_RENDERER);
+
+ view->priv->model_column_mask_visible =
+ gimp_container_tree_store_columns_add (tree_view->model_columns,
+ &tree_view->n_model_columns,
+ G_TYPE_BOOLEAN);
+
+ /* Paint mode menu */
+
+ view->priv->layer_mode_box = gimp_layer_mode_box_new (GIMP_LAYER_MODE_CONTEXT_LAYER);
+ gimp_layer_mode_box_set_label (GIMP_LAYER_MODE_BOX (view->priv->layer_mode_box),
+ _("Mode"));
+ gimp_item_tree_view_add_options (GIMP_ITEM_TREE_VIEW (view), NULL,
+ view->priv->layer_mode_box);
+
+ g_signal_connect (view->priv->layer_mode_box, "notify::layer-mode",
+ G_CALLBACK (gimp_layer_tree_view_layer_mode_box_callback),
+ view);
+
+ gimp_help_set_help_data (view->priv->layer_mode_box, NULL,
+ GIMP_HELP_LAYER_DIALOG_PAINT_MODE_MENU);
+
+ /* Opacity scale */
+
+ view->priv->opacity_adjustment =
+ GTK_ADJUSTMENT (gtk_adjustment_new (100.0, 0.0, 100.0,
+ 1.0, 10.0, 0.0));
+ scale = gimp_spin_scale_new (view->priv->opacity_adjustment, _("Opacity"), 1);
+ gimp_help_set_help_data (scale, NULL,
+ GIMP_HELP_LAYER_DIALOG_OPACITY_SCALE);
+ gimp_item_tree_view_add_options (GIMP_ITEM_TREE_VIEW (view),
+ NULL, scale);
+
+ g_signal_connect (view->priv->opacity_adjustment, "value-changed",
+ G_CALLBACK (gimp_layer_tree_view_opacity_scale_changed),
+ view);
+
+ /* Lock alpha toggle */
+
+ hbox = gimp_item_tree_view_get_lock_box (GIMP_ITEM_TREE_VIEW (view));
+
+ view->priv->lock_alpha_toggle = gtk_toggle_button_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), view->priv->lock_alpha_toggle,
+ FALSE, FALSE, 0);
+ gtk_widget_show (view->priv->lock_alpha_toggle);
+
+ g_signal_connect (view->priv->lock_alpha_toggle, "toggled",
+ G_CALLBACK (gimp_layer_tree_view_lock_alpha_button_toggled),
+ view);
+
+ gimp_help_set_help_data (view->priv->lock_alpha_toggle,
+ _("Lock alpha channel"),
+ GIMP_HELP_LAYER_LOCK_ALPHA);
+
+ gtk_widget_style_get (GTK_WIDGET (view),
+ "button-icon-size", &icon_size,
+ NULL);
+
+ image = gtk_image_new_from_icon_name (GIMP_ICON_TRANSPARENCY, icon_size);
+ gtk_container_add (GTK_CONTAINER (view->priv->lock_alpha_toggle), image);
+ gtk_widget_show (image);
+
+ view->priv->italic_attrs = pango_attr_list_new ();
+ attr = pango_attr_style_new (PANGO_STYLE_ITALIC);
+ attr->start_index = 0;
+ attr->end_index = -1;
+ pango_attr_list_insert (view->priv->italic_attrs, attr);
+
+ view->priv->bold_attrs = pango_attr_list_new ();
+ attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
+ attr->start_index = 0;
+ attr->end_index = -1;
+ pango_attr_list_insert (view->priv->bold_attrs, attr);
+}
+
+static void
+gimp_layer_tree_view_constructed (GObject *object)
+{
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (object);
+ GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (object);
+ GimpLayerTreeView *layer_view = GIMP_LAYER_TREE_VIEW (object);
+ GtkWidget *button;
+
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ gimp_highlightable_button_set_highlight_color (
+ GIMP_HIGHLIGHTABLE_BUTTON (gimp_item_tree_view_get_new_button (item_view)),
+ GIMP_HIGHLIGHTABLE_BUTTON_COLOR_AFFIRMATIVE);
+ gimp_highlightable_button_set_highlight_color (
+ GIMP_HIGHLIGHTABLE_BUTTON (gimp_item_tree_view_get_delete_button (item_view)),
+ GIMP_HIGHLIGHTABLE_BUTTON_COLOR_NEGATIVE);
+
+ layer_view->priv->mask_cell = gimp_cell_renderer_viewable_new ();
+ gtk_tree_view_column_pack_start (tree_view->main_column,
+ layer_view->priv->mask_cell,
+ FALSE);
+ gtk_tree_view_column_set_attributes (tree_view->main_column,
+ layer_view->priv->mask_cell,
+ "renderer",
+ layer_view->priv->model_column_mask,
+ "visible",
+ layer_view->priv->model_column_mask_visible,
+ NULL);
+
+ gimp_container_tree_view_add_renderer_cell (tree_view,
+ layer_view->priv->mask_cell);
+
+ g_signal_connect (tree_view->renderer_cell, "clicked",
+ G_CALLBACK (gimp_layer_tree_view_layer_clicked),
+ layer_view);
+ g_signal_connect (layer_view->priv->mask_cell, "clicked",
+ G_CALLBACK (gimp_layer_tree_view_mask_clicked),
+ layer_view);
+
+ gimp_dnd_component_dest_add (GTK_WIDGET (tree_view->view),
+ NULL, tree_view);
+ gimp_dnd_viewable_dest_add (GTK_WIDGET (tree_view->view), GIMP_TYPE_CHANNEL,
+ NULL, tree_view);
+ gimp_dnd_viewable_dest_add (GTK_WIDGET (tree_view->view), GIMP_TYPE_LAYER_MASK,
+ NULL, tree_view);
+ gimp_dnd_uri_list_dest_add (GTK_WIDGET (tree_view->view),
+ NULL, tree_view);
+ gimp_dnd_pixbuf_dest_add (GTK_WIDGET (tree_view->view),
+ NULL, tree_view);
+
+ button = gimp_editor_add_action_button (GIMP_EDITOR (layer_view), "layers",
+ "layers-new-group", NULL);
+ gtk_box_reorder_child (gimp_editor_get_button_box (GIMP_EDITOR (layer_view)),
+ button, 1);
+
+ button = gimp_editor_add_action_button (GIMP_EDITOR (layer_view), "layers",
+ "layers-anchor", NULL);
+ layer_view->priv->anchor_button = button;
+ gimp_highlightable_button_set_highlight_color (
+ GIMP_HIGHLIGHTABLE_BUTTON (button),
+ GIMP_HIGHLIGHTABLE_BUTTON_COLOR_AFFIRMATIVE);
+ gimp_container_view_enable_dnd (GIMP_CONTAINER_VIEW (layer_view),
+ GTK_BUTTON (button),
+ GIMP_TYPE_LAYER);
+ gtk_box_reorder_child (gimp_editor_get_button_box (GIMP_EDITOR (layer_view)),
+ button, 5);
+
+ button = gimp_editor_add_action_button (GIMP_EDITOR (layer_view), "layers",
+ "layers-merge-down-button",
+ "layers-merge-group",
+ GDK_SHIFT_MASK,
+ "layers-merge-layers",
+ GDK_CONTROL_MASK,
+ "layers-merge-layers-last-values",
+ GDK_CONTROL_MASK |
+ GDK_SHIFT_MASK,
+ NULL);
+ gimp_container_view_enable_dnd (GIMP_CONTAINER_VIEW (layer_view),
+ GTK_BUTTON (button),
+ GIMP_TYPE_LAYER);
+ gtk_box_reorder_child (gimp_editor_get_button_box (GIMP_EDITOR (layer_view)),
+ button, 6);
+
+ button = gimp_editor_add_action_button (GIMP_EDITOR (layer_view), "layers",
+ "layers-mask-add-button",
+ "layers-mask-add-last-values",
+ gimp_get_extend_selection_mask (),
+ "layers-mask-delete",
+ gimp_get_modify_selection_mask (),
+ "layers-mask-apply",
+ gimp_get_extend_selection_mask () |
+ gimp_get_modify_selection_mask (),
+ NULL);
+ gimp_container_view_enable_dnd (GIMP_CONTAINER_VIEW (layer_view),
+ GTK_BUTTON (button),
+ GIMP_TYPE_LAYER);
+ gtk_box_reorder_child (gimp_editor_get_button_box (GIMP_EDITOR (layer_view)),
+ button, 7);
+}
+
+static void
+gimp_layer_tree_view_finalize (GObject *object)
+{
+ GimpLayerTreeView *layer_view = GIMP_LAYER_TREE_VIEW (object);
+
+ if (layer_view->priv->italic_attrs)
+ {
+ pango_attr_list_unref (layer_view->priv->italic_attrs);
+ layer_view->priv->italic_attrs = NULL;
+ }
+
+ if (layer_view->priv->bold_attrs)
+ {
+ pango_attr_list_unref (layer_view->priv->bold_attrs);
+ layer_view->priv->bold_attrs = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+/* GimpContainerView methods */
+
+static void
+gimp_layer_tree_view_set_container (GimpContainerView *view,
+ GimpContainer *container)
+{
+ GimpLayerTreeView *layer_view = GIMP_LAYER_TREE_VIEW (view);
+ GimpContainer *old_container;
+
+ old_container = gimp_container_view_get_container (view);
+
+ if (old_container)
+ {
+ gimp_tree_handler_disconnect (layer_view->priv->mode_changed_handler);
+ layer_view->priv->mode_changed_handler = NULL;
+
+ gimp_tree_handler_disconnect (layer_view->priv->opacity_changed_handler);
+ layer_view->priv->opacity_changed_handler = NULL;
+
+ gimp_tree_handler_disconnect (layer_view->priv->lock_alpha_changed_handler);
+ layer_view->priv->lock_alpha_changed_handler = NULL;
+
+ gimp_tree_handler_disconnect (layer_view->priv->mask_changed_handler);
+ layer_view->priv->mask_changed_handler = NULL;
+
+ gimp_tree_handler_disconnect (layer_view->priv->alpha_changed_handler);
+ layer_view->priv->alpha_changed_handler = NULL;
+ }
+
+ parent_view_iface->set_container (view, container);
+
+ if (container)
+ {
+ layer_view->priv->mode_changed_handler =
+ gimp_tree_handler_connect (container, "mode-changed",
+ G_CALLBACK (gimp_layer_tree_view_layer_signal_handler),
+ view);
+
+ layer_view->priv->opacity_changed_handler =
+ gimp_tree_handler_connect (container, "opacity-changed",
+ G_CALLBACK (gimp_layer_tree_view_layer_signal_handler),
+ view);
+
+ layer_view->priv->lock_alpha_changed_handler =
+ gimp_tree_handler_connect (container, "lock-alpha-changed",
+ G_CALLBACK (gimp_layer_tree_view_layer_signal_handler),
+ view);
+
+ layer_view->priv->mask_changed_handler =
+ gimp_tree_handler_connect (container, "mask-changed",
+ G_CALLBACK (gimp_layer_tree_view_mask_changed),
+ view);
+
+ layer_view->priv->alpha_changed_handler =
+ gimp_tree_handler_connect (container, "alpha-changed",
+ G_CALLBACK (gimp_layer_tree_view_alpha_changed),
+ view);
+ }
+}
+
+typedef struct
+{
+ gint mask_column;
+ GimpContext *context;
+} SetContextForeachData;
+
+static gboolean
+gimp_layer_tree_view_set_context_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ SetContextForeachData *context_data = data;
+ GimpViewRenderer *renderer;
+
+ gtk_tree_model_get (model, iter,
+ context_data->mask_column, &renderer,
+ -1);
+
+ if (renderer)
+ {
+ gimp_view_renderer_set_context (renderer, context_data->context);
+
+ g_object_unref (renderer);
+ }
+
+ return FALSE;
+}
+
+static void
+gimp_layer_tree_view_set_context (GimpContainerView *view,
+ GimpContext *context)
+{
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
+ GimpLayerTreeView *layer_view = GIMP_LAYER_TREE_VIEW (view);
+
+ parent_view_iface->set_context (view, context);
+
+ if (tree_view->model)
+ {
+ SetContextForeachData context_data = { layer_view->priv->model_column_mask,
+ context };
+
+ gtk_tree_model_foreach (tree_view->model,
+ gimp_layer_tree_view_set_context_foreach,
+ &context_data);
+ }
+}
+
+static gpointer
+gimp_layer_tree_view_insert_item (GimpContainerView *view,
+ GimpViewable *viewable,
+ gpointer parent_insert_data,
+ gint index)
+{
+ GimpLayerTreeView *layer_view = GIMP_LAYER_TREE_VIEW (view);
+ GimpLayer *layer;
+ GtkTreeIter *iter;
+
+ iter = parent_view_iface->insert_item (view, viewable,
+ parent_insert_data, index);
+
+ layer = GIMP_LAYER (viewable);
+
+ if (! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
+ gimp_layer_tree_view_alpha_update (layer_view, iter, layer);
+
+ gimp_layer_tree_view_mask_update (layer_view, iter, layer);
+
+ return iter;
+}
+
+static gboolean
+gimp_layer_tree_view_select_item (GimpContainerView *view,
+ GimpViewable *item,
+ gpointer insert_data)
+{
+ GimpLayerTreeView *layer_view = GIMP_LAYER_TREE_VIEW (view);
+ gboolean success;
+
+ success = parent_view_iface->select_item (view, item, insert_data);
+
+ if (item)
+ {
+ if (success)
+ {
+ gimp_layer_tree_view_update_borders (layer_view,
+ (GtkTreeIter *) insert_data);
+ gimp_layer_tree_view_update_options (layer_view, GIMP_LAYER (item));
+ gimp_layer_tree_view_update_menu (layer_view, GIMP_LAYER (item));
+ }
+ }
+
+ if (! success)
+ {
+ GimpEditor *editor = GIMP_EDITOR (view);
+
+ /* currently, select_item() only ever fails when there is a floating
+ * selection, which can be committed/canceled through the editor buttons.
+ */
+ gimp_widget_blink (GTK_WIDGET (gimp_editor_get_button_box (editor)));
+ }
+
+ return success;
+}
+
+typedef struct
+{
+ gint mask_column;
+ gint view_size;
+ gint border_width;
+} SetSizeForeachData;
+
+static gboolean
+gimp_layer_tree_view_set_view_size_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ SetSizeForeachData *size_data = data;
+ GimpViewRenderer *renderer;
+
+ gtk_tree_model_get (model, iter,
+ size_data->mask_column, &renderer,
+ -1);
+
+ if (renderer)
+ {
+ gimp_view_renderer_set_size (renderer,
+ size_data->view_size,
+ size_data->border_width);
+
+ g_object_unref (renderer);
+ }
+
+ return FALSE;
+}
+
+static void
+gimp_layer_tree_view_set_view_size (GimpContainerView *view)
+{
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
+
+ if (tree_view->model)
+ {
+ GimpLayerTreeView *layer_view = GIMP_LAYER_TREE_VIEW (view);
+ SetSizeForeachData size_data;
+
+ size_data.mask_column = layer_view->priv->model_column_mask;
+
+ size_data.view_size =
+ gimp_container_view_get_view_size (view, &size_data.border_width);
+
+ gtk_tree_model_foreach (tree_view->model,
+ gimp_layer_tree_view_set_view_size_foreach,
+ &size_data);
+ }
+
+ parent_view_iface->set_view_size (view);
+}
+
+
+/* GimpContainerTreeView methods */
+
+static gboolean
+gimp_layer_tree_view_drop_possible (GimpContainerTreeView *tree_view,
+ GimpDndType src_type,
+ GimpViewable *src_viewable,
+ GimpViewable *dest_viewable,
+ GtkTreePath *drop_path,
+ GtkTreeViewDropPosition drop_pos,
+ GtkTreeViewDropPosition *return_drop_pos,
+ GdkDragAction *return_drag_action)
+{
+ /* If we are dropping a new layer, check if the destination image
+ * has a floating selection.
+ */
+ if (src_type == GIMP_DND_TYPE_URI_LIST ||
+ src_type == GIMP_DND_TYPE_TEXT_PLAIN ||
+ src_type == GIMP_DND_TYPE_NETSCAPE_URL ||
+ src_type == GIMP_DND_TYPE_COMPONENT ||
+ src_type == GIMP_DND_TYPE_PIXBUF ||
+ GIMP_IS_DRAWABLE (src_viewable))
+ {
+ GimpImage *dest_image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (tree_view));
+
+ if (gimp_image_get_floating_selection (dest_image))
+ return FALSE;
+ }
+
+ return GIMP_CONTAINER_TREE_VIEW_CLASS (parent_class)->drop_possible (tree_view,
+ src_type,
+ src_viewable,
+ dest_viewable,
+ drop_path,
+ drop_pos,
+ return_drop_pos,
+ return_drag_action);
+}
+
+static void
+gimp_layer_tree_view_drop_color (GimpContainerTreeView *view,
+ const GimpRGB *color,
+ GimpViewable *dest_viewable,
+ GtkTreeViewDropPosition drop_pos)
+{
+ if (gimp_item_is_text_layer (GIMP_ITEM (dest_viewable)))
+ {
+ gimp_text_layer_set (GIMP_TEXT_LAYER (dest_viewable), NULL,
+ "color", color,
+ NULL);
+ gimp_image_flush (gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view)));
+ return;
+ }
+
+ GIMP_CONTAINER_TREE_VIEW_CLASS (parent_class)->drop_color (view, color,
+ dest_viewable,
+ drop_pos);
+}
+
+static void
+gimp_layer_tree_view_drop_uri_list (GimpContainerTreeView *view,
+ GList *uri_list,
+ GimpViewable *dest_viewable,
+ GtkTreeViewDropPosition drop_pos)
+{
+ GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (view);
+ GimpContainerView *cont_view = GIMP_CONTAINER_VIEW (view);
+ GimpImage *image = gimp_item_tree_view_get_image (item_view);
+ GimpLayer *parent;
+ gint index;
+ GList *list;
+
+ index = gimp_item_tree_view_get_drop_index (item_view, dest_viewable,
+ drop_pos,
+ (GimpViewable **) &parent);
+
+ g_object_ref (image);
+
+ for (list = uri_list; list; list = g_list_next (list))
+ {
+ const gchar *uri = list->data;
+ GFile *file = g_file_new_for_uri (uri);
+ GList *new_layers;
+ GimpPDBStatusType status;
+ GError *error = NULL;
+
+ new_layers = file_open_layers (image->gimp,
+ gimp_container_view_get_context (cont_view),
+ NULL,
+ image, FALSE,
+ file, GIMP_RUN_INTERACTIVE, NULL,
+ &status, &error);
+
+ if (new_layers)
+ {
+ gimp_image_add_layers (image, new_layers, parent, index,
+ 0, 0,
+ gimp_image_get_width (image),
+ gimp_image_get_height (image),
+ _("Drop layers"));
+
+ index += g_list_length (new_layers);
+
+ g_list_free (new_layers);
+ }
+ else if (status != GIMP_PDB_CANCEL)
+ {
+ gimp_message (image->gimp, G_OBJECT (view), GIMP_MESSAGE_ERROR,
+ _("Opening '%s' failed:\n\n%s"),
+ gimp_file_get_utf8_name (file), error->message);
+ g_clear_error (&error);
+ }
+
+ g_object_unref (file);
+ }
+
+ gimp_image_flush (image);
+
+ g_object_unref (image);
+}
+
+static void
+gimp_layer_tree_view_drop_component (GimpContainerTreeView *tree_view,
+ GimpImage *src_image,
+ GimpChannelType component,
+ GimpViewable *dest_viewable,
+ GtkTreeViewDropPosition drop_pos)
+{
+ GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (tree_view);
+ GimpImage *image = gimp_item_tree_view_get_image (item_view);
+ GimpChannel *channel;
+ GimpItem *new_item;
+ GimpLayer *parent;
+ gint index;
+ const gchar *desc;
+
+ index = gimp_item_tree_view_get_drop_index (item_view, dest_viewable,
+ drop_pos,
+ (GimpViewable **) &parent);
+
+ channel = gimp_channel_new_from_component (src_image, component, NULL, NULL);
+
+ new_item = gimp_item_convert (GIMP_ITEM (channel), image,
+ GIMP_TYPE_LAYER);
+
+ g_object_unref (channel);
+
+ gimp_enum_get_value (GIMP_TYPE_CHANNEL_TYPE, component,
+ NULL, NULL, &desc, NULL);
+ gimp_object_take_name (GIMP_OBJECT (new_item),
+ g_strdup_printf (_("%s Channel Copy"), desc));
+
+ gimp_image_add_layer (image, GIMP_LAYER (new_item), parent, index, TRUE);
+
+ gimp_image_flush (image);
+}
+
+static void
+gimp_layer_tree_view_drop_pixbuf (GimpContainerTreeView *tree_view,
+ GdkPixbuf *pixbuf,
+ GimpViewable *dest_viewable,
+ GtkTreeViewDropPosition drop_pos)
+{
+ GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (tree_view);
+ GimpImage *image = gimp_item_tree_view_get_image (item_view);
+ GimpLayer *new_layer;
+ GimpLayer *parent;
+ gint index;
+
+ index = gimp_item_tree_view_get_drop_index (item_view, dest_viewable,
+ drop_pos,
+ (GimpViewable **) &parent);
+
+ new_layer =
+ gimp_layer_new_from_pixbuf (pixbuf, image,
+ gimp_image_get_layer_format (image, TRUE),
+ _("Dropped Buffer"),
+ GIMP_OPACITY_OPAQUE,
+ gimp_image_get_default_new_layer_mode (image));
+
+ gimp_image_add_layer (image, new_layer, parent, index, TRUE);
+
+ gimp_image_flush (image);
+}
+
+
+/* GimpItemTreeView methods */
+
+static void
+gimp_layer_tree_view_set_image (GimpItemTreeView *view,
+ GimpImage *image)
+{
+ GimpLayerTreeView *layer_view = GIMP_LAYER_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_layer_tree_view_floating_selection_changed,
+ view);
+ }
+
+ GIMP_ITEM_TREE_VIEW_CLASS (parent_class)->set_image (view, image);
+
+ if (gimp_item_tree_view_get_image (view))
+ {
+ g_signal_connect (gimp_item_tree_view_get_image (view),
+ "floating-selection-changed",
+ G_CALLBACK (gimp_layer_tree_view_floating_selection_changed),
+ view);
+
+ /* call gimp_layer_tree_view_floating_selection_changed() now, to update
+ * the floating selection's row attributes.
+ */
+ gimp_layer_tree_view_floating_selection_changed (
+ gimp_item_tree_view_get_image (view),
+ layer_view);
+ }
+
+ gimp_layer_tree_view_update_highlight (layer_view);
+}
+
+static GimpItem *
+gimp_layer_tree_view_item_new (GimpImage *image)
+{
+ GimpLayer *new_layer;
+
+ gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE,
+ _("New Layer"));
+
+ new_layer = gimp_layer_new (image,
+ gimp_image_get_width (image),
+ gimp_image_get_height (image),
+ gimp_image_get_layer_format (image, TRUE),
+ NULL,
+ GIMP_OPACITY_OPAQUE,
+ gimp_image_get_default_new_layer_mode (image));
+
+ gimp_image_add_layer (image, new_layer,
+ GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
+
+ gimp_image_undo_group_end (image);
+
+ return GIMP_ITEM (new_layer);
+}
+
+
+/* callbacks */
+
+static void
+gimp_layer_tree_view_floating_selection_changed (GimpImage *image,
+ GimpLayerTreeView *layer_view)
+{
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (layer_view);
+ GimpContainerView *view = GIMP_CONTAINER_VIEW (layer_view);
+ GimpLayer *floating_sel;
+ GtkTreeIter *iter;
+
+ floating_sel = gimp_image_get_floating_selection (image);
+
+ if (floating_sel)
+ {
+ iter = gimp_container_view_lookup (view, (GimpViewable *) floating_sel);
+
+ if (iter)
+ gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
+ GIMP_CONTAINER_TREE_STORE_COLUMN_NAME_ATTRIBUTES,
+ layer_view->priv->italic_attrs,
+ -1);
+ }
+ else
+ {
+ GList *all_layers;
+ GList *list;
+
+ all_layers = gimp_image_get_layer_list (image);
+
+ for (list = all_layers; list; list = g_list_next (list))
+ {
+ GimpDrawable *drawable = list->data;
+
+ iter = gimp_container_view_lookup (view, (GimpViewable *) drawable);
+
+ if (iter)
+ gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
+ GIMP_CONTAINER_TREE_STORE_COLUMN_NAME_ATTRIBUTES,
+ gimp_drawable_has_alpha (drawable) ?
+ NULL : layer_view->priv->bold_attrs,
+ -1);
+ }
+
+ g_list_free (all_layers);
+ }
+
+ gimp_layer_tree_view_update_highlight (layer_view);
+}
+
+
+/* Paint Mode, Opacity and Lock alpha callbacks */
+
+#define BLOCK() \
+ g_signal_handlers_block_by_func (layer, \
+ gimp_layer_tree_view_layer_signal_handler, view)
+
+#define UNBLOCK() \
+ g_signal_handlers_unblock_by_func (layer, \
+ gimp_layer_tree_view_layer_signal_handler, view)
+
+
+static void
+gimp_layer_tree_view_layer_mode_box_callback (GtkWidget *widget,
+ const GParamSpec *pspec,
+ GimpLayerTreeView *view)
+{
+ GimpImage *image;
+ GimpLayer *layer = NULL;
+
+ image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view));
+
+ if (image)
+ layer = (GimpLayer *)
+ GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_active_item (image);
+
+ if (layer)
+ {
+ GimpLayerMode mode =
+ gimp_layer_mode_box_get_mode (GIMP_LAYER_MODE_BOX (widget));
+
+ if (gimp_layer_get_mode (layer) != mode)
+ {
+ GimpUndo *undo;
+ gboolean push_undo = TRUE;
+
+ /* compress layer mode undos */
+ undo = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
+ GIMP_UNDO_LAYER_MODE);
+
+ if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layer))
+ push_undo = FALSE;
+
+ BLOCK();
+ gimp_layer_set_mode (layer, (GimpLayerMode) mode, push_undo);
+ UNBLOCK();
+
+ gimp_image_flush (image);
+
+ if (! push_undo)
+ gimp_undo_refresh_preview (undo, gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view)));
+ }
+ }
+}
+
+static void
+gimp_layer_tree_view_lock_alpha_button_toggled (GtkWidget *widget,
+ GimpLayerTreeView *view)
+{
+ GimpImage *image;
+ GimpLayer *layer;
+
+ image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view));
+
+ layer = (GimpLayer *)
+ GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_active_item (image);
+
+ if (layer)
+ {
+ gboolean lock_alpha;
+
+ lock_alpha = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+ if (gimp_layer_get_lock_alpha (layer) != lock_alpha)
+ {
+ GimpUndo *undo;
+ gboolean push_undo = TRUE;
+
+ /* compress lock alpha undos */
+ undo = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
+ GIMP_UNDO_LAYER_LOCK_ALPHA);
+
+ if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layer))
+ push_undo = FALSE;
+
+ BLOCK();
+ gimp_layer_set_lock_alpha (layer, lock_alpha, push_undo);
+ UNBLOCK();
+
+ gimp_image_flush (image);
+ }
+ }
+}
+
+static void
+gimp_layer_tree_view_opacity_scale_changed (GtkAdjustment *adjustment,
+ GimpLayerTreeView *view)
+{
+ GimpImage *image;
+ GimpLayer *layer;
+
+ image = gimp_item_tree_view_get_image (GIMP_ITEM_TREE_VIEW (view));
+
+ layer = (GimpLayer *)
+ GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_active_item (image);
+
+ if (layer)
+ {
+ gdouble opacity = gtk_adjustment_get_value (adjustment) / 100.0;
+
+ if (gimp_layer_get_opacity (layer) != opacity)
+ {
+ GimpUndo *undo;
+ gboolean push_undo = TRUE;
+
+ /* compress opacity undos */
+ undo = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
+ GIMP_UNDO_LAYER_OPACITY);
+
+ if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layer))
+ push_undo = FALSE;
+
+ BLOCK();
+ gimp_layer_set_opacity (layer, opacity, push_undo);
+ UNBLOCK();
+
+ gimp_image_flush (image);
+
+ if (! push_undo)
+ gimp_undo_refresh_preview (undo, gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view)));
+ }
+ }
+}
+
+#undef BLOCK
+#undef UNBLOCK
+
+
+static void
+gimp_layer_tree_view_layer_signal_handler (GimpLayer *layer,
+ GimpLayerTreeView *view)
+{
+ GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (view);
+ GimpLayer *active_layer;
+
+ active_layer = (GimpLayer *)
+ GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_active_item (gimp_item_tree_view_get_image (item_view));
+
+ if (active_layer == layer)
+ gimp_layer_tree_view_update_options (view, layer);
+}
+
+
+#define BLOCK(object,function) \
+ g_signal_handlers_block_by_func ((object), (function), view)
+
+#define UNBLOCK(object,function) \
+ g_signal_handlers_unblock_by_func ((object), (function), view)
+
+static void
+gimp_layer_tree_view_update_options (GimpLayerTreeView *view,
+ GimpLayer *layer)
+{
+ BLOCK (view->priv->layer_mode_box,
+ gimp_layer_tree_view_layer_mode_box_callback);
+
+ if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)) == NULL)
+ {
+ gimp_layer_mode_box_set_context (GIMP_LAYER_MODE_BOX (view->priv->layer_mode_box),
+ GIMP_LAYER_MODE_CONTEXT_LAYER);
+ }
+ else
+ {
+ gimp_layer_mode_box_set_context (GIMP_LAYER_MODE_BOX (view->priv->layer_mode_box),
+ GIMP_LAYER_MODE_CONTEXT_GROUP);
+ }
+
+ gimp_layer_mode_box_set_mode (GIMP_LAYER_MODE_BOX (view->priv->layer_mode_box),
+ gimp_layer_get_mode (layer));
+
+ UNBLOCK (view->priv->layer_mode_box,
+ gimp_layer_tree_view_layer_mode_box_callback);
+
+ if (gimp_layer_get_lock_alpha (layer) !=
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (view->priv->lock_alpha_toggle)))
+ {
+ BLOCK (view->priv->lock_alpha_toggle,
+ gimp_layer_tree_view_lock_alpha_button_toggled);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (view->priv->lock_alpha_toggle),
+ gimp_layer_get_lock_alpha (layer));
+
+ UNBLOCK (view->priv->lock_alpha_toggle,
+ gimp_layer_tree_view_lock_alpha_button_toggled);
+ }
+
+ gtk_widget_set_sensitive (view->priv->lock_alpha_toggle,
+ gimp_layer_can_lock_alpha (layer));
+
+ if (gimp_layer_get_opacity (layer) * 100.0 !=
+ gtk_adjustment_get_value (view->priv->opacity_adjustment))
+ {
+ BLOCK (view->priv->opacity_adjustment,
+ gimp_layer_tree_view_opacity_scale_changed);
+
+ gtk_adjustment_set_value (view->priv->opacity_adjustment,
+ gimp_layer_get_opacity (layer) * 100.0);
+
+ UNBLOCK (view->priv->opacity_adjustment,
+ gimp_layer_tree_view_opacity_scale_changed);
+ }
+}
+
+#undef BLOCK
+#undef UNBLOCK
+
+
+static void
+gimp_layer_tree_view_update_menu (GimpLayerTreeView *layer_view,
+ GimpLayer *layer)
+{
+ GimpUIManager *ui_manager = gimp_editor_get_ui_manager (GIMP_EDITOR (layer_view));
+ GimpActionGroup *group;
+ GimpLayerMask *mask;
+
+ group = gimp_ui_manager_get_action_group (ui_manager, "layers");
+
+ mask = gimp_layer_get_mask (layer);
+
+ gimp_action_group_set_action_active (group, "layers-mask-show",
+ mask &&
+ gimp_layer_get_show_mask (layer));
+ gimp_action_group_set_action_active (group, "layers-mask-disable",
+ mask &&
+ ! gimp_layer_get_apply_mask (layer));
+ gimp_action_group_set_action_active (group, "layers-mask-edit",
+ mask &&
+ gimp_layer_get_edit_mask (layer));
+}
+
+static void
+gimp_layer_tree_view_update_highlight (GimpLayerTreeView *layer_view)
+{
+ GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (layer_view);
+ GimpImage *image = gimp_item_tree_view_get_image (item_view);
+ GimpLayer *floating_sel = NULL;
+
+ if (image)
+ floating_sel = gimp_image_get_floating_selection (image);
+
+ gimp_highlightable_button_set_highlight (
+ GIMP_HIGHLIGHTABLE_BUTTON (gimp_item_tree_view_get_new_button (item_view)),
+ floating_sel != NULL &&
+ ! GIMP_IS_CHANNEL (gimp_layer_get_floating_sel_drawable (floating_sel)));
+
+ gimp_highlightable_button_set_highlight (
+ GIMP_HIGHLIGHTABLE_BUTTON (gimp_item_tree_view_get_delete_button (item_view)),
+ floating_sel != NULL);
+
+ gimp_highlightable_button_set_highlight (
+ GIMP_HIGHLIGHTABLE_BUTTON (layer_view->priv->anchor_button),
+ floating_sel != NULL);
+}
+
+
+/* Layer Mask callbacks */
+
+static void
+gimp_layer_tree_view_mask_update (GimpLayerTreeView *layer_view,
+ GtkTreeIter *iter,
+ GimpLayer *layer)
+{
+ GimpContainerView *view = GIMP_CONTAINER_VIEW (layer_view);
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (layer_view);
+ GimpLayerMask *mask;
+ GimpViewRenderer *renderer = NULL;
+ gboolean mask_visible = FALSE;
+
+ mask = gimp_layer_get_mask (layer);
+
+ if (mask)
+ {
+ GClosure *closure;
+ gint view_size;
+ gint border_width;
+
+ view_size = gimp_container_view_get_view_size (view, &border_width);
+
+ mask_visible = TRUE;
+
+ renderer = gimp_view_renderer_new (gimp_container_view_get_context (view),
+ G_TYPE_FROM_INSTANCE (mask),
+ view_size, border_width,
+ FALSE);
+ gimp_view_renderer_set_viewable (renderer, GIMP_VIEWABLE (mask));
+
+ g_signal_connect (renderer, "update",
+ G_CALLBACK (gimp_layer_tree_view_renderer_update),
+ layer_view);
+
+ closure = g_cclosure_new (G_CALLBACK (gimp_layer_tree_view_mask_callback),
+ layer_view, NULL);
+ g_object_watch_closure (G_OBJECT (renderer), closure);
+ g_signal_connect_closure (layer, "apply-mask-changed", closure, FALSE);
+ g_signal_connect_closure (layer, "edit-mask-changed", closure, FALSE);
+ g_signal_connect_closure (layer, "show-mask-changed", closure, FALSE);
+ }
+
+ gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
+ layer_view->priv->model_column_mask, renderer,
+ layer_view->priv->model_column_mask_visible, mask_visible,
+ -1);
+
+ gimp_layer_tree_view_update_borders (layer_view, iter);
+
+ if (renderer)
+ {
+ gimp_view_renderer_remove_idle (renderer);
+ g_object_unref (renderer);
+ }
+}
+
+static void
+gimp_layer_tree_view_mask_changed (GimpLayer *layer,
+ GimpLayerTreeView *layer_view)
+{
+ GimpContainerView *view = GIMP_CONTAINER_VIEW (layer_view);
+ GtkTreeIter *iter;
+
+ iter = gimp_container_view_lookup (view, GIMP_VIEWABLE (layer));
+
+ if (iter)
+ gimp_layer_tree_view_mask_update (layer_view, iter, layer);
+}
+
+static void
+gimp_layer_tree_view_renderer_update (GimpViewRenderer *renderer,
+ GimpLayerTreeView *layer_view)
+{
+ GimpContainerView *view = GIMP_CONTAINER_VIEW (layer_view);
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (layer_view);
+ GimpLayerMask *mask;
+ GtkTreeIter *iter;
+
+ mask = GIMP_LAYER_MASK (renderer->viewable);
+
+ iter = gimp_container_view_lookup (view, (GimpViewable *)
+ gimp_layer_mask_get_layer (mask));
+
+ if (iter)
+ {
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (tree_view->model, iter);
+
+ gtk_tree_model_row_changed (tree_view->model, path, iter);
+
+ gtk_tree_path_free (path);
+ }
+}
+
+static void
+gimp_layer_tree_view_update_borders (GimpLayerTreeView *layer_view,
+ GtkTreeIter *iter)
+{
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (layer_view);
+ GimpViewRenderer *layer_renderer;
+ GimpViewRenderer *mask_renderer;
+ GimpLayer *layer;
+ GimpLayerMask *mask = NULL;
+ GimpViewBorderType layer_type = GIMP_VIEW_BORDER_BLACK;
+
+ gtk_tree_model_get (tree_view->model, iter,
+ GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &layer_renderer,
+ layer_view->priv->model_column_mask, &mask_renderer,
+ -1);
+
+ layer = GIMP_LAYER (layer_renderer->viewable);
+
+ if (mask_renderer)
+ mask = GIMP_LAYER_MASK (mask_renderer->viewable);
+
+ if (! mask || (mask && ! gimp_layer_get_edit_mask (layer)))
+ layer_type = GIMP_VIEW_BORDER_WHITE;
+
+ gimp_view_renderer_set_border_type (layer_renderer, layer_type);
+
+ if (mask)
+ {
+ GimpViewBorderType mask_color = GIMP_VIEW_BORDER_BLACK;
+
+ if (gimp_layer_get_show_mask (layer))
+ {
+ mask_color = GIMP_VIEW_BORDER_GREEN;
+ }
+ else if (! gimp_layer_get_apply_mask (layer))
+ {
+ mask_color = GIMP_VIEW_BORDER_RED;
+ }
+ else if (gimp_layer_get_edit_mask (layer))
+ {
+ mask_color = GIMP_VIEW_BORDER_WHITE;
+ }
+
+ gimp_view_renderer_set_border_type (mask_renderer, mask_color);
+ }
+
+ if (layer_renderer)
+ g_object_unref (layer_renderer);
+
+ if (mask_renderer)
+ g_object_unref (mask_renderer);
+}
+
+static void
+gimp_layer_tree_view_mask_callback (GimpLayer *layer,
+ GimpLayerTreeView *layer_view)
+{
+ GimpContainerView *view = GIMP_CONTAINER_VIEW (layer_view);
+ GtkTreeIter *iter;
+
+ iter = gimp_container_view_lookup (view, (GimpViewable *) layer);
+
+ gimp_layer_tree_view_update_borders (layer_view, iter);
+}
+
+static void
+gimp_layer_tree_view_layer_clicked (GimpCellRendererViewable *cell,
+ const gchar *path_str,
+ GdkModifierType state,
+ GimpLayerTreeView *layer_view)
+{
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (layer_view);
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter (tree_view->model, &iter, path) &&
+ ! (state & GDK_MOD1_MASK))
+ {
+ GimpUIManager *ui_manager;
+ GimpActionGroup *group;
+ GimpViewRenderer *renderer;
+
+ ui_manager = gimp_editor_get_ui_manager (GIMP_EDITOR (tree_view));
+ group = gimp_ui_manager_get_action_group (ui_manager, "layers");
+
+ gtk_tree_model_get (tree_view->model, &iter,
+ GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
+ -1);
+
+ if (renderer)
+ {
+ GimpLayer *layer = GIMP_LAYER (renderer->viewable);
+ GimpLayerMask *mask = gimp_layer_get_mask (layer);
+
+ if (state & gimp_get_extend_selection_mask ())
+ {
+ if (state & gimp_get_modify_selection_mask ())
+ {
+ /* Shift-Control-click apply a layer mask */
+
+ if (mask)
+ gimp_ui_manager_activate_action (ui_manager, "layers",
+ "layers-mask-apply");
+ }
+ else
+ {
+ /* Shift-click add a layer mask with last values */
+
+ if (! mask)
+ gimp_ui_manager_activate_action (ui_manager, "layers",
+ "layers-mask-add-last-values");
+ }
+ }
+ else if (state & gimp_get_modify_selection_mask ())
+ {
+ /* Control-click remove a layer mask */
+
+ if (mask)
+ gimp_ui_manager_activate_action (ui_manager, "layers",
+ "layers-mask-delete");
+ }
+ else if (mask && gimp_layer_get_edit_mask (layer))
+ {
+ /* other clicks activate the layer */
+
+ if (mask)
+ gimp_action_group_set_action_active (group,
+ "layers-mask-edit", FALSE);
+ }
+
+ g_object_unref (renderer);
+ }
+ }
+
+ gtk_tree_path_free (path);
+}
+
+static void
+gimp_layer_tree_view_mask_clicked (GimpCellRendererViewable *cell,
+ const gchar *path_str,
+ GdkModifierType state,
+ GimpLayerTreeView *layer_view)
+{
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (layer_view);
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = gtk_tree_path_new_from_string (path_str);
+
+ if (gtk_tree_model_get_iter (tree_view->model, &iter, path))
+ {
+ GimpViewRenderer *renderer;
+ GimpUIManager *ui_manager;
+ GimpActionGroup *group;
+
+ ui_manager = gimp_editor_get_ui_manager (GIMP_EDITOR (tree_view));
+ group = gimp_ui_manager_get_action_group (ui_manager, "layers");
+
+ gtk_tree_model_get (tree_view->model, &iter,
+ GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
+ -1);
+
+ if (renderer)
+ {
+ GimpLayer *layer = GIMP_LAYER (renderer->viewable);
+
+ if (state & GDK_MOD1_MASK)
+ gimp_action_group_set_action_active (group, "layers-mask-show",
+ ! gimp_layer_get_show_mask (layer));
+ else if (state & gimp_get_toggle_behavior_mask ())
+ gimp_action_group_set_action_active (group, "layers-mask-disable",
+ gimp_layer_get_apply_mask (layer));
+ else if (! gimp_layer_get_edit_mask (layer))
+ gimp_action_group_set_action_active (group,
+ "layers-mask-edit", TRUE);
+
+ g_object_unref (renderer);
+ }
+ }
+
+ gtk_tree_path_free (path);
+}
+
+
+/* GimpDrawable alpha callbacks */
+
+static void
+gimp_layer_tree_view_alpha_update (GimpLayerTreeView *view,
+ GtkTreeIter *iter,
+ GimpLayer *layer)
+{
+ GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
+
+ gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
+ GIMP_CONTAINER_TREE_STORE_COLUMN_NAME_ATTRIBUTES,
+ gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)) ?
+ NULL : view->priv->bold_attrs,
+ -1);
+}
+
+static void
+gimp_layer_tree_view_alpha_changed (GimpLayer *layer,
+ GimpLayerTreeView *layer_view)
+{
+ GimpContainerView *view = GIMP_CONTAINER_VIEW (layer_view);
+ GtkTreeIter *iter;
+
+ iter = gimp_container_view_lookup (view, (GimpViewable *) layer);
+
+ if (iter)
+ {
+ GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (view);
+
+ gimp_layer_tree_view_alpha_update (layer_view, iter, layer);
+
+ /* update button states */
+ if (gimp_image_get_active_layer (gimp_item_tree_view_get_image (item_view)) == layer)
+ gimp_container_view_select_item (GIMP_CONTAINER_VIEW (view),
+ GIMP_VIEWABLE (layer));
+ }
+}