diff options
Diffstat (limited to 'source/blender/editors')
31 files changed, 1323 insertions, 2073 deletions
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index b7eaa1a4a5f..aad4f71fe9a 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -84,12 +84,12 @@ #include "BLI_ghash.h" #include "BLI_string.h" -#include "BKE_animsys.h" #include "BKE_action.h" -#include "BKE_fcurve.h" +#include "BKE_animsys.h" +#include "BKE_collection.h" #include "BKE_context.h" +#include "BKE_fcurve.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_key.h" #include "BKE_layer.h" #include "BKE_main.h" @@ -1727,7 +1727,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi * - used to ease the process of doing multiple-character choreographies */ if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) { - if (BKE_group_object_exists(ads->filter_grp, ob) == 0) + if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) continue; } @@ -2894,7 +2894,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_m * - used to ease the process of doing multiple-character choreographies */ if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) { - if (BKE_group_object_exists(ads->filter_grp, ob) == 0) + if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) return false; } diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 6dfe17f227a..84889033f30 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -48,6 +48,7 @@ #include "DNA_anim_types.h" #include "DNA_curve_types.h" +#include "DNA_group_types.h" #include "DNA_object_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" @@ -1128,7 +1129,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG struct Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - SceneCollection *sc = CTX_data_scene_collection(C); + Collection *collection = CTX_data_collection(C); bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0); bGPDstroke *gps, *prev_gps = NULL; Object *ob; @@ -1158,7 +1159,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG */ ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info); cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE); - BKE_collection_object_add(&scene->id, sc, ob); + BKE_collection_object_add(bmain, collection, ob); base_new = BKE_view_layer_base_find(view_layer, ob); cu->flag |= CU_3D; diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index d9c743aaf27..8d64d8b67e9 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -71,7 +71,6 @@ #include "BKE_displist.h" #include "BKE_effect.h" #include "BKE_font.h" -#include "BKE_group.h" #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_layer.h" @@ -1048,11 +1047,11 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot) ED_object_add_generic_props(ot, false); } -/********************* Add Group Instance Operator ********************/ +/********************* Add Collection Instance Operator ********************/ -static int group_instance_add_exec(bContext *C, wmOperator *op) +static int collection_instance_add_exec(bContext *C, wmOperator *op) { - Group *group; + Collection *collection; unsigned int layer; float loc[3], rot[3]; @@ -1060,7 +1059,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) char name[MAX_ID_NAME - 2]; RNA_string_get(op->ptr, "name", name); - group = (Group *)BKE_libblock_find_name(ID_GR, name); + collection = (Collection *)BKE_libblock_find_name(ID_GR, name); if (0 == RNA_struct_property_is_set(op->ptr, "location")) { const wmEvent *event = CTX_wm_window(C)->eventstate; @@ -1073,22 +1072,30 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) } } else - group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group")); + collection = BLI_findlink(&CTX_data_main(C)->collection, RNA_enum_get(op->ptr, "collection")); if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL)) return OPERATOR_CANCELLED; - if (group) { + if (collection) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer); - ob->dup_group = group; - ob->transflag |= OB_DUPLIGROUP; - id_us_plus(&group->id); + ViewLayer *view_layer = CTX_data_view_layer(C); + + /* Avoid dependency cycles. */ + LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer); + while (BKE_collection_find_cycle(active_lc->collection, collection)) { + active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc); + } + + Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, loc, rot, false, layer); + ob->dup_group = collection; + ob->transflag |= OB_DUPLICOLLECTION; + id_us_plus(&collection->id); /* works without this except if you try render right after, see: 22027 */ DEG_relations_tag_update(bmain); - DEG_id_tag_update(&group->id, 0); + DEG_id_tag_update(&collection->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); @@ -1099,27 +1106,27 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) } /* only used as menu */ -void OBJECT_OT_group_instance_add(wmOperatorType *ot) +void OBJECT_OT_collection_instance_add(wmOperatorType *ot) { PropertyRNA *prop; /* identifiers */ - ot->name = "Add Group Instance"; - ot->description = "Add a dupligroup instance"; - ot->idname = "OBJECT_OT_group_instance_add"; + ot->name = "Add Collection Instance"; + ot->description = "Add a collection instance"; + ot->idname = "OBJECT_OT_collection_instance_add"; /* api callbacks */ ot->invoke = WM_enum_search_invoke; - ot->exec = group_instance_add_exec; + ot->exec = collection_instance_add_exec; ot->poll = ED_operator_objectmode; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_string(ot->srna, "name", "Group", MAX_ID_NAME - 2, "Name", "Group name to add"); - prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", ""); - RNA_def_enum_funcs(prop, RNA_group_itemf); + RNA_def_string(ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Collection name to add"); + prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", ""); + RNA_def_enum_funcs(prop, RNA_collection_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; ED_object_add_generic_props(ot, false); @@ -1197,7 +1204,7 @@ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob) DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_BASE_FLAGS_UPDATE); - BKE_collections_object_remove(bmain, &scene->id, ob, true); + BKE_scene_collections_object_remove(bmain, scene, ob, true); } static int object_delete_exec(bContext *C, wmOperator *op) @@ -1331,7 +1338,7 @@ static void copy_object_set_idnew(bContext *C) /********************* Make Duplicates Real ************************/ /** - * \note regarding hashing dupli-objects when using OB_DUPLIGROUP, skip the first member of #DupliObject.persistent_id + * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, skip the first member of #DupliObject.persistent_id * since its a unique index and we only want to know if the group objects are from the same dupli-group instance. */ static unsigned int dupliobject_group_hash(const void *ptr) @@ -1346,7 +1353,7 @@ static unsigned int dupliobject_group_hash(const void *ptr) } /** - * \note regarding hashing dupli-objects when NOT using OB_DUPLIGROUP, include the first member of #DupliObject.persistent_id + * \note regarding hashing dupli-objects when NOT using OB_DUPLICOLLECTION, include the first member of #DupliObject.persistent_id * since its the index of the vertex/face the object is instantiated on and we want to identify objects on the same vertex/face. */ static unsigned int dupliobject_hash(const void *ptr) @@ -1418,7 +1425,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, dupli_gh = BLI_ghash_ptr_new(__func__); if (use_hierarchy) { - if (base->object->transflag & OB_DUPLIGROUP) { + if (base->object->transflag & OB_DUPLICOLLECTION) { parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); } else { @@ -1438,7 +1445,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, ob_dst->totcol = 0; } - BKE_collection_object_add_from(scene, base->object, ob_dst); + BKE_collection_object_add_from(bmain, scene, base->object, ob_dst); base_dst = BKE_view_layer_base_find(view_layer, ob_dst); BLI_assert(base_dst != NULL); @@ -1492,7 +1499,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, * they won't be read, this is simply for a hash lookup. */ DupliObject dob_key; dob_key.ob = ob_src_par; - if (base->object->transflag & OB_DUPLIGROUP) { + if (base->object->transflag & OB_DUPLICOLLECTION) { memcpy(&dob_key.persistent_id[1], &dob->persistent_id[1], sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); @@ -1537,7 +1544,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, } } - if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) { + if (base->object->transflag & OB_DUPLICOLLECTION && base->object->dup_group) { for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->proxy_group == base->object) { ob->proxy = NULL; @@ -1659,7 +1666,7 @@ static Base *duplibase_for_convert(Main *bmain, Scene *scene, ViewLayer *view_la obn = BKE_object_copy(bmain, ob); DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - BKE_collection_object_add_from(scene, ob, obn); + BKE_collection_object_add_from(bmain, scene, ob, obn); basen = BKE_view_layer_base_find(view_layer, obn); ED_object_base_select(basen, BA_SELECT); @@ -2068,23 +2075,23 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer base = BKE_view_layer_base_find(view_layer, ob); if ((base != NULL) && (base->flag & BASE_VISIBLED)) { - BKE_collection_object_add_from(scene, ob, obn); + BKE_collection_object_add_from(bmain, scene, ob, obn); } else { - LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer); - BKE_collection_object_add(&scene->id, layer_collection->scene_collection, obn); + LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, obn); } basen = BKE_view_layer_base_find(view_layer, obn); - /* 1) duplis should end up in same group as the original - * 2) Rigid Body sim participants MUST always be part of a group... + /* 1) duplis should end up in same collection as the original + * 2) Rigid Body sim participants MUST always be part of a collection... */ // XXX: is 2) really a good measure here? - if ((ob->flag & OB_FROMGROUP) != 0 || ob->rigidbody_object || ob->rigidbody_constraint) { - Group *group; - for (group = bmain->group.first; group; group = group->id.next) { - if (BKE_group_object_exists(group, ob)) - BKE_group_object_add(group, obn); + if (ob->rigidbody_object || ob->rigidbody_constraint) { + Collection *collection; + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + if (BKE_collection_has_object(collection, ob)) + BKE_collection_object_add(bmain, collection, obn); } } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index b9a7da02611..a2e91761a38 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1506,11 +1506,12 @@ bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_onl static int move_to_collection_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); PropertyRNA *prop = RNA_struct_find_property(op->ptr, "collection_index"); - const bool is_add = RNA_boolean_get(op->ptr, "is_add"); + const bool is_link = STREQ(op->idname, "OBJECT_OT_link_to_collection"); const bool is_new = RNA_boolean_get(op->ptr, "is_new"); - SceneCollection *scene_collection; + Collection *collection; if (!RNA_property_is_set(op->ptr, prop)) { BKE_report(op->reports, RPT_ERROR, "No collection selected"); @@ -1518,8 +1519,8 @@ static int move_to_collection_exec(bContext *C, wmOperator *op) } int collection_index = RNA_property_int_get(op->ptr, prop); - scene_collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); - if (scene_collection == NULL) { + collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); + if (collection == NULL) { BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found"); return OPERATOR_CANCELLED; } @@ -1540,24 +1541,24 @@ static int move_to_collection_exec(bContext *C, wmOperator *op) if (is_new) { char new_collection_name[MAX_NAME]; RNA_string_get(op->ptr, "new_collection_name", new_collection_name); - scene_collection = BKE_collection_add(&scene->id, scene_collection, COLLECTION_TYPE_NONE, new_collection_name); + collection = BKE_collection_add(bmain, collection, new_collection_name); } if ((single_object != NULL) && - is_add && - BLI_findptr(&scene_collection->objects, single_object, offsetof(LinkData, data))) + is_link && + BLI_findptr(&collection->gobject, single_object, offsetof(CollectionObject, ob))) { - BKE_reportf(op->reports, RPT_ERROR, "%s already in %s", single_object->id.name + 2, scene_collection->name); + BKE_reportf(op->reports, RPT_ERROR, "%s already in %s", single_object->id.name + 2, collection->id.name + 2); return OPERATOR_CANCELLED; } CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - if (!is_add) { - BKE_collection_object_move(&scene->id, scene_collection, NULL, ob); + if (!is_link) { + BKE_collection_object_move(bmain, scene, collection, NULL, ob); } else { - BKE_collection_object_add(&scene->id, scene_collection, ob); + BKE_collection_object_add(bmain, collection, ob); } } CTX_DATA_END; @@ -1566,8 +1567,8 @@ static int move_to_collection_exec(bContext *C, wmOperator *op) RPT_INFO, "%s %s to %s", (single_object != NULL) ? single_object->id.name + 2 : "Objects", - is_add ? "added" : "moved", - scene_collection->name); + is_link ? "linked" : "moved", + collection->id.name + 2); DEG_relations_tag_update(CTX_data_main(C)); DEG_id_tag_update(&scene->id, 0); @@ -1579,26 +1580,27 @@ static int move_to_collection_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -typedef struct MoveToCollectionData { +struct MoveToCollectionData { struct MoveToCollectionData *next, *prev; int index; - struct SceneCollection *collection; + struct Collection *collection; struct ListBase submenus; PointerRNA ptr; struct wmOperatorType *ot; -} MoveToCollectionData; +}; static int move_to_collection_menus_create(wmOperator *op, MoveToCollectionData *menu) { int index = menu->index; - for (SceneCollection *scene_collection = menu->collection->scene_collections.first; - scene_collection != NULL; - scene_collection = scene_collection->next) + for (CollectionChild *child = menu->collection->children.first; + child != NULL; + child = child->next) { + Collection *collection = child->collection; MoveToCollectionData *submenu = MEM_callocN(sizeof(MoveToCollectionData), "MoveToCollectionData submenu - expected memleak"); BLI_addtail(&menu->submenus, submenu); - submenu->collection = scene_collection; + submenu->collection = collection; submenu->index = ++index; index = move_to_collection_menus_create(op, submenu); submenu->ot = op->type; @@ -1631,11 +1633,19 @@ static void move_to_collection_menus_free(MoveToCollectionData **menu) static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout, void *menu_v) { MoveToCollectionData *menu = menu_v; + const char *name; + + if (menu->collection->flag & COLLECTION_IS_MASTER) { + name = IFACE_("Scene Collection"); + } + else { + name = menu->collection->id.name + 2; + } uiItemIntO(layout, - menu->collection->name, + name, ICON_NONE, - "OBJECT_OT_move_to_collection", + menu->ot->idname, "collection_index", menu->index); uiItemS(layout); @@ -1658,7 +1668,6 @@ static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout "New Collection", ICON_ZOOMIN, menu->ptr.data, - /* We use invoke here so we can read ctrl from event. */ WM_OP_INVOKE_DEFAULT, 0, NULL); @@ -1668,15 +1677,15 @@ static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionDat { if (BLI_listbase_is_empty(&menu->submenus)) { uiItemIntO(layout, - menu->collection->name, + menu->collection->id.name + 2, ICON_NONE, - "OBJECT_OT_move_to_collection", + menu->ot->idname, "collection_index", menu->index); } else { uiItemMenuF(layout, - menu->collection->name, + menu->collection->id.name + 2, ICON_NONE, move_to_collection_menu_create, menu); @@ -1686,8 +1695,10 @@ static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionDat /* This is allocated statically because we need this available for the menus creation callback. */ static MoveToCollectionData *master_collection_menu = NULL; -static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { + Scene *scene = CTX_data_scene(C); + /* Reset the menus data for the current master collection, and free previously allocated data. */ move_to_collection_menus_free(&master_collection_menu); @@ -1695,16 +1706,15 @@ static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent prop = RNA_struct_find_property(op->ptr, "collection_index"); if (RNA_property_is_set(op->ptr, prop)) { int collection_index = RNA_property_int_get(op->ptr, prop); - RNA_boolean_set(op->ptr, "is_add", event->ctrl); if (RNA_boolean_get(op->ptr, "is_new")) { prop = RNA_struct_find_property(op->ptr, "new_collection_name"); if (!RNA_property_is_set(op->ptr, prop)) { char name[MAX_NAME]; - SceneCollection *scene_collection; + Collection *collection; - scene_collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); - BKE_collection_new_name_get(&CTX_data_scene(C)->id, scene_collection, name); + collection = BKE_collection_from_index(scene, collection_index); + BKE_collection_new_name_get(collection, name); RNA_property_string_set(op->ptr, prop, name); return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y); @@ -1713,7 +1723,7 @@ static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent return move_to_collection_exec(C, op); } - SceneCollection *master_collection = BKE_collection_master(&CTX_data_scene(C)->id); + Collection *master_collection = BKE_collection_master(scene); /* We need the data to be allocated so it's available during menu drawing. * Technically we could use wmOperator->customdata. However there is no free callback @@ -1733,10 +1743,10 @@ static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent uiLayout *layout; /* Build the menus. */ - pup = UI_popup_menu_begin(C, IFACE_("Move to Collection"), ICON_NONE); + const char *title = CTX_IFACE_(op->type->translation_context, op->type->name); + pup = UI_popup_menu_begin(C, title, ICON_NONE); layout = UI_popup_menu_layout(pup); - /* We use invoke here so we can read ctrl from event. */ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); move_to_collection_menu_create(C, layout, master_collection_menu); @@ -1752,7 +1762,7 @@ void OBJECT_OT_move_to_collection(wmOperatorType *ot) /* identifiers */ ot->name = "Move to Collection"; - ot->description = "Move to a collection only (Ctrl to add)"; + ot->description = "Move objects to a scene collection"; ot->idname = "OBJECT_OT_move_to_collection"; /* api callbacks */ @@ -1766,7 +1776,32 @@ void OBJECT_OT_move_to_collection(wmOperatorType *ot) prop = RNA_def_int(ot->srna, "collection_index", COLLECTION_INVALID_INDEX, COLLECTION_INVALID_INDEX, INT_MAX, "Collection Index", "Index of the collection to move to", 0, INT_MAX); RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); - prop = RNA_def_boolean(ot->srna, "is_add", false, "Add", "Keep object in original collections as well"); + prop = RNA_def_boolean(ot->srna, "is_new", false, "New", "Move objects to a new collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_string(ot->srna, "new_collection_name", NULL, MAX_NAME, "Name", + "Name of the newly added collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +void OBJECT_OT_link_to_collection(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Link to Collection"; + ot->description = "Link objects to a collection"; + ot->idname = "OBJECT_OT_link_to_collection"; + + /* api callbacks */ + ot->exec = move_to_collection_exec; + ot->invoke = move_to_collection_invoke; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_int(ot->srna, "collection_index", COLLECTION_INVALID_INDEX, COLLECTION_INVALID_INDEX, INT_MAX, + "Collection Index", "Index of the collection to move to", 0, INT_MAX); RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); prop = RNA_def_boolean(ot->srna, "is_new", false, "New", "Move objects to a new collection"); RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index cb0fbdda970..0a6a81d99da 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -39,8 +39,8 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_collection.h" #include "BKE_context.h" -#include "BKE_group.h" #include "BKE_library.h" #include "BKE_library_remap.h" #include "BKE_main.h" @@ -64,8 +64,9 @@ /********************* 3d view operators ***********************/ /* can be called with C == NULL */ -static const EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *collection_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { + Main *bmain = CTX_data_main(C); Object *ob; EnumPropertyItem *item = NULL, item_tmp = {0}; int totitem = 0; @@ -78,25 +79,25 @@ static const EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA /* check that the object exists */ if (ob) { - Group *group; + Collection *collection; int i = 0, count = 0; - /* if 2 or more groups, add option to add to all groups */ - group = NULL; - while ((group = BKE_group_object_find(group, ob))) + /* if 2 or more collections, add option to add to all collections */ + collection = NULL; + while ((collection = BKE_collection_object_find(bmain, collection, ob))) count++; if (count >= 2) { - item_tmp.identifier = item_tmp.name = "All Groups"; + item_tmp.identifier = item_tmp.name = "All Collections"; item_tmp.value = INT_MAX; /* this will give NULL on lookup */ RNA_enum_item_add(&item, &totitem, &item_tmp); RNA_enum_item_add_separator(&item, &totitem); } - /* add groups */ - group = NULL; - while ((group = BKE_group_object_find(group, ob))) { - item_tmp.identifier = item_tmp.name = group->id.name + 2; + /* add collections */ + collection = NULL; + while ((collection = BKE_collection_object_find(bmain, collection, ob))) { + item_tmp.identifier = item_tmp.name = collection->id.name + 2; /* item_tmp.icon = ICON_ARMATURE_DATA; */ item_tmp.value = i; RNA_enum_item_add(&item, &totitem, &item_tmp); @@ -110,48 +111,48 @@ static const EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA return item; } -/* get the group back from the enum index, quite awkward and UI specific */ -static Group *group_object_active_find_index(Object *ob, const int group_object_index) +/* get the collection back from the enum index, quite awkward and UI specific */ +static Collection *collection_object_active_find_index(Main *bmain, Object *ob, const int collection_object_index) { - Group *group = NULL; + Collection *collection = NULL; int i = 0; - while ((group = BKE_group_object_find(group, ob))) { - if (i == group_object_index) { + while ((collection = BKE_collection_object_find(bmain, collection, ob))) { + if (i == collection_object_index) { break; } i++; } - return group; + return collection; } static int objects_add_active_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); Main *bmain = CTX_data_main(C); - int single_group_index = RNA_enum_get(op->ptr, "group"); - Group *single_group = group_object_active_find_index(ob, single_group_index); - Group *group; + int single_collection_index = RNA_enum_get(op->ptr, "collection"); + Collection *single_collection = collection_object_active_find_index(bmain, ob, single_collection_index); + Collection *collection; bool is_cycle = false; bool updated = false; if (ob == NULL) return OPERATOR_CANCELLED; - /* now add all selected objects to the group(s) */ - for (group = bmain->group.first; group; group = group->id.next) { - if (single_group && group != single_group) + /* now add all selected objects to the collection(s) */ + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + if (single_collection && collection != single_collection) continue; - if (!BKE_group_object_exists(group, ob)) + if (!BKE_collection_has_object(collection, ob)) continue; CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - if (BKE_group_object_exists(group, base->object)) + if (BKE_collection_has_object(collection, base->object)) continue; - if (!BKE_group_object_cyclic_check(bmain, base->object, group)) { - BKE_group_object_add(group, base->object); + if (!BKE_collection_object_cyclic_check(bmain, base->object, collection)) { + BKE_collection_object_add(bmain, collection, base->object); updated = true; } else { @@ -162,7 +163,7 @@ static int objects_add_active_exec(bContext *C, wmOperator *op) } if (is_cycle) - BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected"); + BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected"); if (!updated) return OPERATOR_CANCELLED; @@ -173,14 +174,14 @@ static int objects_add_active_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void GROUP_OT_objects_add_active(wmOperatorType *ot) +void COLLECTION_OT_objects_add_active(wmOperatorType *ot) { PropertyRNA *prop; /* identifiers */ - ot->name = "Add Selected To Active Group"; - ot->description = "Add the object to an object group that contains the active object"; - ot->idname = "GROUP_OT_objects_add_active"; + ot->name = "Add Selected To Active Collection"; + ot->description = "Add the object to an object collection that contains the active object"; + ot->idname = "COLLECTION_OT_objects_add_active"; /* api callbacks */ ot->exec = objects_add_active_exec; @@ -191,8 +192,8 @@ void GROUP_OT_objects_add_active(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to add other selected objects to"); - RNA_def_enum_funcs(prop, group_object_active_itemf); + prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "The collection to add other selected objects to"); + RNA_def_enum_funcs(prop, collection_object_active_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } @@ -202,26 +203,26 @@ static int objects_remove_active_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); - int single_group_index = RNA_enum_get(op->ptr, "group"); - Group *single_group = group_object_active_find_index(ob, single_group_index); - Group *group; + int single_collection_index = RNA_enum_get(op->ptr, "collection"); + Collection *single_collection = collection_object_active_find_index(bmain, ob, single_collection_index); + Collection *collection; bool ok = false; if (ob == NULL) return OPERATOR_CANCELLED; - /* linking to same group requires its own loop so we can avoid - * looking up the active objects groups each time */ + /* linking to same collection requires its own loop so we can avoid + * looking up the active objects collections each time */ - for (group = bmain->group.first; group; group = group->id.next) { - if (single_group && group != single_group) + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + if (single_collection && collection != single_collection) continue; - if (BKE_group_object_exists(group, ob)) { - /* Remove groups from selected objects */ + if (BKE_collection_has_object(collection, ob)) { + /* Remove collections from selected objects */ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - BKE_group_object_unlink(group, base->object); + BKE_collection_object_remove(bmain, collection, base->object, false); ok = 1; } CTX_DATA_END; @@ -229,7 +230,7 @@ static int objects_remove_active_exec(bContext *C, wmOperator *op) } if (!ok) - BKE_report(op->reports, RPT_ERROR, "Active object contains no groups"); + BKE_report(op->reports, RPT_ERROR, "Active object contains no collections"); DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); @@ -237,14 +238,14 @@ static int objects_remove_active_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void GROUP_OT_objects_remove_active(wmOperatorType *ot) +void COLLECTION_OT_objects_remove_active(wmOperatorType *ot) { PropertyRNA *prop; /* identifiers */ - ot->name = "Remove Selected From Active Group"; - ot->description = "Remove the object from an object group that contains the active object"; - ot->idname = "GROUP_OT_objects_remove_active"; + ot->name = "Remove Selected From Active Collection"; + ot->description = "Remove the object from an object collection that contains the active object"; + ot->idname = "COLLECTION_OT_objects_remove_active"; /* api callbacks */ ot->exec = objects_remove_active_exec; @@ -255,19 +256,19 @@ void GROUP_OT_objects_remove_active(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove other selected objects from"); - RNA_def_enum_funcs(prop, group_object_active_itemf); + prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "The collection to remove other selected objects from"); + RNA_def_enum_funcs(prop, collection_object_active_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } -static int group_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - BKE_object_groups_clear(base->object); + BKE_object_groups_clear(bmain, base->object); } CTX_DATA_END; @@ -277,43 +278,43 @@ static int group_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void GROUP_OT_objects_remove_all(wmOperatorType *ot) +void COLLECTION_OT_objects_remove_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "Remove From All Groups"; - ot->description = "Remove selected objects from all groups"; - ot->idname = "GROUP_OT_objects_remove_all"; + ot->name = "Remove From All Unlinked Collections"; + ot->description = "Remove selected objects from all collections not used in a scene"; + ot->idname = "COLLECTION_OT_objects_remove_all"; /* api callbacks */ - ot->exec = group_objects_remove_all_exec; + ot->exec = collection_objects_remove_all_exec; ot->poll = ED_operator_objectmode; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int group_objects_remove_exec(bContext *C, wmOperator *op) +static int collection_objects_remove_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); Main *bmain = CTX_data_main(C); - int single_group_index = RNA_enum_get(op->ptr, "group"); - Group *single_group = group_object_active_find_index(ob, single_group_index); - Group *group; + int single_collection_index = RNA_enum_get(op->ptr, "collection"); + Collection *single_collection = collection_object_active_find_index(bmain, ob, single_collection_index); + Collection *collection; bool updated = false; if (ob == NULL) return OPERATOR_CANCELLED; - for (group = bmain->group.first; group; group = group->id.next) { - if (single_group && group != single_group) + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + if (single_collection && collection != single_collection) continue; - if (!BKE_group_object_exists(group, ob)) + if (!BKE_collection_has_object(collection, ob)) continue; - /* now remove all selected objects from the group */ + /* now remove all selected objects from the collection */ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - BKE_group_object_unlink(group, base->object); + BKE_collection_object_remove(bmain, collection, base->object, false); updated = true; } CTX_DATA_END; @@ -328,17 +329,17 @@ static int group_objects_remove_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void GROUP_OT_objects_remove(wmOperatorType *ot) +void COLLECTION_OT_objects_remove(wmOperatorType *ot) { PropertyRNA *prop; /* identifiers */ - ot->name = "Remove From Group"; - ot->description = "Remove selected objects from a group"; - ot->idname = "GROUP_OT_objects_remove"; + ot->name = "Remove From Collection"; + ot->description = "Remove selected objects from a collection"; + ot->idname = "COLLECTION_OT_objects_remove"; /* api callbacks */ - ot->exec = group_objects_remove_exec; + ot->exec = collection_objects_remove_exec; ot->invoke = WM_menu_invoke; ot->poll = ED_operator_objectmode; @@ -346,25 +347,24 @@ void GROUP_OT_objects_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove this object from"); - RNA_def_enum_funcs(prop, group_object_active_itemf); + prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "The collection to remove this object from"); + RNA_def_enum_funcs(prop, collection_object_active_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } -static int group_create_exec(bContext *C, wmOperator *op) +static int collection_create_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Group *group = NULL; char name[MAX_ID_NAME - 2]; /* id name */ RNA_string_get(op->ptr, "name", name); - group = BKE_group_add(bmain, name); + Collection *collection = BKE_collection_add(bmain, NULL, name); CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - BKE_group_object_add(group, base->object); + BKE_collection_object_add(bmain, collection, base->object); } CTX_DATA_END; @@ -374,102 +374,101 @@ static int group_create_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void GROUP_OT_create(wmOperatorType *ot) +void COLLECTION_OT_create(wmOperatorType *ot) { /* identifiers */ - ot->name = "Create New Group"; - ot->description = "Create an object group from selected objects"; - ot->idname = "GROUP_OT_create"; + ot->name = "Create New Collection"; + ot->description = "Create an object collection from selected objects"; + ot->idname = "COLLECTION_OT_create"; /* api callbacks */ - ot->exec = group_create_exec; + ot->exec = collection_create_exec; ot->poll = ED_operator_objectmode; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_string(ot->srna, "name", "Group", MAX_ID_NAME - 2, "Name", "Name of the new group"); + RNA_def_string(ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Name of the new collection"); } /****************** properties window operators *********************/ -static int group_add_exec(bContext *C, wmOperator *UNUSED(op)) +static int collection_add_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); Main *bmain = CTX_data_main(C); - Group *group; if (ob == NULL) return OPERATOR_CANCELLED; - group = BKE_group_add(bmain, "Group"); - BKE_group_object_add(group, ob); + Collection *collection = BKE_collection_add(bmain, NULL, "Collection"); + BKE_collection_object_add(bmain, collection, ob); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; } -void OBJECT_OT_group_add(wmOperatorType *ot) +void OBJECT_OT_collection_add(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add to Group"; - ot->idname = "OBJECT_OT_group_add"; - ot->description = "Add an object to a new group"; + ot->name = "Add to Collection"; + ot->idname = "OBJECT_OT_collection_add"; + ot->description = "Add an object to a new collection"; /* api callbacks */ - ot->exec = group_add_exec; + ot->exec = collection_add_exec; ot->poll = ED_operator_objectmode; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int group_link_exec(bContext *C, wmOperator *op) +static int collection_link_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Object *ob = ED_object_context(C); - Group *group = BLI_findlink(&bmain->group, RNA_enum_get(op->ptr, "group")); + Collection *collection = BLI_findlink(&bmain->collection, RNA_enum_get(op->ptr, "collection")); - if (ELEM(NULL, ob, group)) + if (ELEM(NULL, ob, collection)) return OPERATOR_CANCELLED; - /* Early return check, if the object is already in group + /* Early return check, if the object is already in collection * we could skip all the dependency check and just consider * operator is finished. */ - if (BKE_group_object_exists(group, ob)) { + if (BKE_collection_has_object(collection, ob)) { return OPERATOR_FINISHED; } - /* Adding object to group which is used as dupligroup for self is bad idea. + /* Adding object to collection which is used as duplicollection for self is bad idea. * - * It is also bad idea to add object to group which is in group which + * It is also bad idea to add object to collection which is in collection which * contains our current object. */ - 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"); + if (BKE_collection_object_cyclic_check(bmain, ob, collection)) { + BKE_report(op->reports, RPT_ERROR, "Could not add the collection because of dependency cycle detected"); return OPERATOR_CANCELLED; } - BKE_group_object_add(group, ob); + BKE_collection_object_add(bmain, collection, ob); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; } -void OBJECT_OT_group_link(wmOperatorType *ot) +void OBJECT_OT_collection_link(wmOperatorType *ot) { PropertyRNA *prop; /* identifiers */ - ot->name = "Link to Group"; - ot->idname = "OBJECT_OT_group_link"; - ot->description = "Add an object to an existing group"; + ot->name = "Link to Collection"; + ot->idname = "OBJECT_OT_collection_link"; + ot->description = "Add an object to an existing collection"; /* api callbacks */ - ot->exec = group_link_exec; + ot->exec = collection_link_exec; ot->invoke = WM_enum_search_invoke; ot->poll = ED_operator_objectmode; @@ -477,36 +476,37 @@ void OBJECT_OT_group_link(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", ""); - RNA_def_enum_funcs(prop, RNA_group_local_itemf); + prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", ""); + RNA_def_enum_funcs(prop, RNA_collection_local_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } -static int group_remove_exec(bContext *C, wmOperator *UNUSED(op)) +static int collection_remove_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); Object *ob = ED_object_context(C); - Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; + Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data; - if (!ob || !group) + if (!ob || !collection) return OPERATOR_CANCELLED; - BKE_group_object_unlink(group, ob); + BKE_collection_object_remove(bmain, collection, ob, false); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; } -void OBJECT_OT_group_remove(wmOperatorType *ot) +void OBJECT_OT_collection_remove(wmOperatorType *ot) { /* identifiers */ - ot->name = "Remove Group"; - ot->idname = "OBJECT_OT_group_remove"; - ot->description = "Remove the active object from this group"; + ot->name = "Remove Collection"; + ot->idname = "OBJECT_OT_collection_remove"; + ot->description = "Remove the active object from this collection"; /* api callbacks */ - ot->exec = group_remove_exec; + ot->exec = collection_remove_exec; ot->poll = ED_operator_objectmode; /* flags */ @@ -514,47 +514,47 @@ void OBJECT_OT_group_remove(wmOperatorType *ot) } -static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op)) +static int collection_unlink_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); - Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; + Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data; - if (!group) + if (!collection) return OPERATOR_CANCELLED; - BKE_libblock_delete(bmain, group); + BKE_libblock_delete(bmain, collection); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); return OPERATOR_FINISHED; } -void OBJECT_OT_group_unlink(wmOperatorType *ot) +void OBJECT_OT_collection_unlink(wmOperatorType *ot) { /* identifiers */ - ot->name = "Unlink Group"; - ot->idname = "OBJECT_OT_group_unlink"; - ot->description = "Unlink the group from all objects"; + ot->name = "Unlink Collection"; + ot->idname = "OBJECT_OT_collection_unlink"; + ot->description = "Unlink the collection from all objects"; /* api callbacks */ - ot->exec = group_unlink_exec; + ot->exec = collection_unlink_exec; ot->poll = ED_operator_objectmode; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same group as the active */ +static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same collection as the active */ { - Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; + Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data; - if (!group) + if (!collection) return OPERATOR_CANCELLED; CTX_DATA_BEGIN (C, Base *, base, visible_bases) { if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { - if (BKE_group_object_exists(group, base->object)) { + if (BKE_collection_has_object_recursive(collection, base->object)) { ED_object_base_select(base, BA_SELECT); } } @@ -566,12 +566,12 @@ static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select o return OPERATOR_FINISHED; } -void OBJECT_OT_grouped_select(wmOperatorType *ot) +void OBJECT_OT_collection_objects_select(wmOperatorType *ot) { /* identifiers */ - ot->name = "Select Grouped"; - ot->idname = "OBJECT_OT_grouped_select"; - ot->description = "Select all objects in group"; + ot->name = "Select Objects in Collection"; + ot->idname = "OBJECT_OT_collection_objects_select"; + ot->description = "Select all objects in collection"; /* api callbacks */ ot->exec = select_grouped_exec; diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index dbb81be124a..445b14982ee 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -88,6 +88,7 @@ void OBJECT_OT_paths_clear(struct wmOperatorType *ot); void OBJECT_OT_forcefield_toggle(struct wmOperatorType *ot); void OBJECT_OT_move_to_collection(struct wmOperatorType *ot); +void OBJECT_OT_link_to_collection(struct wmOperatorType *ot); /* object_select.c */ void OBJECT_OT_select_all(struct wmOperatorType *ot); @@ -99,7 +100,6 @@ void OBJECT_OT_select_grouped(struct wmOperatorType *ot); void OBJECT_OT_select_mirror(struct wmOperatorType *ot); void OBJECT_OT_select_more(struct wmOperatorType *ot); void OBJECT_OT_select_less(struct wmOperatorType *ot); -void OBJECT_OT_select_same_group(struct wmOperatorType *ot); void OBJECT_OT_select_same_collection(struct wmOperatorType *ot); /* object_add.c */ @@ -115,7 +115,7 @@ void OBJECT_OT_lamp_add(struct wmOperatorType *ot); void OBJECT_OT_effector_add(struct wmOperatorType *ot); void OBJECT_OT_camera_add(struct wmOperatorType *ot); void OBJECT_OT_speaker_add(struct wmOperatorType *ot); -void OBJECT_OT_group_instance_add(struct wmOperatorType *ot); +void OBJECT_OT_collection_instance_add(struct wmOperatorType *ot); void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot); void OBJECT_OT_duplicate(struct wmOperatorType *ot); @@ -134,11 +134,11 @@ void OBJECT_OT_hook_reset(struct wmOperatorType *ot); void OBJECT_OT_hook_recenter(struct wmOperatorType *ot); /* object_group.c */ -void GROUP_OT_create(struct wmOperatorType *ot); -void GROUP_OT_objects_remove_all(struct wmOperatorType *ot); -void GROUP_OT_objects_remove(struct wmOperatorType *ot); -void GROUP_OT_objects_add_active(struct wmOperatorType *ot); -void GROUP_OT_objects_remove_active(struct wmOperatorType *ot); +void COLLECTION_OT_create(struct wmOperatorType *ot); +void COLLECTION_OT_objects_remove_all(struct wmOperatorType *ot); +void COLLECTION_OT_objects_remove(struct wmOperatorType *ot); +void COLLECTION_OT_objects_add_active(struct wmOperatorType *ot); +void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot); /* object_modifier.c */ int edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, int obtype_flag); @@ -251,11 +251,11 @@ void OBJECT_OT_shape_key_mirror(struct wmOperatorType *ot); void OBJECT_OT_shape_key_move(struct wmOperatorType *ot); /* object_group.c */ -void OBJECT_OT_group_add(struct wmOperatorType *ot); -void OBJECT_OT_group_link(struct wmOperatorType *ot); -void OBJECT_OT_group_remove(struct wmOperatorType *ot); -void OBJECT_OT_group_unlink(struct wmOperatorType *ot); -void OBJECT_OT_grouped_select(struct wmOperatorType *ot); +void OBJECT_OT_collection_add(struct wmOperatorType *ot); +void OBJECT_OT_collection_link(struct wmOperatorType *ot); +void OBJECT_OT_collection_remove(struct wmOperatorType *ot); +void OBJECT_OT_collection_unlink(struct wmOperatorType *ot); +void OBJECT_OT_collection_objects_select(struct wmOperatorType *ot); /* object_bake.c */ void OBJECT_OT_bake_image(wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index c4c86b3932d..c47d741f818 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -93,7 +93,6 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_select_random); WM_operatortype_append(OBJECT_OT_select_all); - WM_operatortype_append(OBJECT_OT_select_same_group); WM_operatortype_append(OBJECT_OT_select_same_collection); WM_operatortype_append(OBJECT_OT_select_by_type); WM_operatortype_append(OBJECT_OT_select_linked); @@ -102,11 +101,11 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_select_more); WM_operatortype_append(OBJECT_OT_select_less); - WM_operatortype_append(GROUP_OT_create); - WM_operatortype_append(GROUP_OT_objects_remove_all); - WM_operatortype_append(GROUP_OT_objects_remove); - WM_operatortype_append(GROUP_OT_objects_add_active); - WM_operatortype_append(GROUP_OT_objects_remove_active); + WM_operatortype_append(COLLECTION_OT_create); + WM_operatortype_append(COLLECTION_OT_objects_remove_all); + WM_operatortype_append(COLLECTION_OT_objects_remove); + WM_operatortype_append(COLLECTION_OT_objects_add_active); + WM_operatortype_append(COLLECTION_OT_objects_remove_active); WM_operatortype_append(OBJECT_OT_delete); WM_operatortype_append(OBJECT_OT_text_add); @@ -120,7 +119,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_add); WM_operatortype_append(OBJECT_OT_add_named); WM_operatortype_append(OBJECT_OT_effector_add); - WM_operatortype_append(OBJECT_OT_group_instance_add); + WM_operatortype_append(OBJECT_OT_collection_instance_add); WM_operatortype_append(OBJECT_OT_metaball_add); WM_operatortype_append(OBJECT_OT_duplicates_make_real); WM_operatortype_append(OBJECT_OT_duplicate); @@ -213,6 +212,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(TRANSFORM_OT_vertex_warp); WM_operatortype_append(OBJECT_OT_move_to_collection); + WM_operatortype_append(OBJECT_OT_link_to_collection); WM_operatortype_append(OBJECT_OT_shape_key_add); WM_operatortype_append(OBJECT_OT_shape_key_remove); @@ -221,11 +221,11 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_shape_key_mirror); WM_operatortype_append(OBJECT_OT_shape_key_move); - WM_operatortype_append(OBJECT_OT_group_add); - WM_operatortype_append(OBJECT_OT_group_link); - WM_operatortype_append(OBJECT_OT_group_remove); - WM_operatortype_append(OBJECT_OT_group_unlink); - WM_operatortype_append(OBJECT_OT_grouped_select); + WM_operatortype_append(OBJECT_OT_collection_add); + WM_operatortype_append(OBJECT_OT_collection_link); + WM_operatortype_append(OBJECT_OT_collection_remove); + WM_operatortype_append(OBJECT_OT_collection_unlink); + WM_operatortype_append(OBJECT_OT_collection_objects_select); WM_operatortype_append(OBJECT_OT_hook_add_selob); WM_operatortype_append(OBJECT_OT_hook_add_newob); @@ -395,11 +395,11 @@ void ED_keymap_object(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_delete_v3d", IKEY, KM_PRESS, KM_ALT, 0); WM_keymap_verify_item(keymap, "ANIM_OT_keying_set_active_set", IKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_create", GKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove", GKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_all", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL | KM_ALT, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_add_active", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_active", GKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0); + WM_keymap_verify_item(keymap, "COLLECTION_OT_create", GKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_verify_item(keymap, "COLLECTION_OT_objects_remove", GKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); + WM_keymap_verify_item(keymap, "COLLECTION_OT_objects_remove_all", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL | KM_ALT, 0); + WM_keymap_verify_item(keymap, "COLLECTION_OT_objects_add_active", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + WM_keymap_verify_item(keymap, "COLLECTION_OT_objects_remove_active", GKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0); WM_keymap_add_menu(keymap, "VIEW3D_MT_object_specials", WKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index dd919aedabb..c5cf946cfb3 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -70,7 +70,6 @@ #include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_fcurve.h" #include "BKE_idprop.h" #include "BKE_lamp.h" @@ -329,7 +328,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event) } else { /* error.. cannot continue */ - BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or group"); + BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or collection"); return OPERATOR_CANCELLED; } @@ -343,7 +342,8 @@ static int make_proxy_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); if (gob->dup_group != NULL) { - Base *base = BLI_findlink(&gob->dup_group->view_layer->object_bases, RNA_enum_get(op->ptr, "object")); + const ListBase dup_group_objects = BKE_collection_object_cache_get(gob->dup_group); + Base *base = BLI_findlink(&dup_group_objects, RNA_enum_get(op->ptr, "object")); ob = base->object; } else { @@ -385,8 +385,8 @@ static int make_proxy_exec(bContext *C, wmOperator *op) } /* Generic itemf's for operators that take library args */ -static const EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *proxy_collection_object_itemf(bContext *C, PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), bool *r_free) { EnumPropertyItem item_tmp = {0}, *item = NULL; int totitem = 0; @@ -397,13 +397,13 @@ static const EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA return DummyRNA_DEFAULT_items; /* find the object to affect */ - FOREACH_GROUP_OBJECT_BEGIN(ob->dup_group, object) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(ob->dup_group, object) { item_tmp.identifier = item_tmp.name = object->id.name + 2; item_tmp.value = i++; RNA_enum_item_add(&item, &totitem, &item_tmp); } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -431,8 +431,8 @@ void OBJECT_OT_proxy_make(wmOperatorType *ot) /* properties */ /* XXX, relies on hard coded ID at the moment */ prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object", - "Name of lib-linked/grouped object to make a proxy for"); - RNA_def_enum_funcs(prop, proxy_group_object_itemf); + "Name of lib-linked/collection object to make a proxy for"); + RNA_def_enum_funcs(prop, proxy_collection_object_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } @@ -1343,7 +1343,8 @@ static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr)) static int make_links_scene_exec(bContext *C, wmOperator *op) { - Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene")); + Main *bmain = CTX_data_main(C); + Scene *scene_to = BLI_findlink(&bmain->scene, RNA_enum_get(op->ptr, "scene")); if (scene_to == NULL) { BKE_report(op->reports, RPT_ERROR, "Could not find scene"); @@ -1360,10 +1361,10 @@ static int make_links_scene_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - SceneCollection *sc_to = BKE_collection_master(&scene_to->id); + Collection *collection_to = BKE_collection_master(scene_to); CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - BKE_collection_object_add(&scene_to->id, sc_to, base->object); + BKE_collection_object_add(bmain, collection_to, base->object); } CTX_DATA_END; @@ -1379,7 +1380,7 @@ enum { MAKE_LINKS_MATERIALS = 2, MAKE_LINKS_ANIMDATA = 3, MAKE_LINKS_GROUP = 4, - MAKE_LINKS_DUPLIGROUP = 5, + MAKE_LINKS_DUPLICOLLECTION = 5, MAKE_LINKS_MODIFIERS = 6, MAKE_LINKS_FONTS = 7, }; @@ -1400,7 +1401,7 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst break; case MAKE_LINKS_ANIMDATA: case MAKE_LINKS_GROUP: - case MAKE_LINKS_DUPLIGROUP: + case MAKE_LINKS_DUPLICOLLECTION: return true; case MAKE_LINKS_MODIFIERS: if (!ELEM(OB_EMPTY, ob_src->type, ob_dst->type)) { @@ -1424,16 +1425,16 @@ static int make_links_data_exec(bContext *C, wmOperator *op) ID *obdata_id; int a; - /* group */ - LinkNode *ob_groups = NULL; + /* collection */ + LinkNode *ob_collections = NULL; bool is_cycle = false; bool is_lib = false; ob_src = ED_object_active_context(C); - /* avoid searching all groups in source object each time */ + /* avoid searching all collections in source object each time */ if (type == MAKE_LINKS_GROUP) { - ob_groups = BKE_object_groups(ob_src); + ob_collections = BKE_object_groups(bmain, ob_src); } CTX_DATA_BEGIN (C, Base *, base_dst, selected_editable_bases) @@ -1478,15 +1479,15 @@ static int make_links_data_exec(bContext *C, wmOperator *op) break; case MAKE_LINKS_GROUP: { - LinkNode *group_node; + LinkNode *collection_node; - /* first clear groups */ - BKE_object_groups_clear(ob_dst); + /* first clear collections */ + BKE_object_groups_clear(bmain, ob_dst); - /* now add in the groups from the link nodes */ - for (group_node = ob_groups; group_node; group_node = group_node->next) { - if (ob_dst->dup_group != group_node->link) { - BKE_group_object_add(group_node->link, ob_dst); + /* now add in the collections from the link nodes */ + for (collection_node = ob_collections; collection_node; collection_node = collection_node->next) { + if (ob_dst->dup_group != collection_node->link) { + BKE_collection_object_add(bmain, collection_node->link, ob_dst); } else { is_cycle = true; @@ -1494,11 +1495,11 @@ static int make_links_data_exec(bContext *C, wmOperator *op) } break; } - case MAKE_LINKS_DUPLIGROUP: + case MAKE_LINKS_DUPLICOLLECTION: ob_dst->dup_group = ob_src->dup_group; if (ob_dst->dup_group) { id_us_plus(&ob_dst->dup_group->id); - ob_dst->transflag |= OB_DUPLIGROUP; + ob_dst->transflag |= OB_DUPLICOLLECTION; } break; case MAKE_LINKS_MODIFIERS: @@ -1542,12 +1543,12 @@ static int make_links_data_exec(bContext *C, wmOperator *op) CTX_DATA_END; if (type == MAKE_LINKS_GROUP) { - if (ob_groups) { - BLI_linklist_free(ob_groups, NULL); + if (ob_collections) { + BLI_linklist_free(ob_collections, NULL); } if (is_cycle) { - BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected"); + BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected"); } } @@ -1595,7 +1596,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) {MAKE_LINKS_MATERIALS, "MATERIAL", 0, "Materials", ""}, {MAKE_LINKS_ANIMDATA, "ANIMATION", 0, "Animation Data", ""}, {MAKE_LINKS_GROUP, "GROUPS", 0, "Group", ""}, - {MAKE_LINKS_DUPLIGROUP, "DUPLIGROUP", 0, "DupliGroup", ""}, + {MAKE_LINKS_DUPLICOLLECTION, "DUPLICOLLECTION", 0, "DupliGroup", ""}, {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Modifiers", ""}, {MAKE_LINKS_FONTS, "FONTS", 0, "Fonts", ""}, {0, NULL, 0, NULL, NULL}}; @@ -1619,19 +1620,11 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) /**************************** Make Single User ********************************/ -static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob, const bool copy_groups) +static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob) { /* base gets copy of object */ Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); - if (copy_groups) { - if (ob->flag & OB_FROMGROUP) { - obn->flag |= OB_FROMGROUP; - } - } - else { - /* copy already clears */ - } /* remap gpencil parenting */ if (scene->gpd) { @@ -1647,42 +1640,42 @@ static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob, return obn; } -static void libblock_relink_scene_collection(SceneCollection *sc) +static void libblock_relink_collection(Collection *collection) { - for (LinkData *link = sc->objects.first; link; link = link->next) { - BKE_libblock_relink_to_newid(link->data); + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + BKE_libblock_relink_to_newid(&cob->ob->id); } - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { - libblock_relink_scene_collection(nsc); + for (CollectionChild *child = collection->children.first; child; child = child->next) { + libblock_relink_collection(child->collection); } } -static void single_object_users_scene_collection(Main *bmain, Scene *scene, SceneCollection *sc, const int flag, const bool copy_groups) +static void single_object_users_collection(Main *bmain, Scene *scene, Collection *collection, const int flag, const bool copy_collections) { - for (LinkData *link = sc->objects.first; link; link = link->next) { - Object *ob = link->data; + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Object *ob = cob->ob; /* an object may be in more than one collection */ if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) { if (!ID_IS_LINKED(ob) && ob->id.us > 1) { - link->data = single_object_users_object(bmain, scene, link->data, copy_groups); + cob->ob = single_object_users_object(bmain, scene, cob->ob); } } } - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { - single_object_users_scene_collection(bmain, scene, nsc, flag, copy_groups); + for (CollectionChild *child = collection->children.first; child; child = child->next) { + single_object_users_collection(bmain, scene, child->collection, flag, copy_collections); } } -/* Warning, sets ID->newid pointers of objects and groups, but does not clear them. */ -static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups) +/* Warning, sets ID->newid pointers of objects and collections, but does not clear them. */ +static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_collections) { - Group *group, *groupn; + Collection *collection, *collectionn; /* duplicate all the objects of the scene */ - SceneCollection *msc = BKE_collection_master(&scene->id); - single_object_users_scene_collection(bmain, scene, msc, flag, copy_groups); + Collection *master_collection = BKE_collection_master(scene); + single_object_users_collection(bmain, scene, master_collection, flag, copy_collections); /* loop over ViewLayers and assign the pointers accordingly */ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { @@ -1691,40 +1684,39 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in } } - /* duplicate groups that consist entirely of duplicated objects */ - for (group = bmain->group.first; group; group = group->id.next) { - if (copy_groups && group->view_layer->object_bases.first) { + /* duplicate collections that consist entirely of duplicated objects */ + for (collection = bmain->collection.first; collection; collection = collection->id.next) { + if (copy_collections) { bool all_duplicated = true; + bool any_duplicated = false; - FOREACH_GROUP_OBJECT_BEGIN(group, object) - { - if (object->id.newid == NULL) { + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + any_duplicated = true; + if (cob->ob->id.newid == NULL) { all_duplicated = false; break; } } - FOREACH_GROUP_OBJECT_END; - if (all_duplicated) { - groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group)); + if (any_duplicated && all_duplicated) { + // TODO: test if this works, with child collections .. + collectionn = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection)); - FOREACH_GROUP_BASE_BEGIN(groupn, base) - { - base->object = (Object *)base->object->id.newid; + for (CollectionObject *cob = collectionn->gobject.first; cob; cob = cob->next) { + cob->ob = (Object *)cob->ob->id.newid; } - FOREACH_GROUP_BASE_END } } } - /* group pointers in scene */ + /* collection pointers in scene */ BKE_scene_groups_relink(scene); ID_NEW_REMAP(scene->camera); if (v3d) ID_NEW_REMAP(v3d->camera); - /* object and group pointers */ - libblock_relink_scene_collection(msc); + /* object and collection pointers */ + libblock_relink_collection(master_collection); } /* not an especially efficient function, only added so the single user @@ -1917,9 +1909,9 @@ static void single_mat_users_expand(Main *bmain) } /* used for copying scenes */ -void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_groups) +void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_collections) { - single_object_users(bmain, scene, NULL, 0, copy_groups); + single_object_users(bmain, scene, NULL, 0, copy_collections); if (full) { single_obdata_users(bmain, scene, NULL, 0); @@ -2038,7 +2030,7 @@ static void tag_localizable_objects(bContext *C, const int mode) * Instance indirectly referenced zero user objects, * otherwise they're lost on reload, see T40595. */ -static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene, ViewLayer *view_layer, SceneCollection *sc) +static bool make_local_all__instance_indirect_unused(Main *bmain, ViewLayer *view_layer, Collection *collection) { Object *ob; bool changed = false; @@ -2049,7 +2041,7 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene, id_us_plus(&ob->id); - BKE_collection_object_add(&scene->id, sc, ob); + BKE_collection_object_add(bmain, collection, ob); base = BKE_view_layer_base_find(view_layer, ob); base->flag |= BASE_SELECTED; BKE_scene_object_base_flag_sync_from_base(base); @@ -2117,7 +2109,6 @@ static void make_local_material_tag(Material *ma) static int make_local_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); ParticleSystem *psys; Material *ma, ***matarar; const int mode = RNA_enum_get(op->ptr, "type"); @@ -2126,14 +2117,14 @@ static int make_local_exec(bContext *C, wmOperator *op) /* Note: we (ab)use LIB_TAG_PRE_EXISTING to cherry pick which ID to make local... */ if (mode == MAKE_LOCAL_ALL) { ViewLayer *view_layer = CTX_data_view_layer(C); - SceneCollection *scene_collection = CTX_data_scene_collection(C); + Collection *collection = CTX_data_collection(C); BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); /* De-select so the user can differentiate newly instanced from existing objects. */ BKE_view_layer_base_deselect_all(view_layer); - if (make_local_all__instance_indirect_unused(bmain, scene, view_layer, scene_collection)) { + if (make_local_all__instance_indirect_unused(bmain, view_layer, collection)) { BKE_report(op->reports, RPT_INFO, "Orphan library objects added to the current scene to avoid loss"); } } @@ -2282,7 +2273,7 @@ static int make_override_static_invoke(bContext *C, wmOperator *op, const wmEven } else { /* Error.. cannot continue. */ - BKE_report(op->reports, RPT_ERROR, "Can only make static override for a referenced object or group"); + BKE_report(op->reports, RPT_ERROR, "Can only make static override for a referenced object or collection"); return OPERATOR_CANCELLED; } @@ -2296,23 +2287,24 @@ static int make_override_static_exec(bContext *C, wmOperator *op) bool success = false; if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { - Base *base = BLI_findlink(&obact->dup_group->view_layer->object_bases, RNA_enum_get(op->ptr, "object")); - Object *obgroup = obact; + const ListBase dup_collection_objects = BKE_collection_object_cache_get(obact->dup_group); + Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object")); + Object *obcollection = obact; obact = base->object; - Group *group = obgroup->dup_group; + Collection *collection = obcollection->dup_group; - /* First, we make a static override of the linked group itself. */ - group->id.tag |= LIB_TAG_DOIT; + /* First, we make a static override of the linked collection itself. */ + collection->id.tag |= LIB_TAG_DOIT; - /* Then, we make static override of the whole set of objects in the group. */ - FOREACH_GROUP_OBJECT_BEGIN(group, ob) + /* Then, we make static override of the whole set of objects in the Collection. */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob) { ob->id.tag |= LIB_TAG_DOIT; } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - /* Then, we make static override of the whole set of objects in the group. */ - FOREACH_GROUP_OBJECT_BEGIN(group, ob) + /* Then, we make static override of the whole set of objects in the collection. */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob) { if (ob->type == OB_ARMATURE && ob->pose != NULL) { for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { @@ -2322,25 +2314,25 @@ static int make_override_static_exec(bContext *C, wmOperator *op) } } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; success = BKE_override_static_create_from_tag(bmain); /* Intantiate our newly overridden objects in scene, if not yet done. */ Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - Group *new_group = (Group *)group->id.newid; - FOREACH_GROUP_OBJECT_BEGIN(new_group, new_ob) + Collection *new_collection = (Collection *)collection->id.newid; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(new_collection, new_ob) { if (new_ob != NULL && new_ob->id.override_static != NULL && (base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) { - BKE_collection_object_add_from(scene, obgroup, new_ob); + BKE_collection_object_add_from(bmain, scene, obcollection, new_ob); DEG_id_tag_update_ex(bmain, &new_ob->id, OB_RECALC_OB | DEG_TAG_BASE_FLAGS_UPDATE); - /* parent to 'group' empty */ + /* parent to 'collection' empty */ if (new_ob->parent == NULL) { - new_ob->parent = obgroup; + new_ob->parent = obcollection; } if (new_ob == (Object *)obact->id.newid) { base = BKE_view_layer_base_find(view_layer, new_ob); @@ -2354,10 +2346,10 @@ static int make_override_static_exec(bContext *C, wmOperator *op) BKE_override_static_operations_create(&new_ob->id, true); } } - FOREACH_GROUP_OBJECT_END; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - /* obgroup is no more dupligroup-ing, it merely parents whole group of overriding instantiated objects. */ - obgroup->dup_group = NULL; + /* obcollection is no more duplicollection-ing, it merely parents whole collection of overriding instantiated objects. */ + obcollection->dup_group = NULL; /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */ @@ -2423,8 +2415,8 @@ void OBJECT_OT_make_override_static(wmOperatorType *ot) /* properties */ PropertyRNA *prop; prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Override Object", - "Name of lib-linked/group object to make an override from"); - RNA_def_enum_funcs(prop, proxy_group_object_itemf); + "Name of lib-linked/collection object to make an override from"); + RNA_def_enum_funcs(prop, proxy_collection_object_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; } @@ -2441,16 +2433,16 @@ static int make_single_user_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); /* ok if this is NULL */ const int flag = (RNA_enum_get(op->ptr, "type") == MAKE_SINGLE_USER_SELECTED) ? SELECT : 0; - const bool copy_groups = false; + const bool copy_collections = false; bool update_deps = false; if (RNA_boolean_get(op->ptr, "object")) { if (flag == SELECT) { BKE_view_layer_selected_objects_tag(view_layer, OB_DONE); - single_object_users(bmain, scene, v3d, OB_DONE, copy_groups); + single_object_users(bmain, scene, v3d, OB_DONE, copy_collections); } else { - single_object_users(bmain, scene, v3d, 0, copy_groups); + single_object_users(bmain, scene, v3d, 0, copy_collections); } /* needed since object relationships may have changed */ diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index d0d0418c861..d5e6f08352f 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -50,8 +50,8 @@ #include "BLT_translation.h" +#include "BKE_collection.h" #include "BKE_context.h" -#include "BKE_group.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" @@ -267,12 +267,12 @@ static bool object_select_all_by_material(bContext *C, Material *mat) static bool object_select_all_by_dup_group(bContext *C, Object *ob) { bool changed = false; - Group *dup_group = (ob->transflag & OB_DUPLIGROUP) ? ob->dup_group : NULL; + Collection *dup_group = (ob->transflag & OB_DUPLICOLLECTION) ? ob->dup_group : NULL; CTX_DATA_BEGIN (C, Base *, base, visible_bases) { if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { - Group *dup_group_other = (base->object->transflag & OB_DUPLIGROUP) ? base->object->dup_group : NULL; + Collection *dup_group_other = (base->object->transflag & OB_DUPLICOLLECTION) ? base->object->dup_group : NULL; if (dup_group == dup_group_other) { ED_object_base_select(base, BA_SELECT); changed = true; @@ -475,7 +475,6 @@ enum { OBJECT_GRPSEL_SIBLINGS = 3, OBJECT_GRPSEL_TYPE = 4, OBJECT_GRPSEL_COLLECTION = 5, - OBJECT_GRPSEL_GROUP = 6, OBJECT_GRPSEL_HOOK = 7, OBJECT_GRPSEL_PASS = 8, OBJECT_GRPSEL_COLOR = 9, @@ -490,7 +489,6 @@ static const EnumPropertyItem prop_select_grouped_types[] = { {OBJECT_GRPSEL_SIBLINGS, "SIBLINGS", 0, "Siblings", "Shared Parent"}, {OBJECT_GRPSEL_TYPE, "TYPE", 0, "Type", "Shared object type"}, {OBJECT_GRPSEL_COLLECTION, "COLLECTION", 0, "Collection", "Shared collection"}, - {OBJECT_GRPSEL_GROUP, "GROUP", 0, "Group", "Shared group"}, {OBJECT_GRPSEL_HOOK, "HOOK", 0, "Hook", ""}, {OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"}, {OBJECT_GRPSEL_COLOR, "COLOR", 0, "Color", "Object Color"}, @@ -542,30 +540,30 @@ static bool select_grouped_parent(bContext *C) /* Makes parent active and de-sel } -#define GROUP_MENU_MAX 24 -static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in the same group as the active */ +#define COLLECTION_MENU_MAX 24 +static bool select_grouped_collection(bContext *C, Object *ob) /* Select objects in the same group as the active */ { bool changed = false; - Group *group, *ob_groups[GROUP_MENU_MAX]; - int group_count = 0, i; + Collection *collection, *ob_collections[COLLECTION_MENU_MAX]; + int collection_count = 0, i; uiPopupMenu *pup; uiLayout *layout; - for (group = CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group = group->id.next) { - if (BKE_group_object_exists(group, ob)) { - ob_groups[group_count] = group; - group_count++; + for (collection = CTX_data_main(C)->collection.first; collection && collection_count < COLLECTION_MENU_MAX; collection = collection->id.next) { + if (BKE_collection_has_object(collection, ob)) { + ob_collections[collection_count] = collection; + collection_count++; } } - if (!group_count) + if (!collection_count) return 0; - else if (group_count == 1) { - group = ob_groups[0]; + else if (collection_count == 1) { + collection = ob_collections[0]; CTX_DATA_BEGIN (C, Base *, base, visible_bases) { if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { - if (BKE_group_object_exists(group, base->object)) { + if (BKE_collection_has_object(collection, base->object)) { ED_object_base_select(base, BA_SELECT); changed = true; } @@ -576,12 +574,12 @@ static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in } /* build the menu. */ - pup = UI_popup_menu_begin(C, IFACE_("Select Group"), ICON_NONE); + pup = UI_popup_menu_begin(C, IFACE_("Select Collection"), ICON_NONE); layout = UI_popup_menu_layout(pup); - for (i = 0; i < group_count; i++) { - group = ob_groups[i]; - uiItemStringO(layout, group->id.name + 2, 0, "OBJECT_OT_select_same_group", "group", group->id.name + 2); + for (i = 0; i < collection_count; i++) { + collection = ob_collections[i]; + uiItemStringO(layout, collection->id.name + 2, 0, "OBJECT_OT_select_same_collection", "collection", collection->id.name + 2); } UI_popup_menu_end(C, pup); @@ -662,60 +660,6 @@ static bool select_grouped_type(bContext *C, Object *ob) return changed; } -#define COLLECTION_MENU_MAX 24 -static bool select_grouped_collection(bContext *C, Object *ob) /* Select objects in the same collection as the active */ -{ - typedef struct EnumeratedCollection { - struct SceneCollection *collection; - int index; - } EnumeratedCollection; - - bool changed = false; - SceneCollection *collection; - EnumeratedCollection ob_collections[COLLECTION_MENU_MAX]; - int collection_count = 0, i; - uiPopupMenu *pup; - uiLayout *layout; - - i = 0; - FOREACH_SCENE_COLLECTION_BEGIN(CTX_data_scene(C), scene_collection) - { - if (BKE_collection_object_exists(scene_collection, ob)) { - ob_collections[collection_count].index = i; - ob_collections[collection_count].collection = scene_collection; - if (++collection_count >= COLLECTION_MENU_MAX) { - break; - } - } - i++; - } - FOREACH_SCENE_COLLECTION_END; - - if (!collection_count) { - return 0; - } - else if (collection_count == 1) { - collection = ob_collections[0].collection; - return BKE_collection_objects_select(CTX_data_view_layer(C), collection); - } - - /* build the menu. */ - pup = UI_popup_menu_begin(C, IFACE_("Select Collection"), ICON_NONE); - layout = UI_popup_menu_layout(pup); - - for (i = 0; i < collection_count; i++) { - uiItemIntO(layout, - ob_collections[i].collection->name, - ICON_NONE, - "OBJECT_OT_select_same_collection", - "collection_index", - ob_collections[i].index); - } - - UI_popup_menu_end(C, pup); - return changed; /* The operator already handle this! */ -} - static bool select_grouped_index_object(bContext *C, Object *ob) { bool changed = false; @@ -841,9 +785,6 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) case OBJECT_GRPSEL_COLLECTION: changed |= select_grouped_collection(C, ob); break; - case OBJECT_GRPSEL_GROUP: - changed |= select_grouped_group(C, ob); - break; case OBJECT_GRPSEL_HOOK: changed |= select_grouped_object_hooks(C, ob); break; @@ -960,28 +901,28 @@ void OBJECT_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/**************************** Select In The Same Group ****************************/ +/**************************** Select In The Same Collection ****************************/ -static int object_select_same_group_exec(bContext *C, wmOperator *op) +static int object_select_same_collection_exec(bContext *C, wmOperator *op) { - Group *group; - char group_name[MAX_ID_NAME]; + Collection *collection; + char collection_name[MAX_ID_NAME]; /* passthrough if no objects are visible */ if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH; - RNA_string_get(op->ptr, "group", group_name); + RNA_string_get(op->ptr, "collection", collection_name); - group = (Group *)BKE_libblock_find_name(ID_GR, group_name); + collection = (Collection *)BKE_libblock_find_name(ID_GR, collection_name); - if (!group) { + if (!collection) { return OPERATOR_PASS_THROUGH; } CTX_DATA_BEGIN (C, Base *, base, visible_bases) { if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLED) != 0)) { - if (BKE_group_object_exists(group, base->object)) { + if (BKE_collection_has_object(collection, base->object)) { ED_object_base_select(base, BA_SELECT); } } @@ -993,67 +934,24 @@ static int object_select_same_group_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void OBJECT_OT_select_same_group(wmOperatorType *ot) -{ - - /* identifiers */ - ot->name = "Select Same Group"; - ot->description = "Select object in the same group"; - ot->idname = "OBJECT_OT_select_same_group"; - - /* api callbacks */ - ot->exec = object_select_same_group_exec; - ot->poll = objects_selectable_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - RNA_def_string(ot->srna, "group", NULL, MAX_ID_NAME, "Group", "Name of the group to select"); -} - -/**************************** Select In The Same Collection ****************************/ - -static int object_select_same_collection_exec(bContext *C, wmOperator *op) -{ - SceneCollection *collection; - - /* passthrough if no objects are visible */ - if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH; - - int collection_index = RNA_int_get(op->ptr, "collection_index"); - collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); - - if (!collection) { - return OPERATOR_PASS_THROUGH; - } - - if (BKE_collection_objects_select(CTX_data_view_layer(C), collection)) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); - } - - return OPERATOR_FINISHED; -} - void OBJECT_OT_select_same_collection(wmOperatorType *ot) { - PropertyRNA *prop; - + /* identifiers */ ot->name = "Select Same Collection"; ot->description = "Select object in the same collection"; ot->idname = "OBJECT_OT_select_same_collection"; - + /* api callbacks */ ot->exec = object_select_same_collection_exec; ot->poll = objects_selectable_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_int(ot->srna, "collection_index", -1, -1, INT_MAX, - "Collection Index", "Index of the collection to select", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_string(ot->srna, "collection", NULL, MAX_ID_NAME, "Collection", "Name of the collection to select"); } + /**************************** Select Mirror ****************************/ static int object_select_mirror_exec(bContext *C, wmOperator *op) { diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index a862ef718d2..6b22521eedd 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -879,7 +879,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (ob->data == NULL) { /* special support for dupligroups */ - if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) { + if ((ob->transflag & OB_DUPLICOLLECTION) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) { if (ID_IS_LINKED(ob->dup_group)) { tot_lib_error++; } @@ -1088,7 +1088,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if ((ob_other->flag & OB_DONE) == 0 && ((ob->data && (ob->data == ob_other->data)) || (ob->dup_group == ob_other->dup_group && - (ob->transflag | ob_other->transflag) & OB_DUPLIGROUP))) + (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION))) { ob_other->flag |= OB_DONE; DEG_id_tag_update(&ob_other->id, OB_RECALC_OB | OB_RECALC_DATA); diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index 3bcc047bf5b..f62b72679d0 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -37,8 +37,8 @@ #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" +#include "BKE_collection.h" #include "BKE_context.h" -#include "BKE_group.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_rigidbody.h" @@ -83,14 +83,14 @@ bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int type } /* create constraint group if it doesn't already exits */ if (rbw->constraints == NULL) { - rbw->constraints = BKE_group_add(bmain, "RigidBodyConstraints"); + rbw->constraints = BKE_collection_add(bmain, NULL, "RigidBodyConstraints"); } /* make rigidbody constraint settings */ ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type); ob->rigidbody_constraint->flag |= RBC_FLAG_NEEDS_VALIDATE; /* add constraint to rigid body constraint group */ - BKE_group_object_add(rbw->constraints, ob); + BKE_collection_object_add(bmain, rbw->constraints, ob); DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, OB_RECALC_OB); @@ -103,7 +103,7 @@ void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob) BKE_rigidbody_remove_constraint(scene, ob); if (rbw) - BKE_group_object_unlink(rbw->constraints, ob); + BKE_collection_object_remove(bmain, rbw->constraints, ob, false); DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, OB_RECALC_OB); diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index 3553ffa5033..99976898ac1 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -42,8 +42,8 @@ #include "BLT_translation.h" +#include "BKE_collection.h" #include "BKE_context.h" -#include "BKE_group.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_rigidbody.h" @@ -109,7 +109,7 @@ bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, Re scene->rigidbody_world = rbw; } if (rbw->group == NULL) { - rbw->group = BKE_group_add(bmain, "RigidBodyWorld"); + rbw->group = BKE_collection_add(bmain, NULL, "RigidBodyWorld"); } /* make rigidbody object settings */ @@ -120,7 +120,7 @@ bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, Re ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_VALIDATE; /* add object to rigid body group */ - BKE_group_object_add(rbw->group, ob); + BKE_collection_object_add(bmain, rbw->group, ob); DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, OB_RECALC_OB); @@ -134,7 +134,7 @@ void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob) BKE_rigidbody_remove_object(scene, ob); if (rbw) - BKE_group_object_unlink(rbw->group, ob); + BKE_collection_object_remove(bmain, rbw->group, ob, false); DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, OB_RECALC_OB); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index d0390985181..946da6f1ed8 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -51,6 +51,7 @@ #include "DNA_world_types.h" #include "DNA_camera_types.h" +#include "DNA_group_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -252,7 +253,7 @@ static Scene *preview_get_scene(Main *pr_main) return pr_main->scene.first; } -static const char *preview_layer_name(const char pr_type) +static const char *preview_collection_name(const char pr_type) { switch (pr_type) { case MA_FLAT: @@ -281,19 +282,21 @@ static const char *preview_layer_name(const char pr_type) } } -static void set_preview_layer(ViewLayer *view_layer, char pr_type) +static void set_preview_collection(Scene *scene, ViewLayer *view_layer, char pr_type) { - LayerCollection *lc; - const char *collection_name = preview_layer_name(pr_type); + LayerCollection *lc = view_layer->layer_collections.first; + const char *collection_name = preview_collection_name(pr_type); - for (lc = view_layer->layer_collections.first; lc; lc = lc->next) { - if (STREQ(lc->scene_collection->name, collection_name)) { - lc->flag = COLLECTION_VIEWPORT | COLLECTION_RENDER; + for (lc = lc->layer_collections.first; lc; lc = lc->next) { + if (STREQ(lc->collection->id.name + 2, collection_name)) { + lc->collection->flag &= ~COLLECTION_RESTRICT_RENDER; } else { - lc->flag = COLLECTION_DISABLED; + lc->collection->flag |= COLLECTION_RESTRICT_RENDER; } } + + BKE_layer_collection_sync(scene, view_layer); } static World *preview_get_localized_world(ShaderPreview *sp, World *world) @@ -389,10 +392,10 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty } if (sp->pr_method == PR_ICON_RENDER) { - set_preview_layer(view_layer, MA_SPHERE_A); + set_preview_collection(sce, view_layer, MA_SPHERE_A); } else { - set_preview_layer(view_layer, mat->pr_type); + set_preview_collection(sce, view_layer, mat->pr_type); if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ @@ -433,7 +436,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty sp->texcopy = tex; BLI_addtail(&pr_main->tex, tex); } - set_preview_layer(view_layer, MA_TEXTURE); + set_preview_collection(sce, view_layer, MA_TEXTURE); if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ @@ -451,7 +454,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty BLI_addtail(&pr_main->lamp, la); } - set_preview_layer(view_layer, MA_LAMP); + set_preview_collection(sce, view_layer, MA_LAMP); if (sce->world) { /* Only use lighting from the lamp. */ @@ -483,7 +486,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty BLI_addtail(&pr_main->world, wrld); } - set_preview_layer(view_layer, MA_SKY); + set_preview_collection(sce, view_layer, MA_SKY); sce->world = wrld; if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) { diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 5353c250d1e..2a0be4eaf0d 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -776,7 +776,7 @@ static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, I } if ((ID *)sact->ads.filter_grp == old_id) { - sact->ads.filter_grp = (Group *)new_id; + sact->ads.filter_grp = (Collection *)new_id; } if ((ID *)sact->ads.source == old_id) { sact->ads.source = new_id; diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 6793f0a0195..207e08c9a44 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -191,40 +191,6 @@ static int buttons_context_path_workspace(ButsContextPath *path) return RNA_struct_is_a(ptr->type, &RNA_WorkSpace); } -static int buttons_context_path_collection(ButsContextPath *path, eSpaceButtons_Collection_Context collection_context) -{ - PointerRNA *ptr = &path->ptr[path->len - 1]; - - /* if we already have a (pinned) Collection, we're done */ - if (RNA_struct_is_a(ptr->type, &RNA_LayerCollection)) { - return 1; - } - else if (RNA_struct_is_a(ptr->type, &RNA_ViewLayer)) { - ViewLayer *view_layer = ptr->data; - - if (collection_context == SB_COLLECTION_CTX_GROUP) { - Object *ob = OBACT(view_layer); - if (ob && ob->dup_group) { - view_layer = ob->dup_group->view_layer; - - /* Replace the view layer by the group in the context path. */ - RNA_pointer_create(NULL, &RNA_Group, ob->dup_group, &path->ptr[path->len - 1]); - } - } - - LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); - - if (layer_collection) { - RNA_pointer_create(NULL, &RNA_LayerCollection, layer_collection, &path->ptr[path->len]); - path->len++; - return 1; - } - } - - /* no path to a collection possible */ - return 0; -} - static int buttons_context_path_object(ButsContextPath *path) { PointerRNA *ptr = &path->ptr[path->len - 1]; @@ -562,9 +528,6 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma case BCONTEXT_WORKSPACE: found = buttons_context_path_workspace(path); break; - case BCONTEXT_COLLECTION: - found = buttons_context_path_collection(path, sbuts->collection_context); - break; case BCONTEXT_OBJECT: case BCONTEXT_PHYSICS: case BCONTEXT_CONSTRAINT: @@ -982,10 +945,6 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r set_pointer_type(path, result, &RNA_FreestyleLineStyle); return 1; } - else if (CTX_data_equals(member, "collection")) { - set_pointer_type(path, result, &RNA_LayerCollection); - return 1; - } else { return 0; /* not found */ } diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 6ad5ed40f74..05304ecbf94 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -156,8 +156,6 @@ static void buttons_main_region_draw(const bContext *C, ARegion *ar) ED_region_panels(C, ar, "world", sbuts->mainb, vertical); else if (sbuts->mainb == BCONTEXT_WORKSPACE) ED_region_panels(C, ar, "workspace", sbuts->mainb, vertical); - else if (sbuts->mainb == BCONTEXT_COLLECTION) - ED_region_panels(C, ar, "collection", sbuts->mainb, vertical); else if (sbuts->mainb == BCONTEXT_OBJECT) ED_region_panels(C, ar, "object", sbuts->mainb, vertical); else if (sbuts->mainb == BCONTEXT_DATA) diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index ff144fec778..8d3647def9e 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -755,7 +755,7 @@ static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID if (sgraph->ads) { if ((ID *)sgraph->ads->filter_grp == old_id) { - sgraph->ads->filter_grp = (Group *)new_id; + sgraph->ads->filter_grp = (Collection *)new_id; } if ((ID *)sgraph->ads->source == old_id) { sgraph->ads->source = new_id; diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index c7d4fa1465b..dfcf5fd5d8d 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -37,6 +37,7 @@ #include "DNA_meta_types.h" #include "DNA_scene_types.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -271,36 +272,26 @@ static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats) stats->tottri = ob->sculpt->bm->totface; } -static void stats_dupli_object_group_count(SceneCollection *scene_collection, int *count) +static void stats_dupli_object_group_count(Collection *collection, int *count) { - for (LinkData *link = scene_collection->objects.first; link; link = link->next) { - (*count)++; - } + *count += BLI_listbase_count(&collection->gobject); - SceneCollection *scene_collection_nested; - for (scene_collection_nested = scene_collection->scene_collections.first; - scene_collection_nested; - scene_collection_nested = scene_collection_nested->next) - { - stats_dupli_object_group_count(scene_collection_nested, count); + for (CollectionChild *child = collection->children.first; child; child = child->next) { + stats_dupli_object_group_count(child->collection, count); } } -static void stats_dupli_object_group_doit(SceneCollection *scene_collection, SceneStats *stats, ParticleSystem *psys, +static void stats_dupli_object_group_doit(Collection *collection, SceneStats *stats, ParticleSystem *psys, const int totgroup, int *cur) { - for (LinkData *link = scene_collection->objects.first; link; link = link->next) { + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { int tot = count_particles_mod(psys, totgroup, *cur); - stats_object(link->data, 0, tot, stats); + stats_object(cob->ob, 0, tot, stats); (*cur)++; } - SceneCollection *scene_collection_nested; - for (scene_collection_nested = scene_collection->scene_collections.first; - scene_collection_nested; - scene_collection_nested = scene_collection_nested->next) - { - stats_dupli_object_group_doit(scene_collection_nested, stats, psys, totgroup, cur); + for (CollectionChild *child = collection->children.first; child; child = child->next) { + stats_dupli_object_group_doit(child->collection, stats, psys, totgroup, cur); } } @@ -323,9 +314,9 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) else if (part->draw_as == PART_DRAW_GR && part->dup_group) { int totgroup = 0, cur = 0; - SceneCollection *scene_collection = part->dup_group->collection; - stats_dupli_object_group_count(scene_collection, &totgroup); - stats_dupli_object_group_doit(scene_collection, stats, psys, totgroup, &cur); + Collection *collection = part->dup_group; + stats_dupli_object_group_count(collection, &totgroup); + stats_dupli_object_group_doit(collection, stats, psys, totgroup, &cur); } } @@ -353,7 +344,7 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) stats->totobj += tot; stats_object(ob, base->flag & BASE_SELECTED, tot, stats); } - else if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { + else if ((ob->transflag & OB_DUPLICOLLECTION) && ob->dup_group) { /* Dupli Group */ int tot = count_duplilist(ob); stats->totobj += tot; diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index 222fb6d8fbd..7245fd9c17f 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -571,7 +571,7 @@ static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID * if (snla->ads) { if ((ID *)snla->ads->filter_grp == old_id) { - snla->ads->filter_grp = (Group *)new_id; + snla->ads->filter_grp = (Collection *)new_id; } if ((ID *)snla->ads->source == old_id) { snla->ads->source = new_id; 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); } } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index df9d8dad6ee..f26da3ad07e 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -549,7 +549,7 @@ static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent return 0; } -static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) +static int view3d_collection_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { ID *id = drag->poin; @@ -624,7 +624,7 @@ static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop) RNA_string_set(drop->ptr, "name", id->name + 2); } -static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop) +static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop) { ID *id = drag->poin; @@ -664,7 +664,7 @@ static void view3d_dropboxes(void) WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy); WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy); WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy); - WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy); + WM_dropbox_add(lb, "OBJECT_OT_collection_instance_add", view3d_collection_drop_poll, view3d_collection_drop_copy); } static void view3d_widgets(void) diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 7fc582a1511..43ff8af42fb 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -45,8 +45,8 @@ #include "BKE_appdir.h" #include "BKE_blender_copybuffer.h" +#include "BKE_collection.h" #include "BKE_context.h" -#include "BKE_group.h" #include "BKE_main.h" #include "BKE_report.h" @@ -81,17 +81,17 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - for (Group *group = bmain->group.first; group; group = group->id.next) { - FOREACH_GROUP_OBJECT_BEGIN(group, object) - { + for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Object *object = cob->ob; + if (object && (object->id.tag & LIB_TAG_DOIT)) { - BKE_copybuffer_tag_ID(&group->id); + BKE_copybuffer_tag_ID(&collection->id); /* don't expand out to all other objects */ - group->id.tag &= ~LIB_TAG_NEED_EXPAND; + collection->id.tag &= ~LIB_TAG_NEED_EXPAND; break; } } - FOREACH_GROUP_OBJECT_END; } BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); |