67126a3e155954522ba16d18704879f7857813ec
[blender.git] / source / blender / editors / space_outliner / outliner_collections.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup spoutliner
19  */
20
21 #include <string.h>
22
23 #include "BLI_utildefines.h"
24 #include "BLI_listbase.h"
25
26 #include "DNA_collection_types.h"
27 #include "DNA_object_types.h"
28
29 #include "BKE_context.h"
30 #include "BKE_collection.h"
31 #include "BKE_layer.h"
32 #include "BKE_library.h"
33 #include "BKE_main.h"
34 #include "BKE_report.h"
35
36 #include "DEG_depsgraph.h"
37 #include "DEG_depsgraph_build.h"
38
39 #include "ED_object.h"
40 #include "ED_outliner.h"
41 #include "ED_screen.h"
42
43 #include "WM_api.h"
44 #include "WM_types.h"
45 #include "WM_message.h"
46
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49 #include "RNA_enum_types.h"
50
51 #include "UI_resources.h"
52
53 #include "outliner_intern.h" /* own include */
54
55 /* -------------------------------------------------------------------- */
56
57 bool outliner_is_collection_tree_element(const TreeElement *te)
58 {
59         TreeStoreElem *tselem = TREESTORE(te);
60
61         if (!tselem) {
62                 return false;
63         }
64
65         if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
66                 return true;
67         }
68         else if (tselem->type == 0 && te->idcode == ID_GR) {
69                 return true;
70         }
71
72         return false;
73 }
74
75 Collection *outliner_collection_from_tree_element(const TreeElement *te)
76 {
77         TreeStoreElem *tselem = TREESTORE(te);
78
79         if (!tselem) {
80                 return NULL;
81         }
82
83         if (tselem->type == TSE_LAYER_COLLECTION) {
84                 LayerCollection *lc = te->directdata;
85                 return lc->collection;
86         }
87         else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
88                 Scene *scene = (Scene *)tselem->id;
89                 return BKE_collection_master(scene);
90         }
91         else if (tselem->type == 0 && te->idcode == ID_GR) {
92                 return (Collection *)tselem->id;
93         }
94
95         return NULL;
96 }
97
98 TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata)
99 {
100         struct IDsSelectedData *data = customdata;
101         TreeStoreElem *tselem = TREESTORE(te);
102
103         if (outliner_is_collection_tree_element(te)) {
104                 BLI_addtail(&data->selected_array, BLI_genericNodeN(te));
105                 return TRAVERSE_CONTINUE;
106         }
107
108         if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) {
109                 return TRAVERSE_SKIP_CHILDS;
110         }
111
112         return TRAVERSE_CONTINUE;
113 }
114
115 TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
116 {
117         struct IDsSelectedData *data = customdata;
118         TreeStoreElem *tselem = TREESTORE(te);
119
120         if (outliner_is_collection_tree_element(te)) {
121                 return TRAVERSE_CONTINUE;
122         }
123
124         if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
125                 return TRAVERSE_SKIP_CHILDS;
126         }
127
128         BLI_addtail(&data->selected_array, BLI_genericNodeN(te));
129
130         return TRAVERSE_CONTINUE;
131 }
132
133 /* -------------------------------------------------------------------- */
134 /* Poll functions. */
135
136 bool ED_outliner_collections_editor_poll(bContext *C)
137 {
138         SpaceOutliner *so = CTX_wm_space_outliner(C);
139         return (so != NULL) && ELEM(so->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES);
140 }
141
142 static bool outliner_view_layer_collections_editor_poll(bContext *C)
143 {
144         SpaceOutliner *so = CTX_wm_space_outliner(C);
145         return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER);
146 }
147
148 /********************************* New Collection ****************************/
149
150 struct CollectionNewData
151 {
152         bool error;
153         Collection *collection;
154 };
155
156 static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
157 {
158         struct CollectionNewData *data = customdata;
159         Collection *collection = outliner_collection_from_tree_element(te);
160
161         if (!collection) {
162                 return TRAVERSE_SKIP_CHILDS;
163         }
164
165         if (data->collection != NULL) {
166                 data->error = true;
167                 return TRAVERSE_BREAK;
168         }
169
170         data->collection = collection;
171         return TRAVERSE_CONTINUE;
172 }
173
174 static int collection_new_exec(bContext *C, wmOperator *op)
175 {
176         SpaceOutliner *soops = CTX_wm_space_outliner(C);
177         ARegion *ar = CTX_wm_region(C);
178         Main *bmain = CTX_data_main(C);
179         Scene *scene = CTX_data_scene(C);
180         ViewLayer *view_layer = CTX_data_view_layer(C);
181
182         struct CollectionNewData data = {
183                 .error = false,
184                 .collection = NULL,
185         };
186
187         if (RNA_boolean_get(op->ptr, "nested")) {
188                 outliner_build_tree(bmain, scene, view_layer, soops, ar);
189
190                 outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data);
191
192                 if (data.error) {
193                         BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
194                         return OPERATOR_CANCELLED;
195                 }
196         }
197
198         if (data.collection == NULL) {
199                 data.collection = BKE_collection_master(scene);
200         }
201
202         BKE_collection_add(
203                     bmain,
204                     data.collection,
205                     NULL);
206
207         DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE);
208         DEG_relations_tag_update(bmain);
209
210         outliner_cleanup_tree(soops);
211         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
212         return OPERATOR_FINISHED;
213 }
214
215 void OUTLINER_OT_collection_new(wmOperatorType *ot)
216 {
217         /* identifiers */
218         ot->name = "New Collection";
219         ot->idname = "OUTLINER_OT_collection_new";
220         ot->description = "Add a new collection inside selected collection";
221
222         /* api callbacks */
223         ot->exec = collection_new_exec;
224         ot->poll = ED_outliner_collections_editor_poll;
225
226         /* flags */
227         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
228
229         /* properties */
230         PropertyRNA *prop = RNA_def_boolean(ot->srna, "nested", true, "Nested", "Add as child of selected collection");
231         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
232 }
233
234 /**************************** Delete Collection ******************************/
235
236 struct CollectionEditData {
237         Scene *scene;
238         SpaceOutliner *soops;
239         GSet *collections_to_edit;
240 };
241
242 static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata)
243 {
244         struct CollectionEditData *data = customdata;
245         Collection *collection = outliner_collection_from_tree_element(te);
246
247         if (!collection) {
248                 return TRAVERSE_SKIP_CHILDS;
249         }
250
251         if (collection->flag & COLLECTION_IS_MASTER) {
252                 /* skip - showing warning/error message might be misleading
253                  * when deleting multiple collections, so just do nothing */
254         }
255         else {
256                 /* Delete, duplicate and link don't edit children, those will come along
257                  * with the parents. */
258                 BLI_gset_add(data->collections_to_edit, collection);
259                 return TRAVERSE_SKIP_CHILDS;
260         }
261
262         return TRAVERSE_CONTINUE;
263 }
264
265 static int collection_delete_exec(bContext *C, wmOperator *op)
266 {
267         struct wmMsgBus *mbus = CTX_wm_message_bus(C);
268         Main *bmain = CTX_data_main(C);
269         Scene *scene = CTX_data_scene(C);
270         ViewLayer *view_layer = CTX_data_view_layer(C);
271         const Base *basact_prev = BASACT(view_layer);
272         SpaceOutliner *soops = CTX_wm_space_outliner(C);
273         struct CollectionEditData data = {.scene = scene, .soops = soops,};
274         bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
275
276         data.collections_to_edit = BLI_gset_ptr_new(__func__);
277
278         /* We first walk over and find the Collections we actually want to delete (ignoring duplicates). */
279         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
280
281         /* Effectively delete the collections. */
282         GSetIterator collections_to_edit_iter;
283         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
284                 Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
285
286                 /* Test in case collection got deleted as part of another one. */
287                 if (BLI_findindex(&bmain->collection, collection) != -1) {
288                         BKE_collection_delete(bmain, collection, hierarchy);
289                 }
290         }
291
292         BLI_gset_free(data.collections_to_edit, NULL);
293
294         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
295         DEG_relations_tag_update(bmain);
296
297         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
298
299         if (basact_prev != BASACT(view_layer)) {
300                 WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
301         }
302
303         return OPERATOR_FINISHED;
304 }
305
306 void OUTLINER_OT_collection_delete(wmOperatorType *ot)
307 {
308         /* identifiers */
309         ot->name = "Delete Collection";
310         ot->idname = "OUTLINER_OT_collection_delete";
311         ot->description = "Delete selected collections";
312
313         /* api callbacks */
314         ot->exec = collection_delete_exec;
315         ot->poll = ED_outliner_collections_editor_poll;
316
317         /* flags */
318         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
319
320         /* properties */
321         PropertyRNA *prop = RNA_def_boolean(ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
322         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
323 }
324
325 /****************************** Select Objects *******************************/
326
327 struct CollectionObjectsSelectData {
328         bool error;
329         LayerCollection *layer_collection;
330 };
331
332 static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata)
333 {
334         struct CollectionObjectsSelectData *data = customdata;
335         TreeStoreElem *tselem = TREESTORE(te);
336
337         switch (tselem->type) {
338                 case TSE_LAYER_COLLECTION:
339                         data->layer_collection = te->directdata;
340                         return TRAVERSE_BREAK;
341                 case TSE_R_LAYER:
342                 case TSE_SCENE_COLLECTION_BASE:
343                 case TSE_VIEW_COLLECTION_BASE:
344                         return TRAVERSE_CONTINUE;
345                 default:
346                         return TRAVERSE_SKIP_CHILDS;
347         }
348 }
349
350 static LayerCollection *outliner_active_layer_collection(bContext *C)
351 {
352         SpaceOutliner *soops = CTX_wm_space_outliner(C);
353
354         struct CollectionObjectsSelectData data = {
355                 .layer_collection = NULL,
356         };
357
358         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_layer_collection, &data);
359         return data.layer_collection;
360 }
361
362 static int collection_objects_select_exec(bContext *C, wmOperator *op)
363 {
364         ViewLayer *view_layer = CTX_data_view_layer(C);
365         LayerCollection *layer_collection = outliner_active_layer_collection(C);
366         bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect");
367
368         if (layer_collection == NULL) {
369                 return OPERATOR_CANCELLED;
370         }
371
372         BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
373
374         Scene *scene = CTX_data_scene(C);
375         DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
376         WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
377
378         return OPERATOR_FINISHED;
379 }
380
381 void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
382 {
383         /* identifiers */
384         ot->name = "Select Objects";
385         ot->idname = "OUTLINER_OT_collection_objects_select";
386         ot->description = "Select objects in collection";
387
388         /* api callbacks */
389         ot->exec = collection_objects_select_exec;
390         ot->poll = ED_outliner_collections_editor_poll;
391
392         /* flags */
393         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
394 }
395
396 void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot)
397 {
398         /* identifiers */
399         ot->name = "Deselect Objects";
400         ot->idname = "OUTLINER_OT_collection_objects_deselect";
401         ot->description = "Deselect objects in collection";
402
403         /* api callbacks */
404         ot->exec = collection_objects_select_exec;
405         ot->poll = ED_outliner_collections_editor_poll;
406
407         /* flags */
408         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
409 }
410
411 /************************** Duplicate Collection *****************************/
412
413 struct CollectionDuplicateData {
414         TreeElement *te;
415 };
416
417 static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata)
418 {
419         struct CollectionDuplicateData *data = customdata;
420         TreeStoreElem *tselem = TREESTORE(te);
421
422         switch (tselem->type) {
423                 case TSE_LAYER_COLLECTION:
424                         data->te = te;
425                         return TRAVERSE_BREAK;
426                 case TSE_R_LAYER:
427                 case TSE_SCENE_COLLECTION_BASE:
428                 case TSE_VIEW_COLLECTION_BASE:
429                 default:
430                         return TRAVERSE_CONTINUE;
431         }
432 }
433
434 static TreeElement *outliner_active_collection(bContext *C)
435 {
436         SpaceOutliner *soops = CTX_wm_space_outliner(C);
437
438         struct CollectionDuplicateData data = {
439                 .te = NULL,
440         };
441
442         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_collection, &data);
443         return data.te;
444 }
445
446 static int collection_duplicate_exec(bContext *C, wmOperator *op)
447 {
448         Main *bmain = CTX_data_main(C);
449         SpaceOutliner *soops = CTX_wm_space_outliner(C);
450         TreeElement *te = outliner_active_collection(C);
451
452         /* Can happen when calling from a key binding. */
453         if (te == NULL) {
454                 BKE_report(op->reports, RPT_ERROR, "No active collection");
455                 return OPERATOR_CANCELLED;
456         }
457
458         Collection *collection = outliner_collection_from_tree_element(te);
459         Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL;
460
461         if (collection->flag & COLLECTION_IS_MASTER) {
462                 BKE_report(op->reports, RPT_ERROR, "Can't duplicate the master collection");
463                 return OPERATOR_CANCELLED;
464         }
465
466         switch (soops->outlinevis) {
467                 case SO_SCENES:
468                 case SO_VIEW_LAYER:
469                 case SO_LIBRARIES:
470                         BKE_collection_copy(bmain, parent, collection);
471                         break;
472         }
473
474         DEG_relations_tag_update(bmain);
475         WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C));
476
477         return OPERATOR_FINISHED;
478 }
479
480 void OUTLINER_OT_collection_duplicate(wmOperatorType *ot)
481 {
482         /* identifiers */
483         ot->name = "Duplicate Collection";
484         ot->idname = "OUTLINER_OT_collection_duplicate";
485         ot->description = "Duplicate selected collections";
486
487         /* api callbacks */
488         ot->exec = collection_duplicate_exec;
489         ot->poll = ED_outliner_collections_editor_poll;
490
491         /* flags */
492         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
493 }
494
495 /**************************** Link Collection ******************************/
496
497 static int collection_link_exec(bContext *C, wmOperator *UNUSED(op))
498 {
499         Main *bmain = CTX_data_main(C);
500         Scene *scene = CTX_data_scene(C);
501         Collection *active_collection = CTX_data_layer_collection(C)->collection;
502         SpaceOutliner *soops = CTX_wm_space_outliner(C);
503         struct CollectionEditData data = {.scene = scene, .soops = soops,};
504
505         data.collections_to_edit = BLI_gset_ptr_new(__func__);
506
507         /* We first walk over and find the Collections we actually want to link (ignoring duplicates). */
508         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
509
510         /* Effectively link the collections. */
511         GSetIterator collections_to_edit_iter;
512         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
513                 Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
514                 BKE_collection_child_add(bmain, active_collection, collection);
515                 id_fake_user_clear(&collection->id);
516         }
517
518         BLI_gset_free(data.collections_to_edit, NULL);
519
520         DEG_id_tag_update(&active_collection->id, ID_RECALC_COPY_ON_WRITE);
521         DEG_relations_tag_update(bmain);
522
523         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
524
525         return OPERATOR_FINISHED;
526 }
527
528 void OUTLINER_OT_collection_link(wmOperatorType *ot)
529 {
530         /* identifiers */
531         ot->name = "Link Collection";
532         ot->idname = "OUTLINER_OT_collection_link";
533         ot->description = "Link selected collections to active scene";
534
535         /* api callbacks */
536         ot->exec = collection_link_exec;
537         ot->poll = ED_outliner_collections_editor_poll;
538
539         /* flags */
540         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
541 }
542
543 /************************** Instance Collection ******************************/
544
545 static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
546 {
547         Main *bmain = CTX_data_main(C);
548         Scene *scene = CTX_data_scene(C);
549         ViewLayer *view_layer = CTX_data_view_layer(C);
550         SpaceOutliner *soops = CTX_wm_space_outliner(C);
551         struct CollectionEditData data = {.scene = scene, .soops = soops,};
552
553         data.collections_to_edit = BLI_gset_ptr_new(__func__);
554
555         /* We first walk over and find the Collections we actually want to instance (ignoring duplicates). */
556         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
557
558         /* Find an active collection to add to, that doesn't give dependency cycles. */
559         LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
560
561         GSetIterator collections_to_edit_iter;
562         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
563                 Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
564
565                 while (BKE_collection_find_cycle(active_lc->collection, collection)) {
566                         active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
567                 }
568         }
569
570         /* Effectively instance the collections. */
571         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
572                 Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
573                 Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, 0);
574                 ob->instance_collection = collection;
575                 ob->transflag |= OB_DUPLICOLLECTION;
576                 id_lib_extern(&collection->id);
577         }
578
579         BLI_gset_free(data.collections_to_edit, NULL);
580
581         DEG_relations_tag_update(bmain);
582
583         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
584
585         return OPERATOR_FINISHED;
586 }
587
588 void OUTLINER_OT_collection_instance(wmOperatorType *ot)
589 {
590         /* identifiers */
591         ot->name = "Instance Collection";
592         ot->idname = "OUTLINER_OT_collection_instance";
593         ot->description = "Instance selected collections to active scene";
594
595         /* api callbacks */
596         ot->exec = collection_instance_exec;
597         ot->poll = ED_outliner_collections_editor_poll;
598
599         /* flags */
600         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
601 }
602
603 /************************** Exclude Collection ******************************/
604
605 static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata)
606 {
607         struct CollectionEditData *data = customdata;
608         TreeStoreElem *tselem = TREESTORE(te);
609
610         if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) {
611                 return TRAVERSE_CONTINUE;
612         }
613
614         LayerCollection *lc = te->directdata;
615
616         if (lc->collection->flag & COLLECTION_IS_MASTER) {
617                 /* skip - showing warning/error message might be misleading
618                  * when deleting multiple collections, so just do nothing */
619         }
620         else {
621                 /* Delete, duplicate and link don't edit children, those will come along
622                  * with the parents. */
623                 BLI_gset_add(data->collections_to_edit, lc);
624         }
625
626         return TRAVERSE_CONTINUE;
627 }
628
629 static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
630 {
631         /* Poll function so the right click menu show current state of selected collections. */
632         SpaceOutliner *soops = CTX_wm_space_outliner(C);
633         if (!(soops && soops->outlinevis == SO_VIEW_LAYER)) {
634                 return false;
635         }
636
637         Scene *scene = CTX_data_scene(C);
638         struct CollectionEditData data = {.scene = scene, .soops = soops,};
639         data.collections_to_edit = BLI_gset_ptr_new(__func__);
640         bool result = false;
641
642         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
643
644         GSetIterator collections_to_edit_iter;
645         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
646                 LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
647
648                 if (clear && (lc->flag & flag)) {
649                         result = true;
650                 }
651                 else if (!clear && !(lc->flag & flag)) {
652                         result = true;
653                 }
654         }
655
656         BLI_gset_free(data.collections_to_edit, NULL);
657         return result;
658 }
659
660 static bool collections_exclude_set_poll(bContext *C)
661 {
662         return collections_view_layer_poll(C, false, LAYER_COLLECTION_EXCLUDE);
663 }
664
665 static bool collections_exclude_clear_poll(bContext *C)
666 {
667         return collections_view_layer_poll(C, true, LAYER_COLLECTION_EXCLUDE);
668 }
669
670 static bool collections_holdout_set_poll(bContext *C)
671 {
672         return collections_view_layer_poll(C, false, LAYER_COLLECTION_HOLDOUT);
673 }
674
675 static bool collections_holdout_clear_poll(bContext *C)
676 {
677         return collections_view_layer_poll(C, true, LAYER_COLLECTION_HOLDOUT);
678 }
679
680 static bool collections_indirect_only_set_poll(bContext *C)
681 {
682         return collections_view_layer_poll(C, false, LAYER_COLLECTION_INDIRECT_ONLY);
683 }
684
685 static bool collections_indirect_only_clear_poll(bContext *C)
686 {
687         return collections_view_layer_poll(C, true, LAYER_COLLECTION_INDIRECT_ONLY);
688 }
689
690 static void layer_collection_flag_recursive_set(LayerCollection *lc, int flag)
691 {
692         for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
693                 if (lc->flag & flag) {
694                         nlc->flag |= flag;
695                 }
696                 else {
697                         nlc->flag &= ~flag;
698                 }
699
700                 layer_collection_flag_recursive_set(nlc, flag);
701         }
702 }
703
704 static int collection_view_layer_exec(bContext *C, wmOperator *op)
705 {
706         Main *bmain = CTX_data_main(C);
707         Scene *scene = CTX_data_scene(C);
708         ViewLayer *view_layer = CTX_data_view_layer(C);
709         SpaceOutliner *soops = CTX_wm_space_outliner(C);
710         struct CollectionEditData data = {.scene = scene, .soops = soops,};
711         bool clear = strstr(op->idname, "clear") != NULL;
712         int flag = strstr(op->idname, "holdout") ?       LAYER_COLLECTION_HOLDOUT :
713                    strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY :
714                                                          LAYER_COLLECTION_EXCLUDE;
715
716         data.collections_to_edit = BLI_gset_ptr_new(__func__);
717
718         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
719
720         GSetIterator collections_to_edit_iter;
721         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
722                 LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
723
724                 if (clear) {
725                         lc->flag &= ~flag;
726                 }
727                 else {
728                         lc->flag |= flag;
729                 }
730
731                 layer_collection_flag_recursive_set(lc, flag);
732         }
733
734         BLI_gset_free(data.collections_to_edit, NULL);
735
736         BKE_layer_collection_sync(scene, view_layer);
737         DEG_relations_tag_update(bmain);
738
739         WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
740
741         return OPERATOR_FINISHED;
742 }
743
744 void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot)
745 {
746         /* identifiers */
747         ot->name = "Set Exclude";
748         ot->idname = "OUTLINER_OT_collection_exclude_set";
749         ot->description = "Exclude collection from the active view layer";
750
751         /* api callbacks */
752         ot->exec = collection_view_layer_exec;
753         ot->poll = collections_exclude_set_poll;
754
755         /* flags */
756         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
757 }
758
759 void OUTLINER_OT_collection_exclude_clear(wmOperatorType *ot)
760 {
761         /* identifiers */
762         ot->name = "Clear Exclude";
763         ot->idname = "OUTLINER_OT_collection_exclude_clear";
764         ot->description = "Include collection in the active view layer";
765
766         /* api callbacks */
767         ot->exec = collection_view_layer_exec;
768         ot->poll = collections_exclude_clear_poll;
769
770         /* flags */
771         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
772 }
773
774 void OUTLINER_OT_collection_holdout_set(wmOperatorType *ot)
775 {
776         /* identifiers */
777         ot->name = "Set Holdout";
778         ot->idname = "OUTLINER_OT_collection_holdout_set";
779         ot->description = "Mask collection in the active view layer";
780
781         /* api callbacks */
782         ot->exec = collection_view_layer_exec;
783         ot->poll = collections_holdout_set_poll;
784
785         /* flags */
786         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
787 }
788
789 void OUTLINER_OT_collection_holdout_clear(wmOperatorType *ot)
790 {
791         /* identifiers */
792         ot->name = "Clear Holdout";
793         ot->idname = "OUTLINER_OT_collection_holdout_clear";
794         ot->description = "Clear masking of collection in the active view layer";
795
796         /* api callbacks */
797         ot->exec = collection_view_layer_exec;
798         ot->poll = collections_holdout_clear_poll;
799
800         /* flags */
801         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
802 }
803
804 void OUTLINER_OT_collection_indirect_only_set(wmOperatorType *ot)
805 {
806         /* identifiers */
807         ot->name = "Set Indirect Only";
808         ot->idname = "OUTLINER_OT_collection_indirect_only_set";
809         ot->description = "Set collection to only contribute indirectly (through shadows and reflections) in the view layer";
810
811         /* api callbacks */
812         ot->exec = collection_view_layer_exec;
813         ot->poll = collections_indirect_only_set_poll;
814
815         /* flags */
816         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
817 }
818
819 void OUTLINER_OT_collection_indirect_only_clear(wmOperatorType *ot)
820 {
821         /* identifiers */
822         ot->name = "Clear Indirect Only";
823         ot->idname = "OUTLINER_OT_collection_indirect_only_clear";
824         ot->description = "Clear collection contributing only indirectly in the view layer";
825
826         /* api callbacks */
827         ot->exec = collection_view_layer_exec;
828         ot->poll = collections_indirect_only_clear_poll;
829
830         /* flags */
831         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
832 }
833
834 /************************** Visibility Operators ******************************/
835
836 static int collection_isolate_exec(bContext *C, wmOperator *op)
837 {
838         Scene *scene = CTX_data_scene(C);
839         ViewLayer *view_layer = CTX_data_view_layer(C);
840         SpaceOutliner *soops = CTX_wm_space_outliner(C);
841         const bool extend = RNA_boolean_get(op->ptr, "extend");
842         bool depsgraph_changed = false;
843         struct CollectionEditData data = {.scene = scene, .soops = soops,};
844         data.collections_to_edit = BLI_gset_ptr_new(__func__);
845
846         /* Hide all collections before the isolate function - needed in order to support multiple selected collections. */
847         if (!extend) {
848                 LayerCollection *lc_master = view_layer->layer_collections.first;
849                 for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
850                         lc_iter->flag |= LAYER_COLLECTION_RESTRICT_VIEW;
851                         layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW);
852                 }
853         }
854
855         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
856
857         GSetIterator collections_to_edit_iter;
858         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
859                 LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
860                 depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, layer_collection, true);
861         }
862         BLI_gset_free(data.collections_to_edit, NULL);
863
864         BKE_layer_collection_sync(scene, view_layer);
865         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
866
867         if (depsgraph_changed) {
868                 DEG_relations_tag_update(CTX_data_main(C));
869         }
870
871         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
872         return OPERATOR_FINISHED;
873 }
874
875 static int collection_isolate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
876 {
877         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "extend");
878         if (!RNA_property_is_set(op->ptr, prop) && (event->shift)) {
879                 RNA_property_boolean_set(op->ptr, prop, true);
880         }
881         return collection_isolate_exec(C, op);
882 }
883
884 void OUTLINER_OT_collection_isolate(wmOperatorType *ot)
885 {
886         /* identifiers */
887         ot->name = "Isolate Collection";
888         ot->idname = "OUTLINER_OT_collection_isolate";
889         ot->description = "Hide all but this collection and its parents";
890
891         /* api callbacks */
892         ot->exec = collection_isolate_exec;
893         ot->invoke = collection_isolate_invoke;
894         ot->poll = ED_outliner_collections_editor_poll;
895
896         /* flags */
897         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
898
899         /* properties */
900         PropertyRNA *prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend current visible collections");
901         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
902 }
903
904 static bool collection_show_poll(bContext *C)
905 {
906         return collections_view_layer_poll(C, true, LAYER_COLLECTION_RESTRICT_VIEW);
907 }
908
909 static bool collection_hide_poll(bContext *C)
910 {
911         return collections_view_layer_poll(C, false, LAYER_COLLECTION_RESTRICT_VIEW);
912 }
913
914 static bool collection_inside_poll(bContext *C)
915 {
916         if (!ED_outliner_collections_editor_poll(C)) {
917                 return false;
918         }
919         return outliner_active_layer_collection(C) != NULL;
920 }
921
922 static int collection_visibility_exec(bContext *C, wmOperator *op)
923 {
924         Scene *scene = CTX_data_scene(C);
925         ViewLayer *view_layer = CTX_data_view_layer(C);
926         SpaceOutliner *soops = CTX_wm_space_outliner(C);
927         const bool is_inside = strstr(op->idname, "inside") != NULL;
928         const bool show = strstr(op->idname, "show") != NULL;
929         bool depsgraph_changed = false;
930         struct CollectionEditData data = {.scene = scene, .soops = soops,};
931         data.collections_to_edit = BLI_gset_ptr_new(__func__);
932
933         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
934
935         GSetIterator collections_to_edit_iter;
936         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
937                 LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
938                 depsgraph_changed |= BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside);
939         }
940         BLI_gset_free(data.collections_to_edit, NULL);
941
942         BKE_layer_collection_sync(scene, view_layer);
943         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
944
945         if (depsgraph_changed) {
946                 DEG_relations_tag_update(CTX_data_main(C));
947         }
948
949         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
950         return OPERATOR_FINISHED;
951 }
952
953 void OUTLINER_OT_collection_show(wmOperatorType *ot)
954 {
955         /* identifiers */
956         ot->name = "Show Collection";
957         ot->idname = "OUTLINER_OT_collection_show";
958         ot->description = "Show the collection in this view layer";
959
960         /* api callbacks */
961         ot->exec = collection_visibility_exec;
962         ot->poll = collection_show_poll;
963
964         /* flags */
965         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
966 }
967
968 void OUTLINER_OT_collection_hide(wmOperatorType *ot)
969 {
970         /* identifiers */
971         ot->name = "Hide Collection";
972         ot->idname = "OUTLINER_OT_collection_hide";
973         ot->description = "Hide the collection in this view layer";
974
975         /* api callbacks */
976         ot->exec = collection_visibility_exec;
977         ot->poll = collection_hide_poll;
978
979         /* flags */
980         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
981 }
982
983 void OUTLINER_OT_collection_show_inside(wmOperatorType *ot)
984 {
985         /* identifiers */
986         ot->name = "Show Inside Collection";
987         ot->idname = "OUTLINER_OT_collection_show_inside";
988         ot->description = "Show all the objects and collections inside the collection";
989
990         /* api callbacks */
991         ot->exec = collection_visibility_exec;
992         ot->poll = collection_inside_poll;
993
994         /* flags */
995         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
996 }
997
998 void OUTLINER_OT_collection_hide_inside(wmOperatorType *ot)
999 {
1000         /* identifiers */
1001         ot->name = "Hide Inside Collection";
1002         ot->idname = "OUTLINER_OT_collection_hide_inside";
1003         ot->description = "Hide all the objects and collections inside the collection";
1004
1005         /* api callbacks */
1006         ot->exec = collection_visibility_exec;
1007         ot->poll = collection_inside_poll;
1008
1009         /* flags */
1010         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1011 }
1012
1013 static bool collection_flag_poll(bContext *C, bool clear, int flag)
1014 {
1015         if (!ED_outliner_collections_editor_poll(C)) {
1016                 return false;
1017         }
1018
1019         TreeElement *te = outliner_active_collection(C);
1020         if (te == NULL) {
1021                 return false;
1022         }
1023
1024         Collection *collection = outliner_collection_from_tree_element(te);
1025         if (collection == NULL) {
1026                 return false;
1027         }
1028
1029         if (clear && (collection->flag & flag)) {
1030                 return true;
1031         }
1032         else if (!clear && !(collection->flag & flag)) {
1033                 return true;
1034         }
1035
1036         return false;
1037 }
1038
1039 static bool collection_enable_poll(bContext *C)
1040 {
1041         return collection_flag_poll(C, true, COLLECTION_RESTRICT_VIEW);
1042 }
1043
1044 static bool collection_disable_poll(bContext *C)
1045 {
1046         return collection_flag_poll(C, false, COLLECTION_RESTRICT_VIEW);
1047 }
1048
1049 static bool collection_enable_render_poll(bContext *C)
1050 {
1051         return collection_flag_poll(C, true, COLLECTION_RESTRICT_RENDER);
1052 }
1053
1054 static bool collection_disable_render_poll(bContext *C)
1055 {
1056         return collection_flag_poll(C, false, COLLECTION_RESTRICT_RENDER);
1057 }
1058
1059 static int collection_flag_exec(bContext *C, wmOperator *op)
1060 {
1061         Scene *scene = CTX_data_scene(C);
1062         ViewLayer *view_layer = CTX_data_view_layer(C);
1063         SpaceOutliner *soops = CTX_wm_space_outliner(C);
1064         const bool is_render = strstr(op->idname, "render");
1065         const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable");
1066         int flag = is_render ? COLLECTION_RESTRICT_RENDER : COLLECTION_RESTRICT_VIEW;
1067         struct CollectionEditData data = {.scene = scene, .soops = soops,};
1068         data.collections_to_edit = BLI_gset_ptr_new(__func__);
1069         const bool has_layer_collection = soops->outlinevis == SO_VIEW_LAYER;
1070
1071         if (has_layer_collection) {
1072                 outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
1073                 GSetIterator collections_to_edit_iter;
1074                 GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
1075                         LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
1076                         Collection *collection = layer_collection->collection;
1077                         if (ID_IS_LINKED(collection)) {
1078                                 continue;
1079                         }
1080                         if (clear) {
1081                                 collection->flag &= ~flag;
1082                         }
1083                         else {
1084                                 collection->flag |= flag;
1085                         }
1086
1087                         /* Make sure (at least for this view layer) the collection is visible. */
1088                         if (clear && !is_render) {
1089                                 layer_collection->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW;
1090                         }
1091                 }
1092                 BLI_gset_free(data.collections_to_edit, NULL);
1093         }
1094         else {
1095                 outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
1096                 GSetIterator collections_to_edit_iter;
1097                 GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
1098                         Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
1099
1100                         if (clear) {
1101                                 collection->flag &= ~flag;
1102                         }
1103                         else {
1104                                 collection->flag |= flag;
1105                         }
1106                 }
1107                 BLI_gset_free(data.collections_to_edit, NULL);
1108         }
1109
1110         BKE_layer_collection_sync(scene, view_layer);
1111         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
1112
1113         if (!is_render) {
1114                 DEG_relations_tag_update(CTX_data_main(C));
1115         }
1116
1117         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
1118         return OPERATOR_FINISHED;
1119 }
1120
1121 void OUTLINER_OT_collection_enable(wmOperatorType *ot)
1122 {
1123         /* identifiers */
1124         ot->name = "Enable Collection";
1125         ot->idname = "OUTLINER_OT_collection_enable";
1126         ot->description = "Enable viewport drawing in the view layers";
1127
1128         /* api callbacks */
1129         ot->exec = collection_flag_exec;
1130         ot->poll = collection_enable_poll;
1131
1132         /* flags */
1133         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1134 }
1135
1136 void OUTLINER_OT_collection_disable(wmOperatorType *ot)
1137 {
1138         /* identifiers */
1139         ot->name = "Disable Collection";
1140         ot->idname = "OUTLINER_OT_collection_disable";
1141         ot->description = "Disable viewport drawing in the view layers";
1142
1143         /* api callbacks */
1144         ot->exec = collection_flag_exec;
1145         ot->poll = collection_disable_poll;
1146
1147         /* flags */
1148         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1149 }
1150
1151 void OUTLINER_OT_collection_enable_render(wmOperatorType *ot)
1152 {
1153         /* identifiers */
1154         ot->name = "Enable Collection in Render";
1155         ot->idname = "OUTLINER_OT_collection_enable_render";
1156         ot->description = "Render the collection";
1157
1158         /* api callbacks */
1159         ot->exec = collection_flag_exec;
1160         ot->poll = collection_enable_render_poll;
1161
1162         /* flags */
1163         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1164 }
1165
1166 void OUTLINER_OT_collection_disable_render(wmOperatorType *ot)
1167 {
1168         /* identifiers */
1169         ot->name = "Disable Collection in Render";
1170         ot->idname = "OUTLINER_OT_collection_disable_render";
1171         ot->description = "Do not render this collection";
1172
1173         /* api callbacks */
1174         ot->exec = collection_flag_exec;
1175         ot->poll = collection_disable_render_poll;
1176
1177         /* flags */
1178         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1179 }
1180
1181 struct OutlinerHideEditData {
1182         Scene *scene;
1183         ViewLayer *view_layer;
1184         SpaceOutliner *soops;
1185         GSet *collections_to_edit;
1186         GSet *bases_to_edit;
1187 };
1188
1189 static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata)
1190 {
1191         struct OutlinerHideEditData *data = customdata;
1192         TreeStoreElem *tselem = TREESTORE(te);
1193
1194         if (tselem == NULL) {
1195                 return TRAVERSE_CONTINUE;
1196         }
1197
1198         if (tselem->type == TSE_LAYER_COLLECTION) {
1199                 LayerCollection *lc = te->directdata;
1200
1201                 if (lc->collection->flag & COLLECTION_IS_MASTER) {
1202                         /* Skip - showing warning/error message might be misleading
1203                          * when deleting multiple collections, so just do nothing. */
1204                 }
1205                 else {
1206                         /* Delete, duplicate and link don't edit children,
1207                          * those will come along with the parents. */
1208                         BLI_gset_add(data->collections_to_edit, lc);
1209                 }
1210         }
1211         else if (tselem->type == 0 && te->idcode == ID_OB) {
1212                 Object *ob = (Object *)tselem->id;
1213                 Base *base = BKE_view_layer_base_find(data->view_layer, ob);
1214                 BLI_gset_add(data->bases_to_edit, base);
1215         }
1216
1217         return TRAVERSE_CONTINUE;
1218 }
1219
1220 static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
1221 {
1222         Scene *scene = CTX_data_scene(C);
1223         ViewLayer *view_layer = CTX_data_view_layer(C);
1224         SpaceOutliner *soops = CTX_wm_space_outliner(C);
1225         struct OutlinerHideEditData data = {.scene = scene, .view_layer = view_layer, .soops = soops,};
1226         data.collections_to_edit = BLI_gset_ptr_new("outliner_hide_exec__collections_to_edit");
1227         data.bases_to_edit = BLI_gset_ptr_new("outliner_hide_exec__bases_to_edit");
1228
1229         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_hide_find_data_to_edit, &data);
1230
1231         GSetIterator collections_to_edit_iter;
1232         GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
1233                 LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
1234                 BKE_layer_collection_set_visible(view_layer, layer_collection, false, false);
1235         }
1236         BLI_gset_free(data.collections_to_edit, NULL);
1237
1238         GSetIterator bases_to_edit_iter;
1239         GSET_ITER(bases_to_edit_iter, data.bases_to_edit) {
1240                 Base *base = BLI_gsetIterator_getKey(&bases_to_edit_iter);
1241                 base->flag |= BASE_HIDDEN;
1242         }
1243         BLI_gset_free(data.bases_to_edit, NULL);
1244
1245         BKE_layer_collection_sync(scene, view_layer);
1246         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
1247
1248         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
1249         return OPERATOR_FINISHED;
1250 }
1251
1252 void OUTLINER_OT_hide(wmOperatorType *ot)
1253 {
1254         /* identifiers */
1255         ot->name = "Hide";
1256         ot->idname = "OUTLINER_OT_hide";
1257         ot->description = "Hide selected objects and collections";
1258
1259         /* api callbacks */
1260         ot->exec = outliner_hide_exec;
1261         ot->poll = outliner_view_layer_collections_editor_poll;
1262
1263         /* flags */
1264         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1265 }
1266
1267 static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
1268 {
1269         Scene *scene = CTX_data_scene(C);
1270         ViewLayer *view_layer = CTX_data_view_layer(C);
1271
1272         /* Unhide all the collections. */
1273         LayerCollection *lc_master = view_layer->layer_collections.first;
1274         for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
1275                 lc_iter->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW;
1276                 layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW);
1277         }
1278
1279         /* Unhide all objects. */
1280         for (Base *base = view_layer->object_bases.first; base; base = base->next) {
1281                 base->flag &= ~BASE_HIDDEN;
1282         }
1283
1284         BKE_layer_collection_sync(scene, view_layer);
1285         DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
1286
1287         WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
1288         return OPERATOR_FINISHED;
1289 }
1290
1291 void OUTLINER_OT_unhide_all(wmOperatorType *ot)
1292 {
1293         /* identifiers */
1294         ot->name = "Unhide All";
1295         ot->idname = "OUTLINER_OT_unhide_all";
1296         ot->description = "Unhide all objects and collections";
1297
1298         /* api callbacks */
1299         ot->exec = outliner_unhide_all_exec;
1300         ot->poll = outliner_view_layer_collections_editor_poll;
1301
1302         /* flags */
1303         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1304 }
1305
1306 /**
1307  * Populates the \param objects: ListBase with all the outliner selected objects
1308  * We store it as (Object *)LinkData->data
1309  * \param objects: expected to be empty
1310  */
1311 void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
1312 {
1313         SpaceOutliner *soops = CTX_wm_space_outliner(C);
1314         struct IDsSelectedData data = {{NULL}};
1315         outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
1316         LISTBASE_FOREACH (LinkData *, link, &data.selected_array) {
1317                 TreeElement *ten_selected = (TreeElement *)link->data;
1318                 Object *ob = (Object *)TREESTORE(ten_selected)->id;
1319                 BLI_addtail(objects, BLI_genericNodeN(ob));
1320         }
1321         BLI_freelistN(&data.selected_array);
1322 }