diff options
Diffstat (limited to 'source/blender/editors/space_outliner')
10 files changed, 853 insertions, 1487 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; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index d3e70da80c8..90b137bcd7d 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -248,19 +248,6 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } -static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(poin2)) -{ - ID *id = (ID *)poin; - - /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(id, 0); - - if (GS(id->name) == ID_SCE) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, id); - } - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); -} - static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2)) { ID *id = (ID *)poin; @@ -275,9 +262,9 @@ static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void } } - static void namebutton_cb(bContext *C, void *tsep, char *oldname) { + Main *bmain = CTX_data_main(C); SpaceOops *soops = CTX_wm_space_outliner(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -289,7 +276,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) TreeElement *te = outliner_find_tree_element(&soops->tree, tselem); if (tselem->type == 0) { - BLI_libblock_ensure_unique_name(G.main, tselem->id->name); + BLI_libblock_ensure_unique_name(bmain, tselem->id->name); switch (GS(tselem->id->name)) { case ID_MA: @@ -311,7 +298,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) BKE_library_filepath_set(lib, lib->name); BLI_strncpy(expanded, lib->name, sizeof(expanded)); - BLI_path_abs(expanded, G.main->name); + BLI_path_abs(expanded, bmain->name); if (!BLI_exists(expanded)) { BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Library path '%s' does not exist, correct this before saving", expanded); @@ -329,7 +316,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) defgroup_unique_name(te->directdata, (Object *)tselem->id); // id = object break; case TSE_NLA_ACTION: - BLI_libblock_ensure_unique_name(G.main, tselem->id->name); + BLI_libblock_ensure_unique_name(bmain, tselem->id->name); break; case TSE_EBONE: { @@ -404,14 +391,10 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd); break; } - case TSE_R_LAYER: - break; - case TSE_SCENE_COLLECTION: case TSE_LAYER_COLLECTION: { - SceneCollection *sc = outliner_scene_collection_from_tree_element(te); - BKE_collection_rename(tselem->id, sc, te->name); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + BLI_libblock_ensure_unique_name(bmain, tselem->id->name); + WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); break; break; } } @@ -427,16 +410,16 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar TreeStoreElem *tselem; Object *ob = NULL; -#if 0 - PropertyRNA *object_prop_hide, *object_prop_hide_select, *object_prop_hide_render; - - /* get RNA properties (once) */ - object_prop_hide = RNA_struct_type_find_property(&RNA_Object, "hide"); - object_prop_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select"); - object_prop_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render"); - BLI_assert(object_prop_hide && object_prop_hide_select && object_prop_hide_render); -#endif - + /* get RNA properties (once for speed) */ + PropertyRNA *collection_prop_hide_viewport; + PropertyRNA *collection_prop_hide_select; + PropertyRNA *collection_prop_hide_render; + collection_prop_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select"); + collection_prop_hide_viewport = RNA_struct_type_find_property(&RNA_Collection, "hide_viewport"); + collection_prop_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render"); + BLI_assert(collection_prop_hide_viewport && + collection_prop_hide_select && + collection_prop_hide_render); for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); @@ -540,46 +523,33 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar UI_block_emboss_set(block, UI_EMBOSS); } - else if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *collection = te->directdata; - - const bool is_enabled = (collection->flag & COLLECTION_DISABLED) == 0; + else if (outliner_is_collection_tree_element(te)) { + LayerCollection *lc = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata : NULL; + Collection *collection = outliner_collection_from_tree_element(te); UI_block_emboss_set(block, UI_EMBOSS_NONE); - if (collection->scene_collection->type == COLLECTION_TYPE_NONE) { - bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Restrict/Allow 3D View selection of objects in the collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - else if ((soops->outlinevis == SO_GROUPS) && - (collection->scene_collection->type == COLLECTION_TYPE_GROUP_INTERNAL)) + if ((!lc || !(lc->flag & LAYER_COLLECTION_EXCLUDE)) && + !(collection->flag & COLLECTION_IS_MASTER)) { - bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VIEWPORT, 0, ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Restrict/Allow 3D View selection of objects in the collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); + PointerRNA collection_ptr; + RNA_id_pointer_create(&collection->id, &collection_ptr); + + bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection_ptr, collection_prop_hide_viewport, -1, 0, 0, 0, 0, NULL); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_RENDER, 0, ICON_RESTRICT_RENDER_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Restrict/Allow 3D View selection of objects in the collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); + bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_RENDER_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection_ptr, collection_prop_hide_render, -1, 0, 0, 0, 0, NULL); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - bt = uiDefIconButBitS(block, UI_BTYPE_BUT_TOGGLE, COLLECTION_DISABLED, 0, - is_enabled ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Enable/Disable collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection_ptr, collection_prop_hide_select, -1, 0, 0, 0, 0, NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } UI_block_emboss_set(block, UI_EMBOSS); } @@ -1090,8 +1060,9 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto } break; case TSE_LAYER_COLLECTION: - case TSE_SCENE_COLLECTION: - ICON_DRAW(ICON_COLLAPSEMENU); + case TSE_SCENE_COLLECTION_BASE: + case TSE_VIEW_COLLECTION_BASE: + ICON_DRAW(ICON_GROUP); break; /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */ #if 0 @@ -1131,7 +1102,13 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto case OB_LIGHTPROBE: tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LIGHTPROBE); break; case OB_EMPTY: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break; + if (ob->dup_group) { + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_GROUP_INSTANCE); + } + else { + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); + } + break; } } else { @@ -1339,7 +1316,7 @@ static void outliner_draw_tree_element( tselem = TREESTORE(te); if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) { - const float alpha_fac = draw_grayed_out ? 0.5f : 1.0f; + const float alpha_fac = ((te->flag & TE_DISABLED) || draw_grayed_out) ? 0.5f : 1.0f; const float alpha = 0.5f * alpha_fac; int xmax = ar->v2d.cur.xmax; @@ -1422,8 +1399,8 @@ static void outliner_draw_tree_element( te->flag |= TE_ACTIVE; // for lookup in display hierarchies } - if ((soops->outlinevis == SO_COLLECTIONS) && (tselem->type == TSE_R_LAYER)) { - /* View layer in collections can't expand/collapse. */ + if (tselem->type == TSE_VIEW_COLLECTION_BASE) { + /* Scene collection in view layer can't expand/collapse. */ } else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { /* open/close icon, only when sublevels, except for scene */ @@ -1448,7 +1425,7 @@ static void outliner_draw_tree_element( else offsx += 2 * ufac; - if (tselem->type == 0 && ID_IS_LINKED(tselem->id)) { + if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_LINKED(tselem->id)) { if (tselem->id->tag & LIB_TAG_MISSING) { UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN, alpha_fac); @@ -1463,7 +1440,7 @@ static void outliner_draw_tree_element( } offsx += UI_UNIT_X + 2 * ufac; } - else if (tselem->type == 0 && ID_IS_STATIC_OVERRIDE(tselem->id)) { + else if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_STATIC_OVERRIDE(tselem->id)) { UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_OVERRIDE, alpha_fac); offsx += UI_UNIT_X + 2 * ufac; diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 5187de00cff..5922e208f36 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -50,6 +50,7 @@ #include "BLT_translation.h" #include "BKE_animsys.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_idcode.h" #include "BKE_layer.h" @@ -61,7 +62,6 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_material.h" -#include "BKE_group.h" #include "DEG_depsgraph_build.h" @@ -254,7 +254,7 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot) /* Rename --------------------------------------------------- */ -static void do_item_rename(const Scene *scene, ARegion *ar, TreeElement *te, TreeStoreElem *tselem, +static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, ReportList *reports) { bool add_textbut = false; @@ -264,19 +264,18 @@ static void do_item_rename(const Scene *scene, ARegion *ar, TreeElement *te, Tre /* do nothing */; } else if (ELEM(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, - TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE)) + TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_SCENE_COLLECTION_BASE, + TSE_VIEW_COLLECTION_BASE)) { BKE_report(reports, RPT_WARNING, "Cannot edit builtin name"); } else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); } - else if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { - SceneCollection *master = BKE_collection_master(&scene->id); + else if (outliner_is_collection_tree_element(te)) { + Collection *collection = outliner_collection_from_tree_element(te); - if ((tselem->type == TSE_SCENE_COLLECTION && te->directdata == master) || - (((LayerCollection *)te->directdata)->scene_collection == master)) - { + if (collection->flag & COLLECTION_IS_MASTER) { BKE_report(reports, RPT_WARNING, "Cannot edit name of master collection"); } else { @@ -300,14 +299,14 @@ static void do_item_rename(const Scene *scene, ARegion *ar, TreeElement *te, Tre } void item_rename_cb( - bContext *C, ReportList *reports, Scene *scene, TreeElement *te, + bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ARegion *ar = CTX_wm_region(C); - do_item_rename(scene, ar, te, tselem, reports); + do_item_rename(ar, te, tselem, reports); } -static int do_outliner_item_rename(const Scene *scene, ReportList *reports, ARegion *ar, TreeElement *te, +static int do_outliner_item_rename(ReportList *reports, ARegion *ar, TreeElement *te, const float mval[2]) { if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { @@ -315,14 +314,14 @@ static int do_outliner_item_rename(const Scene *scene, ReportList *reports, AReg /* click on name */ if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) { - do_item_rename(scene, ar, te, tselem, reports); + do_item_rename(ar, te, tselem, reports); return 1; } return 0; } for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_rename(scene, reports, ar, te, mval)) return 1; + if (do_outliner_item_rename(reports, ar, te, mval)) return 1; } return 0; } @@ -338,7 +337,7 @@ static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *even UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_rename(CTX_data_scene(C), op->reports, ar, te, fmval)) { + if (do_outliner_item_rename(op->reports, ar, te, fmval)) { changed = true; break; } @@ -1915,7 +1914,6 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) Main *bmain = CTX_data_main(C); Scene *scene = NULL; TreeElement *te = NULL; - TreeStoreElem *tselem; char childname[MAX_ID_NAME]; char parname[MAX_ID_NAME]; int partype = 0; @@ -1925,21 +1923,8 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* Find object hovered over */ te = outliner_dropzone_find(soops, fmval, true); - tselem = te ? TREESTORE(te) : NULL; - - if (tselem && ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { - SceneCollection *sc = outliner_scene_collection_from_tree_element(te); - - scene = BKE_scene_find_from_collection(bmain, sc); - BLI_assert(scene); - RNA_string_get(op->ptr, "child", childname); - ob = (Object *)BKE_libblock_find_name(ID_OB, childname); - BKE_collection_object_add(&scene->id, sc, ob); - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - } - else if (te) { + if (te) { RNA_string_set(op->ptr, "parent", te->name); /* Identify parent and child */ RNA_string_get(op->ptr, "child", childname); @@ -2082,9 +2067,10 @@ static int outliner_parenting_poll(bContext *C) if (soops->outlinevis == SO_SCENES) { return true; } - - if (soops->outlinevis == SO_COLLECTIONS) { - return (soops->filter & SO_FILTER_NO_COLLECTION); + else if ((soops->outlinevis == SO_VIEW_LAYER) && + (soops->filter & SO_FILTER_NO_COLLECTION)) + { + return true; } } @@ -2163,16 +2149,16 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - SceneCollection *sc; + Collection *collection; if (scene != CTX_data_scene(C)) { /* when linking to an inactive scene link to the master collection */ - sc = BKE_collection_master(&scene->id); + collection = BKE_collection_master(scene); } else { - sc = CTX_data_scene_collection(C); + collection = CTX_data_collection(C); } - BKE_collection_object_add(&scene->id, sc, ob); + BKE_collection_object_add(bmain, collection, ob); for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { Base *base = BKE_view_layer_base_find(view_layer, ob); @@ -2268,58 +2254,81 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot) RNA_def_string(ot->srna, "material", "Material", MAX_ID_NAME, "Material", "Target Material"); } -static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) +/* ******************** Collection Drop Operator *********************** */ + +static int collection_drop_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) { + /* TODO: implement */ +#if 0 + Object *par = NULL, *ob = NULL; Main *bmain = CTX_data_main(C); - Group *group = NULL; - Object *ob = NULL; + Scene *scene = CTX_data_scene(C); + int partype = -1; + char parname[MAX_ID_NAME], childname[MAX_ID_NAME]; + + RNA_string_get(op->ptr, "parent", parname); + par = (Object *)BKE_libblock_find_name(ID_OB, parname); + RNA_string_get(op->ptr, "child", childname); + ob = (Object *)BKE_libblock_find_name(ID_OB, childname); + + if (ID_IS_LINKED(ob)) { + BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); + return OPERATOR_CANCELLED; + } + + ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL); + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); +#endif + + return OPERATOR_FINISHED; +} + +static int collection_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ SpaceOops *soops = CTX_wm_space_outliner(C); ARegion *ar = CTX_wm_region(C); - TreeElement *te = NULL; - char ob_name[MAX_ID_NAME - 2]; + Main *bmain = CTX_data_main(C); + char childname[MAX_ID_NAME]; float fmval[2]; UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); /* Find object hovered over */ - te = outliner_dropzone_find(soops, fmval, true); - - if (te) { - group = (Group *)BKE_libblock_find_name(ID_GR, te->name); - - RNA_string_get(op->ptr, "object", ob_name); - ob = (Object *)BKE_libblock_find_name(ID_OB, ob_name); + TreeElement *te = outliner_dropzone_find(soops, fmval, true); - if (ELEM(NULL, group, ob)) { - return OPERATOR_CANCELLED; - } - if (BKE_group_object_exists(group, ob)) { - return OPERATOR_FINISHED; - } + if (!te || !outliner_is_collection_tree_element(te)) { + return OPERATOR_CANCELLED; + } - if (BKE_group_object_cyclic_check(bmain, ob, group)) { - BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected"); - return OPERATOR_CANCELLED; - } + Collection *collection = outliner_collection_from_tree_element(te); - BKE_group_object_add(group, ob); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + // TODO: don't use scene, makes no sense anymore + // TODO: move rather than link, change hover text + Scene *scene = BKE_scene_find_from_collection(bmain, collection); + BLI_assert(scene); + RNA_string_get(op->ptr, "child", childname); + Object *ob = (Object *)BKE_libblock_find_name(ID_OB, childname); + BKE_collection_object_add(bmain, collection, ob); - return OPERATOR_FINISHED; - } + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - return OPERATOR_CANCELLED; + return OPERATOR_FINISHED; } -void OUTLINER_OT_group_link(wmOperatorType *ot) +void OUTLINER_OT_collection_drop(wmOperatorType *ot) { /* identifiers */ - ot->name = "Link Object to Group"; - ot->description = "Link Object to Group in Outliner"; - ot->idname = "OUTLINER_OT_group_link"; + ot->name = "Link to Collection"; // TODO: rename to move? + ot->description = "Drag to move to collection in Outliner"; + ot->idname = "OUTLINER_OT_collection_drop"; /* api callbacks */ - ot->invoke = group_link_invoke; + ot->invoke = collection_drop_invoke; + ot->exec = collection_drop_exec; ot->poll = ED_operator_outliner_active; @@ -2327,5 +2336,6 @@ void OUTLINER_OT_group_link(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; /* properties */ - RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object"); + RNA_def_string(ot->srna, "child", "Object", MAX_ID_NAME, "Child", "Child Object"); + RNA_def_string(ot->srna, "parent", "Collection", MAX_ID_NAME, "Parent", "Parent Collection"); } diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index a0de3a06556..73494b890ed 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -71,6 +71,7 @@ typedef enum TreeTraversalAction { * Callback type for reinserting elements at a different position, used to allow user customizable element order. */ typedef void (*TreeElementReinsertFunc)(struct Main *bmain, + struct Scene *scene, struct SpaceOops *soops, struct TreeElement *insert_element, struct TreeElement *insert_handle, @@ -124,6 +125,7 @@ enum { TE_ICONROW = (1 << 1), TE_LAZY_CLOSED = (1 << 2), TE_FREE_NAME = (1 << 3), + TE_DISABLED = (1 << 4), }; /* button events */ @@ -149,11 +151,11 @@ typedef enum { /* size constants */ #define OL_Y_OFFSET 2 -#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3.0f) -#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2.0f) +#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 3.0f) +#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f) #define OL_TOG_RESTRICT_RENDERX UI_UNIT_X -#define OL_TOGW OL_TOG_RESTRICT_VIEWX +#define OL_TOGW OL_TOG_RESTRICT_SELECTX #define OL_RNA_COLX (UI_UNIT_X * 15) #define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) @@ -161,7 +163,7 @@ typedef enum { /* The outliner display modes that support the filter system. * Note: keep it synced with space_outliner.py */ -#define SUPPORT_FILTER_OUTLINER(soops_) ((soops_)->outlinevis == SO_COLLECTIONS) +#define SUPPORT_FILTER_OUTLINER(soops_) (ELEM((soops_)->outlinevis, SO_VIEW_LAYER)) /* Outliner Searching -- * @@ -253,16 +255,6 @@ void object_toggle_renderability_cb( TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void group_toggle_visibility_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, - TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void group_toggle_selectability_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, - TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void group_toggle_renderability_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, - TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); - void item_rename_cb( struct bContext *C, struct ReportList *reports, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); @@ -319,14 +311,13 @@ void OUTLINER_OT_parent_drop(struct wmOperatorType *ot); void OUTLINER_OT_parent_clear(struct wmOperatorType *ot); void OUTLINER_OT_scene_drop(struct wmOperatorType *ot); void OUTLINER_OT_material_drop(struct wmOperatorType *ot); -void OUTLINER_OT_group_link(struct wmOperatorType *ot); +void OUTLINER_OT_collection_drop(struct wmOperatorType *ot); /* outliner_tools.c ---------------------------------------------- */ void OUTLINER_OT_operation(struct wmOperatorType *ot); void OUTLINER_OT_scene_operation(struct wmOperatorType *ot); void OUTLINER_OT_object_operation(struct wmOperatorType *ot); -void OUTLINER_OT_group_operation(struct wmOperatorType *ot); void OUTLINER_OT_lib_operation(struct wmOperatorType *ot); void OUTLINER_OT_id_operation(struct wmOperatorType *ot); void OUTLINER_OT_id_remap(struct wmOperatorType *ot); @@ -335,7 +326,7 @@ void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); void OUTLINER_OT_action_set(struct wmOperatorType *ot); void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot); void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot); -void OUTLINER_OT_collection_operation(struct wmOperatorType *ot); + /* ---------------------------------------------------------------- */ /* outliner_ops.c */ @@ -344,23 +335,18 @@ void outliner_keymap(struct wmKeyConfig *keyconf); /* outliner_collections.c */ -struct SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te); +bool outliner_is_collection_tree_element(const TreeElement *te); +struct Collection *outliner_collection_from_tree_element(const TreeElement *te); -void OUTLINER_OT_collections_delete(struct wmOperatorType *ot); -void OUTLINER_OT_collection_select(struct wmOperatorType *ot); -void OUTLINER_OT_collection_toggle(struct wmOperatorType *ot); -void OUTLINER_OT_collection_link(struct wmOperatorType *ot); -void OUTLINER_OT_collection_unlink(struct wmOperatorType *ot); void OUTLINER_OT_collection_new(struct wmOperatorType *ot); void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot); -void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot); +void OUTLINER_OT_collection_delete(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); -void OUTLINER_OT_object_add_to_new_collection(struct wmOperatorType *ot); -void OUTLINER_OT_object_remove_from_collection(struct wmOperatorType *ot); - -void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot); -void OUTLINER_OT_collection_nested_new(struct wmOperatorType *ot); -void OUTLINER_OT_collection_delete_selected(struct wmOperatorType *ot); +void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); +void OUTLINER_OT_collection_link(struct wmOperatorType *ot); +void OUTLINER_OT_collection_instance(struct wmOperatorType *ot); +void OUTLINER_OT_collection_exclude_set(struct wmOperatorType *ot); +void OUTLINER_OT_collection_include_set(struct wmOperatorType *ot); /* outliner_utils.c ---------------------------------------------- */ @@ -368,6 +354,7 @@ TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tre TreeElement *outliner_find_item_at_x_in_row(const SpaceOops *soops, const TreeElement *parent_te, float view_co_x); TreeElement *outliner_find_tse(struct SpaceOops *soops, const TreeStoreElem *tse); TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem); +TreeElement *outliner_find_parent_element(ListBase *lb, TreeElement *parent_te, const TreeElement *child_te); TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, const struct ID *id); TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel *pchan); TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 9f466d331f3..9c1b9bf2630 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -33,6 +33,8 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "DNA_group_types.h" + #include "BLT_translation.h" #include "BKE_context.h" @@ -67,7 +69,7 @@ static int outliner_item_drag_drop_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); return ED_operator_outliner_active(C) && /* Only collection display modes supported for now. Others need more design work */ - ELEM(soops->outlinevis, SO_COLLECTIONS, SO_GROUPS); + ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_LIBRARIES); } static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) @@ -184,25 +186,19 @@ static void outliner_item_drag_handle( */ static bool is_empty_collection(TreeElement *te) { - if (!ELEM(TREESTORE(te)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { - return false; - } + Collection *collection = outliner_collection_from_tree_element(te); - SceneCollection *scene_collection; - if (TREESTORE(te)->type == TSE_SCENE_COLLECTION) { - scene_collection = (SceneCollection *)te->directdata; - } - else { - BLI_assert(TREESTORE(te)->type == TSE_LAYER_COLLECTION); - scene_collection = ((LayerCollection *)te->directdata)->scene_collection; + if (!collection) { + return false; } - return BLI_listbase_is_empty(&scene_collection->objects) && - BLI_listbase_is_empty(&scene_collection->scene_collections); + return BLI_listbase_is_empty(&collection->gobject) && + BLI_listbase_is_empty(&collection->children); } static bool outliner_item_drag_drop_apply( Main *bmain, + Scene *scene, SpaceOops *soops, OutlinerDragDropTooltip *data, const wmEvent *event) @@ -225,7 +221,7 @@ static bool outliner_item_drag_drop_apply( * it is strange to have it closed and we not see the newly dragged elements. */ const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle); - dragged_te->reinsert(bmain, soops, dragged_te, insert_handle, insert_type, event); + dragged_te->reinsert(bmain, scene, soops, dragged_te, insert_handle, insert_type, event); if (should_open_collection && !is_empty_collection(insert_handle)) { TREESTORE(insert_handle)->flag &= ~TSE_CLOSED; @@ -239,6 +235,7 @@ static bool outliner_item_drag_drop_apply( static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event) { Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); OutlinerDragDropTooltip *data = op->customdata; @@ -250,7 +247,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv switch (event->type) { case EVT_MODAL_MAP: if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { - if (outliner_item_drag_drop_apply(bmain, soops, data, event)) { + if (outliner_item_drag_drop_apply(bmain, scene, soops, data, event)) { skip_rebuild = false; } retval = OPERATOR_FINISHED; @@ -283,37 +280,20 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv return retval; } -/** - * Check if the given TreeElement is a collection - * - * This test is mainly used to see if next/prev TreeElement is a collection. - * It will fail when there is no next/prev TreeElement, or when the - * element is an Override or something else in the future. - */ -static bool tree_element_is_collection_get(const TreeElement *te) -{ - if (te == NULL) { - return false; - } - - TreeStoreElem *tselem = TREESTORE(te); - return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION); -} - static const char *outliner_drag_drop_tooltip_get( const TreeElement *te_float) { const char *name = NULL; const TreeElement *te_insert = te_float->drag_data->insert_handle; - if (tree_element_is_collection_get(te_float)) { + if (te_float && outliner_is_collection_tree_element(te_float)) { if (te_insert == NULL) { name = TIP_("Move collection"); } else { switch (te_float->drag_data->insert_type) { case TE_INSERT_BEFORE: - if (tree_element_is_collection_get(te_insert->prev)) { + if (te_insert->prev && outliner_is_collection_tree_element(te_insert->prev)) { name = TIP_("Move between collections"); } else { @@ -321,7 +301,7 @@ static const char *outliner_drag_drop_tooltip_get( } break; case TE_INSERT_AFTER: - if (tree_element_is_collection_get(te_insert->next)) { + if (te_insert->next && outliner_is_collection_tree_element(te_insert->next)) { name = TIP_("Move between collections"); } else { @@ -335,7 +315,7 @@ static const char *outliner_drag_drop_tooltip_get( } } else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) { - name = TIP_("Move to collection (Ctrl to add)"); + name = TIP_("Move to collection (Ctrl to link)"); } return name; @@ -434,7 +414,6 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_operation); WM_operatortype_append(OUTLINER_OT_scene_operation); WM_operatortype_append(OUTLINER_OT_object_operation); - WM_operatortype_append(OUTLINER_OT_group_operation); WM_operatortype_append(OUTLINER_OT_lib_operation); WM_operatortype_append(OUTLINER_OT_lib_relocate); WM_operatortype_append(OUTLINER_OT_id_operation); @@ -445,7 +424,6 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_action_set); WM_operatortype_append(OUTLINER_OT_constraint_operation); WM_operatortype_append(OUTLINER_OT_modifier_operation); - WM_operatortype_append(OUTLINER_OT_collection_operation); WM_operatortype_append(OUTLINER_OT_show_one_level); WM_operatortype_append(OUTLINER_OT_show_active); @@ -467,24 +445,18 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_parent_clear); WM_operatortype_append(OUTLINER_OT_scene_drop); WM_operatortype_append(OUTLINER_OT_material_drop); - WM_operatortype_append(OUTLINER_OT_group_link); + WM_operatortype_append(OUTLINER_OT_collection_drop); /* collections */ - WM_operatortype_append(OUTLINER_OT_collections_delete); - WM_operatortype_append(OUTLINER_OT_collection_select); - WM_operatortype_append(OUTLINER_OT_collection_toggle); - WM_operatortype_append(OUTLINER_OT_collection_link); - WM_operatortype_append(OUTLINER_OT_collection_unlink); WM_operatortype_append(OUTLINER_OT_collection_new); WM_operatortype_append(OUTLINER_OT_collection_duplicate); - - WM_operatortype_append(OUTLINER_OT_collection_nested_new); - WM_operatortype_append(OUTLINER_OT_collection_delete_selected); - WM_operatortype_append(OUTLINER_OT_collection_objects_add); - WM_operatortype_append(OUTLINER_OT_collection_objects_remove); + WM_operatortype_append(OUTLINER_OT_collection_delete); WM_operatortype_append(OUTLINER_OT_collection_objects_select); - WM_operatortype_append(OUTLINER_OT_object_add_to_new_collection); - WM_operatortype_append(OUTLINER_OT_object_remove_from_collection); + WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); + WM_operatortype_append(OUTLINER_OT_collection_link); + WM_operatortype_append(OUTLINER_OT_collection_instance); + WM_operatortype_append(OUTLINER_OT_collection_exclude_set); + WM_operatortype_append(OUTLINER_OT_collection_include_set); } static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) @@ -582,8 +554,8 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_nested_new", CKEY, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_delete_selected", XKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_new", CKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_delete", XKEY, KM_PRESS, 0, 0); outliner_item_drag_drop_modal_keymap(keyconf); } diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index d62f542e1d1..42fe70be527 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -44,8 +44,8 @@ #include "BLI_listbase.h" #include "BKE_armature.h" +#include "BKE_collection.h" #include "BKE_context.h" -#include "BKE_group.h" #include "BKE_layer.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -681,43 +681,42 @@ static eOLDrawState tree_element_active_keymap_item( return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_collection( - bContext *C, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) +static eOLDrawState tree_element_active_master_collection( + bContext *C, TreeElement *UNUSED(te), const eOLSetState set) { if (set == OL_SETSEL_NONE) { + ViewLayer *view_layer = CTX_data_view_layer(C); LayerCollection *active = CTX_data_layer_collection(C); - /* sometimes the renderlayer has no LayerCollection at all */ - if (active == NULL) { - return OL_DRAWSEL_NONE; - } - - if ((tselem->type == TSE_SCENE_COLLECTION && active->scene_collection == te->directdata) || - (tselem->type == TSE_LAYER_COLLECTION && active == te->directdata)) - { + if (active == view_layer->layer_collections.first) { return OL_DRAWSEL_NORMAL; } } - /* don't allow selecting a scene collection, it can have multiple layer collection - * instances (which one would the user want to be selected then?) */ - else if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *layer_collection = te->directdata; + else { + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *layer_collection = view_layer->layer_collections.first; + BKE_layer_collection_activate(view_layer, layer_collection); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + } - switch (layer_collection->scene_collection->type) { - case COLLECTION_TYPE_NONE: - case COLLECTION_TYPE_GROUP_INTERNAL: - { - ViewLayer *view_layer = BKE_view_layer_find_from_collection(tselem->id, layer_collection); - const int collection_index = BKE_layer_collection_findindex(view_layer, layer_collection); + return OL_DRAWSEL_NONE; +} - if (collection_index > -1) { - view_layer->active_collection = collection_index; - } - break; - } - default: - BLI_assert(!"Collection type not fully implemented"); +static eOLDrawState tree_element_active_layer_collection( + bContext *C, TreeElement *te, const eOLSetState set) +{ + if (set == OL_SETSEL_NONE) { + LayerCollection *active = CTX_data_layer_collection(C); + + if (active == te->directdata) { + return OL_DRAWSEL_NORMAL; } + } + else { + Scene *scene = CTX_data_scene(C); + LayerCollection *layer_collection = te->directdata; + ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); + BKE_layer_collection_activate(view_layer, layer_collection); WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); } @@ -785,12 +784,7 @@ eOLDrawState tree_element_type_active( case TSE_CONSTRAINT: return tree_element_active_constraint(C, scene, view_layer, te, tselem, set); case TSE_R_LAYER: - if (soops->outlinevis == SO_SCENES) { - return active_viewlayer(C, scene, view_layer, te, tselem, set); - } - else { - return OL_DRAWSEL_NONE; - } + return active_viewlayer(C, scene, view_layer, te, tselem, set); case TSE_POSEGRP: return tree_element_active_posegroup(C, scene, view_layer, te, tselem, set); case TSE_SEQUENCE: @@ -802,9 +796,10 @@ eOLDrawState tree_element_type_active( case TSE_GP_LAYER: //return tree_element_active_gplayer(C, scene, s, te, tselem, set); break; - case TSE_SCENE_COLLECTION: + case TSE_VIEW_COLLECTION_BASE: + return tree_element_active_master_collection(C, te, set); case TSE_LAYER_COLLECTION: - return tree_element_active_collection(C, te, tselem, set); + return tree_element_active_layer_collection(C, te, set); } return OL_DRAWSEL_NONE; } @@ -840,29 +835,29 @@ static void do_outliner_item_activate_tree_element( } } else if (te->idcode == ID_GR) { - Group *gr = (Group *)tselem->id; + Collection *gr = (Collection *)tselem->id; if (extend) { int sel = BA_SELECT; - FOREACH_GROUP_BASE_BEGIN(gr, base) + FOREACH_COLLECTION_BASE_RECURSIVE_BEGIN(gr, base) { if (base->flag & BASE_SELECTED) { sel = BA_DESELECT; break; } } - FOREACH_GROUP_BASE_END + FOREACH_COLLECTION_BASE_RECURSIVE_END - FOREACH_GROUP_OBJECT_BEGIN(gr, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(gr, object) { ED_object_base_select(BKE_view_layer_base_find(view_layer, object), sel); } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } else { BKE_view_layer_base_deselect_all(view_layer); - FOREACH_GROUP_OBJECT_BEGIN(gr, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(gr, object) { Base *base = BKE_view_layer_base_find(view_layer, object); /* Object may not be in this scene */ @@ -872,7 +867,7 @@ static void do_outliner_item_activate_tree_element( } } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index fd5f29aec39..5ae6cec84ba 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -51,10 +51,10 @@ #include "BLI_utildefines.h" #include "BKE_animsys.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_constraint.h" #include "BKE_fcurve.h" -#include "BKE_group.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_override.h" @@ -105,7 +105,8 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { - if (tselem->type) { + /* Layer collection points to collection ID. */ + if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { if (*datalevel == 0) *datalevel = tselem->type; else if (*datalevel != tselem->type) @@ -129,6 +130,9 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, case ID_LI: if (*idlevel == 0) *idlevel = idcode; else if (*idlevel != idcode) *idlevel = -1; + if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { + *datalevel = 0; + } break; } } @@ -214,21 +218,52 @@ static void unlink_texture_cb( } } -static void unlink_group_cb( +static void unlink_collection_cb( bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) { - Group *group = (Group *)tselem->id; - + Main *bmain = CTX_data_main(C); + Collection *collection = (Collection *)tselem->id; + if (tsep) { if (GS(tsep->id->name) == ID_OB) { Object *ob = (Object *)tsep->id; ob->dup_group = NULL; + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_GR) { + Collection *parent = (Collection *)tsep->id; + id_fake_user_set(&collection->id); + BKE_collection_child_remove(bmain, parent, collection); + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_SCE) { + Collection *parent = BKE_collection_master((Scene *)tsep->id); + id_fake_user_set(&collection->id); + BKE_collection_child_remove(bmain, parent, collection); + DEG_relations_tag_update(bmain); } } - else { - Main *bmain = CTX_data_main(C); - BKE_libblock_delete(bmain, group); +} + +static void unlink_object_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + Main *bmain = CTX_data_main(C); + Object *ob = (Object *)tselem->id; + + if (tsep) { + if (GS(tsep->id->name) == ID_GR) { + Collection *parent = (Collection *)tsep->id; + BKE_collection_object_remove(bmain, parent, ob, true); + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_SCE) { + Collection *parent = BKE_collection_master((Scene *)tsep->id); + BKE_collection_object_remove(bmain, parent, ob, true); + DEG_relations_tag_update(bmain); + } } } @@ -255,7 +290,7 @@ static void outliner_do_libdata_operation( for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { - if (tselem->type == 0) { + if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; operation_cb(C, reports, scene, te, tsep, tselem, user_data); } @@ -520,42 +555,6 @@ static void singleuser_world_cb( } } -static void group_linkobs2scene_cb( - bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - ViewLayer *view_layer = CTX_data_view_layer(C); - SceneCollection *sc = CTX_data_scene_collection(C); - Group *group = (Group *)tselem->id; - Base *base; - - FOREACH_GROUP_OBJECT_BEGIN(group, object) - { - base = BKE_view_layer_base_find(view_layer, object); - if (!base) { - /* link to scene */ - BKE_collection_object_add(&scene->id, sc, object); - base = BKE_view_layer_base_find(view_layer, object); - id_us_plus(&object->id); - } - - base->flag |= BASE_SELECTED; - } - FOREACH_GROUP_OBJECT_END; -} - -static void group_instance_cb( - bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Group *group = (Group *)tselem->id; - - Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, scene->cursor.location, NULL, false, scene->layact); - ob->dup_group = group; - ob->transflag |= OB_DUPLIGROUP; - id_lib_extern(&group->id); -} - /** * \param select_recurse: Set to false for operations which are already recursively operating on their children. */ @@ -660,17 +659,6 @@ typedef enum eOutliner_PropModifierOps { OL_MODIFIER_OP_DELETE } eOutliner_PropModifierOps; -typedef enum eOutliner_PropCollectionOps { - OL_COLLECTION_OP_OBJECTS_ADD = 1, - OL_COLLECTION_OP_OBJECTS_REMOVE, - OL_COLLECTION_OP_OBJECTS_SELECT, - OL_COLLECTION_OP_COLLECTION_NEW, - OL_COLLECTION_OP_COLLECTION_COPY, - OL_COLLECTION_OP_COLLECTION_DEL, - OL_COLLECTION_OP_COLLECTION_UNLINK, - OL_COLLECTION_OP_GROUP_CREATE, -} eOutliner_PropCollectionOps; - static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) { bPoseChannel *pchan = (bPoseChannel *)te->directdata; @@ -821,90 +809,6 @@ static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem } } -static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg) -{ - bContext *C = (bContext *)Carg; - Scene *scene = CTX_data_scene(C); - LayerCollection *lc = te->directdata; - ID *id = te->store_elem->id; - SceneCollection *sc = lc->scene_collection; - - if (event == OL_COLLECTION_OP_OBJECTS_ADD) { - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - BKE_collection_object_add(id, sc, ob); - } - CTX_DATA_END; - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - } - else if (event == OL_COLLECTION_OP_OBJECTS_REMOVE) { - Main *bmain = CTX_data_main(C); - - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - BKE_collection_object_remove(bmain, id, sc, ob, true); - } - CTX_DATA_END; - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - te->store_elem->flag &= ~TSE_SELECTED; - } - else if (event == OL_COLLECTION_OP_OBJECTS_SELECT) { - BKE_layer_collection_objects_select(lc); - WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); - } - else if (event == OL_COLLECTION_OP_COLLECTION_NEW) { - if (GS(id->name) == ID_GR) { - BKE_collection_add(id, sc, COLLECTION_TYPE_GROUP_INTERNAL, NULL); - } - else { - BLI_assert(GS(id->name) == ID_SCE); - BKE_collection_add(id, sc, COLLECTION_TYPE_NONE, NULL); - } - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - } - else if (event == OL_COLLECTION_OP_COLLECTION_COPY) { - BKE_layer_collection_duplicate(id, lc); - DEG_relations_tag_update(CTX_data_main(C)); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - } - else if (event == OL_COLLECTION_OP_COLLECTION_UNLINK) { - ViewLayer *view_layer = CTX_data_view_layer(C); - - if (BLI_findindex(&view_layer->layer_collections, lc) == -1) { - /* we can't unlink if the layer collection wasn't directly linked */ - TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */ - } - else { - BKE_collection_unlink(view_layer, lc); - DEG_relations_tag_update(CTX_data_main(C)); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - } - } - else if (event == OL_COLLECTION_OP_COLLECTION_DEL) { - if (BKE_collection_remove(id, sc)) { - DEG_relations_tag_update(CTX_data_main(C)); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - } - else { - /* we can't remove the master collection */ - TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */ - } - } - else if (event == OL_COLLECTION_OP_GROUP_CREATE) { - Main *bmain = CTX_data_main(C); - BKE_collection_group_create(bmain, scene, lc); - 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_LAYER, scene); - } - else { - BLI_assert(!"Collection operation not fully implemented!"); - } -} - static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *), void *arg) @@ -1124,106 +1028,6 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) /* **************************************** */ -typedef enum eOutliner_PropGroupOps { - OL_GROUPOP_UNLINK = 1, - OL_GROUPOP_LOCAL, - OL_GROUPOP_STATIC_OVERRIDE, - OL_GROUPOP_LINK, - OL_GROUPOP_DELETE, - OL_GROUPOP_REMAP, - OL_GROUPOP_INSTANCE, - OL_GROUPOP_TOGVIS, - OL_GROUPOP_TOGSEL, - OL_GROUPOP_TOGREN, - OL_GROUPOP_RENAME, -} eOutliner_PropGroupOps; - -static const EnumPropertyItem prop_group_op_types[] = { - {OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""}, - {OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""}, - {OL_GROUPOP_STATIC_OVERRIDE, "STATIC_OVERRIDE", - 0, "Add Static Override", "Add a local static override of that group"}, - {OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""}, - {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", ""}, - {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users", - "Make all users of selected data-blocks to use instead current (clicked) one"}, - {OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""}, - {OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""}, - {OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, - {OL_GROUPOP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, - {OL_GROUPOP_RENAME, "RENAME", 0, "Rename", ""}, - {0, NULL, 0, NULL, NULL} -}; - -static int outliner_group_operation_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - int event; - - /* check for invalid states */ - if (soops == NULL) - return OPERATOR_CANCELLED; - - event = RNA_enum_get(op->ptr, "type"); - - switch (event) { - case OL_GROUPOP_UNLINK: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL); - break; - case OL_GROUPOP_LOCAL: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); - break; - case OL_GROUPOP_STATIC_OVERRIDE: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL); - break; - case OL_GROUPOP_LINK: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL); - break; - case OL_GROUPOP_INSTANCE: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL); - /* works without this except if you try render right after, see: 22027 */ - DEG_relations_tag_update(CTX_data_main(C)); - break; - case OL_GROUPOP_DELETE: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); - break; - case OL_GROUPOP_REMAP: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); - break; - case OL_GROUPOP_RENAME: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); - break; - default: - BLI_assert(0); - } - - ED_undo_push(C, prop_group_op_types[event - 1].name); - WM_event_add_notifier(C, NC_GROUP, NULL); - - return OPERATOR_FINISHED; -} - - -void OUTLINER_OT_group_operation(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Outliner Group Operation"; - ot->idname = "OUTLINER_OT_group_operation"; - ot->description = ""; - - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = outliner_group_operation_exec; - ot->poll = ED_operator_outliner_active; - - ot->flag = 0; - - ot->prop = RNA_def_enum(ot->srna, "type", prop_group_op_types, 0, "Group Operation", ""); -} - -/* **************************************** */ - typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_INVALID = 0, @@ -1278,6 +1082,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_UNLINK: { /* unlink datablock from its parent */ + if (objectlevel) { + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_object_cb, NULL); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); + ED_undo_push(C, "Unlink Object"); + break; + } + switch (idlevel) { case ID_AC: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL); @@ -1303,6 +1115,12 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); ED_undo_push(C, "Unlink world"); break; + case ID_GR: + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_collection_cb, NULL); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); + ED_undo_push(C, "Unlink Collection"); + break; default: BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); break; @@ -1840,84 +1658,6 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot) /* ******************** */ -static EnumPropertyItem prop_collection_op_types[] = { - {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"}, - {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"}, - {OL_COLLECTION_OP_OBJECTS_SELECT, "OBJECTS_SELECT", ICON_RESTRICT_SELECT_OFF, "Select Objects", "Select collection objects"}, - {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, - {OL_COLLECTION_OP_COLLECTION_COPY, "COLLECTION_DUPLI", ICON_NONE, "Duplicate Collection", "Duplicate the collection"}, - {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"}, - {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"}, - {OL_COLLECTION_OP_GROUP_CREATE, "GROUP_CREATE", ICON_GROUP, "Create Group", "Turn the collection into a group collection"}, - {0, NULL, 0, NULL, NULL} -}; - -static int outliner_collection_operation_exec(bContext *C, wmOperator *op) -{ - SpaceOops *soops = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutliner_PropCollectionOps event; - - event = RNA_enum_get(op->ptr, "type"); - set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - - outliner_do_data_operation(soops, datalevel, event, &soops->tree, collection_cb, C); - - outliner_cleanup_tree(soops); - - ED_undo_push(C, "Collection operation"); - - return OPERATOR_FINISHED; -} - -static int outliner_collection_operation_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - SpaceOops *soops = CTX_wm_space_outliner(C); - wmOperatorType *ot = op->type; - EnumPropertyItem *prop = &prop_collection_op_types[0]; - - uiPopupMenu *pup = UI_popup_menu_begin(C, "Collection", ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); - - for (int i = 0; i < (ARRAY_SIZE(prop_collection_op_types) - 1); i++, prop++) { - if (soops->outlinevis != SO_GROUPS || - !ELEM(prop->value, - OL_COLLECTION_OP_OBJECTS_SELECT, - OL_COLLECTION_OP_COLLECTION_UNLINK, - OL_COLLECTION_OP_GROUP_CREATE)) - { - uiItemEnumO_ptr(layout, ot, NULL, prop->icon, "type", prop->value); - } - } - - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; -} - -void OUTLINER_OT_collection_operation(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Outliner Collection Operation"; - ot->idname = "OUTLINER_OT_collection_operation"; - ot->description = ""; - - /* callbacks */ - ot->invoke = outliner_collection_operation_invoke; - ot->exec = outliner_collection_operation_exec; - ot->poll = ED_operator_outliner_active; - - ot->flag = 0; - - prop = RNA_def_enum(ot->srna, "type", prop_collection_op_types, OL_COLLECTION_OP_OBJECTS_ADD, "Collection Operation", ""); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; -} - -/* ******************** */ - // XXX: select linked is for RNA structs only static const EnumPropertyItem prop_data_op_types[] = { {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, @@ -2041,7 +1781,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop } set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - + if (scenelevel) { if (objectlevel || datalevel || idlevel) { BKE_report(reports, RPT_WARNING, "Mixed selection"); @@ -2051,7 +1791,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop } } else if (objectlevel) { - WM_menu_name_call(C, "OUTLINER_MT_context_object", WM_OP_INVOKE_REGION_WIN); + WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN); } else if (idlevel) { if (idlevel == -1 || datalevel) { @@ -2060,7 +1800,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop else { switch (idlevel) { case ID_GR: - WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL); + WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); break; case ID_LI: WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL); @@ -2081,8 +1821,11 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop else if (datalevel == TSE_DRIVER_BASE) { /* do nothing... no special ops needed yet */ } - else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER)) { - /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/ + else if (datalevel == TSE_LAYER_COLLECTION) { + WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); + } + else if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { + WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); } else if (datalevel == TSE_ID_BASE) { /* do nothing... there are no ops needed here yet */ @@ -2093,12 +1836,6 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop else if (datalevel == TSE_MODIFIER) { WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL); } - else if (datalevel == TSE_LAYER_COLLECTION) { - WM_operator_name_call(C, "OUTLINER_OT_collection_operation", WM_OP_INVOKE_REGION_WIN, NULL); - } - else if (datalevel == TSE_SCENE_COLLECTION) { - WM_menu_name_call(C, "OUTLINER_MT_context_scene_collection", WM_OP_INVOKE_REGION_WIN); - } else { WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); } @@ -2123,6 +1860,7 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent uiBut *but = UI_context_active_but_get(C); TreeElement *te; float fmval[2]; + bool found = false; if (but) { UI_but_tooltip_timer_remove(C, but); @@ -2132,9 +1870,17 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent for (te = soops->tree.first; te; te = te->next) { if (do_outliner_operation_event(C, ar, soops, te, fmval)) { + found = true; break; } } + + if (!found) { + /* Menus for clicking in empty space. */ + if (soops->outlinevis == SO_VIEW_LAYER) { + WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); + } + } return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index ed809062a29..58ab8f3735e 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -91,14 +91,8 @@ #endif /* prototypes */ -static void outliner_add_layer_collections_recursive( - SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten, - const bool show_objects); -static TreeElement *outliner_add_scene_collection_recursive( - SpaceOops *soops, ListBase *tree, Scene *scene, SceneCollection *scene_collection, TreeElement *parent_ten); -static void outliner_add_view_layer( - SpaceOops *soops, ListBase *tree, TreeElement *parent, - Scene *scene, ViewLayer *layer, const bool show_objects); +static TreeElement *outliner_add_collection_recursive( + SpaceOops *soops, Collection *collection, TreeElement *ten); static void outliner_make_object_parent_hierarchy(ListBase *lb); /* ********************************************************* */ @@ -293,28 +287,30 @@ static void outliner_add_line_styles(SpaceOops *soops, ListBase *lb, Scene *sce, static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te) { /* View layers */ - TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); - tenla->name = IFACE_("View Layers"); + TreeElement *ten = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); + ten->name = IFACE_("View Layers"); ViewLayer *view_layer; for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, 0); + TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0); tenlay->name = view_layer->name; tenlay->directdata = view_layer; } /* Collections */ - outliner_add_scene_collection_recursive(soops, lb, sce, sce->collection, NULL); + ten = outliner_add_element(soops, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); + ten->name = IFACE_("Scene Collection"); + outliner_add_collection_recursive(soops, sce->master_collection, ten); /* Objects */ - tenla = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); - tenla->name = IFACE_("Objects"); + ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); + ten->name = IFACE_("Objects"); FOREACH_SCENE_OBJECT_BEGIN(sce, ob) { - outliner_add_element(soops, &tenla->subtree, ob, NULL, 0, 0); + outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0); } FOREACH_SCENE_OBJECT_END; - outliner_make_object_parent_hierarchy(&tenla->subtree); + outliner_make_object_parent_hierarchy(&ten->subtree); /* Animation Data */ if (outliner_animdata_test(sce->adt)) @@ -329,7 +325,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom struct ObjectsSelectedData *data = customdata; TreeStoreElem *tselem = TREESTORE(te); - if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { + if (outliner_is_collection_tree_element(te)) { return TRAVERSE_CONTINUE; } @@ -348,13 +344,14 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom * Instead we move all the selected objects around. */ static void outliner_object_reorder( - Main *bmain, SpaceOops *soops, + Main *bmain, Scene *scene, + SpaceOops *soops, TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, const wmEvent *event) { - SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle); - SceneCollection *sc_ob_parent = NULL; + Collection *collection = outliner_collection_from_tree_element(insert_handle); + Collection *collection_ob_parent = NULL; ID *id = insert_handle->store_elem->id; BLI_assert(action == TE_INSERT_INTO); @@ -375,24 +372,24 @@ static void outliner_object_reorder( Object *ob = (Object *)TREESTORE(ten_selected)->id; if (is_append) { - BKE_collection_object_add(id, sc, ob); + BKE_collection_object_add(bmain, collection, ob); continue; } - /* Find parent scene-collection of object. */ + /* Find parent collection of object. */ if (ten_selected->parent) { for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { - if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { - sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent); + if (outliner_is_collection_tree_element(te_ob_parent)) { + collection_ob_parent = outliner_collection_from_tree_element(te_ob_parent); break; } } } else { - sc_ob_parent = BKE_collection_master(id); + collection_ob_parent = BKE_collection_master(scene); } - BKE_collection_object_move(id, sc, sc_ob_parent, ob); + BKE_collection_object_move(bmain, scene, collection, collection_ob_parent, ob); } BLI_freelistN(&data.objects_selected_array); @@ -409,8 +406,7 @@ static bool outliner_object_reorder_poll( const TreeElement *insert_element, TreeElement **io_insert_handle, TreeElementInsertType *io_action) { - TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); - if (ELEM(tselem_handle->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION) && + if (outliner_is_collection_tree_element(*io_insert_handle) && (insert_element->parent != *io_insert_handle)) { *io_action = TE_INSERT_INTO; @@ -815,6 +811,11 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor } break; } + case ID_GR: + { + Collection *collection = (Collection *)id; + outliner_add_collection_recursive(soops, collection, te); + } default: break; } @@ -876,7 +877,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i else if (type == TSE_GP_LAYER) { /* pass */ } - else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { + else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { /* pass */ } else if (type == TSE_ID_BASE) { @@ -895,8 +896,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; /* ID datablock */ - if (tsepar == NULL || tsepar->type != TSE_ID_BASE) + if (tsepar == NULL || tsepar->type != TSE_ID_BASE || soops->filter_id_type) { outliner_add_id_contents(soops, te, tselem, id); + } } else if (type == TSE_ANIM_DATA) { IdAdtTemplate *iat = (IdAdtTemplate *)idv; @@ -1177,11 +1179,6 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i te->flag |= TE_LAZY_CLOSED; } - if ((type != TSE_LAYER_COLLECTION) && (te->idcode == ID_GR)) { - Group *group = (Group *)id; - outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL, true); - } - return te; } @@ -1263,6 +1260,32 @@ static const char *outliner_idcode_to_plural(short idcode) return (prop) ? RNA_property_ui_name(prop) : "UNKNOWN"; } +static bool outliner_library_id_show(Library *lib, ID *id, short filter_id_type) +{ + if (id->lib != lib) { + return false; + } + + if (filter_id_type == ID_GR) { + /* Don't show child collections of non-scene master collection, + * they are already shown as children. */ + Collection *collection = (Collection *)id; + bool has_non_scene_parent = false; + + for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { + if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) { + has_non_scene_parent = true; + } + } + + if (has_non_scene_parent) { + return false; + } + } + + return true; +} + static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib) { TreeElement *ten; @@ -1298,13 +1321,13 @@ static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeE } for (id = lbarray[a]->first; id; id = id->next) { - if (id->lib == lib) + if (outliner_library_id_show(lib, id, filter_id_type)) { outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); + } } } } } - } static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) @@ -1353,170 +1376,165 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) } } -static void outliner_layer_collections_reorder( +static void outliner_collections_reorder( Main *bmain, - SpaceOops *UNUSED(soops), - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, + Scene *UNUSED(scene), + SpaceOops *soops, + TreeElement *insert_element, + TreeElement *insert_handle, + TreeElementInsertType action, const wmEvent *UNUSED(event)) { - LayerCollection *lc_insert = insert_element->directdata; - LayerCollection *lc_handle = insert_handle->directdata; - ID *id = insert_element->store_elem->id; + TreeElement *from_parent_te, *to_parent_te; + Collection *from_parent, *to_parent; - if (action == TE_INSERT_BEFORE) { - BKE_layer_collection_move_above(id, lc_handle, lc_insert); - } - else if (action == TE_INSERT_AFTER) { - BKE_layer_collection_move_below(id, lc_handle, lc_insert); + Collection *collection = outliner_collection_from_tree_element(insert_element); + Collection *relative = NULL; + bool relative_after = false; + + from_parent_te = outliner_find_parent_element(&soops->tree, NULL, insert_element); + from_parent = (from_parent_te) ? outliner_collection_from_tree_element(from_parent_te) : NULL; + + if (ELEM(action, TE_INSERT_BEFORE, TE_INSERT_AFTER)) { + to_parent_te = outliner_find_parent_element(&soops->tree, NULL, insert_handle); + to_parent = (to_parent_te) ? outliner_collection_from_tree_element(to_parent_te) : NULL; + + relative = outliner_collection_from_tree_element(insert_handle); + relative_after = (action == TE_INSERT_AFTER); } else if (action == TE_INSERT_INTO) { - BKE_layer_collection_move_into(id, lc_handle, lc_insert); + to_parent = outliner_collection_from_tree_element(insert_handle); } else { BLI_assert(0); + return; } + if (!to_parent) { + return; + } + + BKE_collection_move(bmain, to_parent, from_parent, relative, relative_after, collection); + DEG_relations_tag_update(bmain); } -static bool outliner_layer_collections_reorder_poll( + +static bool outliner_collections_reorder_poll( const TreeElement *insert_element, - TreeElement **io_insert_handle, TreeElementInsertType *UNUSED(io_action)) + TreeElement **io_insert_handle, + TreeElementInsertType *io_action) { - const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); + /* Can't move master collection. */ + Collection *collection = outliner_collection_from_tree_element(insert_element); + if (collection->flag & COLLECTION_IS_MASTER) { + return false; + } + + /* Can only move into collections. */ + Collection *collection_handle = outliner_collection_from_tree_element(*io_insert_handle); + if (collection_handle == NULL) { + return false; + } - if (tselem_handle->id != insert_element->store_elem->id) { - return false; + /* We can't insert/before after master collection. */ + if (collection_handle->flag & COLLECTION_IS_MASTER) { + if (*io_action == TE_INSERT_BEFORE) { + /* can't go higher than master collection, insert into it */ + *io_action = TE_INSERT_INTO; + } + else if (*io_action == TE_INSERT_AFTER) { + *io_insert_handle = (*io_insert_handle)->subtree.last; + } } - return ELEM(tselem_handle->type, TSE_LAYER_COLLECTION); + return true; +} + +static void outliner_add_layer_collection_objects( + SpaceOops *soops, ListBase *tree, ViewLayer *layer, + LayerCollection *lc, TreeElement *ten) +{ + for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(layer, cob->ob); + TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0); + te_object->directdata = base; + } } static void outliner_add_layer_collections_recursive( - SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten, + SpaceOops *soops, ListBase *tree, ViewLayer *layer, + ListBase *layer_collections, TreeElement *parent_ten, const bool show_objects) { - for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) { + for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) { + ID *id = &lc->collection->id; TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); - ten->name = collection->scene_collection->name; - ten->directdata = collection; - ten->reinsert = outliner_layer_collections_reorder; - ten->reinsert_poll = outliner_layer_collections_reorder_poll; + ten->name = id->name + 2; + ten->directdata = lc; + ten->reinsert = outliner_collections_reorder; + ten->reinsert_poll = outliner_collections_reorder_poll; - outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten, show_objects); - if (show_objects) { - for (LinkData *link = collection->object_bases.first; link; link = link->next) { - Base *base = (Base *)link->data; - TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0); - te_object->directdata = base; - } + const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; + if (exclude) { + ten->flag |= TE_DISABLED; + } + + outliner_add_layer_collections_recursive(soops, &ten->subtree, layer, &lc->layer_collections, ten, show_objects); + if (!exclude && show_objects) { + outliner_add_layer_collection_objects(soops, &ten->subtree, layer, lc, ten); } } } static void outliner_add_view_layer(SpaceOops *soops, ListBase *tree, TreeElement *parent, - Scene *scene, ViewLayer *layer, const bool show_objects) -{ - outliner_add_layer_collections_recursive(soops, tree, &scene->id, &layer->layer_collections, parent, show_objects); -} - -static void outliner_scene_collections_reorder( - Main *bmain, - SpaceOops *UNUSED(soops), - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, - const wmEvent *UNUSED(event)) -{ - SceneCollection *sc_insert = insert_element->directdata; - SceneCollection *sc_handle = insert_handle->directdata; - ID *id = insert_handle->store_elem->id; - BLI_assert(id == insert_element->store_elem->id); - - BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(id))); - if (action == TE_INSERT_BEFORE) { - BKE_collection_move_above(id, sc_handle, sc_insert); - } - else if (action == TE_INSERT_AFTER) { - BKE_collection_move_below(id, sc_handle, sc_insert); - } - else if (action == TE_INSERT_INTO) { - BKE_collection_move_into(id, sc_handle, sc_insert); - } - else { - BLI_assert(0); - } - - DEG_relations_tag_update(bmain); -} -static bool outliner_scene_collections_reorder_poll( - const TreeElement *insert_element, - TreeElement **io_insert_handle, TreeElementInsertType *io_action) + ViewLayer *layer, const bool show_objects) { - const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); - ID *id = tselem_handle->id; - - if (id != insert_element->store_elem->id) { - return false; - } - - if (!ELEM(tselem_handle->type, TSE_SCENE_COLLECTION)) { - return false; + /* First layer collection is for master collection, don't show it. */ + LayerCollection *lc = layer->layer_collections.first; + if (lc == NULL) { + return; } - SceneCollection *sc_master = BKE_collection_master(id); - SceneCollection *sc_handle = (*io_insert_handle)->directdata; - - if (sc_handle == sc_master) { - /* exception: Can't insert before/after master selection, has to be one of its childs */ - TreeElement *te_master = *io_insert_handle; - if (*io_action == TE_INSERT_BEFORE) { - /* can't go higher than master collection, insert into it */ - *io_action = TE_INSERT_INTO; - } - else if (*io_action == TE_INSERT_AFTER) { - *io_insert_handle = te_master->subtree.last; - } + outliner_add_layer_collections_recursive(soops, tree, layer, &lc->layer_collections, parent, show_objects); + if (show_objects) { + outliner_add_layer_collection_objects(soops, tree, layer, lc, parent); } - return true; } -BLI_INLINE void outliner_add_scene_collection_init(TreeElement *te, Scene *scene, SceneCollection *collection) +BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection) { - if (collection == scene->collection) { - // Don't display name of master collection - te->name = IFACE_("Collections"); + if (collection->flag & COLLECTION_IS_MASTER) { + te->name = IFACE_("Scene Collection"); } else { - te->name = collection->name; + te->name = collection->id.name + 2; } te->directdata = collection; - te->reinsert = outliner_scene_collections_reorder; - te->reinsert_poll = outliner_scene_collections_reorder_poll; + te->reinsert = outliner_collections_reorder; + te->reinsert_poll = outliner_collections_reorder_poll; } -BLI_INLINE void outliner_add_scene_collection_objects( - SpaceOops *soops, ListBase *tree, SceneCollection *collection, TreeElement *parent) +BLI_INLINE void outliner_add_collection_objects( + SpaceOops *soops, ListBase *tree, Collection *collection, TreeElement *parent) { - for (LinkData *link = collection->objects.first; link; link = link->next) { - outliner_add_element(soops, tree, link->data, parent, 0, 0); + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + outliner_add_element(soops, tree, cob->ob, parent, 0, 0); } } -static TreeElement *outliner_add_scene_collection_recursive( - SpaceOops *soops, ListBase *tree, Scene *scene, SceneCollection *scene_collection, TreeElement *parent_ten) +static TreeElement *outliner_add_collection_recursive( + SpaceOops *soops, Collection *collection, TreeElement *ten) { - TreeElement *ten = outliner_add_element(soops, tree, &scene->id, parent_ten, TSE_SCENE_COLLECTION, 0); - outliner_add_scene_collection_init(ten, scene, scene_collection); + outliner_add_collection_init(ten, collection); - if (soops->outlinevis != SO_SCENES) { - outliner_add_scene_collection_objects(soops, &ten->subtree, scene_collection, ten); + for (CollectionChild *child = collection->children.first; child; child = child->next) { + outliner_add_element(soops, &ten->subtree, &child->collection->id, ten, 0, 0); } - for (SceneCollection *scene_collection_nested = scene_collection->scene_collections.first; - scene_collection_nested != NULL; - scene_collection_nested = scene_collection_nested->next) - { - outliner_add_scene_collection_recursive(soops, &ten->subtree, scene, scene_collection_nested, ten); + if (soops->outlinevis != SO_SCENES) { + outliner_add_collection_objects(soops, &ten->subtree, collection, ten); } return ten; @@ -1732,8 +1750,7 @@ static void outliner_restore_scrolling_position(SpaceOops *soops, ARegion *ar, O static bool test_collection_callback(TreeElement *te) { - TreeStoreElem *tselem = TREESTORE(te); - return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION); + return outliner_is_collection_tree_element(te); } static bool test_object_callback(TreeElement *te) @@ -1787,7 +1804,8 @@ static TreeElement *outliner_find_first_desired_element_at_y( te = outliner_find_item_at_y(soops, &soops->tree, view_co); bool (*callback_test)(TreeElement *); - if (soops->filter & SO_FILTER_NO_COLLECTION) { + if ((soops->outlinevis == SO_VIEW_LAYER) && + (soops->filter & SO_FILTER_NO_COLLECTION)) { callback_test = test_object_callback; } else { @@ -1866,10 +1884,11 @@ static int outliner_exclude_filter_get(SpaceOops *soops) return (exclude_filter & SO_FILTER_SEARCH); } + if (soops->filter & SO_FILTER_NO_OBJECT) { + exclude_filter |= SO_FILTER_OB_TYPE; + } + switch (soops->filter_state) { - case SO_FILTER_OB_NONE: - exclude_filter |= SO_FILTER_OB_TYPE; - break; case SO_FILTER_OB_VISIBLE: exclude_filter |= SO_FILTER_OB_STATE_VISIBLE; break; @@ -2163,12 +2182,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa outliner_make_object_parent_hierarchy(&te->subtree); } } - else if (soops->outlinevis == SO_GROUPS) { - Group *group; - for (group = mainvar->group.first; group; group = group->id.next) { - te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0); - } - } else if (soops->outlinevis == SO_SEQUENCE) { Sequence *seq; Editing *ed = BKE_sequencer_editing_get(scene, false); @@ -2208,27 +2221,24 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa else if (soops->outlinevis == SO_ID_ORPHANS) { outliner_add_orphaned_datablocks(mainvar, soops); } - else if (soops->outlinevis == SO_COLLECTIONS) { - TreeElement *tenlay = outliner_add_element(soops, &soops->tree, scene, te, TSE_R_LAYER, 0); - tenlay->name = view_layer->name; - tenlay->directdata = view_layer; - TREESTORE(tenlay)->flag &= ~TSE_CLOSED; - + else if (soops->outlinevis == SO_VIEW_LAYER) { if (soops->filter & SO_FILTER_NO_COLLECTION) { + /* Show objects in the view layer. */ for (Base *base = view_layer->object_bases.first; base; base = base->next) { - TreeElement *te_object = outliner_add_element(soops, &tenlay->subtree, base->object, NULL, 0, 0); + TreeElement *te_object = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); te_object->directdata = base; } - outliner_make_object_parent_hierarchy(&tenlay->subtree); + + outliner_make_object_parent_hierarchy(&soops->tree); } else { - outliner_add_view_layer(soops, &tenlay->subtree, NULL, scene, view_layer, true); - } - } - else { - if (BASACT(view_layer)) { - ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0); - ten->directdata = BASACT(view_layer); + /* Show collections in the view layer. */ + ten = outliner_add_element(soops, &soops->tree, scene, NULL, TSE_VIEW_COLLECTION_BASE, 0); + ten->name = IFACE_("Scene Collection"); + TREESTORE(ten)->flag &= ~TSE_CLOSED; + + bool show_objects = !(soops->filter & SO_FILTER_NO_OBJECT); + outliner_add_view_layer(soops, &ten->subtree, ten, view_layer, show_objects); } } diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index d3f7fd7055e..896f6c016d0 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -101,6 +101,23 @@ TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store return NULL; } +/* Find parent element of te */ +TreeElement *outliner_find_parent_element(ListBase *lb, TreeElement *parent_te, const TreeElement *child_te) +{ + TreeElement *te; + for (te = lb->first; te; te = te->next) { + if (te == child_te) { + return parent_te; + } + + TreeElement *find_te = outliner_find_parent_element(&te->subtree, te, child_te); + if (find_te) { + return find_te; + } + } + return NULL; +} + /* tse is not in the treestore, we use its contents to find a match */ TreeElement *outliner_find_tse(SpaceOops *soops, const TreeStoreElem *tse) { @@ -125,10 +142,8 @@ TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, const ID *id) if (tselem->id == id) { return te; } - /* only deeper on scene or object */ - if (ELEM(te->idcode, ID_OB, ID_SCE) || - ((soops->outlinevis == SO_GROUPS) && (te->idcode == ID_GR))) - { + /* only deeper on scene collection or object */ + if (ELEM(te->idcode, ID_OB, ID_SCE, ID_GR)) { TreeElement *tes = outliner_find_id(soops, &te->subtree, id); if (tes) { return tes; diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index b762dd31f58..72ce24aaff5 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -138,10 +138,6 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e } } } - else if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { - /* support adding object from different scene to collection */ - return 1; - } } } return 0; @@ -163,7 +159,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - if (!ELEM(soops->outlinevis, SO_SCENES, SO_GROUPS, SO_COLLECTIONS)) { + if (!ELEM(soops->outlinevis, SO_VIEW_LAYER)) { return false; } @@ -250,7 +246,7 @@ static void outliner_material_drop_copy(wmDrag *drag, wmDropBox *drop) RNA_string_set(drop->ptr, "material", id->name + 2); } -static int outliner_group_link_poll(bContext *C, wmDrag *drag, const wmEvent *event) +static int outliner_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); @@ -259,19 +255,19 @@ static int outliner_group_link_poll(bContext *C, wmDrag *drag, const wmEvent *ev if (drag->type == WM_DRAG_ID) { ID *id = drag->poin; - if (GS(id->name) == ID_OB) { + if (ELEM(GS(id->name), ID_OB, ID_GR)) { /* Ensure item under cursor is valid drop target */ TreeElement *te = outliner_dropzone_find(soops, fmval, true); - return (te && te->idcode == ID_GR && TREESTORE(te)->type == 0); + return (te && outliner_is_collection_tree_element(te)); } } return 0; } -static void outliner_group_link_copy(wmDrag *drag, wmDropBox *drop) +static void outliner_collection_drop_copy(wmDrag *drag, wmDropBox *drop) { ID *id = drag->poin; - RNA_string_set(drop->ptr, "object", id->name + 2); + RNA_string_set(drop->ptr, "child", id->name + 2); } /* region dropbox definition */ @@ -283,7 +279,7 @@ static void outliner_dropboxes(void) WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy); WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", outliner_scene_drop_poll, outliner_scene_drop_copy); WM_dropbox_add(lb, "OUTLINER_OT_material_drop", outliner_material_drop_poll, outliner_material_drop_copy); - WM_dropbox_add(lb, "OUTLINER_OT_group_link", outliner_group_link_poll, outliner_group_link_copy); + WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", outliner_collection_drop_poll, outliner_collection_drop_copy); } static void outliner_main_region_draw(const bContext *C, ARegion *ar) @@ -438,7 +434,7 @@ static void outliner_main_region_message_subscribe( .notify = ED_region_do_msg_notify_tag_redraw, }; - if (soops->outlinevis == SO_COLLECTIONS) { + if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_SCENES)) { WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); } } |