From 0a7510ebaa35f41e248d3dd10d735f58d84739ec Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 15 Apr 2024 18:41:17 +0200 Subject: [PATCH] Fix #116818: Unlinking an Object in the Scene Collection unlinks all linked objects Code was assuming that if an object had a Scene parent ID (in Outliner context), Outliner was in Scene view and object had to be removed from whole scene. However, in ViewLayer view, in case an object is in a Scene's main collection, its parent item is the scene. --- .../editors/space_outliner/outliner_tools.cc | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index e1fb3eda7e7..89082e3718d 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -428,6 +428,8 @@ static void unlink_object_fn(bContext *C, if (tsep && tsep->id) { Main *bmain = CTX_data_main(C); Object *ob = (Object *)tselem->id; + const eSpaceOutliner_Mode outliner_mode = eSpaceOutliner_Mode( + CTX_wm_space_outliner(C)->outlinevis); if (GS(tsep->id->name) == ID_OB) { /* Parented objects need to find which collection to unlink from. */ @@ -455,29 +457,41 @@ static void unlink_object_fn(bContext *C, tsep->id->name + 2); return; } - if (GS(tsep->id->name) == ID_GR) { - Collection *parent = (Collection *)tsep->id; - BKE_collection_object_remove(bmain, parent, ob, true); - DEG_id_tag_update(&parent->id, ID_RECALC_SYNC_TO_EVAL | ID_RECALC_HIERARCHY); - DEG_id_tag_update(&ob->id, ID_RECALC_HIERARCHY); - DEG_relations_tag_update(bmain); - } - else if (GS(tsep->id->name) == ID_SCE) { - /* Following execution is expected to happen exclusively in the Outliner scene view. */ -#ifdef NDEBUG - BLI_assert(CTX_wm_space_outliner(C)->outlinevis == SO_SCENES); -#endif - - Scene *scene = (Scene *)tsep->id; - FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { - if (BKE_collection_has_object(collection, ob)) { - BKE_collection_object_remove(bmain, collection, ob, true); - } + switch (GS(tsep->id->name)) { + case ID_GR: { + Collection *parent = (Collection *)tsep->id; + BKE_collection_object_remove(bmain, parent, ob, true); + break; + } + case ID_SCE: { + Scene *scene = reinterpret_cast(tsep->id); + /* In Scene view, remove the object from all collections in the scene. */ + if (outliner_mode == SO_SCENES) { + FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { + if (BKE_collection_has_object(collection, ob)) { + BKE_collection_object_remove(bmain, collection, ob, true); + DEG_id_tag_update(&collection->id, ID_RECALC_HIERARCHY); + } + } + FOREACH_SCENE_COLLECTION_END; + } + /* Otherwise, remove the object from the scene's main collection. */ + else { + Collection *parent = scene->master_collection; + BKE_collection_object_remove(bmain, parent, ob, true); + } + break; + } + default: { + /* Un-handled case, should never be reached. */ + BLI_assert_unreachable(); + return; } - FOREACH_SCENE_COLLECTION_END; - DEG_id_tag_update(&scene->id, ID_RECALC_SYNC_TO_EVAL | ID_RECALC_HIERARCHY); - DEG_relations_tag_update(bmain); } + /* NOTE: Cannot risk tagging the object here, as it may have been deleted if its last usage + * was removed by above code. */ + DEG_id_tag_update(tsep->id, ID_RECALC_HIERARCHY); + DEG_relations_tag_update(bmain); } } }