Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_outliner/outliner_collections.c')
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c1056
1 files changed, 357 insertions, 699 deletions
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index 4ea2c243365..9bb3871c247 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -24,9 +24,14 @@
* \ingroup spoutliner
*/
+#include <string.h>
+
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
+#include "DNA_group_types.h"
+#include "DNA_object_types.h"
+
#include "BKE_context.h"
#include "BKE_collection.h"
#include "BKE_layer.h"
@@ -36,9 +41,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DNA_group_types.h"
-#include "DNA_object_types.h"
-
+#include "ED_object.h"
#include "ED_screen.h"
#include "WM_api.h"
@@ -52,26 +55,44 @@
#include "outliner_intern.h" /* own include */
-/* Prototypes. */
-static int collection_delete_exec(struct bContext *C, struct wmOperator *op);
-
/* -------------------------------------------------------------------- */
-static LayerCollection *outliner_collection_active(bContext *C)
+bool outliner_is_collection_tree_element(const TreeElement *te)
{
- return CTX_data_layer_collection(C);
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (!tselem) {
+ return false;
+ }
+
+ if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
+ return true;
+ }
+ else if (tselem->type == 0 && te->idcode == ID_GR) {
+ return true;
+ }
+
+ return false;
}
-SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te)
+Collection *outliner_collection_from_tree_element(const TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == TSE_SCENE_COLLECTION) {
- return te->directdata;
+ if (!tselem) {
+ return false;
}
- else if (tselem->type == TSE_LAYER_COLLECTION) {
+
+ if (tselem->type == TSE_LAYER_COLLECTION) {
LayerCollection *lc = te->directdata;
- return lc->scene_collection;
+ return lc->collection;
+ }
+ else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
+ Scene *scene = (Scene*)tselem->id;
+ return BKE_collection_master(scene);
+ }
+ else if (tselem->type == 0 && te->idcode == ID_GR) {
+ return (Collection*)tselem->id;
}
return NULL;
@@ -83,956 +104,593 @@ SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te)
static int collections_editor_poll(bContext *C)
{
SpaceOops *so = CTX_wm_space_outliner(C);
- return (so != NULL) && (so->outlinevis == SO_COLLECTIONS);
+ return (so != NULL) && ELEM(so->outlinevis, SO_VIEW_LAYER, SO_SCENES);
}
-static int outliner_objects_collection_poll(bContext *C)
-{
- SpaceOops *so = CTX_wm_space_outliner(C);
- if (so == NULL) {
- return 0;
- }
-
- /* Groups don't support filtering. */
- if ((so->outlinevis != SO_GROUPS) && (so->filter & SO_FILTER_NO_COLLECTION)) {
- return 0;
- }
+/********************************* New Collection ****************************/
- return ELEM(so->outlinevis, SO_COLLECTIONS, SO_GROUPS);
-}
-
-/* -------------------------------------------------------------------- */
-/* collection manager operators */
-
-/**
- * Recursively get the collection for a given index
- */
-static SceneCollection *scene_collection_from_index(ListBase *lb, const int number, int *i)
+struct CollectionNewData
{
- for (SceneCollection *sc = lb->first; sc; sc = sc->next) {
- if (*i == number) {
- return sc;
- }
+ bool error;
+ Collection *collection;
+};
- (*i)++;
+static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
+{
+ struct CollectionNewData *data = customdata;
+ Collection *collection = outliner_collection_from_tree_element(te);
- SceneCollection *sc_nested = scene_collection_from_index(&sc->scene_collections, number, i);
- if (sc_nested) {
- return sc_nested;
- }
+ if (!collection) {
+ return TRAVERSE_SKIP_CHILDS;
}
- return NULL;
-}
-typedef struct TreeElementFindData {
- SceneCollection *collection;
- TreeElement *r_result_te;
-} TreeElementFindData;
-
-static TreeTraversalAction tree_element_find_by_scene_collection_cb(TreeElement *te, void *customdata)
-{
- TreeElementFindData *data = customdata;
- const SceneCollection *current_element_sc = outliner_scene_collection_from_tree_element(te);
-
- if (current_element_sc == data->collection) {
- data->r_result_te = te;
+ if (data->collection != NULL) {
+ data->error = true;
return TRAVERSE_BREAK;
}
+ data->collection = collection;
return TRAVERSE_CONTINUE;
}
-static TreeElement *outliner_tree_element_from_layer_collection_index(
- SpaceOops *soops, ViewLayer *view_layer,
- const int index)
+static int collection_new_exec(bContext *C, wmOperator *op)
{
- LayerCollection *lc = BKE_layer_collection_from_index(view_layer, index);
-
- if (lc == NULL) {
- return NULL;
- }
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
- /* Find the tree element containing the LayerCollection's scene_collection. */
- TreeElementFindData data = {
- .collection = lc->scene_collection,
- .r_result_te = NULL,
+ struct CollectionNewData data = {
+ .error = false,
+ .collection = NULL,
};
- outliner_tree_traverse(soops, &soops->tree, 0, 0, tree_element_find_by_scene_collection_cb, &data);
-
- return data.r_result_te;
-}
-static int collection_link_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- SceneCollection *sc_master = BKE_collection_master(&scene->id);
- SceneCollection *sc;
+ if (RNA_boolean_get(op->ptr, "nested")) {
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data);
- int scene_collection_index = RNA_enum_get(op->ptr, "scene_collection");
- if (scene_collection_index == 0) {
- sc = sc_master;
- }
- else {
- int index = 1;
- sc = scene_collection_from_index(&sc_master->scene_collections, scene_collection_index, &index);
- BLI_assert(sc);
+ if (data.error) {
+ BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
+ return OPERATOR_CANCELLED;
+ }
}
- BKE_collection_link(view_layer, sc);
-
- DEG_relations_tag_update(CTX_data_main(C));
+ if (!data.collection && (soops->outlinevis == SO_VIEW_LAYER)) {
+ data.collection = BKE_collection_master(scene);
+ }
- /* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&scene->id, 0);
+ BKE_collection_add(
+ bmain,
+ data.collection,
+ NULL);
+ outliner_cleanup_tree(soops);
+ DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
return OPERATOR_FINISHED;
}
-static int collection_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Scene *scene = CTX_data_scene(C);
- SceneCollection *master_collection = BKE_collection_master(&scene->id);
- if (master_collection->scene_collections.first == NULL) {
- RNA_enum_set(op->ptr, "scene_collection", 0);
- return collection_link_exec(C, op);
- }
- else {
- return WM_enum_search_invoke(C, op, event);
- }
-}
-
-static void collection_scene_collection_itemf_recursive(
- EnumPropertyItem *tmp, EnumPropertyItem **item, int *totitem, int *value, SceneCollection *sc)
-{
- tmp->value = *value;
- tmp->icon = ICON_COLLAPSEMENU;
- tmp->identifier = sc->name;
- tmp->name = sc->name;
- RNA_enum_item_add(item, totitem, tmp);
-
- (*value)++;
-
- for (SceneCollection *ncs = sc->scene_collections.first; ncs; ncs = ncs->next) {
- collection_scene_collection_itemf_recursive(tmp, item, totitem, value, ncs);
- }
-}
-
-static const EnumPropertyItem *collection_scene_collection_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem tmp = {0, "", 0, "", ""};
- EnumPropertyItem *item = NULL;
- int value = 0, totitem = 0;
-
- Scene *scene = CTX_data_scene(C);
- SceneCollection *sc = BKE_collection_master(&scene->id);
-
- collection_scene_collection_itemf_recursive(&tmp, &item, &totitem, &value, sc);
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-void OUTLINER_OT_collection_link(wmOperatorType *ot)
+void OUTLINER_OT_collection_new(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
- ot->name = "Link Collection";
- ot->idname = "OUTLINER_OT_collection_link";
- ot->description = "Link a new collection to the active layer";
+ ot->name = "New Collection";
+ ot->idname = "OUTLINER_OT_collection_new";
+ ot->description = "Add a new collection inside selected collection";
/* api callbacks */
- ot->exec = collection_link_exec;
- ot->invoke = collection_link_invoke;
+ ot->exec = collection_new_exec;
+ ot->poll = collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_enum(ot->srna, "scene_collection", DummyRNA_NULL_items, 0, "Scene Collection", "");
- RNA_def_enum_funcs(prop, collection_scene_collection_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
+ /* properties */
+ PropertyRNA *prop = RNA_def_boolean(ot->srna, "nested", true, "Nested", "Add as child of selected collection");;
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/**
- * Returns true if selected element is a collection directly
- * linked to the active ViewLayer (not a nested collection)
- */
-static int collection_unlink_poll(bContext *C)
+/**************************** Delete Collection ******************************/
+
+struct CollectionEditData {
+ Scene *scene;
+ SpaceOops *soops;
+ GSet *collections_to_edit;
+};
+
+static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata)
{
- if (collections_editor_poll(C) == 0) {
- return 0;
- }
+ struct CollectionEditData *data = customdata;
+ Collection *collection = outliner_collection_from_tree_element(te);
- LayerCollection *lc = outliner_collection_active(C);
+ if (!collection) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
- if (lc == NULL) {
- return 0;
+ if (collection == BKE_collection_master(data->scene)) {
+ /* skip - showing warning/error message might be missleading
+ * when deleting multiple collections, so just do nothing */
+ }
+ else {
+ /* Delete, duplicate and link don't edit children, those will come along
+ * with the parents. */
+ BLI_gset_add(data->collections_to_edit, collection);
+ return TRAVERSE_SKIP_CHILDS;
}
- ViewLayer *view_layer = CTX_data_view_layer(C);
- return BLI_findindex(&view_layer->layer_collections, lc) != -1 ? 1 : 0;
+ return TRAVERSE_CONTINUE;
}
-static int collection_unlink_exec(bContext *C, wmOperator *op)
+static int collection_delete_exec(bContext *C, wmOperator *op)
{
- LayerCollection *lc = outliner_collection_active(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
+ bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
- if (lc == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Active element is not a collection");
- return OPERATOR_CANCELLED;
- }
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_collection_unlink(view_layer, lc);
+ /* We first walk over and find the Collections we actually want to delete (ignoring duplicates). */
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
- if (soops) {
- outliner_cleanup_tree(soops);
+ /* Effectively delete the collections. */
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ /* TODO: what if collection was child and got deleted in the meantime? */
+ Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ BKE_collection_delete(bmain, collection, hierarchy);
}
- DEG_relations_tag_update(CTX_data_main(C));
+ BLI_gset_free(data.collections_to_edit, NULL);
+
+ DEG_relations_tag_update(bmain);
/* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&CTX_data_scene(C)->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
- return OPERATOR_FINISHED;
-}
-
-void OUTLINER_OT_collection_unlink(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Unlink Collection";
- ot->idname = "OUTLINER_OT_collection_unlink";
- ot->description = "Unlink collection from the active layer";
-
- /* api callbacks */
- ot->exec = collection_unlink_exec;
- ot->poll = collection_unlink_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/**********************************************************************************/
-/* Add new collection. */
-static int collection_new_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- SceneCollection *scene_collection_parent = BKE_collection_master(&scene->id);
- SceneCollection *scene_collection = BKE_collection_add(&scene->id, scene_collection_parent, COLLECTION_TYPE_NONE, NULL);
- BKE_collection_link(view_layer, scene_collection);
-
- DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_collection_new(wmOperatorType *ot)
+void OUTLINER_OT_collection_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "New Collection";
- ot->idname = "OUTLINER_OT_collection_new";
- ot->description = "Add a new collection to the scene";
+ ot->name = "Delete Collection";
+ ot->idname = "OUTLINER_OT_collection_delete";
+ ot->description = "Delete selected collections";
/* api callbacks */
- ot->exec = collection_new_exec;
+ ot->exec = collection_delete_exec;
+ ot->poll = collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop = RNA_def_boolean(ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/**********************************************************************************/
-/* Add new nested collection. */
+/****************************** Select Objects *******************************/
-struct CollectionNewData
-{
+struct CollectionObjectsSelectData {
bool error;
- SceneCollection *scene_collection;
+ LayerCollection *layer_collection;
};
-static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
+static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata)
{
- struct CollectionNewData *data = customdata;
- SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
-
- if (!scene_collection) {
- return TRAVERSE_SKIP_CHILDS;
- }
+ struct CollectionObjectsSelectData *data = customdata;
+ TreeStoreElem *tselem = TREESTORE(te);
- if (data->scene_collection != NULL) {
- data->error = true;
- return TRAVERSE_BREAK;
+ switch (tselem->type) {
+ case TSE_LAYER_COLLECTION:
+ data->layer_collection = te->directdata;
+ return TRAVERSE_BREAK;
+ case TSE_R_LAYER:
+ case TSE_SCENE_COLLECTION_BASE:
+ case TSE_VIEW_COLLECTION_BASE:
+ return TRAVERSE_CONTINUE;
+ default:
+ return TRAVERSE_SKIP_CHILDS;
}
-
- data->scene_collection = scene_collection;
- return TRAVERSE_CONTINUE;
}
-static int collection_nested_new_exec(bContext *C, wmOperator *op)
+static LayerCollection *outliner_active_layer_collection(bContext *C)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- struct CollectionNewData data = {
- .error = false,
- .scene_collection = NULL,
+ struct CollectionObjectsSelectData data = {
+ .layer_collection = NULL,
};
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data);
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_layer_collection, &data);
+ return data.layer_collection;
+}
+
+static int collection_objects_select_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *layer_collection = outliner_active_layer_collection(C);
+ bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect");
- if (data.error) {
- BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
+ if (layer_collection == NULL) {
return OPERATOR_CANCELLED;
}
- BKE_collection_add(
- &scene->id,
- data.scene_collection,
- COLLECTION_TYPE_NONE,
- NULL);
+ BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
+ WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
- outliner_cleanup_tree(soops);
- DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_collection_nested_new(wmOperatorType *ot)
+void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "New Nested Collection";
- ot->idname = "OUTLINER_OT_collection_nested_new";
- ot->description = "Add a new collection inside selected collection";
+ ot->name = "Select Objects";
+ ot->idname = "OUTLINER_OT_collection_objects_select";
+ ot->description = "Select objects in collection";
/* api callbacks */
- ot->exec = collection_nested_new_exec;
+ ot->exec = collection_objects_select_exec;
ot->poll = collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/**********************************************************************************/
-/* Delete selected collection. */
-
-void OUTLINER_OT_collection_delete_selected(wmOperatorType *ot)
+void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete Selected Collections";
- ot->idname = "OUTLINER_OT_collection_delete_selected";
- ot->description = "Delete all the selected collections";
+ ot->name = "Deselect Objects";
+ ot->idname = "OUTLINER_OT_collection_objects_deselect";
+ ot->description = "Deselect objects in collection";
/* api callbacks */
- ot->exec = collection_delete_exec;
+ ot->exec = collection_objects_select_exec;
ot->poll = collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/**********************************************************************************/
-/* Add new selected objects. */
+/************************** Duplicate Collection *****************************/
-struct SceneCollectionSelectedData {
- ListBase scene_collections_array;
+struct CollectionDuplicateData {
+ TreeElement *te;
};
-static TreeTraversalAction collection_find_selected_scene_collections(TreeElement *te, void *customdata)
+static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata)
{
- struct SceneCollectionSelectedData *data = customdata;
- SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
+ struct CollectionDuplicateData *data = customdata;
+ TreeStoreElem *tselem = TREESTORE(te);
- if (!scene_collection) {
- return TRAVERSE_SKIP_CHILDS;
+ switch (tselem->type) {
+ case TSE_LAYER_COLLECTION:
+ data->te = te;
+ return TRAVERSE_BREAK;
+ case TSE_R_LAYER:
+ case TSE_SCENE_COLLECTION_BASE:
+ case TSE_VIEW_COLLECTION_BASE:
+ default:
+ return TRAVERSE_CONTINUE;
}
-
- BLI_addtail(&data->scene_collections_array, BLI_genericNodeN(scene_collection));
- return TRAVERSE_CONTINUE;
}
-static int collection_objects_add_exec(bContext *C, wmOperator *op)
+static TreeElement *outliner_active_collection(bContext *C)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- struct SceneCollectionSelectedData data = {
- .scene_collections_array = {NULL, NULL},
+ struct CollectionDuplicateData data = {
+ .te = NULL,
};
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data);
-
- if (BLI_listbase_is_empty(&data.scene_collections_array)) {
- BKE_report(op->reports, RPT_ERROR, "No collection is selected");
- return OPERATOR_CANCELLED;
- }
-
- CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects)
- {
- LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) {
- SceneCollection *scene_collection = link->data;
- BKE_collection_object_add(
- &scene->id,
- scene_collection,
- ob);
- }
- }
- CTX_DATA_END;
- BLI_freelistN(&data.scene_collections_array);
-
- outliner_cleanup_tree(soops);
- DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
- return OPERATOR_FINISHED;
-}
-
-void OUTLINER_OT_collection_objects_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Objects";
- ot->idname = "OUTLINER_OT_collection_objects_add";
- ot->description = "Add selected objects to collection";
-
- /* api callbacks */
- ot->exec = collection_objects_add_exec;
- ot->poll = collections_editor_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_collection, &data);
+ return data.te;
}
-/**********************************************************************************/
-/* Remove selected objects. */
-
-
-static int collection_objects_remove_exec(bContext *C, wmOperator *op)
+static int collection_duplicate_exec(bContext *C, wmOperator *op)
{
- SpaceOops *soops = CTX_wm_space_outliner(C);
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
-
- struct SceneCollectionSelectedData data = {
- .scene_collections_array = {NULL, NULL},
- };
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te = outliner_active_collection(C);
+ BLI_assert(te != NULL);
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data);
+ Collection *collection = outliner_collection_from_tree_element(te);
+ Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL;
- if (BLI_listbase_is_empty(&data.scene_collections_array)) {
- BKE_report(op->reports, RPT_ERROR, "No collection is selected");
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BKE_report(op->reports, RPT_ERROR, "Can't duplicate the master collection");
return OPERATOR_CANCELLED;
}
- CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects)
- {
- LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) {
- SceneCollection *scene_collection = link->data;
- BKE_collection_object_remove(
- bmain,
- &scene->id,
- scene_collection,
- ob,
- true);
- }
+ switch (soops->outlinevis) {
+ case SO_SCENES:
+ case SO_VIEW_LAYER:
+ case SO_LIBRARIES:
+ BKE_collection_copy(bmain, parent, collection);
+ break;
}
- CTX_DATA_END;
- BLI_freelistN(&data.scene_collections_array);
- outliner_cleanup_tree(soops);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C));
+
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot)
+void OUTLINER_OT_collection_duplicate(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove Objects";
- ot->idname = "OUTLINER_OT_collection_objects_remove";
- ot->description = "Remove selected objects from collection";
+ ot->name = "Duplicate Collection";
+ ot->idname = "OUTLINER_OT_collection_duplicate";
+ ot->description = "Duplicate selected collections";
/* api callbacks */
- ot->exec = collection_objects_remove_exec;
+ ot->exec = collection_duplicate_exec;
ot->poll = collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static TreeElement *outliner_collection_parent_element_get(TreeElement *te)
-{
- TreeElement *te_parent = te;
- while ((te_parent = te_parent->parent)) {
- if (outliner_scene_collection_from_tree_element(te->parent)) {
- return te_parent;
- }
- }
- return NULL;
-}
+/**************************** Link Collection ******************************/
-static int object_collection_remove_exec(bContext *C, wmOperator *UNUSED(op))
+static int collection_link_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceOops *soops = CTX_wm_space_outliner(C);
Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Collection *active_collection = CTX_data_layer_collection(C)->collection;
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
- struct ObjectsSelectedData data = {
- .objects_selected_array = {NULL, NULL},
- };
-
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
- LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) {
- TreeElement *te = (TreeElement *)link->data;
- Object *ob = (Object *)TREESTORE(te)->id;
- SceneCollection *scene_collection = NULL;
+ /* We first walk over and find the Collections we actually want to link (ignoring duplicates). */
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
- TreeElement *te_parent = outliner_collection_parent_element_get(te);
- if (te_parent != NULL) {
- scene_collection = outliner_scene_collection_from_tree_element(te_parent);
- ID *owner_id = TREESTORE(te_parent)->id;
- BKE_collection_object_remove(bmain, owner_id, scene_collection, ob, true);
- DEG_id_tag_update(owner_id, DEG_TAG_BASE_FLAGS_UPDATE);
- }
+ /* Effectively link the collections. */
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ BKE_collection_child_add(bmain, active_collection, collection);
+ id_fake_user_clear(&collection->id);
}
- BLI_freelistN(&data.objects_selected_array);
+ BLI_gset_free(data.collections_to_edit, NULL);
- outliner_cleanup_tree(soops);
DEG_relations_tag_update(bmain);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+
WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
- WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, NULL);
- WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, NULL);
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_object_remove_from_collection(wmOperatorType *ot)
+void OUTLINER_OT_collection_link(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove Object from Collection";
- ot->idname = "OUTLINER_OT_object_remove_from_collection";
- ot->description = "Remove selected objects from their respective collection";
+ ot->name = "Link Collection";
+ ot->idname = "OUTLINER_OT_collection_link";
+ ot->description = "Link selected collections to active scene";
/* api callbacks */
- ot->exec = object_collection_remove_exec;
- ot->poll = outliner_objects_collection_poll;
+ ot->exec = collection_link_exec;
+ ot->poll = collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int object_add_to_new_collection_exec(bContext *C, wmOperator *op)
-{
- int operator_result = OPERATOR_CANCELLED;
+/************************** Instance Collection ******************************/
- SpaceOops *soops = CTX_wm_space_outliner(C);
+static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
+{
Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
- SceneCollection *scene_collection_parent, *scene_collection_new;
- TreeElement *te_active, *te_parent;
-
- struct ObjectsSelectedData data = {{NULL}}, active = {{NULL}};
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_HIGHLIGHTED, outliner_find_selected_objects, &active);
- if (BLI_listbase_is_empty(&active.objects_selected_array)) {
- BKE_report(op->reports, RPT_ERROR, "No object is selected");
- goto cleanup;
- }
+ /* We first walk over and find the Collections we actually want to instance (ignoring duplicates). */
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
- if (BLI_listbase_is_empty(&data.objects_selected_array)) {
- BKE_report(op->reports, RPT_ERROR, "No objects are selected");
- goto cleanup;
- }
+ /* Find an active collection to add to, that doesn't give dependency cycles. */
+ LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
- /* Heuristic to get the "active" / "last object" */
- te_active = ((LinkData *)active.objects_selected_array.first)->data;
- te_parent = outliner_collection_parent_element_get(te_active);
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
- if (te_parent == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Couldn't find collection of \"%s\" object", te_active->name);
- goto cleanup;
+ while (BKE_collection_find_cycle(active_lc->collection, collection)) {
+ active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
+ }
}
- ID *owner_id = TREESTORE(te_parent)->id;
- scene_collection_parent = outliner_scene_collection_from_tree_element(te_parent);
- scene_collection_new = BKE_collection_add(owner_id, scene_collection_parent, scene_collection_parent->type, NULL);
-
- LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) {
- TreeElement *te = (TreeElement *)link->data;
- Object *ob = (Object *)TREESTORE(te)->id;
- BKE_collection_object_add(owner_id, scene_collection_new, ob);
+ /* Effectively instance the collections. */
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, scene->layact);
+ ob->dup_group = collection;
+ ob->transflag |= OB_DUPLICOLLECTION;
+ id_lib_extern(&collection->id);
}
- outliner_cleanup_tree(soops);
+ BLI_gset_free(data.collections_to_edit, NULL);
+
DEG_relations_tag_update(bmain);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+
WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
- operator_result = OPERATOR_FINISHED;
-cleanup:
- BLI_freelistN(&active.objects_selected_array);
- BLI_freelistN(&data.objects_selected_array);
- return operator_result;
+ return OPERATOR_FINISHED;
}
-void OUTLINER_OT_object_add_to_new_collection(wmOperatorType *ot)
+void OUTLINER_OT_collection_instance(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Objects to New Collection";
- ot->idname = "OUTLINER_OT_object_add_to_new_collection";
- ot->description = "Add objects to a new collection";
+ ot->name = "Instance Collection";
+ ot->idname = "OUTLINER_OT_collection_instance";
+ ot->description = "Instance selected collections to active scene";
/* api callbacks */
- ot->exec = object_add_to_new_collection_exec;
- ot->poll = outliner_objects_collection_poll;
+ ot->exec = collection_instance_exec;
+ ot->poll = collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-struct CollectionDeleteData {
- Scene *scene;
- SpaceOops *soops;
- GSet *collections_to_delete;
-};
+/************************** Exclude Collection ******************************/
-static TreeTraversalAction collection_find_data_to_delete(TreeElement *te, void *customdata)
+static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct CollectionDeleteData *data = customdata;
- SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
+ struct CollectionEditData *data = customdata;
+ TreeStoreElem *tselem = TREESTORE(te);
- if (!scene_collection) {
- return TRAVERSE_SKIP_CHILDS;
+ if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) {
+ return TRAVERSE_CONTINUE;
}
- if (scene_collection == BKE_collection_master(&data->scene->id)) {
+ LayerCollection *lc = te->directdata;
+
+ if (lc->collection->flag & COLLECTION_IS_MASTER) {
/* skip - showing warning/error message might be missleading
* when deleting multiple collections, so just do nothing */
}
else {
- BLI_gset_add(data->collections_to_delete, scene_collection);
- return TRAVERSE_SKIP_CHILDS; /* Childs will be gone anyway, no need to recurse deeper. */
+ /* Delete, duplicate and link don't edit children, those will come along
+ * with the parents. */
+ BLI_gset_add(data->collections_to_edit, lc);
}
return TRAVERSE_CONTINUE;
}
-static TreeTraversalAction collection_delete_elements_from_collection(TreeElement *te, void *customdata)
+static int collections_view_layer_poll(bContext *C, bool include)
{
- struct CollectionDeleteData *data = customdata;
- SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
-
- if (!scene_collection) {
- return TRAVERSE_SKIP_CHILDS;
- }
-
- const bool will_be_deleted = BLI_gset_haskey(data->collections_to_delete, scene_collection);
- if (will_be_deleted) {
- outliner_free_tree_element(te, te->parent ? &te->parent->subtree : &data->soops->tree);
- /* Childs are freed now, so don't recurse into them. */
- return TRAVERSE_SKIP_CHILDS;
+ /* Poll function so the right click menu show current state of selected collections. */
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ if (!(soops && soops->outlinevis == SO_VIEW_LAYER)) {
+ return false;
}
- return TRAVERSE_CONTINUE;
-}
-
-static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op))
-{
Scene *scene = CTX_data_scene(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- struct CollectionDeleteData data = {.scene = scene, .soops = soops};
-
- data.collections_to_delete = BLI_gset_ptr_new(__func__);
-
- /* We first walk over and find the SceneCollections we actually want to delete (ignoring duplicates). */
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_delete, &data);
-
- /* Now, delete all tree elements representing a collection that will be deleted. We'll look for a
- * new element to select in a few lines, so we can't wait until the tree is recreated on redraw. */
- outliner_tree_traverse(soops, &soops->tree, 0, 0, collection_delete_elements_from_collection, &data);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
+ bool result = false;
- /* Effectively delete the collections. */
- GSetIterator collections_to_delete_iter;
- GSET_ITER(collections_to_delete_iter, data.collections_to_delete) {
- SceneCollection *sc = BLI_gsetIterator_getKey(&collections_to_delete_iter);
- BKE_collection_remove(&data.scene->id, sc);
- }
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
- BLI_gset_free(data.collections_to_delete, NULL);
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
- TreeElement *select_te = outliner_tree_element_from_layer_collection_index(soops, CTX_data_view_layer(C), 0);
- if (select_te) {
- outliner_item_select(soops, select_te, false, false);
+ if (include && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ result = true;
+ }
+ else if (!include && !(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ result = true;
+ }
}
- DEG_relations_tag_update(CTX_data_main(C));
-
- /* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&scene->id, 0);
-
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
-
- return OPERATOR_FINISHED;
+ BLI_gset_free(data.collections_to_edit, NULL);
+ return result;
}
-void OUTLINER_OT_collections_delete(wmOperatorType *ot)
+static int collections_exclude_poll(bContext *C)
{
- /* identifiers */
- ot->name = "Delete";
- ot->idname = "OUTLINER_OT_collections_delete";
- ot->description = "Delete selected overrides or collections";
-
- /* api callbacks */
- ot->exec = collection_delete_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ return collections_view_layer_poll(C, false);
}
-static int collection_select_exec(bContext *C, wmOperator *op)
+static int collections_include_poll(bContext *C)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const int collection_index = RNA_int_get(op->ptr, "collection_index");
- view_layer->active_collection = collection_index;
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
- return OPERATOR_FINISHED;
-}
-
-void OUTLINER_OT_collection_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select";
- ot->idname = "OUTLINER_OT_collection_select";
- ot->description = "Change active collection or override";
-
- /* api callbacks */
- ot->exec = collection_select_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_int(ot->srna, "collection_index", 0, 0, INT_MAX, "Index",
- "Index of collection to select", 0, INT_MAX);
+ return collections_view_layer_poll(C, true);
}
-#define ACTION_DISABLE 0
-#define ACTION_ENABLE 1
-#define ACTION_TOGGLE 2
-
-static int collection_toggle_exec(bContext *C, wmOperator *op)
+static void layer_collection_exclude_recursive_set(LayerCollection *lc)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- int action = RNA_enum_get(op->ptr, "action");
- LayerCollection *layer_collection = CTX_data_layer_collection(C);
-
- if (layer_collection->flag & COLLECTION_DISABLED) {
- if (ELEM(action, ACTION_TOGGLE, ACTION_ENABLE)) {
- layer_collection->flag &= ~COLLECTION_DISABLED;
- }
- else { /* ACTION_DISABLE */
- BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already disabled",
- layer_collection->scene_collection->name);
- return OPERATOR_CANCELLED;
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ nlc->flag |= LAYER_COLLECTION_EXCLUDE;
}
- }
- else {
- if (ELEM(action, ACTION_TOGGLE, ACTION_DISABLE)) {
- layer_collection->flag |= COLLECTION_DISABLED;
- }
- else { /* ACTION_ENABLE */
- BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already enabled",
- layer_collection->scene_collection->name);
- return OPERATOR_CANCELLED;
+ else {
+ nlc->flag &= ~LAYER_COLLECTION_EXCLUDE;
}
- }
-
- DEG_relations_tag_update(bmain);
- /* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&scene->id, 0);
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
- return OPERATOR_FINISHED;
+ layer_collection_exclude_recursive_set(nlc);
+ }
}
-void OUTLINER_OT_collection_toggle(wmOperatorType *ot)
+static int collection_view_layer_exec(bContext *C, wmOperator *op)
{
- PropertyRNA *prop;
-
- static EnumPropertyItem actions_items[] = {
- {ACTION_DISABLE, "DISABLE", 0, "Disable", "Disable selected markers"},
- {ACTION_ENABLE, "ENABLE", 0, "Enable", "Enable selected markers"},
- {ACTION_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Toggle Collection";
- ot->idname = "OUTLINER_OT_collection_toggle";
- ot->description = "Deselect collection objects";
-
- /* api callbacks */
- ot->exec = collection_toggle_exec;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
+ bool include = STREQ(op->idname, "OUTLINER_OT_collection_include_set");
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
- /* properties */
- prop = RNA_def_int(ot->srna, "collection_index", -1, -1, INT_MAX, "Collection Index", "Index of collection to toggle", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_enum(ot->srna, "action", actions_items, ACTION_TOGGLE, "Action", "Selection action to execute");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
-#undef ACTION_TOGGLE
-#undef ACTION_ENABLE
-#undef ACTION_DISABLE
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
-struct CollectionObjectsSelectData {
- bool error;
- LayerCollection *layer_collection;
-};
+ if (!(lc->collection->flag & COLLECTION_IS_MASTER)) {
+ if (include) {
+ lc->flag &= ~LAYER_COLLECTION_EXCLUDE;
+ }
+ else {
+ lc->flag |= LAYER_COLLECTION_EXCLUDE;
+ }
-static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata)
-{
- struct CollectionObjectsSelectData *data = customdata;
- TreeStoreElem *tselem = TREESTORE(te);
-
- switch (tselem->type) {
- case TSE_LAYER_COLLECTION:
- data->layer_collection = te->directdata;
- return TRAVERSE_BREAK;
- case TSE_LAYER_COLLECTION_BASE:
- return TRAVERSE_CONTINUE;
- default:
- return TRAVERSE_SKIP_CHILDS;
+ layer_collection_exclude_recursive_set(lc);
+ }
}
-}
-
-static LayerCollection *outliner_active_layer_collection(bContext *C)
-{
- SpaceOops *soops = CTX_wm_space_outliner(C);
- struct CollectionObjectsSelectData data = {
- .layer_collection = NULL,
- };
-
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_layer_collection, &data);
- return data.layer_collection;
-}
+ BLI_gset_free(data.collections_to_edit, NULL);
-static int collection_objects_select_exec(bContext *C, wmOperator *UNUSED(op))
-{
- LayerCollection *layer_collection = outliner_active_layer_collection(C);
-
- if (layer_collection == NULL) {
- return OPERATOR_CANCELLED;
- }
+ BKE_layer_collection_sync(scene, view_layer);
+ DEG_relations_tag_update(bmain);
- BKE_layer_collection_objects_select(layer_collection);
- WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
+void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Select Objects";
- ot->idname = "OUTLINER_OT_collection_objects_select";
- ot->description = "Select all the collection objects";
+ ot->name = "Exclude from View Layer";
+ ot->idname = "OUTLINER_OT_collection_exclude_set";
+ ot->description = "Exclude collection from the active view layer";
/* api callbacks */
- ot->exec = collection_objects_select_exec;
- ot->poll = collections_editor_poll;
+ ot->exec = collection_view_layer_exec;
+ ot->poll = collections_exclude_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-struct CollectionDuplicateData {
- TreeElement *te;
-};
-
-static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata)
-{
- struct CollectionDuplicateData *data = customdata;
- TreeStoreElem *tselem = TREESTORE(te);
-
- switch (tselem->type) {
- case TSE_LAYER_COLLECTION:
- case TSE_SCENE_COLLECTION:
- data->te = te;
- return TRAVERSE_BREAK;
- case TSE_LAYER_COLLECTION_BASE:
- default:
- return TRAVERSE_CONTINUE;
- }
-}
-
-static TreeElement *outliner_active_collection(bContext *C)
-{
- SpaceOops *soops = CTX_wm_space_outliner(C);
-
- struct CollectionDuplicateData data = {
- .te = NULL,
- };
-
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_collection, &data);
- return data.te;
-}
-
-static int collection_duplicate_exec(bContext *C, wmOperator *op)
-{
- SpaceOops *soops = CTX_wm_space_outliner(C);
- TreeElement *te = outliner_active_collection(C);
-
- BLI_assert(te != NULL);
- if (BKE_collection_master(TREESTORE(te)->id) == outliner_scene_collection_from_tree_element(te)) {
- BKE_report(op->reports, RPT_ERROR, "You can't duplicate the master collection");
- return OPERATOR_CANCELLED;
- }
-
- switch (soops->outlinevis) {
- case SO_SCENES:
- BKE_collection_duplicate(TREESTORE(te)->id, (SceneCollection *)te->directdata);
- break;
- case SO_COLLECTIONS:
- case SO_GROUPS:
- BKE_layer_collection_duplicate(TREESTORE(te)->id, (LayerCollection *)te->directdata);
- break;
- }
-
- DEG_relations_tag_update(CTX_data_main(C));
- WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C));
-
- return OPERATOR_FINISHED;
-}
-
-void OUTLINER_OT_collection_duplicate(wmOperatorType *ot)
+void OUTLINER_OT_collection_include_set(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Duplicate Collection";
- ot->idname = "OUTLINER_OT_collection_duplicate";
- ot->description = "Duplicate collection";
+ ot->name = "Include in View Layer";
+ ot->idname = "OUTLINER_OT_collection_include_set";
+ ot->description = "Include collection in the active view layer";
/* api callbacks */
- ot->exec = collection_duplicate_exec;
- ot->poll = collections_editor_poll;
+ ot->exec = collection_view_layer_exec;
+ ot->poll = collections_include_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;