1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpchanneltreeview.c
5  * Copyright (C) 2001-2009 Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <gegl.h>
24 #include <gtk/gtk.h>
25 
26 #include "libgimpbase/gimpbase.h"
27 #include "libgimpcolor/gimpcolor.h"
28 #include "libgimpwidgets/gimpwidgets.h"
29 
30 #include "widgets-types.h"
31 
32 #include "core/gimpchannel.h"
33 #include "core/gimpcontainer.h"
34 #include "core/gimpimage.h"
35 #include "core/gimpimage-undo.h"
36 #include "core/gimplayer.h"
37 #include "core/gimplayermask.h"
38 
39 #include "gimpactiongroup.h"
40 #include "gimpchanneltreeview.h"
41 #include "gimpcomponenteditor.h"
42 #include "gimpcontainerview.h"
43 #include "gimpdnd.h"
44 #include "gimpdocked.h"
45 #include "gimphelp-ids.h"
46 #include "gimpuimanager.h"
47 #include "gimpwidgets-utils.h"
48 
49 #include "gimp-intl.h"
50 
51 
52 struct _GimpChannelTreeViewPrivate
53 {
54   GtkWidget *component_editor;
55 
56   GtkWidget *toselection_button;
57 };
58 
59 
60 static void  gimp_channel_tree_view_view_iface_init   (GimpContainerViewInterface *iface);
61 
62 static void   gimp_channel_tree_view_constructed      (GObject                 *object);
63 
64 static void   gimp_channel_tree_view_drop_viewable    (GimpContainerTreeView   *view,
65                                                        GimpViewable            *src_viewable,
66                                                        GimpViewable            *dest_viewable,
67                                                        GtkTreeViewDropPosition  drop_pos);
68 static void   gimp_channel_tree_view_drop_component   (GimpContainerTreeView   *tree_view,
69                                                        GimpImage               *image,
70                                                        GimpChannelType          component,
71                                                        GimpViewable            *dest_viewable,
72                                                        GtkTreeViewDropPosition  drop_pos);
73 static void   gimp_channel_tree_view_set_image        (GimpItemTreeView        *item_view,
74                                                        GimpImage               *image);
75 static GimpItem * gimp_channel_tree_view_item_new     (GimpImage               *image);
76 
77 static void   gimp_channel_tree_view_set_context      (GimpContainerView       *view,
78                                                        GimpContext             *context);
79 static void   gimp_channel_tree_view_set_view_size    (GimpContainerView       *view);
80 
81 
82 G_DEFINE_TYPE_WITH_CODE (GimpChannelTreeView, gimp_channel_tree_view,
83                          GIMP_TYPE_DRAWABLE_TREE_VIEW,
84                          G_ADD_PRIVATE (GimpChannelTreeView)
85                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONTAINER_VIEW,
86                                                 gimp_channel_tree_view_view_iface_init))
87 
88 #define parent_class gimp_channel_tree_view_parent_class
89 
90 static GimpContainerViewInterface *parent_view_iface = NULL;
91 
92 
93 static void
gimp_channel_tree_view_class_init(GimpChannelTreeViewClass * klass)94 gimp_channel_tree_view_class_init (GimpChannelTreeViewClass *klass)
95 {
96   GObjectClass               *object_class = G_OBJECT_CLASS (klass);
97   GimpContainerTreeViewClass *view_class   = GIMP_CONTAINER_TREE_VIEW_CLASS (klass);
98   GimpItemTreeViewClass      *iv_class     = GIMP_ITEM_TREE_VIEW_CLASS (klass);
99 
100   object_class->constructed  = gimp_channel_tree_view_constructed;
101 
102   view_class->drop_viewable  = gimp_channel_tree_view_drop_viewable;
103   view_class->drop_component = gimp_channel_tree_view_drop_component;
104 
105   iv_class->set_image        = gimp_channel_tree_view_set_image;
106 
107   iv_class->item_type        = GIMP_TYPE_CHANNEL;
108   iv_class->signal_name      = "active-channel-changed";
109 
110   iv_class->get_container    = gimp_image_get_channels;
111   iv_class->get_active_item  = (GimpGetItemFunc) gimp_image_get_active_channel;
112   iv_class->set_active_item  = (GimpSetItemFunc) gimp_image_set_active_channel;
113   iv_class->add_item         = (GimpAddItemFunc) gimp_image_add_channel;
114   iv_class->remove_item      = (GimpRemoveItemFunc) gimp_image_remove_channel;
115   iv_class->new_item         = gimp_channel_tree_view_item_new;
116 
117   iv_class->action_group          = "channels";
118   iv_class->activate_action       = "channels-edit-attributes";
119   iv_class->new_action            = "channels-new";
120   iv_class->new_default_action    = "channels-new-last-values";
121   iv_class->raise_action          = "channels-raise";
122   iv_class->raise_top_action      = "channels-raise-to-top";
123   iv_class->lower_action          = "channels-lower";
124   iv_class->lower_bottom_action   = "channels-lower-to-bottom";
125   iv_class->duplicate_action      = "channels-duplicate";
126   iv_class->delete_action         = "channels-delete";
127   iv_class->lock_content_help_id  = GIMP_HELP_CHANNEL_LOCK_PIXELS;
128   iv_class->lock_position_help_id = GIMP_HELP_CHANNEL_LOCK_POSITION;
129 }
130 
131 static void
gimp_channel_tree_view_view_iface_init(GimpContainerViewInterface * view_iface)132 gimp_channel_tree_view_view_iface_init (GimpContainerViewInterface *view_iface)
133 {
134   parent_view_iface = g_type_interface_peek_parent (view_iface);
135 
136   view_iface->set_context   = gimp_channel_tree_view_set_context;
137   view_iface->set_view_size = gimp_channel_tree_view_set_view_size;
138 }
139 
140 static void
gimp_channel_tree_view_init(GimpChannelTreeView * view)141 gimp_channel_tree_view_init (GimpChannelTreeView *view)
142 {
143   view->priv = gimp_channel_tree_view_get_instance_private (view);
144 
145   view->priv->component_editor   = NULL;
146   view->priv->toselection_button = NULL;
147 }
148 
149 static void
gimp_channel_tree_view_constructed(GObject * object)150 gimp_channel_tree_view_constructed (GObject *object)
151 {
152   GimpChannelTreeView   *view      = GIMP_CHANNEL_TREE_VIEW (object);
153   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (object);
154   GdkModifierType        extend_mask;
155   GdkModifierType        modify_mask;
156 
157   G_OBJECT_CLASS (parent_class)->constructed (object);
158 
159   extend_mask = gtk_widget_get_modifier_mask (GTK_WIDGET (object),
160                                               GDK_MODIFIER_INTENT_EXTEND_SELECTION);
161   modify_mask = gtk_widget_get_modifier_mask (GTK_WIDGET (object),
162                                               GDK_MODIFIER_INTENT_MODIFY_SELECTION);
163 
164   gimp_dnd_viewable_dest_add  (GTK_WIDGET (tree_view->view), GIMP_TYPE_LAYER,
165                                NULL, tree_view);
166   gimp_dnd_viewable_dest_add  (GTK_WIDGET (tree_view->view), GIMP_TYPE_LAYER_MASK,
167                                NULL, tree_view);
168   gimp_dnd_component_dest_add (GTK_WIDGET (tree_view->view),
169                                NULL, tree_view);
170 
171   view->priv->toselection_button =
172     gimp_editor_add_action_button (GIMP_EDITOR (view), "channels",
173                                    "channels-selection-replace",
174                                    "channels-selection-add",
175                                    extend_mask,
176                                    "channels-selection-subtract",
177                                    modify_mask,
178                                    "channels-selection-intersect",
179                                    extend_mask | modify_mask,
180                                    NULL);
181   gimp_container_view_enable_dnd (GIMP_CONTAINER_VIEW (view),
182                                   GTK_BUTTON (view->priv->toselection_button),
183                                   GIMP_TYPE_CHANNEL);
184   gtk_box_reorder_child (gimp_editor_get_button_box (GIMP_EDITOR (view)),
185                          view->priv->toselection_button, 4);
186 }
187 
188 
189 /*  GimpContainerTreeView methods  */
190 
191 static void
gimp_channel_tree_view_drop_viewable(GimpContainerTreeView * tree_view,GimpViewable * src_viewable,GimpViewable * dest_viewable,GtkTreeViewDropPosition drop_pos)192 gimp_channel_tree_view_drop_viewable (GimpContainerTreeView   *tree_view,
193                                       GimpViewable            *src_viewable,
194                                       GimpViewable            *dest_viewable,
195                                       GtkTreeViewDropPosition  drop_pos)
196 {
197   GimpItemTreeView      *item_view = GIMP_ITEM_TREE_VIEW (tree_view);
198   GimpImage             *image     = gimp_item_tree_view_get_image (item_view);
199   GimpItemTreeViewClass *item_view_class;
200 
201   item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (item_view);
202 
203   if (GIMP_IS_DRAWABLE (src_viewable) &&
204       (image != gimp_item_get_image (GIMP_ITEM (src_viewable)) ||
205        G_TYPE_FROM_INSTANCE (src_viewable) != item_view_class->item_type))
206     {
207       GimpItem *new_item;
208       GimpItem *parent;
209       gint      index;
210 
211       index = gimp_item_tree_view_get_drop_index (item_view, dest_viewable,
212                                                   drop_pos,
213                                                   (GimpViewable **) &parent);
214 
215       new_item = gimp_item_convert (GIMP_ITEM (src_viewable),
216                                     gimp_item_tree_view_get_image (item_view),
217                                     item_view_class->item_type);
218 
219       gimp_item_set_linked (new_item, FALSE, FALSE);
220 
221       item_view_class->add_item (image, new_item, parent, index, TRUE);
222 
223       gimp_image_flush (image);
224 
225       return;
226     }
227 
228   GIMP_CONTAINER_TREE_VIEW_CLASS (parent_class)->drop_viewable (tree_view,
229                                                                 src_viewable,
230                                                                 dest_viewable,
231                                                                 drop_pos);
232 }
233 
234 static void
gimp_channel_tree_view_drop_component(GimpContainerTreeView * tree_view,GimpImage * src_image,GimpChannelType component,GimpViewable * dest_viewable,GtkTreeViewDropPosition drop_pos)235 gimp_channel_tree_view_drop_component (GimpContainerTreeView   *tree_view,
236                                        GimpImage               *src_image,
237                                        GimpChannelType          component,
238                                        GimpViewable            *dest_viewable,
239                                        GtkTreeViewDropPosition  drop_pos)
240 {
241   GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (tree_view);
242   GimpImage        *image     = gimp_item_tree_view_get_image (item_view);
243   GimpItem         *new_item;
244   GimpChannel      *parent;
245   gint              index;
246   const gchar      *desc;
247   gchar            *name;
248 
249   index = gimp_item_tree_view_get_drop_index (item_view, dest_viewable,
250                                               drop_pos,
251                                               (GimpViewable **) &parent);
252 
253   gimp_enum_get_value (GIMP_TYPE_CHANNEL_TYPE, component,
254                        NULL, NULL, &desc, NULL);
255   name = g_strdup_printf (_("%s Channel Copy"), desc);
256 
257   new_item = GIMP_ITEM (gimp_channel_new_from_component (src_image, component,
258                                                          name, NULL));
259 
260   /*  copied components are invisible by default so subsequent copies
261    *  of components don't affect each other
262    */
263   gimp_item_set_visible (new_item, FALSE, FALSE);
264 
265   g_free (name);
266 
267   if (src_image != image)
268     GIMP_ITEM_GET_CLASS (new_item)->convert (new_item, image,
269                                              GIMP_TYPE_CHANNEL);
270 
271   gimp_image_add_channel (image, GIMP_CHANNEL (new_item), parent, index, TRUE);
272 
273   gimp_image_flush (image);
274 }
275 
276 
277 /*  GimpItemTreeView methods  */
278 
279 static void
gimp_channel_tree_view_set_image(GimpItemTreeView * item_view,GimpImage * image)280 gimp_channel_tree_view_set_image (GimpItemTreeView *item_view,
281                                   GimpImage        *image)
282 {
283   GimpChannelTreeView *channel_view = GIMP_CHANNEL_TREE_VIEW (item_view);
284 
285   if (! channel_view->priv->component_editor)
286     {
287       GimpContainerView *view = GIMP_CONTAINER_VIEW (item_view);
288       gint               view_size;
289 
290       view_size = gimp_container_view_get_view_size (view, NULL);
291 
292       channel_view->priv->component_editor =
293         gimp_component_editor_new (view_size,
294                                    gimp_editor_get_menu_factory (GIMP_EDITOR (item_view)));
295       gimp_docked_set_context (GIMP_DOCKED (channel_view->priv->component_editor),
296                                gimp_container_view_get_context (view));
297       gtk_box_pack_start (GTK_BOX (item_view), channel_view->priv->component_editor,
298                           FALSE, FALSE, 0);
299       gtk_box_reorder_child (GTK_BOX (item_view),
300                              channel_view->priv->component_editor, 0);
301     }
302 
303   if (! image)
304     gtk_widget_hide (channel_view->priv->component_editor);
305 
306   gimp_image_editor_set_image (GIMP_IMAGE_EDITOR (channel_view->priv->component_editor),
307                                image);
308 
309   GIMP_ITEM_TREE_VIEW_CLASS (parent_class)->set_image (item_view, image);
310 
311   if (gimp_item_tree_view_get_image (item_view))
312     gtk_widget_show (channel_view->priv->component_editor);
313 }
314 
315 static GimpItem *
gimp_channel_tree_view_item_new(GimpImage * image)316 gimp_channel_tree_view_item_new (GimpImage *image)
317 {
318   GimpChannel *new_channel;
319   GimpRGB      color;
320 
321   gimp_rgba_set (&color, 0.0, 0.0, 0.0, 0.5);
322 
323   gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE,
324                                _("New Channel"));
325 
326   new_channel = gimp_channel_new (image,
327                                   gimp_image_get_width (image),
328                                   gimp_image_get_height (image),
329                                   _("Channel"), &color);
330 
331   gimp_image_add_channel (image, new_channel,
332                           GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
333 
334   gimp_image_undo_group_end (image);
335 
336   return GIMP_ITEM (new_channel);
337 }
338 
339 
340 /*  GimpContainerView methods  */
341 
342 static void
gimp_channel_tree_view_set_context(GimpContainerView * view,GimpContext * context)343 gimp_channel_tree_view_set_context (GimpContainerView *view,
344                                     GimpContext       *context)
345 {
346   GimpChannelTreeView *channel_view = GIMP_CHANNEL_TREE_VIEW (view);
347 
348   parent_view_iface->set_context (view, context);
349 
350   if (channel_view->priv->component_editor)
351     gimp_docked_set_context (GIMP_DOCKED (channel_view->priv->component_editor),
352                              context);
353 }
354 
355 static void
gimp_channel_tree_view_set_view_size(GimpContainerView * view)356 gimp_channel_tree_view_set_view_size (GimpContainerView *view)
357 {
358   GimpChannelTreeView *channel_view = GIMP_CHANNEL_TREE_VIEW (view);
359   gint                 view_size;
360 
361   parent_view_iface->set_view_size (view);
362 
363   view_size = gimp_container_view_get_view_size (view, NULL);
364 
365   if (channel_view->priv->component_editor)
366     gimp_component_editor_set_view_size (GIMP_COMPONENT_EDITOR (channel_view->priv->component_editor),
367                                          view_size);
368 }
369