1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimptooleditor.c
5  * Copyright (C) 2001-2009 Michael Natterer <mitch@gimp.org>
6  *                         Stephen Griffiths <scgmk5@gmail.com>
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #include <gegl.h>
25 #include <gtk/gtk.h>
26 
27 #include "libgimpconfig/gimpconfig.h"
28 #include "libgimpwidgets/gimpwidgets.h"
29 
30 #include "widgets-types.h"
31 
32 #include "core/gimp.h"
33 #include "core/gimpcontainer.h"
34 #include "core/gimpcontext.h"
35 #include "core/gimptoolgroup.h"
36 #include "core/gimptreehandler.h"
37 
38 #include "tools/gimp-tools.h"
39 
40 #include "gimpcontainertreestore.h"
41 #include "gimpcontainerview.h"
42 #include "gimpdnd.h"
43 #include "gimpviewrenderer.h"
44 #include "gimptooleditor.h"
45 #include "gimphelp-ids.h"
46 #include "gimpwidgets-utils.h"
47 
48 #include "gimp-intl.h"
49 
50 
51 struct _GimpToolEditorPrivate
52 {
53   GimpContainer   *container;
54   GimpContext     *context;
55 
56   GtkWidget       *scrolled;
57 
58   GtkWidget       *new_group_button;
59   GtkWidget       *raise_button;
60   GtkWidget       *lower_button;
61   GtkWidget       *delete_button;
62   GtkWidget       *reset_button;
63 
64   GimpTreeHandler *tool_item_notify_handler;
65 
66   /* State of tools at creation of the editor, stored to support
67    * reverting changes
68    */
69   gchar           *initial_tool_state;
70 };
71 
72 
73 /*  local function prototypes  */
74 
75 static void            gimp_tool_editor_view_iface_init           (GimpContainerViewInterface *iface);
76 
77 static void            gimp_tool_editor_constructed               (GObject                    *object);
78 
79 static gboolean        gimp_tool_editor_select_item               (GimpContainerView          *view,
80                                                                    GimpViewable               *viewable,
81                                                                    gpointer                    insert_data);
82 static void            gimp_tool_editor_set_container             (GimpContainerView          *container_view,
83                                                                    GimpContainer              *container);
84 static void            gimp_tool_editor_set_context               (GimpContainerView          *container_view,
85                                                                    GimpContext                *context);
86 
87 static gboolean        gimp_tool_editor_drop_possible             (GimpContainerTreeView      *tree_view,
88                                                                    GimpDndType                 src_type,
89                                                                    GimpViewable               *src_viewable,
90                                                                    GimpViewable               *dest_viewable,
91                                                                    GtkTreePath                *drop_path,
92                                                                    GtkTreeViewDropPosition     drop_pos,
93                                                                    GtkTreeViewDropPosition    *return_drop_pos,
94                                                                    GdkDragAction              *return_drag_action);
95 static void            gimp_tool_editor_drop_viewable             (GimpContainerTreeView      *tree_view,
96                                                                    GimpViewable               *src_viewable,
97                                                                    GimpViewable               *dest_viewable,
98                                                                    GtkTreeViewDropPosition     drop_pos);
99 
100 static void            gimp_tool_editor_tool_item_notify         (GimpToolItem                *tool_item,
101                                                                   GParamSpec                  *pspec,
102                                                                   GimpToolEditor              *tool_editor);
103 
104 static void            gimp_tool_editor_eye_data_func            (GtkTreeViewColumn           *tree_column,
105                                                                   GtkCellRenderer             *cell,
106                                                                   GtkTreeModel                *tree_model,
107                                                                   GtkTreeIter                 *iter,
108                                                                   gpointer                     data);
109 static void            gimp_tool_editor_eye_clicked              (GtkCellRendererToggle       *toggle,
110                                                                   gchar                       *path_str,
111                                                                   GdkModifierType              state,
112                                                                   GimpToolEditor              *tool_editor);
113 
114 static void            gimp_tool_editor_new_group_clicked        (GtkButton                   *button,
115                                                                   GimpToolEditor              *tool_editor);
116 static void            gimp_tool_editor_raise_clicked            (GtkButton                   *button,
117                                                                   GimpToolEditor              *tool_editor);
118 static void            gimp_tool_editor_raise_extend_clicked     (GtkButton                   *button,
119                                                                   GdkModifierType              mask,
120                                                                   GimpToolEditor              *tool_editor);
121 static void            gimp_tool_editor_lower_clicked            (GtkButton                   *button,
122                                                                   GimpToolEditor              *tool_editor);
123 static void            gimp_tool_editor_lower_extend_clicked     (GtkButton                   *button,
124                                                                   GdkModifierType              mask,
125                                                                   GimpToolEditor              *tool_editor);
126 static void            gimp_tool_editor_delete_clicked           (GtkButton                   *button,
127                                                                   GimpToolEditor              *tool_editor);
128 static void            gimp_tool_editor_reset_clicked            (GtkButton                   *button,
129                                                                   GimpToolEditor              *tool_editor);
130 
131 static GimpToolItem  * gimp_tool_editor_get_selected_tool_item   (GimpToolEditor              *tool_editor);
132 static GimpContainer * gimp_tool_editor_get_tool_item_container  (GimpToolEditor              *tool_editor,
133                                                                   GimpToolItem                *tool_item);
134 
135 static void            gimp_tool_editor_update_container         (GimpToolEditor              *tool_editor);
136 static void            gimp_tool_editor_update_sensitivity       (GimpToolEditor              *tool_editor);
137 
138 
139 G_DEFINE_TYPE_WITH_CODE (GimpToolEditor, gimp_tool_editor,
140                          GIMP_TYPE_CONTAINER_TREE_VIEW,
141                          G_ADD_PRIVATE (GimpToolEditor)
142                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONTAINER_VIEW,
143                                                 gimp_tool_editor_view_iface_init))
144 
145 #define parent_class gimp_tool_editor_parent_class
146 
147 static GimpContainerViewInterface *parent_view_iface = NULL;
148 
149 
150 /*  private functions  */
151 
152 static void
gimp_tool_editor_class_init(GimpToolEditorClass * klass)153 gimp_tool_editor_class_init (GimpToolEditorClass *klass)
154 {
155   GObjectClass               *object_class    = G_OBJECT_CLASS (klass);
156   GimpContainerTreeViewClass *tree_view_class = GIMP_CONTAINER_TREE_VIEW_CLASS (klass);
157 
158   object_class->constructed      = gimp_tool_editor_constructed;
159 
160   tree_view_class->drop_possible = gimp_tool_editor_drop_possible;
161   tree_view_class->drop_viewable = gimp_tool_editor_drop_viewable;
162 }
163 
164 static void
gimp_tool_editor_view_iface_init(GimpContainerViewInterface * iface)165 gimp_tool_editor_view_iface_init (GimpContainerViewInterface *iface)
166 {
167   parent_view_iface = g_type_interface_peek_parent (iface);
168 
169   if (! parent_view_iface)
170     parent_view_iface = g_type_default_interface_peek (GIMP_TYPE_CONTAINER_VIEW);
171 
172   iface->select_item   = gimp_tool_editor_select_item;
173   iface->set_container = gimp_tool_editor_set_container;
174   iface->set_context   = gimp_tool_editor_set_context;
175 }
176 
177 static void
gimp_tool_editor_init(GimpToolEditor * tool_editor)178 gimp_tool_editor_init (GimpToolEditor *tool_editor)
179 {
180   tool_editor->priv = gimp_tool_editor_get_instance_private (tool_editor);
181 }
182 
183 static void
gimp_tool_editor_constructed(GObject * object)184 gimp_tool_editor_constructed (GObject *object)
185 {
186   GimpToolEditor        *tool_editor    = GIMP_TOOL_EDITOR (object);
187   GimpContainerTreeView *tree_view      = GIMP_CONTAINER_TREE_VIEW (object);
188   GimpContainerView     *container_view = GIMP_CONTAINER_VIEW (object);
189   gint                   view_size;
190   gint                   border_width;
191 
192   G_OBJECT_CLASS (parent_class)->constructed (object);
193 
194   view_size = gimp_container_view_get_view_size (container_view,
195                                                  &border_width);
196 
197   gimp_editor_set_show_name (GIMP_EDITOR (tool_editor), FALSE);
198 
199   gtk_tree_view_set_level_indentation (tree_view->view,
200                                        0.8 * (view_size + 2 * border_width));
201 
202   gimp_dnd_viewable_dest_add (GTK_WIDGET (tree_view->view),
203                               GIMP_TYPE_TOOL_ITEM,
204                               NULL, NULL);
205 
206   /* construct tree view */
207   {
208     GtkTreeViewColumn *column;
209     GtkCellRenderer   *eye_cell;
210     GtkStyle          *tree_style;
211     GtkIconSize        icon_size;
212 
213     tree_style = gtk_widget_get_style (GTK_WIDGET (tool_editor));
214 
215     icon_size = gimp_get_icon_size (GTK_WIDGET (tool_editor),
216                                     GIMP_ICON_VISIBLE,
217                                     GTK_ICON_SIZE_BUTTON,
218                                     view_size -
219                                     2 * tree_style->xthickness,
220                                     view_size -
221                                     2 * tree_style->ythickness);
222 
223     column = gtk_tree_view_column_new ();
224     gtk_tree_view_insert_column (tree_view->view, column, 0);
225 
226     eye_cell = gimp_cell_renderer_toggle_new (GIMP_ICON_VISIBLE);
227     g_object_set (eye_cell, "stock-size", icon_size, NULL);
228     gtk_tree_view_column_pack_start (column, eye_cell, FALSE);
229     gtk_tree_view_column_set_cell_data_func  (column, eye_cell,
230                                               gimp_tool_editor_eye_data_func,
231                                               tree_view, NULL);
232 
233     gimp_container_tree_view_add_toggle_cell (tree_view, eye_cell);
234 
235     g_signal_connect (eye_cell, "clicked",
236                       G_CALLBACK (gimp_tool_editor_eye_clicked),
237                       tool_editor);
238   }
239 
240   /* buttons */
241   tool_editor->priv->new_group_button =
242     gimp_editor_add_button (GIMP_EDITOR (tool_editor), GIMP_ICON_FOLDER_NEW,
243                             _("Create a new tool group"), NULL,
244                             G_CALLBACK (gimp_tool_editor_new_group_clicked),
245                             NULL,
246                             tool_editor);
247 
248   tool_editor->priv->raise_button =
249     gimp_editor_add_button (GIMP_EDITOR (tool_editor), GIMP_ICON_GO_UP,
250                             _("Raise this item"),
251                             _("Raise this item to the top"),
252                             G_CALLBACK (gimp_tool_editor_raise_clicked),
253                             G_CALLBACK (gimp_tool_editor_raise_extend_clicked),
254                             tool_editor);
255 
256   tool_editor->priv->lower_button =
257     gimp_editor_add_button (GIMP_EDITOR (tool_editor), GIMP_ICON_GO_DOWN,
258                             _("Lower this item"),
259                             _("Lower this item to the bottom"),
260                             G_CALLBACK (gimp_tool_editor_lower_clicked),
261                             G_CALLBACK (gimp_tool_editor_lower_extend_clicked),
262                             tool_editor);
263 
264   tool_editor->priv->delete_button =
265     gimp_editor_add_button (GIMP_EDITOR (tool_editor), GIMP_ICON_EDIT_DELETE,
266                             _("Delete this tool group"), NULL,
267                             G_CALLBACK (gimp_tool_editor_delete_clicked),
268                             NULL,
269                             tool_editor);
270 
271   tool_editor->priv->reset_button =
272     gimp_editor_add_button (GIMP_EDITOR (tool_editor), GIMP_ICON_RESET,
273                             _("Reset tool order and visibility"), NULL,
274                             G_CALLBACK (gimp_tool_editor_reset_clicked),
275                             NULL,
276                             tool_editor);
277 
278   gimp_tool_editor_update_sensitivity (tool_editor);
279 }
280 
281 static gboolean
gimp_tool_editor_select_item(GimpContainerView * container_view,GimpViewable * viewable,gpointer insert_data)282 gimp_tool_editor_select_item (GimpContainerView *container_view,
283                               GimpViewable      *viewable,
284                               gpointer           insert_data)
285 {
286   GimpToolEditor *tool_editor = GIMP_TOOL_EDITOR (container_view);
287   gboolean        result;
288 
289   result = parent_view_iface->select_item (container_view,
290                                            viewable, insert_data);
291 
292   gimp_tool_editor_update_sensitivity (tool_editor);
293 
294   return result;
295 }
296 
297 static void
gimp_tool_editor_set_container(GimpContainerView * container_view,GimpContainer * container)298 gimp_tool_editor_set_container (GimpContainerView *container_view,
299                                 GimpContainer     *container)
300 {
301   GimpToolEditor *tool_editor = GIMP_TOOL_EDITOR (container_view);
302 
303   parent_view_iface->set_container (container_view, container);
304 
305   gimp_tool_editor_update_container (tool_editor);
306 }
307 
308 static void
gimp_tool_editor_set_context(GimpContainerView * container_view,GimpContext * context)309 gimp_tool_editor_set_context (GimpContainerView *container_view,
310                               GimpContext       *context)
311 {
312   GimpToolEditor *tool_editor = GIMP_TOOL_EDITOR (container_view);
313 
314   parent_view_iface->set_context (container_view, context);
315 
316   gimp_tool_editor_update_container (tool_editor);
317 }
318 
319 static gboolean
gimp_tool_editor_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)320 gimp_tool_editor_drop_possible (GimpContainerTreeView   *tree_view,
321                                 GimpDndType              src_type,
322                                 GimpViewable            *src_viewable,
323                                 GimpViewable            *dest_viewable,
324                                 GtkTreePath             *drop_path,
325                                 GtkTreeViewDropPosition  drop_pos,
326                                 GtkTreeViewDropPosition *return_drop_pos,
327                                 GdkDragAction           *return_drag_action)
328 {
329   if (GIMP_CONTAINER_TREE_VIEW_CLASS (parent_class)->drop_possible (
330         tree_view,
331         src_type, src_viewable, dest_viewable, drop_path, drop_pos,
332         return_drop_pos, return_drag_action))
333     {
334       if (gimp_viewable_get_parent (dest_viewable)       ||
335           (gimp_viewable_get_children (dest_viewable)    &&
336            (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
337             drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
338         {
339           return ! gimp_viewable_get_children (src_viewable);
340         }
341 
342       return TRUE;
343     }
344 
345   return FALSE;
346 }
347 
348 static void
gimp_tool_editor_drop_viewable(GimpContainerTreeView * tree_view,GimpViewable * src_viewable,GimpViewable * dest_viewable,GtkTreeViewDropPosition drop_pos)349 gimp_tool_editor_drop_viewable (GimpContainerTreeView   *tree_view,
350                                 GimpViewable            *src_viewable,
351                                 GimpViewable            *dest_viewable,
352                                 GtkTreeViewDropPosition  drop_pos)
353 {
354   GimpContainerView *container_view = GIMP_CONTAINER_VIEW (tree_view);
355 
356   GIMP_CONTAINER_TREE_VIEW_CLASS (parent_class)->drop_viewable (tree_view,
357                                                                 src_viewable,
358                                                                 dest_viewable,
359                                                                 drop_pos);
360 
361   gimp_container_view_select_item (container_view, src_viewable);
362 }
363 
364 static void
gimp_tool_editor_new_group_clicked(GtkButton * button,GimpToolEditor * tool_editor)365 gimp_tool_editor_new_group_clicked (GtkButton      *button,
366                                     GimpToolEditor *tool_editor)
367 {
368   GimpContainerView *container_view = GIMP_CONTAINER_VIEW (tool_editor);
369   GimpContainer     *container;
370   GimpToolItem      *tool_item;
371   GimpToolGroup     *group;
372   gint               index = 0;
373 
374   tool_item = gimp_tool_editor_get_selected_tool_item (tool_editor);
375 
376   if (tool_item)
377     {
378       if (gimp_viewable_get_parent (GIMP_VIEWABLE (tool_item)) != NULL)
379         return;
380 
381       container = gimp_tool_editor_get_tool_item_container (tool_editor,
382                                                             tool_item);
383 
384       index = gimp_container_get_child_index (container,
385                                               GIMP_OBJECT (tool_item));
386     }
387   else
388     {
389       container = tool_editor->priv->container;
390     }
391 
392   if (container)
393     {
394       group = gimp_tool_group_new ();
395 
396       gimp_container_insert (container, GIMP_OBJECT (group), index);
397 
398       g_object_unref (group);
399 
400       gimp_container_view_select_item (container_view, GIMP_VIEWABLE (group));
401     }
402 }
403 
404 static void
gimp_tool_editor_raise_clicked(GtkButton * button,GimpToolEditor * tool_editor)405 gimp_tool_editor_raise_clicked (GtkButton      *button,
406                                 GimpToolEditor *tool_editor)
407 {
408   GimpToolItem *tool_item;
409 
410   tool_item = gimp_tool_editor_get_selected_tool_item (tool_editor);
411 
412   if (tool_item)
413     {
414       GimpContainer *container;
415       gint           index;
416 
417       container = gimp_tool_editor_get_tool_item_container (tool_editor,
418                                                             tool_item);
419 
420       index = gimp_container_get_child_index (container,
421                                               GIMP_OBJECT (tool_item));
422 
423       if (index > 0)
424         {
425           gimp_container_reorder (container,
426                                   GIMP_OBJECT (tool_item), index - 1);
427         }
428     }
429 }
430 
431 static void
gimp_tool_editor_raise_extend_clicked(GtkButton * button,GdkModifierType mask,GimpToolEditor * tool_editor)432 gimp_tool_editor_raise_extend_clicked (GtkButton       *button,
433                                        GdkModifierType  mask,
434                                        GimpToolEditor  *tool_editor)
435 {
436   GimpToolItem *tool_item;
437 
438   tool_item = gimp_tool_editor_get_selected_tool_item (tool_editor);
439 
440   if (tool_item && (mask & GDK_SHIFT_MASK))
441     {
442       GimpContainer *container;
443       gint           index;
444 
445       container = gimp_tool_editor_get_tool_item_container (tool_editor,
446                                                             tool_item);
447 
448       index = gimp_container_get_child_index (container,
449                                               GIMP_OBJECT (tool_item));
450 
451       if (index > 0)
452         {
453           gimp_container_reorder (container,
454                                   GIMP_OBJECT (tool_item), 0);
455         }
456     }
457 }
458 
459 static void
gimp_tool_editor_lower_clicked(GtkButton * button,GimpToolEditor * tool_editor)460 gimp_tool_editor_lower_clicked (GtkButton      *button,
461                                 GimpToolEditor *tool_editor)
462 {
463   GimpToolItem *tool_item;
464 
465   tool_item = gimp_tool_editor_get_selected_tool_item (tool_editor);
466 
467   if (tool_item)
468     {
469       GimpContainer *container;
470       gint           index;
471 
472       container = gimp_tool_editor_get_tool_item_container (tool_editor,
473                                                             tool_item);
474 
475       index = gimp_container_get_child_index (container,
476                                               GIMP_OBJECT (tool_item));
477 
478       if (index + 1 < gimp_container_get_n_children (container))
479         {
480           gimp_container_reorder (container,
481                                   GIMP_OBJECT (tool_item), index + 1);
482         }
483     }
484 }
485 
486 static void
gimp_tool_editor_lower_extend_clicked(GtkButton * button,GdkModifierType mask,GimpToolEditor * tool_editor)487 gimp_tool_editor_lower_extend_clicked (GtkButton       *button,
488                                        GdkModifierType  mask,
489                                        GimpToolEditor  *tool_editor)
490 {
491   GimpToolItem *tool_item;
492 
493   tool_item = gimp_tool_editor_get_selected_tool_item (tool_editor);
494 
495   if (tool_item && (mask & GDK_SHIFT_MASK))
496     {
497       GimpContainer *container;
498       gint           index;
499 
500       container = gimp_tool_editor_get_tool_item_container (tool_editor,
501                                                             tool_item);
502 
503       index = gimp_container_get_n_children (container) - 1;
504       index = MAX (index, 0);
505 
506       gimp_container_reorder (container,
507                               GIMP_OBJECT (tool_item), index);
508     }
509 }
510 
511 static void
gimp_tool_editor_delete_clicked(GtkButton * button,GimpToolEditor * tool_editor)512 gimp_tool_editor_delete_clicked (GtkButton      *button,
513                                  GimpToolEditor *tool_editor)
514 {
515   GimpContainerView *container_view = GIMP_CONTAINER_VIEW (tool_editor);
516   GimpToolItem     *tool_item;
517 
518   tool_item = gimp_tool_editor_get_selected_tool_item (tool_editor);
519 
520   if (tool_item)
521     {
522       GimpContainer *src_container;
523       GimpContainer *dest_container;
524       gint           index;
525       gint           dest_index;
526 
527       src_container  = gimp_viewable_get_children (GIMP_VIEWABLE (tool_item));
528       dest_container = gimp_tool_editor_get_tool_item_container (tool_editor,
529                                                                  tool_item);
530 
531       if (! src_container)
532         return;
533 
534       index      = gimp_container_get_child_index (dest_container,
535                                                    GIMP_OBJECT (tool_item));
536       dest_index = index;
537 
538       g_object_ref (tool_item);
539 
540       gimp_container_freeze (src_container);
541       gimp_container_freeze (dest_container);
542 
543       gimp_container_remove (dest_container, GIMP_OBJECT (tool_item));
544 
545       while (! gimp_container_is_empty (src_container))
546         {
547           GimpObject *object = gimp_container_get_first_child (src_container);
548 
549           g_object_ref (object);
550 
551           gimp_container_remove (src_container,  object);
552           gimp_container_insert (dest_container, object, dest_index++);
553 
554           g_object_unref (object);
555         }
556 
557       gimp_container_thaw (dest_container);
558       gimp_container_thaw (src_container);
559 
560       gimp_container_view_select_item (
561         container_view,
562         GIMP_VIEWABLE (gimp_container_get_child_by_index (dest_container,
563                                                           index)));
564 
565       g_object_unref (tool_item);
566     }
567 }
568 
569 static void
gimp_tool_editor_reset_clicked(GtkButton * button,GimpToolEditor * tool_editor)570 gimp_tool_editor_reset_clicked (GtkButton      *button,
571                                 GimpToolEditor *tool_editor)
572 {
573   gimp_tools_reset (tool_editor->priv->context->gimp,
574                     tool_editor->priv->container,
575                     FALSE);
576 }
577 
578 static void
gimp_tool_editor_tool_item_notify(GimpToolItem * tool_item,GParamSpec * pspec,GimpToolEditor * tool_editor)579 gimp_tool_editor_tool_item_notify (GimpToolItem   *tool_item,
580                                    GParamSpec     *pspec,
581                                    GimpToolEditor *tool_editor)
582 {
583   GimpContainerTreeView *tree_view      = GIMP_CONTAINER_TREE_VIEW (tool_editor);
584   GimpContainerView     *container_view = GIMP_CONTAINER_VIEW (tool_editor);
585   GtkTreeIter           *iter;
586 
587   iter = gimp_container_view_lookup (container_view,
588                                      GIMP_VIEWABLE (tool_item));
589 
590   if (iter)
591     {
592       GtkTreePath *path;
593 
594       path = gtk_tree_model_get_path (tree_view->model, iter);
595 
596       gtk_tree_model_row_changed (tree_view->model, path, iter);
597 
598       gtk_tree_path_free (path);
599     }
600 }
601 
602 static void
gimp_tool_editor_eye_data_func(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,GtkTreeModel * tree_model,GtkTreeIter * iter,gpointer data)603 gimp_tool_editor_eye_data_func (GtkTreeViewColumn *tree_column,
604                                 GtkCellRenderer   *cell,
605                                 GtkTreeModel      *tree_model,
606                                 GtkTreeIter       *iter,
607                                 gpointer           data)
608 {
609   GimpViewRenderer *renderer;
610   GimpToolItem     *tool_item;
611 
612   gtk_tree_model_get (tree_model, iter,
613                       GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
614                       -1);
615 
616   tool_item = GIMP_TOOL_ITEM (renderer->viewable);
617 
618   g_object_set (cell,
619                 "active",       gimp_tool_item_get_visible (tool_item),
620                 "inconsistent", gimp_tool_item_get_visible (tool_item) &&
621                                 ! gimp_tool_item_get_shown (tool_item),
622                 NULL);
623 
624   g_object_unref (renderer);
625 }
626 
627 static void
gimp_tool_editor_eye_clicked(GtkCellRendererToggle * toggle,gchar * path_str,GdkModifierType state,GimpToolEditor * tool_editor)628 gimp_tool_editor_eye_clicked (GtkCellRendererToggle *toggle,
629                               gchar                 *path_str,
630                               GdkModifierType        state,
631                               GimpToolEditor        *tool_editor)
632 {
633   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (tool_editor);
634   GtkTreePath           *path;
635   GtkTreeIter            iter;
636 
637   path = gtk_tree_path_new_from_string (path_str);
638 
639   if (gtk_tree_model_get_iter (tree_view->model, &iter, path))
640     {
641       GimpViewRenderer *renderer;
642       GimpToolItem     *tool_item;
643       gboolean          active;
644 
645       gtk_tree_model_get (tree_view->model, &iter,
646                           GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
647                           -1);
648 
649       tool_item = GIMP_TOOL_ITEM (renderer->viewable);
650 
651       g_object_get (toggle,
652                     "active", &active,
653                     NULL);
654 
655       gimp_tool_item_set_visible (tool_item, ! active);
656 
657       g_object_unref (renderer);
658     }
659 
660   gtk_tree_path_free (path);
661 }
662 
663 static GimpToolItem *
gimp_tool_editor_get_selected_tool_item(GimpToolEditor * tool_editor)664 gimp_tool_editor_get_selected_tool_item (GimpToolEditor *tool_editor)
665 {
666   GimpContainerTreeView *tree_view = GIMP_CONTAINER_TREE_VIEW (tool_editor);
667 
668   if (tool_editor->priv->container)
669     {
670       GimpViewRenderer *renderer;
671       GimpToolItem     *tool_item;
672       GtkTreeSelection *selection;
673       GtkTreeModel     *model;
674       GtkTreeIter       iter;
675 
676       selection = gtk_tree_view_get_selection (tree_view->view);
677 
678       if (! gtk_tree_selection_get_selected (selection, &model, &iter))
679         return NULL;
680 
681       gtk_tree_model_get (model, &iter,
682                           GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
683                           -1);
684 
685       tool_item = GIMP_TOOL_ITEM (renderer->viewable);
686 
687       g_object_unref (renderer);
688 
689       return tool_item;
690     }
691 
692   return NULL;
693 }
694 
695 static GimpContainer *
gimp_tool_editor_get_tool_item_container(GimpToolEditor * tool_editor,GimpToolItem * tool_item)696 gimp_tool_editor_get_tool_item_container (GimpToolEditor *tool_editor,
697                                           GimpToolItem   *tool_item)
698 {
699   GimpViewable *parent;
700 
701   parent = gimp_viewable_get_parent (GIMP_VIEWABLE (tool_item));
702 
703   if (parent)
704     {
705       return gimp_viewable_get_children (parent);
706     }
707   else
708     {
709       return tool_editor->priv->container;
710     }
711 }
712 
713 static void
gimp_tool_editor_update_container(GimpToolEditor * tool_editor)714 gimp_tool_editor_update_container (GimpToolEditor *tool_editor)
715 {
716   GimpContainerView *container_view = GIMP_CONTAINER_VIEW (tool_editor);
717   GimpContainer     *container;
718   GimpContext       *context;
719 
720   g_clear_pointer (&tool_editor->priv->tool_item_notify_handler,
721                    gimp_tree_handler_disconnect);
722 
723   g_clear_pointer (&tool_editor->priv->initial_tool_state, g_free);
724 
725   container = gimp_container_view_get_container (container_view);
726   context   = gimp_container_view_get_context   (container_view);
727 
728   if (container && context)
729     {
730       GString          *string;
731       GimpConfigWriter *writer;
732 
733       tool_editor->priv->container = container;
734       tool_editor->priv->context   = context;
735 
736       tool_editor->priv->tool_item_notify_handler = gimp_tree_handler_connect (
737         container, "notify",
738         G_CALLBACK (gimp_tool_editor_tool_item_notify),
739         tool_editor);
740 
741       /* save initial tool order */
742       string = g_string_new (NULL);
743 
744       writer = gimp_config_writer_new_string (string);
745 
746       gimp_tools_serialize (context->gimp, container, writer);
747 
748       gimp_config_writer_finish (writer, NULL, NULL);
749 
750       tool_editor->priv->initial_tool_state = g_string_free (string, FALSE);
751     }
752 }
753 
754 static void
gimp_tool_editor_update_sensitivity(GimpToolEditor * tool_editor)755 gimp_tool_editor_update_sensitivity (GimpToolEditor *tool_editor)
756 {
757   GimpToolItem *tool_item;
758 
759   tool_item = gimp_tool_editor_get_selected_tool_item (tool_editor);
760 
761   if (tool_item)
762     {
763       GimpContainer *container;
764       gint           index;
765 
766       container = gimp_tool_editor_get_tool_item_container (tool_editor,
767                                                             tool_item);
768 
769       index = gimp_container_get_child_index (container,
770                                               GIMP_OBJECT (tool_item));
771 
772       gtk_widget_set_sensitive (
773         tool_editor->priv->new_group_button,
774         gimp_viewable_get_parent (GIMP_VIEWABLE (tool_item)) == NULL);
775 
776       gtk_widget_set_sensitive (
777         tool_editor->priv->raise_button,
778         index > 0);
779 
780       gtk_widget_set_sensitive (
781         tool_editor->priv->lower_button,
782         index < gimp_container_get_n_children (container) - 1);
783 
784       gtk_widget_set_sensitive (
785         tool_editor->priv->delete_button,
786         gimp_viewable_get_children (GIMP_VIEWABLE (tool_item)) != NULL);
787     }
788   else
789     {
790       gtk_widget_set_sensitive (tool_editor->priv->new_group_button, TRUE);
791       gtk_widget_set_sensitive (tool_editor->priv->raise_button,     FALSE);
792       gtk_widget_set_sensitive (tool_editor->priv->lower_button,     FALSE);
793       gtk_widget_set_sensitive (tool_editor->priv->delete_button,    FALSE);
794     }
795 }
796 
797 
798 /*  public functions  */
799 
800 GtkWidget *
gimp_tool_editor_new(GimpContainer * container,GimpContext * context,gint view_size,gint view_border_width)801 gimp_tool_editor_new (GimpContainer *container,
802                       GimpContext   *context,
803                       gint           view_size,
804                       gint           view_border_width)
805 {
806   GimpContainerView *container_view;
807 
808   g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
809   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
810 
811   container_view = g_object_new (GIMP_TYPE_TOOL_EDITOR,
812                                  "view-size",         view_size,
813                                  "view-border-width", view_border_width,
814                                  NULL);
815 
816   gimp_container_view_set_context     (container_view, context);
817   gimp_container_view_set_container   (container_view, container);
818   gimp_container_view_set_reorderable (container_view, TRUE);
819 
820   return GTK_WIDGET (container_view);
821 }
822 
823 /**
824  * gimp_tool_editor_revert_changes:
825  * @tool_editor:
826  *
827  * Reverts the tool order and visibility to the state at creation.
828  **/
829 void
gimp_tool_editor_revert_changes(GimpToolEditor * tool_editor)830 gimp_tool_editor_revert_changes (GimpToolEditor *tool_editor)
831 {
832   GScanner *scanner;
833 
834   g_return_if_fail (GIMP_IS_TOOL_EDITOR (tool_editor));
835 
836   scanner = gimp_scanner_new_string (tool_editor->priv->initial_tool_state, -1,
837                                      NULL);
838 
839   gimp_tools_deserialize (tool_editor->priv->context->gimp,
840                           tool_editor->priv->container,
841                           scanner);
842 
843   gimp_scanner_destroy (scanner);
844 }
845