diff options
Diffstat (limited to '')
-rw-r--r-- | app/widgets/gimplayertreeview.c | 1555 |
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)); + } +} |