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