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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_outliner')
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c1056
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c123
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c148
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h47
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c78
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c81
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c404
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c360
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c23
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c20
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);
}
}