1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpitemtreeview.c
5  * Copyright (C) 2001-2011 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 <string.h>
24 
25 #include <gegl.h>
26 #include <gtk/gtk.h>
27 
28 #include "libgimpmath/gimpmath.h"
29 #include "libgimpwidgets/gimpwidgets.h"
30 
31 #include "widgets-types.h"
32 
33 #include "core/gimp.h"
34 #include "core/gimpchannel.h"
35 #include "core/gimpcontainer.h"
36 #include "core/gimpcontext.h"
37 #include "core/gimpimage.h"
38 #include "core/gimpimage-undo.h"
39 #include "core/gimpimage-undo-push.h"
40 #include "core/gimpitem-exclusive.h"
41 #include "core/gimpitemundo.h"
42 #include "core/gimpmarshal.h"
43 #include "core/gimptreehandler.h"
44 #include "core/gimpundostack.h"
45 
46 #include "vectors/gimpvectors.h"
47 
48 #include "gimpaction.h"
49 #include "gimpcontainertreestore.h"
50 #include "gimpcontainerview.h"
51 #include "gimpdnd.h"
52 #include "gimpdocked.h"
53 #include "gimpitemtreeview.h"
54 #include "gimpmenufactory.h"
55 #include "gimpviewrenderer.h"
56 #include "gimpuimanager.h"
57 #include "gimpwidgets-utils.h"
58 
59 #include "gimp-intl.h"
60 
61 
62 enum
63 {
64   SET_IMAGE,
65   LAST_SIGNAL
66 };
67 
68 
69 struct _GimpItemTreeViewPrivate
70 {
71   GimpImage       *image;
72 
73   GtkWidget       *options_box;
74   GtkSizeGroup    *options_group;
75   GtkWidget       *lock_box;
76 
77   GtkWidget       *lock_content_toggle;
78   GtkWidget       *lock_position_toggle;
79 
80   GtkWidget       *new_button;
81   GtkWidget       *raise_button;
82   GtkWidget       *lower_button;
83   GtkWidget       *duplicate_button;
84   GtkWidget       *delete_button;
85 
86   gint             model_column_visible;
87   gint             model_column_viewable;
88   gint             model_column_linked;
89   gint             model_column_color_tag;
90   GtkCellRenderer *eye_cell;
91   GtkCellRenderer *chain_cell;
92 
93   GimpTreeHandler *visible_changed_handler;
94   GimpTreeHandler *linked_changed_handler;
95   GimpTreeHandler *color_tag_changed_handler;
96   GimpTreeHandler *lock_content_changed_handler;
97   GimpTreeHandler *lock_position_changed_handler;
98 };
99 
100 
101 static void   gimp_item_tree_view_view_iface_init   (GimpContainerViewInterface *view_iface);
102 static void   gimp_item_tree_view_docked_iface_init (GimpDockedInterface *docked_iface);
103 
104 static void   gimp_item_tree_view_constructed       (GObject           *object);
105 static void   gimp_item_tree_view_dispose           (GObject           *object);
106 
107 static void   gimp_item_tree_view_style_set         (GtkWidget         *widget,
108                                                      GtkStyle          *prev_style);
109 
110 static void   gimp_item_tree_view_real_set_image    (GimpItemTreeView  *view,
111                                                      GimpImage         *image);
112 
113 static void   gimp_item_tree_view_image_flush       (GimpImage         *image,
114                                                      gboolean           invalidate_preview,
115                                                      GimpItemTreeView  *view);
116 
117 static void   gimp_item_tree_view_set_container     (GimpContainerView *view,
118                                                      GimpContainer     *container);
119 static void   gimp_item_tree_view_set_context       (GimpContainerView *view,
120                                                      GimpContext       *context);
121 
122 static gpointer gimp_item_tree_view_insert_item     (GimpContainerView *view,
123                                                      GimpViewable      *viewable,
124                                                      gpointer           parent_insert_data,
125                                                      gint               index);
126 static void   gimp_item_tree_view_insert_item_after (GimpContainerView *view,
127                                                      GimpViewable      *viewable,
128                                                      gpointer           insert_data);
129 static gboolean gimp_item_tree_view_select_item     (GimpContainerView *view,
130                                                      GimpViewable      *item,
131                                                      gpointer           insert_data);
132 static void   gimp_item_tree_view_activate_item     (GimpContainerView *view,
133                                                      GimpViewable      *item,
134                                                      gpointer           insert_data);
135 static void   gimp_item_tree_view_context_item      (GimpContainerView *view,
136                                                      GimpViewable      *item,
137                                                      gpointer           insert_data);
138 
139 static gboolean gimp_item_tree_view_drop_possible   (GimpContainerTreeView *view,
140                                                      GimpDndType        src_type,
141                                                      GimpViewable      *src_viewable,
142                                                      GimpViewable      *dest_viewable,
143                                                      GtkTreePath       *drop_path,
144                                                      GtkTreeViewDropPosition  drop_pos,
145                                                      GtkTreeViewDropPosition *return_drop_pos,
146                                                      GdkDragAction     *return_drag_action);
147 static void     gimp_item_tree_view_drop_viewable   (GimpContainerTreeView *view,
148                                                      GimpViewable      *src_viewable,
149                                                      GimpViewable      *dest_viewable,
150                                                      GtkTreeViewDropPosition  drop_pos);
151 
152 static void   gimp_item_tree_view_new_dropped       (GtkWidget         *widget,
153                                                      gint               x,
154                                                      gint               y,
155                                                      GimpViewable      *viewable,
156                                                      gpointer           data);
157 
158 static void   gimp_item_tree_view_item_changed      (GimpImage         *image,
159                                                      GimpItemTreeView  *view);
160 static void   gimp_item_tree_view_size_changed      (GimpImage         *image,
161                                                      GimpItemTreeView  *view);
162 
163 static void   gimp_item_tree_view_name_edited       (GtkCellRendererText *cell,
164                                                      const gchar       *path,
165                                                      const gchar       *new_name,
166                                                      GimpItemTreeView  *view);
167 
168 static void   gimp_item_tree_view_visible_changed      (GimpItem          *item,
169                                                         GimpItemTreeView  *view);
170 static void   gimp_item_tree_view_linked_changed       (GimpItem          *item,
171                                                         GimpItemTreeView  *view);
172 static void   gimp_item_tree_view_color_tag_changed    (GimpItem          *item,
173                                                         GimpItemTreeView  *view);
174 static void   gimp_item_tree_view_lock_content_changed (GimpItem          *item,
175                                                         GimpItemTreeView  *view);
176 static void   gimp_item_tree_view_lock_position_changed(GimpItem          *item,
177                                                         GimpItemTreeView  *view);
178 
179 static void   gimp_item_tree_view_eye_clicked       (GtkCellRendererToggle *toggle,
180                                                      gchar             *path,
181                                                      GdkModifierType    state,
182                                                      GimpItemTreeView  *view);
183 static void   gimp_item_tree_view_chain_clicked     (GtkCellRendererToggle *toggle,
184                                                      gchar             *path,
185                                                      GdkModifierType    state,
186                                                      GimpItemTreeView  *view);
187 static void   gimp_item_tree_view_lock_content_toggled
188                                                     (GtkWidget         *widget,
189                                                      GimpItemTreeView  *view);
190 static void   gimp_item_tree_view_lock_position_toggled
191                                                     (GtkWidget         *widget,
192                                                      GimpItemTreeView  *view);
193 static void   gimp_item_tree_view_update_options    (GimpItemTreeView  *view,
194                                                      GimpItem          *item);
195 
196 static gboolean gimp_item_tree_view_item_pre_clicked(GimpCellRendererViewable *cell,
197                                                      const gchar              *path_str,
198                                                      GdkModifierType           state,
199                                                      GimpItemTreeView         *item_view);
200 
201 /*  utility function to avoid code duplication  */
202 static void   gimp_item_tree_view_toggle_clicked    (GtkCellRendererToggle *toggle,
203                                                      gchar             *path_str,
204                                                      GdkModifierType    state,
205                                                      GimpItemTreeView  *view,
206                                                      GimpUndoType       undo_type);
207 
208 static void   gimp_item_tree_view_row_expanded      (GtkTreeView       *tree_view,
209                                                      GtkTreeIter       *iter,
210                                                      GtkTreePath       *path,
211                                                      GimpItemTreeView  *item_view);
212 
213 
214 G_DEFINE_TYPE_WITH_CODE (GimpItemTreeView, gimp_item_tree_view,
215                          GIMP_TYPE_CONTAINER_TREE_VIEW,
216                          G_ADD_PRIVATE (GimpItemTreeView)
217                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONTAINER_VIEW,
218                                                 gimp_item_tree_view_view_iface_init)
219                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
220                                                 gimp_item_tree_view_docked_iface_init))
221 
222 #define parent_class gimp_item_tree_view_parent_class
223 
224 static GimpContainerViewInterface *parent_view_iface = NULL;
225 
226 static guint view_signals[LAST_SIGNAL] = { 0 };
227 
228 
229 static void
gimp_item_tree_view_class_init(GimpItemTreeViewClass * klass)230 gimp_item_tree_view_class_init (GimpItemTreeViewClass *klass)
231 {
232   GObjectClass               *object_class = G_OBJECT_CLASS (klass);
233   GtkWidgetClass             *widget_class = GTK_WIDGET_CLASS (klass);
234   GimpContainerTreeViewClass *tree_view_class;
235 
236   tree_view_class = GIMP_CONTAINER_TREE_VIEW_CLASS (klass);
237 
238   view_signals[SET_IMAGE] =
239     g_signal_new ("set-image",
240                   G_TYPE_FROM_CLASS (klass),
241                   G_SIGNAL_RUN_LAST,
242                   G_STRUCT_OFFSET (GimpItemTreeViewClass, set_image),
243                   NULL, NULL,
244                   gimp_marshal_VOID__OBJECT,
245                   G_TYPE_NONE, 1,
246                   GIMP_TYPE_OBJECT);
247 
248   object_class->constructed      = gimp_item_tree_view_constructed;
249   object_class->dispose          = gimp_item_tree_view_dispose;
250 
251   widget_class->style_set        = gimp_item_tree_view_style_set;
252 
253   tree_view_class->drop_possible = gimp_item_tree_view_drop_possible;
254   tree_view_class->drop_viewable = gimp_item_tree_view_drop_viewable;
255 
256   klass->set_image               = gimp_item_tree_view_real_set_image;
257 
258   klass->item_type               = G_TYPE_NONE;
259   klass->signal_name             = NULL;
260 
261   klass->get_container           = NULL;
262   klass->get_active_item         = NULL;
263   klass->set_active_item         = NULL;
264   klass->add_item                = NULL;
265   klass->remove_item             = NULL;
266   klass->new_item                = NULL;
267 
268   klass->action_group            = NULL;
269   klass->new_action              = NULL;
270   klass->new_default_action      = NULL;
271   klass->raise_action            = NULL;
272   klass->raise_top_action        = NULL;
273   klass->lower_action            = NULL;
274   klass->lower_bottom_action     = NULL;
275   klass->duplicate_action        = NULL;
276   klass->delete_action           = NULL;
277 
278   klass->lock_content_icon_name  = NULL;
279   klass->lock_content_tooltip    = NULL;
280   klass->lock_content_help_id    = NULL;
281 
282   klass->lock_position_icon_name  = NULL;
283   klass->lock_position_tooltip    = NULL;
284   klass->lock_position_help_id    = NULL;
285 }
286 
287 static void
gimp_item_tree_view_view_iface_init(GimpContainerViewInterface * iface)288 gimp_item_tree_view_view_iface_init (GimpContainerViewInterface *iface)
289 {
290   parent_view_iface = g_type_interface_peek_parent (iface);
291 
292   iface->set_container     = gimp_item_tree_view_set_container;
293   iface->set_context       = gimp_item_tree_view_set_context;
294   iface->insert_item       = gimp_item_tree_view_insert_item;
295   iface->insert_item_after = gimp_item_tree_view_insert_item_after;
296   iface->select_item       = gimp_item_tree_view_select_item;
297   iface->activate_item     = gimp_item_tree_view_activate_item;
298   iface->context_item      = gimp_item_tree_view_context_item;
299 }
300 
301 static void
gimp_item_tree_view_docked_iface_init(GimpDockedInterface * iface)302 gimp_item_tree_view_docked_iface_init (GimpDockedInterface *iface)
303 {
304   iface->get_preview = NULL;
305 }
306 
307 static void
gimp_item_tree_view_init(GimpItemTreeView * view)308 gimp_item_tree_view_init (GimpItemTreeView *view)
309 {
310   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
311 
312   view->priv = gimp_item_tree_view_get_instance_private (view);
313 
314   view->priv->model_column_visible =
315     gimp_container_tree_store_columns_add (tree_view->model_columns,
316                                            &tree_view->n_model_columns,
317                                            G_TYPE_BOOLEAN);
318 
319   view->priv->model_column_viewable =
320     gimp_container_tree_store_columns_add (tree_view->model_columns,
321                                            &tree_view->n_model_columns,
322                                            G_TYPE_BOOLEAN);
323 
324   view->priv->model_column_linked =
325     gimp_container_tree_store_columns_add (tree_view->model_columns,
326                                            &tree_view->n_model_columns,
327                                            G_TYPE_BOOLEAN);
328 
329   view->priv->model_column_color_tag =
330     gimp_container_tree_store_columns_add (tree_view->model_columns,
331                                            &tree_view->n_model_columns,
332                                            GDK_TYPE_COLOR);
333 
334   gimp_container_tree_view_set_dnd_drop_to_empty (tree_view, TRUE);
335 
336   view->priv->image  = NULL;
337 }
338 
339 static void
gimp_item_tree_view_constructed(GObject * object)340 gimp_item_tree_view_constructed (GObject *object)
341 {
342   GimpItemTreeViewClass *item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (object);
343   GimpEditor            *editor          = GIMP_EDITOR (object);
344   GimpContainerTreeView *tree_view       = GIMP_CONTAINER_TREE_VIEW (object);
345   GimpItemTreeView      *item_view       = GIMP_ITEM_TREE_VIEW (object);
346   GtkTreeViewColumn     *column;
347   GtkWidget             *hbox;
348   GtkWidget             *image;
349   GtkIconSize            icon_size;
350 
351   G_OBJECT_CLASS (parent_class)->constructed (object);
352 
353   gimp_container_tree_view_connect_name_edited (tree_view,
354                                                 G_CALLBACK (gimp_item_tree_view_name_edited),
355                                                 item_view);
356 
357   g_signal_connect (tree_view->view, "row-expanded",
358                     G_CALLBACK (gimp_item_tree_view_row_expanded),
359                     tree_view);
360 
361   g_signal_connect (tree_view->renderer_cell, "pre-clicked",
362                     G_CALLBACK (gimp_item_tree_view_item_pre_clicked),
363                     item_view);
364 
365   column = gtk_tree_view_column_new ();
366   gtk_tree_view_insert_column (tree_view->view, column, 0);
367 
368   item_view->priv->eye_cell = gimp_cell_renderer_toggle_new (GIMP_ICON_VISIBLE);
369   g_object_set (item_view->priv->eye_cell,
370                 "xpad",                0,
371                 "ypad",                0,
372                 "override-background", TRUE,
373                 NULL);
374   gtk_tree_view_column_pack_start (column, item_view->priv->eye_cell, FALSE);
375   gtk_tree_view_column_set_attributes (column, item_view->priv->eye_cell,
376                                        "active",
377                                        item_view->priv->model_column_visible,
378                                        "inconsistent",
379                                        item_view->priv->model_column_viewable,
380                                        "cell-background-gdk",
381                                        item_view->priv->model_column_color_tag,
382                                        NULL);
383 
384   gimp_container_tree_view_add_toggle_cell (tree_view,
385                                             item_view->priv->eye_cell);
386 
387   g_signal_connect (item_view->priv->eye_cell, "clicked",
388                     G_CALLBACK (gimp_item_tree_view_eye_clicked),
389                     item_view);
390 
391   column = gtk_tree_view_column_new ();
392   gtk_tree_view_insert_column (tree_view->view, column, 1);
393 
394   item_view->priv->chain_cell = gimp_cell_renderer_toggle_new (GIMP_ICON_LINKED);
395   g_object_set (item_view->priv->chain_cell,
396                 "xpad", 0,
397                 "ypad", 0,
398                 NULL);
399   gtk_tree_view_column_pack_start (column, item_view->priv->chain_cell, FALSE);
400   gtk_tree_view_column_set_attributes (column, item_view->priv->chain_cell,
401                                        "active",
402                                        item_view->priv->model_column_linked,
403                                        NULL);
404 
405   gimp_container_tree_view_add_toggle_cell (tree_view,
406                                             item_view->priv->chain_cell);
407 
408   g_signal_connect (item_view->priv->chain_cell, "clicked",
409                     G_CALLBACK (gimp_item_tree_view_chain_clicked),
410                     item_view);
411 
412   /*  disable the default GimpContainerView drop handler  */
413   gimp_container_view_set_dnd_widget (GIMP_CONTAINER_VIEW (item_view), NULL);
414 
415   gimp_dnd_drag_dest_set_by_type (GTK_WIDGET (tree_view->view),
416                                   GTK_DEST_DEFAULT_HIGHLIGHT,
417                                   item_view_class->item_type,
418                                   GDK_ACTION_MOVE | GDK_ACTION_COPY);
419 
420   item_view->priv->new_button =
421     gimp_editor_add_action_button (editor, item_view_class->action_group,
422                                    item_view_class->new_action,
423                                    item_view_class->new_default_action,
424                                    GDK_SHIFT_MASK,
425                                    NULL);
426   /*  connect "drop to new" manually as it makes a difference whether
427    *  it was clicked or dropped
428    */
429   gimp_dnd_viewable_dest_add (item_view->priv->new_button,
430                               item_view_class->item_type,
431                               gimp_item_tree_view_new_dropped,
432                               item_view);
433 
434   item_view->priv->raise_button =
435     gimp_editor_add_action_button (editor, item_view_class->action_group,
436                                    item_view_class->raise_action,
437                                    item_view_class->raise_top_action,
438                                    GDK_SHIFT_MASK,
439                                    NULL);
440 
441   item_view->priv->lower_button =
442     gimp_editor_add_action_button (editor, item_view_class->action_group,
443                                    item_view_class->lower_action,
444                                    item_view_class->lower_bottom_action,
445                                    GDK_SHIFT_MASK,
446                                    NULL);
447 
448   item_view->priv->duplicate_button =
449     gimp_editor_add_action_button (editor, item_view_class->action_group,
450                                    item_view_class->duplicate_action, NULL);
451   gimp_container_view_enable_dnd (GIMP_CONTAINER_VIEW (item_view),
452                                   GTK_BUTTON (item_view->priv->duplicate_button),
453                                   item_view_class->item_type);
454 
455   item_view->priv->delete_button =
456     gimp_editor_add_action_button (editor, item_view_class->action_group,
457                                    item_view_class->delete_action, NULL);
458   gimp_container_view_enable_dnd (GIMP_CONTAINER_VIEW (item_view),
459                                   GTK_BUTTON (item_view->priv->delete_button),
460                                   item_view_class->item_type);
461 
462   hbox = gimp_item_tree_view_get_lock_box (item_view);
463 
464   /*  Lock content toggle  */
465   item_view->priv->lock_content_toggle = gtk_toggle_button_new ();
466   gtk_box_pack_start (GTK_BOX (hbox), item_view->priv->lock_content_toggle,
467                       FALSE, FALSE, 0);
468   gtk_box_reorder_child (GTK_BOX (hbox),
469                          item_view->priv->lock_content_toggle, 0);
470   gtk_widget_show (item_view->priv->lock_content_toggle);
471 
472   g_signal_connect (item_view->priv->lock_content_toggle, "toggled",
473                     G_CALLBACK (gimp_item_tree_view_lock_content_toggled),
474                     item_view);
475 
476   gimp_help_set_help_data (item_view->priv->lock_content_toggle,
477                            item_view_class->lock_content_tooltip,
478                            item_view_class->lock_content_help_id);
479 
480   gtk_widget_style_get (GTK_WIDGET (item_view),
481                         "button-icon-size", &icon_size,
482                         NULL);
483 
484   image = gtk_image_new_from_icon_name (item_view_class->lock_content_icon_name,
485                                         icon_size);
486   gtk_container_add (GTK_CONTAINER (item_view->priv->lock_content_toggle),
487                      image);
488   gtk_widget_show (image);
489 
490   /*  Lock position toggle  */
491   item_view->priv->lock_position_toggle = gtk_toggle_button_new ();
492   gtk_box_pack_start (GTK_BOX (hbox), item_view->priv->lock_position_toggle,
493                       FALSE, FALSE, 0);
494   gtk_box_reorder_child (GTK_BOX (hbox),
495                          item_view->priv->lock_position_toggle, 1);
496   gtk_widget_show (item_view->priv->lock_position_toggle);
497 
498   g_signal_connect (item_view->priv->lock_position_toggle, "toggled",
499                     G_CALLBACK (gimp_item_tree_view_lock_position_toggled),
500                     item_view);
501 
502   gimp_help_set_help_data (item_view->priv->lock_position_toggle,
503                            item_view_class->lock_position_tooltip,
504                            item_view_class->lock_position_help_id);
505 
506   image = gtk_image_new_from_icon_name (item_view_class->lock_position_icon_name,
507                                         icon_size);
508   gtk_container_add (GTK_CONTAINER (item_view->priv->lock_position_toggle),
509                      image);
510   gtk_widget_show (image);
511 }
512 
513 static void
gimp_item_tree_view_dispose(GObject * object)514 gimp_item_tree_view_dispose (GObject *object)
515 {
516   GimpItemTreeView *view = GIMP_ITEM_TREE_VIEW (object);
517 
518   if (view->priv->image)
519     gimp_item_tree_view_set_image (view, NULL);
520 
521   G_OBJECT_CLASS (parent_class)->dispose (object);
522 }
523 
524 static void
gimp_item_tree_view_style_set(GtkWidget * widget,GtkStyle * prev_style)525 gimp_item_tree_view_style_set (GtkWidget *widget,
526                                GtkStyle  *prev_style)
527 {
528   GimpItemTreeView *view = GIMP_ITEM_TREE_VIEW (widget);
529   GList            *children;
530   GList            *list;
531   GtkReliefStyle    button_relief;
532   GtkIconSize       button_icon_size;
533   gint              content_spacing;
534   gint              button_spacing;
535 
536   gtk_widget_style_get (widget,
537                         "button-relief",    &button_relief,
538                         "button-icon-size", &button_icon_size,
539                         "content-spacing",  &content_spacing,
540                         "button-spacing",   &button_spacing,
541                         NULL);
542 
543   if (view->priv->options_box)
544     {
545       gtk_box_set_spacing (GTK_BOX (view->priv->options_box), content_spacing);
546 
547       children =
548         gtk_container_get_children (GTK_CONTAINER (view->priv->options_box));
549 
550       for (list = children; list; list = g_list_next (list))
551         {
552           GtkWidget *child = list->data;
553 
554           if (GTK_IS_BOX (child))
555             gtk_box_set_spacing (GTK_BOX (child), button_spacing);
556         }
557 
558       g_list_free (children);
559     }
560 
561   if (view->priv->lock_box)
562     {
563       gtk_box_set_spacing (GTK_BOX (view->priv->lock_box), button_spacing);
564 
565       children =
566         gtk_container_get_children (GTK_CONTAINER (view->priv->lock_box));
567 
568       for (list = children; list; list = g_list_next (list))
569         {
570           GtkWidget *child = list->data;
571 
572           if (GTK_IS_BUTTON (child))
573             {
574               GtkWidget *image;
575 
576               gtk_button_set_relief (GTK_BUTTON (child), button_relief);
577 
578               image = gtk_bin_get_child (GTK_BIN (child));
579 
580               if (GTK_IS_IMAGE (image))
581                 {
582                   GtkIconSize  old_size;
583                   const gchar *icon_name;
584 
585                   gtk_image_get_icon_name (GTK_IMAGE (image),
586                                            &icon_name, &old_size);
587 
588                   if (button_icon_size != old_size)
589                     gtk_image_set_from_icon_name (GTK_IMAGE (image),
590                                                   icon_name, button_icon_size);
591                 }
592             }
593         }
594 
595       g_list_free (children);
596     }
597 
598   /* force the toggle cells to recreate their icon */
599   g_object_set (view->priv->eye_cell,
600                 "icon-name", GIMP_ICON_VISIBLE,
601                 NULL);
602   g_object_set (view->priv->chain_cell,
603                 "icon-name", GIMP_ICON_LINKED,
604                 NULL);
605 
606   GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
607 }
608 
609 GtkWidget *
gimp_item_tree_view_new(GType view_type,gint view_size,gint view_border_width,GimpImage * image,GimpMenuFactory * menu_factory,const gchar * menu_identifier,const gchar * ui_path)610 gimp_item_tree_view_new (GType            view_type,
611                          gint             view_size,
612                          gint             view_border_width,
613                          GimpImage       *image,
614                          GimpMenuFactory *menu_factory,
615                          const gchar     *menu_identifier,
616                          const gchar     *ui_path)
617 {
618   GimpItemTreeView *item_view;
619 
620   g_return_val_if_fail (g_type_is_a (view_type, GIMP_TYPE_ITEM_TREE_VIEW), NULL);
621   g_return_val_if_fail (view_size >  0 &&
622                         view_size <= GIMP_VIEWABLE_MAX_PREVIEW_SIZE, NULL);
623   g_return_val_if_fail (view_border_width >= 0 &&
624                         view_border_width <= GIMP_VIEW_MAX_BORDER_WIDTH,
625                         NULL);
626   g_return_val_if_fail (image == NULL || GIMP_IS_IMAGE (image), NULL);
627   g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
628   g_return_val_if_fail (menu_identifier != NULL, NULL);
629   g_return_val_if_fail (ui_path != NULL, NULL);
630 
631   item_view = g_object_new (view_type,
632                             "reorderable",     TRUE,
633                             "menu-factory",    menu_factory,
634                             "menu-identifier", menu_identifier,
635                             "ui-path",         ui_path,
636                             NULL);
637 
638   gimp_container_view_set_view_size (GIMP_CONTAINER_VIEW (item_view),
639                                      view_size, view_border_width);
640 
641   gimp_item_tree_view_set_image (item_view, image);
642 
643   return GTK_WIDGET (item_view);
644 }
645 
646 void
gimp_item_tree_view_set_image(GimpItemTreeView * view,GimpImage * image)647 gimp_item_tree_view_set_image (GimpItemTreeView *view,
648                                GimpImage        *image)
649 {
650   g_return_if_fail (GIMP_IS_ITEM_TREE_VIEW (view));
651   g_return_if_fail (image == NULL || GIMP_IS_IMAGE (image));
652 
653   g_signal_emit (view, view_signals[SET_IMAGE], 0, image);
654 
655   gimp_ui_manager_update (gimp_editor_get_ui_manager (GIMP_EDITOR (view)), view);
656 }
657 
658 GimpImage *
gimp_item_tree_view_get_image(GimpItemTreeView * view)659 gimp_item_tree_view_get_image (GimpItemTreeView *view)
660 {
661   g_return_val_if_fail (GIMP_IS_ITEM_TREE_VIEW (view), NULL);
662 
663   return view->priv->image;
664 }
665 
666 void
gimp_item_tree_view_add_options(GimpItemTreeView * view,const gchar * label,GtkWidget * options)667 gimp_item_tree_view_add_options (GimpItemTreeView *view,
668                                  const gchar      *label,
669                                  GtkWidget        *options)
670 {
671   gint content_spacing;
672   gint button_spacing;
673 
674   g_return_if_fail (GIMP_IS_ITEM_TREE_VIEW (view));
675   g_return_if_fail (GTK_IS_WIDGET (options));
676 
677   gtk_widget_style_get (GTK_WIDGET (view),
678                         "content-spacing", &content_spacing,
679                         "button-spacing",  &button_spacing,
680                         NULL);
681 
682   if (! view->priv->options_box)
683     {
684       GimpItemTreeViewClass *item_view_class;
685 
686       item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (view);
687 
688       view->priv->options_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, content_spacing);
689       gtk_box_pack_start (GTK_BOX (view), view->priv->options_box,
690                           FALSE, FALSE, 0);
691       gtk_box_reorder_child (GTK_BOX (view), view->priv->options_box, 0);
692       gtk_widget_show (view->priv->options_box);
693 
694       if (! view->priv->image ||
695           ! item_view_class->get_active_item (view->priv->image))
696         {
697           gtk_widget_set_sensitive (view->priv->options_box, FALSE);
698         }
699     }
700 
701   if (label)
702     {
703       GtkWidget *hbox;
704       GtkWidget *label_widget;
705       gboolean   group_created = FALSE;
706 
707       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, button_spacing);
708       gtk_box_pack_start (GTK_BOX (view->priv->options_box), hbox,
709                           FALSE, FALSE, 0);
710       gtk_widget_show (hbox);
711 
712       if (! view->priv->options_group)
713         {
714           view->priv->options_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
715           group_created = TRUE;
716         }
717 
718       label_widget = gtk_label_new (label);
719       gtk_label_set_xalign (GTK_LABEL (label_widget), 0.0);
720       gtk_size_group_add_widget (view->priv->options_group, label_widget);
721       gtk_box_pack_start (GTK_BOX (hbox), label_widget, FALSE, FALSE, 0);
722       gtk_widget_show (label_widget);
723 
724       if (group_created)
725         g_object_unref (view->priv->options_group);
726 
727       gtk_box_pack_start (GTK_BOX (hbox), options, TRUE, TRUE, 0);
728       gtk_widget_show (options);
729     }
730   else
731     {
732       gtk_box_pack_start (GTK_BOX (view->priv->options_box), options,
733                           FALSE, FALSE, 0);
734       gtk_widget_show (options);
735     }
736 }
737 
738 GtkWidget *
gimp_item_tree_view_get_lock_box(GimpItemTreeView * view)739 gimp_item_tree_view_get_lock_box (GimpItemTreeView *view)
740 {
741   g_return_val_if_fail (GIMP_IS_ITEM_TREE_VIEW (view), NULL);
742 
743   if (! view->priv->lock_box)
744     {
745       gint button_spacing;
746 
747       gtk_widget_style_get (GTK_WIDGET (view),
748                             "button-spacing", &button_spacing,
749                             NULL);
750 
751       view->priv->lock_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, button_spacing);
752 
753       gimp_item_tree_view_add_options (view, _("Lock:"), view->priv->lock_box);
754 
755       gtk_box_set_child_packing (GTK_BOX (view->priv->options_box),
756                                  gtk_widget_get_parent (view->priv->lock_box),
757                                  FALSE, FALSE, 0, GTK_PACK_END);
758     }
759 
760   return view->priv->lock_box;
761 }
762 
763 GtkWidget *
gimp_item_tree_view_get_new_button(GimpItemTreeView * view)764 gimp_item_tree_view_get_new_button (GimpItemTreeView *view)
765 {
766   g_return_val_if_fail (GIMP_IS_ITEM_TREE_VIEW (view), NULL);
767 
768   return view->priv->new_button;
769 }
770 
771 GtkWidget *
gimp_item_tree_view_get_delete_button(GimpItemTreeView * view)772 gimp_item_tree_view_get_delete_button (GimpItemTreeView *view)
773 {
774   g_return_val_if_fail (GIMP_IS_ITEM_TREE_VIEW (view), NULL);
775 
776   return view->priv->delete_button;
777 }
778 
779 gint
gimp_item_tree_view_get_drop_index(GimpItemTreeView * view,GimpViewable * dest_viewable,GtkTreeViewDropPosition drop_pos,GimpViewable ** parent)780 gimp_item_tree_view_get_drop_index (GimpItemTreeView         *view,
781                                     GimpViewable             *dest_viewable,
782                                     GtkTreeViewDropPosition   drop_pos,
783                                     GimpViewable            **parent)
784 {
785   gint index = -1;
786 
787   g_return_val_if_fail (GIMP_IS_ITEM_TREE_VIEW (view), -1);
788   g_return_val_if_fail (dest_viewable == NULL ||
789                         GIMP_IS_VIEWABLE (dest_viewable), -1);
790   g_return_val_if_fail (parent != NULL, -1);
791 
792   *parent = NULL;
793 
794   if (dest_viewable)
795     {
796       *parent = gimp_viewable_get_parent (dest_viewable);
797       index   = gimp_item_get_index (GIMP_ITEM (dest_viewable));
798 
799       if (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
800         {
801           GimpContainer *children = gimp_viewable_get_children (dest_viewable);
802 
803           if (children)
804             {
805               *parent = dest_viewable;
806               index   = 0;
807             }
808           else
809             {
810               index++;
811             }
812         }
813       else if (drop_pos == GTK_TREE_VIEW_DROP_AFTER)
814         {
815           index++;
816         }
817     }
818 
819   return index;
820 }
821 
822 static void
gimp_item_tree_view_real_set_image(GimpItemTreeView * view,GimpImage * image)823 gimp_item_tree_view_real_set_image (GimpItemTreeView *view,
824                                     GimpImage        *image)
825 {
826   if (view->priv->image == image)
827     return;
828 
829   if (view->priv->image)
830     {
831       g_signal_handlers_disconnect_by_func (view->priv->image,
832                                             gimp_item_tree_view_item_changed,
833                                             view);
834       g_signal_handlers_disconnect_by_func (view->priv->image,
835                                             gimp_item_tree_view_size_changed,
836                                             view);
837 
838       gimp_container_view_set_container (GIMP_CONTAINER_VIEW (view), NULL);
839 
840       g_signal_handlers_disconnect_by_func (view->priv->image,
841                                             gimp_item_tree_view_image_flush,
842                                             view);
843     }
844 
845   view->priv->image = image;
846 
847   if (view->priv->image)
848     {
849       GimpContainer *container;
850 
851       container =
852         GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_container (view->priv->image);
853 
854       gimp_container_view_set_container (GIMP_CONTAINER_VIEW (view), container);
855 
856       g_signal_connect (view->priv->image,
857                         GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->signal_name,
858                         G_CALLBACK (gimp_item_tree_view_item_changed),
859                         view);
860       g_signal_connect (view->priv->image, "size-changed",
861                         G_CALLBACK (gimp_item_tree_view_size_changed),
862                         view);
863 
864       g_signal_connect (view->priv->image, "flush",
865                         G_CALLBACK (gimp_item_tree_view_image_flush),
866                         view);
867 
868       gimp_item_tree_view_item_changed (view->priv->image, view);
869     }
870 }
871 
872 static void
gimp_item_tree_view_image_flush(GimpImage * image,gboolean invalidate_preview,GimpItemTreeView * view)873 gimp_item_tree_view_image_flush (GimpImage        *image,
874                                  gboolean          invalidate_preview,
875                                  GimpItemTreeView *view)
876 {
877   gimp_ui_manager_update (gimp_editor_get_ui_manager (GIMP_EDITOR (view)), view);
878 }
879 
880 
881 /*  GimpContainerView methods  */
882 
883 static void
gimp_item_tree_view_set_container(GimpContainerView * view,GimpContainer * container)884 gimp_item_tree_view_set_container (GimpContainerView *view,
885                                    GimpContainer     *container)
886 {
887   GimpItemTreeView *item_view = GIMP_ITEM_TREE_VIEW (view);
888   GimpContainer    *old_container;
889 
890   old_container = gimp_container_view_get_container (view);
891 
892   if (old_container)
893     {
894       gimp_tree_handler_disconnect (item_view->priv->visible_changed_handler);
895       item_view->priv->visible_changed_handler = NULL;
896 
897       gimp_tree_handler_disconnect (item_view->priv->linked_changed_handler);
898       item_view->priv->linked_changed_handler = NULL;
899 
900       gimp_tree_handler_disconnect (item_view->priv->color_tag_changed_handler);
901       item_view->priv->color_tag_changed_handler = NULL;
902 
903       gimp_tree_handler_disconnect (item_view->priv->lock_content_changed_handler);
904       item_view->priv->lock_content_changed_handler = NULL;
905 
906       gimp_tree_handler_disconnect (item_view->priv->lock_position_changed_handler);
907       item_view->priv->lock_position_changed_handler = NULL;
908     }
909 
910   parent_view_iface->set_container (view, container);
911 
912   if (container)
913     {
914       item_view->priv->visible_changed_handler =
915         gimp_tree_handler_connect (container, "visibility-changed",
916                                    G_CALLBACK (gimp_item_tree_view_visible_changed),
917                                    view);
918 
919       item_view->priv->linked_changed_handler =
920         gimp_tree_handler_connect (container, "linked-changed",
921                                    G_CALLBACK (gimp_item_tree_view_linked_changed),
922                                    view);
923 
924       item_view->priv->color_tag_changed_handler =
925         gimp_tree_handler_connect (container, "color-tag-changed",
926                                    G_CALLBACK (gimp_item_tree_view_color_tag_changed),
927                                    view);
928 
929       item_view->priv->lock_content_changed_handler =
930         gimp_tree_handler_connect (container, "lock-content-changed",
931                                    G_CALLBACK (gimp_item_tree_view_lock_content_changed),
932                                    view);
933 
934       item_view->priv->lock_position_changed_handler =
935         gimp_tree_handler_connect (container, "lock-position-changed",
936                                    G_CALLBACK (gimp_item_tree_view_lock_position_changed),
937                                    view);
938     }
939 }
940 
941 static void
gimp_item_tree_view_set_context(GimpContainerView * view,GimpContext * context)942 gimp_item_tree_view_set_context (GimpContainerView *view,
943                                  GimpContext       *context)
944 {
945   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
946   GimpItemTreeView      *item_view = GIMP_ITEM_TREE_VIEW (view);
947   GimpImage             *image     = NULL;
948   GimpContext           *old_context;
949 
950   old_context = gimp_container_view_get_context (view);
951 
952   if (old_context)
953     {
954       g_signal_handlers_disconnect_by_func (old_context,
955                                             gimp_item_tree_view_set_image,
956                                             item_view);
957     }
958 
959   parent_view_iface->set_context (view, context);
960 
961   if (context)
962     {
963       if (! tree_view->dnd_gimp)
964         tree_view->dnd_gimp = context->gimp;
965 
966       g_signal_connect_swapped (context, "image-changed",
967                                 G_CALLBACK (gimp_item_tree_view_set_image),
968                                 item_view);
969 
970       image = gimp_context_get_image (context);
971     }
972 
973   gimp_item_tree_view_set_image (item_view, image);
974 }
975 
976 static gpointer
gimp_item_tree_view_insert_item(GimpContainerView * view,GimpViewable * viewable,gpointer parent_insert_data,gint index)977 gimp_item_tree_view_insert_item (GimpContainerView *view,
978                                  GimpViewable      *viewable,
979                                  gpointer           parent_insert_data,
980                                  gint               index)
981 {
982   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
983   GimpItemTreeView      *item_view = GIMP_ITEM_TREE_VIEW (view);
984   GimpItem              *item      = GIMP_ITEM (viewable);
985   GtkTreeIter           *iter;
986   GimpRGB                color;
987   GdkColor               gdk_color;
988   gboolean               has_color;
989 
990   iter = parent_view_iface->insert_item (view, viewable,
991                                          parent_insert_data, index);
992 
993   has_color = gimp_get_color_tag_color (gimp_item_get_merged_color_tag (item),
994                                         &color,
995                                         gimp_item_get_color_tag (item) ==
996                                         GIMP_COLOR_TAG_NONE);
997   if (has_color)
998     gimp_rgb_get_gdk_color (&color, &gdk_color);
999 
1000   gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
1001                       item_view->priv->model_column_visible,
1002                       gimp_item_get_visible (item),
1003                       item_view->priv->model_column_viewable,
1004                       gimp_item_get_visible (item) &&
1005                       ! gimp_item_is_visible (item),
1006                       item_view->priv->model_column_linked,
1007                       gimp_item_get_linked (item),
1008                       item_view->priv->model_column_color_tag,
1009                       has_color ? &gdk_color : NULL,
1010                       -1);
1011 
1012   return iter;
1013 }
1014 
1015 static void
gimp_item_tree_view_insert_item_after(GimpContainerView * view,GimpViewable * viewable,gpointer insert_data)1016 gimp_item_tree_view_insert_item_after (GimpContainerView *view,
1017                                        GimpViewable      *viewable,
1018                                        gpointer           insert_data)
1019 {
1020   GimpItemTreeView      *item_view = GIMP_ITEM_TREE_VIEW (view);
1021   GimpItemTreeViewClass *item_view_class;
1022   GimpItem              *active_item;
1023 
1024   item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (item_view);
1025 
1026   active_item = item_view_class->get_active_item (item_view->priv->image);
1027 
1028   if (active_item == (GimpItem *) viewable)
1029     gimp_container_view_select_item (view, viewable);
1030 }
1031 
1032 static gboolean
gimp_item_tree_view_select_item(GimpContainerView * view,GimpViewable * item,gpointer insert_data)1033 gimp_item_tree_view_select_item (GimpContainerView *view,
1034                                  GimpViewable      *item,
1035                                  gpointer           insert_data)
1036 {
1037   GimpItemTreeView *tree_view         = GIMP_ITEM_TREE_VIEW (view);
1038   gboolean          options_sensitive = FALSE;
1039   gboolean          success;
1040 
1041   success = parent_view_iface->select_item (view, item, insert_data);
1042 
1043   if (item)
1044     {
1045       GimpItemTreeViewClass *item_view_class;
1046       GimpItem              *active_item;
1047 
1048       item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (tree_view);
1049 
1050       active_item = item_view_class->get_active_item (tree_view->priv->image);
1051 
1052       if (active_item != (GimpItem *) item)
1053         {
1054           item_view_class->set_active_item (tree_view->priv->image,
1055                                             GIMP_ITEM (item));
1056 
1057           gimp_image_flush (tree_view->priv->image);
1058         }
1059 
1060       options_sensitive = TRUE;
1061 
1062       gimp_item_tree_view_update_options (tree_view, GIMP_ITEM (item));
1063     }
1064 
1065   gimp_ui_manager_update (gimp_editor_get_ui_manager (GIMP_EDITOR (tree_view)), tree_view);
1066 
1067   if (tree_view->priv->options_box)
1068     gtk_widget_set_sensitive (tree_view->priv->options_box, options_sensitive);
1069 
1070   return success;
1071 }
1072 
1073 static void
gimp_item_tree_view_activate_item(GimpContainerView * view,GimpViewable * item,gpointer insert_data)1074 gimp_item_tree_view_activate_item (GimpContainerView *view,
1075                                    GimpViewable      *item,
1076                                    gpointer           insert_data)
1077 {
1078   GimpItemTreeViewClass *item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (view);
1079 
1080   if (parent_view_iface->activate_item)
1081     parent_view_iface->activate_item (view, item, insert_data);
1082 
1083   if (item_view_class->activate_action)
1084     {
1085       gimp_ui_manager_activate_action (gimp_editor_get_ui_manager (GIMP_EDITOR (view)),
1086                                        item_view_class->action_group,
1087                                        item_view_class->activate_action);
1088     }
1089 }
1090 
1091 static void
gimp_item_tree_view_context_item(GimpContainerView * view,GimpViewable * item,gpointer insert_data)1092 gimp_item_tree_view_context_item (GimpContainerView *view,
1093                                   GimpViewable      *item,
1094                                   gpointer           insert_data)
1095 {
1096   if (parent_view_iface->context_item)
1097     parent_view_iface->context_item (view, item, insert_data);
1098 
1099   gimp_editor_popup_menu (GIMP_EDITOR (view), NULL, NULL);
1100 }
1101 
1102 static gboolean
gimp_item_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)1103 gimp_item_tree_view_drop_possible (GimpContainerTreeView   *tree_view,
1104                                    GimpDndType              src_type,
1105                                    GimpViewable            *src_viewable,
1106                                    GimpViewable            *dest_viewable,
1107                                    GtkTreePath             *drop_path,
1108                                    GtkTreeViewDropPosition  drop_pos,
1109                                    GtkTreeViewDropPosition *return_drop_pos,
1110                                    GdkDragAction           *return_drag_action)
1111 {
1112   if (GIMP_IS_ITEM (src_viewable) &&
1113       (dest_viewable == NULL ||
1114        gimp_item_get_image (GIMP_ITEM (src_viewable)) !=
1115        gimp_item_get_image (GIMP_ITEM (dest_viewable))))
1116     {
1117       if (return_drop_pos)
1118         *return_drop_pos = drop_pos;
1119 
1120       if (return_drag_action)
1121         *return_drag_action = GDK_ACTION_COPY;
1122 
1123       return TRUE;
1124     }
1125 
1126   return GIMP_CONTAINER_TREE_VIEW_CLASS (parent_class)->drop_possible (tree_view,
1127                                                                        src_type,
1128                                                                        src_viewable,
1129                                                                        dest_viewable,
1130                                                                        drop_path,
1131                                                                        drop_pos,
1132                                                                        return_drop_pos,
1133                                                                        return_drag_action);
1134 }
1135 
1136 static void
gimp_item_tree_view_drop_viewable(GimpContainerTreeView * tree_view,GimpViewable * src_viewable,GimpViewable * dest_viewable,GtkTreeViewDropPosition drop_pos)1137 gimp_item_tree_view_drop_viewable (GimpContainerTreeView   *tree_view,
1138                                    GimpViewable            *src_viewable,
1139                                    GimpViewable            *dest_viewable,
1140                                    GtkTreeViewDropPosition  drop_pos)
1141 {
1142   GimpItemTreeViewClass *item_view_class;
1143   GimpItemTreeView      *item_view  = GIMP_ITEM_TREE_VIEW (tree_view);
1144   gint                   dest_index = -1;
1145 
1146   item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (item_view);
1147 
1148   if (item_view->priv->image != gimp_item_get_image (GIMP_ITEM (src_viewable)) ||
1149       ! g_type_is_a (G_TYPE_FROM_INSTANCE (src_viewable),
1150                      item_view_class->item_type))
1151     {
1152       GType     item_type = item_view_class->item_type;
1153       GimpItem *new_item;
1154       GimpItem *parent;
1155 
1156       if (g_type_is_a (G_TYPE_FROM_INSTANCE (src_viewable), item_type))
1157         item_type = G_TYPE_FROM_INSTANCE (src_viewable);
1158 
1159       dest_index = gimp_item_tree_view_get_drop_index (item_view, dest_viewable,
1160                                                        drop_pos,
1161                                                        (GimpViewable **) &parent);
1162 
1163       new_item = gimp_item_convert (GIMP_ITEM (src_viewable),
1164                                     item_view->priv->image, item_type);
1165 
1166       gimp_item_set_linked (new_item, FALSE, FALSE);
1167 
1168       item_view_class->add_item (item_view->priv->image, new_item,
1169                                  parent, dest_index, TRUE);
1170     }
1171   else if (dest_viewable)
1172     {
1173       GimpItem *src_parent;
1174       GimpItem *dest_parent;
1175       gint      src_index;
1176       gint      dest_index;
1177 
1178       src_parent = GIMP_ITEM (gimp_viewable_get_parent (src_viewable));
1179       src_index  = gimp_item_get_index (GIMP_ITEM (src_viewable));
1180 
1181       dest_index = gimp_item_tree_view_get_drop_index (item_view, dest_viewable,
1182                                                        drop_pos,
1183                                                        (GimpViewable **) &dest_parent);
1184 
1185       if (src_parent == dest_parent)
1186         {
1187           if (src_index < dest_index)
1188             dest_index--;
1189         }
1190 
1191       gimp_image_reorder_item (item_view->priv->image,
1192                                GIMP_ITEM (src_viewable),
1193                                dest_parent,
1194                                dest_index,
1195                                TRUE, NULL);
1196     }
1197 
1198   gimp_image_flush (item_view->priv->image);
1199 }
1200 
1201 
1202 /*  "New" functions  */
1203 
1204 static void
gimp_item_tree_view_new_dropped(GtkWidget * widget,gint x,gint y,GimpViewable * viewable,gpointer data)1205 gimp_item_tree_view_new_dropped (GtkWidget    *widget,
1206                                  gint          x,
1207                                  gint          y,
1208                                  GimpViewable *viewable,
1209                                  gpointer      data)
1210 {
1211   GimpItemTreeViewClass *item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (data);
1212   GimpContainerView     *view            = GIMP_CONTAINER_VIEW (data);
1213 
1214   if (item_view_class->new_default_action &&
1215       viewable && gimp_container_view_lookup (view, viewable))
1216     {
1217       GimpAction *action;
1218 
1219       action = gimp_ui_manager_find_action (gimp_editor_get_ui_manager (GIMP_EDITOR (view)),
1220                                             item_view_class->action_group,
1221                                             item_view_class->new_default_action);
1222 
1223       if (action)
1224         {
1225           g_object_set (action, "viewable", viewable, NULL);
1226           gimp_action_activate (action);
1227           g_object_set (action, "viewable", NULL, NULL);
1228         }
1229     }
1230 }
1231 
1232 
1233 /*  GimpImage callbacks  */
1234 
1235 static void
gimp_item_tree_view_item_changed(GimpImage * image,GimpItemTreeView * view)1236 gimp_item_tree_view_item_changed (GimpImage        *image,
1237                                   GimpItemTreeView *view)
1238 {
1239   GimpItem *item;
1240 
1241   item = GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_active_item (view->priv->image);
1242 
1243   gimp_container_view_select_item (GIMP_CONTAINER_VIEW (view),
1244                                    (GimpViewable *) item);
1245 }
1246 
1247 static void
gimp_item_tree_view_size_changed(GimpImage * image,GimpItemTreeView * tree_view)1248 gimp_item_tree_view_size_changed (GimpImage        *image,
1249                                   GimpItemTreeView *tree_view)
1250 {
1251   GimpContainerView *view = GIMP_CONTAINER_VIEW (tree_view);
1252   gint               view_size;
1253   gint               border_width;
1254 
1255   view_size = gimp_container_view_get_view_size (view, &border_width);
1256 
1257   gimp_container_view_set_view_size (view, view_size, border_width);
1258 }
1259 
1260 static void
gimp_item_tree_view_name_edited(GtkCellRendererText * cell,const gchar * path_str,const gchar * new_name,GimpItemTreeView * view)1261 gimp_item_tree_view_name_edited (GtkCellRendererText *cell,
1262                                  const gchar         *path_str,
1263                                  const gchar         *new_name,
1264                                  GimpItemTreeView    *view)
1265 {
1266   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
1267   GtkTreePath           *path;
1268   GtkTreeIter            iter;
1269 
1270   path = gtk_tree_path_new_from_string (path_str);
1271 
1272   if (gtk_tree_model_get_iter (tree_view->model, &iter, path))
1273     {
1274       GimpViewRenderer *renderer;
1275       GimpItem         *item;
1276       const gchar      *old_name;
1277       GError           *error = NULL;
1278 
1279       gtk_tree_model_get (tree_view->model, &iter,
1280                           GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
1281                           -1);
1282 
1283       item = GIMP_ITEM (renderer->viewable);
1284 
1285       old_name = gimp_object_get_name (item);
1286 
1287       if (! old_name) old_name = "";
1288       if (! new_name) new_name = "";
1289 
1290       if (strcmp (old_name, new_name) &&
1291           gimp_item_rename (item, new_name, &error))
1292         {
1293           gimp_image_flush (gimp_item_get_image (item));
1294         }
1295       else
1296         {
1297           gchar *name = gimp_viewable_get_description (renderer->viewable, NULL);
1298 
1299           gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), &iter,
1300                               GIMP_CONTAINER_TREE_STORE_COLUMN_NAME, name,
1301                               -1);
1302           g_free (name);
1303 
1304           if (error)
1305             {
1306               gimp_message_literal (view->priv->image->gimp, G_OBJECT (view),
1307                                     GIMP_MESSAGE_WARNING,
1308                                     error->message);
1309               g_clear_error (&error);
1310             }
1311         }
1312 
1313       g_object_unref (renderer);
1314     }
1315 
1316   gtk_tree_path_free (path);
1317 }
1318 
1319 
1320 /*  "Visible" callbacks  */
1321 
1322 static void
gimp_item_tree_view_visible_changed(GimpItem * item,GimpItemTreeView * view)1323 gimp_item_tree_view_visible_changed (GimpItem         *item,
1324                                      GimpItemTreeView *view)
1325 {
1326   GimpContainerView     *container_view = GIMP_CONTAINER_VIEW (view);
1327   GimpContainerTreeView *tree_view      = GIMP_CONTAINER_TREE_VIEW (view);
1328   GtkTreeIter           *iter;
1329 
1330   iter = gimp_container_view_lookup (container_view,
1331                                      (GimpViewable *) item);
1332 
1333   if (iter)
1334     {
1335       GimpContainer *children;
1336 
1337       gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
1338                           view->priv->model_column_visible,
1339                           gimp_item_get_visible (item),
1340                           view->priv->model_column_viewable,
1341                           gimp_item_get_visible (item) &&
1342                           ! gimp_item_is_visible (item),
1343                           -1);
1344 
1345       children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
1346 
1347       if (children)
1348         gimp_container_foreach (children,
1349                                 (GFunc) gimp_item_tree_view_visible_changed,
1350                                 view);
1351     }
1352 }
1353 
1354 static void
gimp_item_tree_view_eye_clicked(GtkCellRendererToggle * toggle,gchar * path_str,GdkModifierType state,GimpItemTreeView * view)1355 gimp_item_tree_view_eye_clicked (GtkCellRendererToggle *toggle,
1356                                  gchar                 *path_str,
1357                                  GdkModifierType        state,
1358                                  GimpItemTreeView      *view)
1359 {
1360   gimp_item_tree_view_toggle_clicked (toggle, path_str, state, view,
1361                                       GIMP_UNDO_ITEM_VISIBILITY);
1362 }
1363 
1364 
1365 /*  "Linked" callbacks  */
1366 
1367 static void
gimp_item_tree_view_linked_changed(GimpItem * item,GimpItemTreeView * view)1368 gimp_item_tree_view_linked_changed (GimpItem         *item,
1369                                     GimpItemTreeView *view)
1370 {
1371   GimpContainerView     *container_view = GIMP_CONTAINER_VIEW (view);
1372   GimpContainerTreeView *tree_view      = GIMP_CONTAINER_TREE_VIEW (view);
1373   GtkTreeIter           *iter;
1374 
1375   iter = gimp_container_view_lookup (container_view,
1376                                      (GimpViewable *) item);
1377 
1378   if (iter)
1379     gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
1380                         view->priv->model_column_linked,
1381                         gimp_item_get_linked (item),
1382                         -1);
1383 }
1384 
1385 static void
gimp_item_tree_view_chain_clicked(GtkCellRendererToggle * toggle,gchar * path_str,GdkModifierType state,GimpItemTreeView * view)1386 gimp_item_tree_view_chain_clicked (GtkCellRendererToggle *toggle,
1387                                    gchar                 *path_str,
1388                                    GdkModifierType        state,
1389                                    GimpItemTreeView      *view)
1390 {
1391   gimp_item_tree_view_toggle_clicked (toggle, path_str, state, view,
1392                                       GIMP_UNDO_ITEM_LINKED);
1393 }
1394 
1395 
1396 /*  "Color Tag" callbacks  */
1397 
1398 static void
gimp_item_tree_view_color_tag_changed(GimpItem * item,GimpItemTreeView * view)1399 gimp_item_tree_view_color_tag_changed (GimpItem         *item,
1400                                        GimpItemTreeView *view)
1401 {
1402   GimpContainerView     *container_view = GIMP_CONTAINER_VIEW (view);
1403   GimpContainerTreeView *tree_view      = GIMP_CONTAINER_TREE_VIEW (view);
1404   GtkTreeIter           *iter;
1405 
1406   iter = gimp_container_view_lookup (container_view,
1407                                      (GimpViewable *) item);
1408 
1409   if (iter)
1410     {
1411       GimpContainer *children;
1412       GimpRGB        color;
1413       GdkColor       gdk_color;
1414       gboolean       has_color;
1415 
1416       has_color = gimp_get_color_tag_color (gimp_item_get_merged_color_tag (item),
1417                                             &color,
1418                                             gimp_item_get_color_tag (item) ==
1419                                             GIMP_COLOR_TAG_NONE);
1420       if (has_color)
1421         gimp_rgb_get_gdk_color (&color, &gdk_color);
1422 
1423       gtk_tree_store_set (GTK_TREE_STORE (tree_view->model), iter,
1424                           view->priv->model_column_color_tag,
1425                           has_color ? &gdk_color : NULL,
1426                           -1);
1427 
1428       children = gimp_viewable_get_children (GIMP_VIEWABLE (item));
1429 
1430       if (children)
1431         gimp_container_foreach (children,
1432                                 (GFunc) gimp_item_tree_view_color_tag_changed,
1433                                 view);
1434     }
1435 }
1436 
1437 
1438 /*  "Lock Content" callbacks  */
1439 
1440 static void
gimp_item_tree_view_lock_content_changed(GimpItem * item,GimpItemTreeView * view)1441 gimp_item_tree_view_lock_content_changed (GimpItem         *item,
1442                                           GimpItemTreeView *view)
1443 {
1444   GimpImage *image = view->priv->image;
1445   GimpItem  *active_item;
1446 
1447   active_item = GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_active_item (image);
1448 
1449   if (active_item == item)
1450     gimp_item_tree_view_update_options (view, item);
1451 }
1452 
1453 static void
gimp_item_tree_view_lock_content_toggled(GtkWidget * widget,GimpItemTreeView * view)1454 gimp_item_tree_view_lock_content_toggled (GtkWidget         *widget,
1455                                           GimpItemTreeView  *view)
1456 {
1457   GimpImage *image = view->priv->image;
1458   GimpItem  *item;
1459 
1460   item = GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_active_item (image);
1461 
1462   if (item)
1463     {
1464       gboolean lock_content;
1465 
1466       lock_content = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
1467 
1468       if (gimp_item_get_lock_content (item) != lock_content)
1469         {
1470 #if 0
1471           GimpUndo *undo;
1472 #endif
1473           gboolean  push_undo = TRUE;
1474 
1475 #if 0
1476           /*  compress lock content undos  */
1477           undo = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
1478                                                GIMP_UNDO_ITEM_LOCK_CONTENT);
1479 
1480           if (undo && GIMP_ITEM_UNDO (undo)->item == item)
1481             push_undo = FALSE;
1482 #endif
1483 
1484           g_signal_handlers_block_by_func (item,
1485                                            gimp_item_tree_view_lock_content_changed,
1486                                            view);
1487 
1488           gimp_item_set_lock_content (item, lock_content, push_undo);
1489 
1490           g_signal_handlers_unblock_by_func (item,
1491                                              gimp_item_tree_view_lock_content_changed,
1492                                              view);
1493 
1494           gimp_image_flush (image);
1495         }
1496     }
1497 }
1498 
1499 static void
gimp_item_tree_view_lock_position_changed(GimpItem * item,GimpItemTreeView * view)1500 gimp_item_tree_view_lock_position_changed (GimpItem         *item,
1501                                            GimpItemTreeView *view)
1502 {
1503   GimpImage *image = view->priv->image;
1504   GimpItem  *active_item;
1505 
1506   active_item = GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_active_item (image);
1507 
1508   if (active_item == item)
1509     gimp_item_tree_view_update_options (view, item);
1510 }
1511 
1512 static void
gimp_item_tree_view_lock_position_toggled(GtkWidget * widget,GimpItemTreeView * view)1513 gimp_item_tree_view_lock_position_toggled (GtkWidget         *widget,
1514                                            GimpItemTreeView  *view)
1515 {
1516   GimpImage *image = view->priv->image;
1517   GimpItem  *item;
1518 
1519   item = GIMP_ITEM_TREE_VIEW_GET_CLASS (view)->get_active_item (image);
1520 
1521   if (item)
1522     {
1523       gboolean lock_position;
1524 
1525       lock_position = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
1526 
1527       if (gimp_item_get_lock_position (item) != lock_position)
1528         {
1529           GimpUndo *undo;
1530           gboolean  push_undo = TRUE;
1531 
1532           /*  compress lock position undos  */
1533           undo = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
1534                                                GIMP_UNDO_ITEM_LOCK_POSITION);
1535 
1536           if (undo && GIMP_ITEM_UNDO (undo)->item == item)
1537             push_undo = FALSE;
1538 
1539           g_signal_handlers_block_by_func (item,
1540                                            gimp_item_tree_view_lock_position_changed,
1541                                            view);
1542 
1543           gimp_item_set_lock_position (item, lock_position, push_undo);
1544 
1545           g_signal_handlers_unblock_by_func (item,
1546                                              gimp_item_tree_view_lock_position_changed,
1547                                              view);
1548 
1549           gimp_image_flush (image);
1550         }
1551     }
1552 }
1553 
1554 static gboolean
gimp_item_tree_view_item_pre_clicked(GimpCellRendererViewable * cell,const gchar * path_str,GdkModifierType state,GimpItemTreeView * item_view)1555 gimp_item_tree_view_item_pre_clicked (GimpCellRendererViewable *cell,
1556                                       const gchar              *path_str,
1557                                       GdkModifierType           state,
1558                                       GimpItemTreeView         *item_view)
1559 {
1560   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (item_view);
1561   GtkTreePath           *path;
1562   GtkTreeIter            iter;
1563   gboolean               handled = FALSE;
1564 
1565   path = gtk_tree_path_new_from_string (path_str);
1566 
1567   if (gtk_tree_model_get_iter (tree_view->model, &iter, path) &&
1568       (state & GDK_MOD1_MASK))
1569     {
1570       GimpImage        *image    = gimp_item_tree_view_get_image (item_view);
1571       GimpViewRenderer *renderer = NULL;
1572 
1573       gtk_tree_model_get (tree_view->model, &iter,
1574                           GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
1575                           -1);
1576 
1577       if (renderer)
1578         {
1579           GimpItem       *item = GIMP_ITEM (renderer->viewable);
1580           GimpChannelOps  op   = gimp_modifiers_to_channel_op (state);
1581 
1582           gimp_item_to_selection (item, op,
1583                                   TRUE, FALSE, 0.0, 0.0);
1584           gimp_image_flush (image);
1585 
1586           g_object_unref (renderer);
1587 
1588           /* Don't select the clicked layer */
1589           handled = TRUE;
1590         }
1591     }
1592 
1593   gtk_tree_path_free (path);
1594 
1595   return handled;
1596 }
1597 
1598 static void
gimp_item_tree_view_update_options(GimpItemTreeView * view,GimpItem * item)1599 gimp_item_tree_view_update_options (GimpItemTreeView *view,
1600                                     GimpItem         *item)
1601 {
1602   if (gimp_item_get_lock_content (item) !=
1603       gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (view->priv->lock_content_toggle)))
1604     {
1605       g_signal_handlers_block_by_func (view->priv->lock_content_toggle,
1606                                        gimp_item_tree_view_lock_content_toggled,
1607                                        view);
1608 
1609       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (view->priv->lock_content_toggle),
1610                                     gimp_item_get_lock_content (item));
1611 
1612       g_signal_handlers_unblock_by_func (view->priv->lock_content_toggle,
1613                                          gimp_item_tree_view_lock_content_toggled,
1614                                          view);
1615     }
1616 
1617   if (gimp_item_get_lock_position (item) !=
1618       gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (view->priv->lock_position_toggle)))
1619     {
1620       g_signal_handlers_block_by_func (view->priv->lock_position_toggle,
1621                                        gimp_item_tree_view_lock_position_toggled,
1622                                        view);
1623 
1624       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (view->priv->lock_position_toggle),
1625                                     gimp_item_get_lock_position (item));
1626 
1627       g_signal_handlers_unblock_by_func (view->priv->lock_position_toggle,
1628                                          gimp_item_tree_view_lock_position_toggled,
1629                                          view);
1630     }
1631 
1632   gtk_widget_set_sensitive (view->priv->lock_content_toggle,
1633                             gimp_item_can_lock_content (item));
1634 
1635   gtk_widget_set_sensitive (view->priv->lock_position_toggle,
1636                             gimp_item_can_lock_position (item));
1637 }
1638 
1639 
1640 /*  Utility functions used from eye_clicked and chain_clicked.
1641  *  Would make sense to do this in a generic fashion using
1642  *  properties, but for now it's better than duplicating the code.
1643  */
1644 static void
gimp_item_tree_view_toggle_clicked(GtkCellRendererToggle * toggle,gchar * path_str,GdkModifierType state,GimpItemTreeView * view,GimpUndoType undo_type)1645 gimp_item_tree_view_toggle_clicked (GtkCellRendererToggle *toggle,
1646                                     gchar                 *path_str,
1647                                     GdkModifierType        state,
1648                                     GimpItemTreeView      *view,
1649                                     GimpUndoType           undo_type)
1650 {
1651   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (view);
1652   GtkTreePath           *path;
1653   GtkTreeIter            iter;
1654 
1655   void (* setter)    (GimpItem    *item,
1656                       gboolean     value,
1657                       gboolean     push_undo);
1658   void (* exclusive) (GimpItem    *item,
1659                       GimpContext *context);
1660 
1661   switch (undo_type)
1662     {
1663     case GIMP_UNDO_ITEM_VISIBILITY:
1664       setter     = gimp_item_set_visible;
1665       exclusive  = gimp_item_toggle_exclusive_visible;
1666       break;
1667 
1668     case GIMP_UNDO_ITEM_LINKED:
1669       setter     = gimp_item_set_linked;
1670       exclusive  = gimp_item_toggle_exclusive_linked;
1671       break;
1672 
1673     default:
1674       return;
1675     }
1676 
1677   path = gtk_tree_path_new_from_string (path_str);
1678 
1679   if (gtk_tree_model_get_iter (tree_view->model, &iter, path))
1680     {
1681       GimpContext      *context;
1682       GimpViewRenderer *renderer;
1683       GimpItem         *item;
1684       GimpImage        *image;
1685       gboolean          active;
1686 
1687       context = gimp_container_view_get_context (GIMP_CONTAINER_VIEW (view));
1688 
1689       gtk_tree_model_get (tree_view->model, &iter,
1690                           GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
1691                           -1);
1692       g_object_get (toggle,
1693                     "active", &active,
1694                     NULL);
1695 
1696       item = GIMP_ITEM (renderer->viewable);
1697       g_object_unref (renderer);
1698 
1699       image = gimp_item_get_image (item);
1700 
1701       if ((state & GDK_SHIFT_MASK) && exclusive)
1702         {
1703           exclusive (item, context);
1704         }
1705       else
1706         {
1707           GimpUndo *undo;
1708           gboolean  push_undo = TRUE;
1709 
1710           undo = gimp_image_undo_can_compress (image, GIMP_TYPE_ITEM_UNDO,
1711                                                undo_type);
1712 
1713           if (undo && GIMP_ITEM_UNDO (undo)->item == item)
1714             push_undo = FALSE;
1715 
1716           setter (item, ! active, push_undo);
1717 
1718           if (!push_undo)
1719             gimp_undo_refresh_preview (undo, context);
1720         }
1721 
1722       gimp_image_flush (image);
1723     }
1724 
1725   gtk_tree_path_free (path);
1726 }
1727 
1728 
1729 /*  GtkTreeView callbacks  */
1730 
1731 static void
gimp_item_tree_view_row_expanded(GtkTreeView * tree_view,GtkTreeIter * iter,GtkTreePath * path,GimpItemTreeView * item_view)1732 gimp_item_tree_view_row_expanded (GtkTreeView      *tree_view,
1733                                   GtkTreeIter      *iter,
1734                                   GtkTreePath      *path,
1735                                   GimpItemTreeView *item_view)
1736 {
1737   GimpItemTreeViewClass *item_view_class;
1738   GimpItem              *active_item;
1739 
1740   item_view_class = GIMP_ITEM_TREE_VIEW_GET_CLASS (item_view);
1741   active_item = item_view_class->get_active_item (item_view->priv->image);
1742 
1743   /*  don't select the item while it is being inserted  */
1744   if (active_item &&
1745       gimp_container_view_lookup (GIMP_CONTAINER_VIEW (item_view),
1746                                   GIMP_VIEWABLE (active_item)))
1747     {
1748       GimpViewRenderer *renderer;
1749       GimpItem         *expanded_item;
1750 
1751       gtk_tree_model_get (GIMP_CONTAINER_TREE_VIEW (item_view)->model, iter,
1752                           GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
1753                           -1);
1754       expanded_item = GIMP_ITEM (renderer->viewable);
1755       g_object_unref (renderer);
1756 
1757       /*  select the active item only if it was made visible by expanding
1758        *  its immediate parent. See bug #666561.
1759        */
1760       if (gimp_item_get_parent (active_item) == expanded_item)
1761         {
1762           gimp_container_view_select_item (GIMP_CONTAINER_VIEW (item_view),
1763                                            GIMP_VIEWABLE (active_item));
1764         }
1765     }
1766 }
1767