/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pikachanneltreeview.c * Copyright (C) 2001-2009 Michael Natterer * * 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 "libpikabase/pikabase.h" #include "libpikacolor/pikacolor.h" #include "libpikawidgets/pikawidgets.h" #include "widgets-types.h" #include "core/pikachannel.h" #include "core/pikacontainer.h" #include "core/pikaimage.h" #include "core/pikaimage-undo.h" #include "core/pikalayer.h" #include "core/pikalayermask.h" #include "pikaactiongroup.h" #include "pikachanneltreeview.h" #include "pikacomponenteditor.h" #include "pikacontainerview.h" #include "pikadnd.h" #include "pikadocked.h" #include "pikahelp-ids.h" #include "pikauimanager.h" #include "pikawidgets-utils.h" #include "pika-intl.h" struct _PikaChannelTreeViewPrivate { GtkWidget *component_editor; GtkWidget *toselection_button; }; static void pika_channel_tree_view_view_iface_init (PikaContainerViewInterface *iface); static void pika_channel_tree_view_constructed (GObject *object); static void pika_channel_tree_view_drop_viewables (PikaContainerTreeView *view, GList *src_viewables, PikaViewable *dest_viewable, GtkTreeViewDropPosition drop_pos); static void pika_channel_tree_view_drop_component (PikaContainerTreeView *tree_view, PikaImage *image, PikaChannelType component, PikaViewable *dest_viewable, GtkTreeViewDropPosition drop_pos); static void pika_channel_tree_view_set_image (PikaItemTreeView *item_view, PikaImage *image); static PikaItem * pika_channel_tree_view_item_new (PikaImage *image); static void pika_channel_tree_view_set_context (PikaContainerView *view, PikaContext *context); static void pika_channel_tree_view_set_view_size (PikaContainerView *view); G_DEFINE_TYPE_WITH_CODE (PikaChannelTreeView, pika_channel_tree_view, PIKA_TYPE_DRAWABLE_TREE_VIEW, G_ADD_PRIVATE (PikaChannelTreeView) G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONTAINER_VIEW, pika_channel_tree_view_view_iface_init)) #define parent_class pika_channel_tree_view_parent_class static PikaContainerViewInterface *parent_view_iface = NULL; static void pika_channel_tree_view_class_init (PikaChannelTreeViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); PikaContainerTreeViewClass *view_class = PIKA_CONTAINER_TREE_VIEW_CLASS (klass); PikaItemTreeViewClass *iv_class = PIKA_ITEM_TREE_VIEW_CLASS (klass); object_class->constructed = pika_channel_tree_view_constructed; view_class->drop_viewables = pika_channel_tree_view_drop_viewables; view_class->drop_component = pika_channel_tree_view_drop_component; iv_class->set_image = pika_channel_tree_view_set_image; iv_class->item_type = PIKA_TYPE_CHANNEL; iv_class->signal_name = "selected-channels-changed"; iv_class->get_container = pika_image_get_channels; iv_class->get_selected_items = (PikaGetItemsFunc) pika_image_get_selected_channels; iv_class->set_selected_items = (PikaSetItemsFunc) pika_image_set_selected_channels; iv_class->add_item = (PikaAddItemFunc) pika_image_add_channel; iv_class->remove_item = (PikaRemoveItemFunc) pika_image_remove_channel; iv_class->new_item = pika_channel_tree_view_item_new; iv_class->action_group = "channels"; iv_class->activate_action = "channels-edit-attributes"; iv_class->new_action = "channels-new"; iv_class->new_default_action = "channels-new-last-values"; iv_class->raise_action = "channels-raise"; iv_class->raise_top_action = "channels-raise-to-top"; iv_class->lower_action = "channels-lower"; iv_class->lower_bottom_action = "channels-lower-to-bottom"; iv_class->duplicate_action = "channels-duplicate"; iv_class->delete_action = "channels-delete"; iv_class->lock_content_help_id = PIKA_HELP_CHANNEL_LOCK_PIXELS; iv_class->lock_position_help_id = PIKA_HELP_CHANNEL_LOCK_POSITION; } static void pika_channel_tree_view_view_iface_init (PikaContainerViewInterface *view_iface) { parent_view_iface = g_type_interface_peek_parent (view_iface); view_iface->set_context = pika_channel_tree_view_set_context; view_iface->set_view_size = pika_channel_tree_view_set_view_size; } static void pika_channel_tree_view_init (PikaChannelTreeView *view) { view->priv = pika_channel_tree_view_get_instance_private (view); view->priv->component_editor = NULL; view->priv->toselection_button = NULL; } static void pika_channel_tree_view_constructed (GObject *object) { PikaChannelTreeView *view = PIKA_CHANNEL_TREE_VIEW (object); PikaContainerTreeView *tree_view = PIKA_CONTAINER_TREE_VIEW (object); GdkModifierType extend_mask; GdkModifierType modify_mask; G_OBJECT_CLASS (parent_class)->constructed (object); extend_mask = gtk_widget_get_modifier_mask (GTK_WIDGET (object), GDK_MODIFIER_INTENT_EXTEND_SELECTION); modify_mask = gtk_widget_get_modifier_mask (GTK_WIDGET (object), GDK_MODIFIER_INTENT_MODIFY_SELECTION); pika_dnd_viewable_dest_add (GTK_WIDGET (tree_view->view), PIKA_TYPE_LAYER, NULL, tree_view); pika_dnd_viewable_dest_add (GTK_WIDGET (tree_view->view), PIKA_TYPE_LAYER_MASK, NULL, tree_view); pika_dnd_component_dest_add (GTK_WIDGET (tree_view->view), NULL, tree_view); view->priv->toselection_button = pika_editor_add_action_button (PIKA_EDITOR (view), "channels", "channels-selection-replace", "channels-selection-add", extend_mask, "channels-selection-subtract", modify_mask, "channels-selection-intersect", extend_mask | modify_mask, NULL); pika_container_view_enable_dnd (PIKA_CONTAINER_VIEW (view), GTK_BUTTON (view->priv->toselection_button), PIKA_TYPE_CHANNEL); gtk_box_reorder_child (pika_editor_get_button_box (PIKA_EDITOR (view)), view->priv->toselection_button, 4); } /* PikaContainerTreeView methods */ static void pika_channel_tree_view_drop_viewables (PikaContainerTreeView *tree_view, GList *src_viewables, PikaViewable *dest_viewable, GtkTreeViewDropPosition drop_pos) { PikaItemTreeView *item_view = PIKA_ITEM_TREE_VIEW (tree_view); PikaImage *image = pika_item_tree_view_get_image (item_view); PikaItemTreeViewClass *item_view_class; GList *iter; item_view_class = PIKA_ITEM_TREE_VIEW_GET_CLASS (item_view); for (iter = src_viewables; iter; iter = iter->next) { PikaViewable *src_viewable = iter->data; if (PIKA_IS_DRAWABLE (src_viewable) && (image != pika_item_get_image (PIKA_ITEM (src_viewable)) || G_TYPE_FROM_INSTANCE (src_viewable) != item_view_class->item_type)) { PikaItem *new_item; PikaItem *parent; gint index; index = pika_item_tree_view_get_drop_index (item_view, dest_viewable, drop_pos, (PikaViewable **) &parent); new_item = pika_item_convert (PIKA_ITEM (src_viewable), pika_item_tree_view_get_image (item_view), item_view_class->item_type); item_view_class->add_item (image, new_item, parent, index, TRUE); pika_image_flush (image); return; } } PIKA_CONTAINER_TREE_VIEW_CLASS (parent_class)->drop_viewables (tree_view, src_viewables, dest_viewable, drop_pos); } static void pika_channel_tree_view_drop_component (PikaContainerTreeView *tree_view, PikaImage *src_image, PikaChannelType component, PikaViewable *dest_viewable, GtkTreeViewDropPosition drop_pos) { PikaItemTreeView *item_view = PIKA_ITEM_TREE_VIEW (tree_view); PikaImage *image = pika_item_tree_view_get_image (item_view); PikaItem *new_item; PikaChannel *parent; gint index; const gchar *desc; gchar *name; index = pika_item_tree_view_get_drop_index (item_view, dest_viewable, drop_pos, (PikaViewable **) &parent); pika_enum_get_value (PIKA_TYPE_CHANNEL_TYPE, component, NULL, NULL, &desc, NULL); name = g_strdup_printf (_("%s Channel Copy"), desc); new_item = PIKA_ITEM (pika_channel_new_from_component (src_image, component, name, NULL)); /* copied components are invisible by default so subsequent copies * of components don't affect each other */ pika_item_set_visible (new_item, FALSE, FALSE); g_free (name); if (src_image != image) PIKA_ITEM_GET_CLASS (new_item)->convert (new_item, image, PIKA_TYPE_CHANNEL); pika_image_add_channel (image, PIKA_CHANNEL (new_item), parent, index, TRUE); pika_image_flush (image); } /* PikaItemTreeView methods */ static void pika_channel_tree_view_set_image (PikaItemTreeView *item_view, PikaImage *image) { PikaChannelTreeView *channel_view = PIKA_CHANNEL_TREE_VIEW (item_view); if (! channel_view->priv->component_editor) { PikaContainerView *view = PIKA_CONTAINER_VIEW (item_view); gint view_size; view_size = pika_container_view_get_view_size (view, NULL); channel_view->priv->component_editor = pika_component_editor_new (view_size, pika_editor_get_menu_factory (PIKA_EDITOR (item_view))); pika_docked_set_context (PIKA_DOCKED (channel_view->priv->component_editor), pika_container_view_get_context (view)); gtk_box_pack_start (GTK_BOX (item_view), channel_view->priv->component_editor, FALSE, FALSE, 0); gtk_box_reorder_child (GTK_BOX (item_view), channel_view->priv->component_editor, 0); } if (! image) gtk_widget_hide (channel_view->priv->component_editor); pika_image_editor_set_image (PIKA_IMAGE_EDITOR (channel_view->priv->component_editor), image); PIKA_ITEM_TREE_VIEW_CLASS (parent_class)->set_image (item_view, image); if (pika_item_tree_view_get_image (item_view)) gtk_widget_show (channel_view->priv->component_editor); } static PikaItem * pika_channel_tree_view_item_new (PikaImage *image) { PikaChannel *new_channel; PikaRGB color; pika_rgba_set (&color, 0.0, 0.0, 0.0, 0.5); pika_image_undo_group_start (image, PIKA_UNDO_GROUP_EDIT_PASTE, _("New Channel")); new_channel = pika_channel_new (image, pika_image_get_width (image), pika_image_get_height (image), _("Channel"), &color); pika_image_add_channel (image, new_channel, PIKA_IMAGE_ACTIVE_PARENT, -1, TRUE); pika_image_undo_group_end (image); return PIKA_ITEM (new_channel); } /* PikaContainerView methods */ static void pika_channel_tree_view_set_context (PikaContainerView *view, PikaContext *context) { PikaChannelTreeView *channel_view = PIKA_CHANNEL_TREE_VIEW (view); parent_view_iface->set_context (view, context); if (channel_view->priv->component_editor) pika_docked_set_context (PIKA_DOCKED (channel_view->priv->component_editor), context); } static void pika_channel_tree_view_set_view_size (PikaContainerView *view) { PikaChannelTreeView *channel_view = PIKA_CHANNEL_TREE_VIEW (view); gint view_size; parent_view_iface->set_view_size (view); view_size = pika_container_view_get_view_size (view, NULL); if (channel_view->priv->component_editor) pika_component_editor_set_view_size (PIKA_COMPONENT_EDITOR (channel_view->priv->component_editor), view_size); }