Groups and collection: create group from collection
You could still create groups as before, with Ctl + G. This will create a group with a single visible collection. However you can also create a group from an existing collection. Just go to the menu you get in the outliner when clicking in a collection and pick "Create Group". Remember to instance the group afterwards, or link it into a new scene or file. The group and the collection are not kept in sync afterwards. You need to manually edit the group for further changes.
This commit is contained in:
@@ -58,6 +58,8 @@ bool BKE_collection_object_remove(struct Main *bmain, struct ID *owner_id, struc
|
|||||||
bool BKE_collections_object_remove(struct Main *bmain, struct ID *owner_id, struct Object *object, const bool free_us);
|
bool BKE_collections_object_remove(struct Main *bmain, struct ID *owner_id, struct Object *object, const bool free_us);
|
||||||
void BKE_collection_object_move(struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src, struct Object *ob);
|
void BKE_collection_object_move(struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src, struct Object *ob);
|
||||||
|
|
||||||
|
struct Group *BKE_collection_group_create(struct Main *bmain, struct Scene *scene, struct LayerCollection *lc);
|
||||||
|
|
||||||
void BKE_collection_reinsert_after(const struct Scene *scene, struct SceneCollection *sc_reinsert, struct SceneCollection *sc_after);
|
void BKE_collection_reinsert_after(const struct Scene *scene, struct SceneCollection *sc_reinsert, struct SceneCollection *sc_after);
|
||||||
void BKE_collection_reinsert_into(struct SceneCollection *sc_reinsert, struct SceneCollection *sc_into);
|
void BKE_collection_reinsert_into(struct SceneCollection *sc_reinsert, struct SceneCollection *sc_into);
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@
|
|||||||
#include "BLI_string_utils.h"
|
#include "BLI_string_utils.h"
|
||||||
|
|
||||||
#include "BKE_collection.h"
|
#include "BKE_collection.h"
|
||||||
|
#include "BKE_group.h"
|
||||||
#include "BKE_idprop.h"
|
#include "BKE_idprop.h"
|
||||||
#include "BKE_layer.h"
|
#include "BKE_layer.h"
|
||||||
#include "BKE_library.h"
|
#include "BKE_library.h"
|
||||||
@@ -48,6 +49,9 @@
|
|||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
/* Prototypes. */
|
||||||
|
static bool is_collection_in_tree(const struct SceneCollection *sc_reference, struct SceneCollection *sc_parent);
|
||||||
|
|
||||||
static SceneCollection *collection_master_from_id(const ID *owner_id)
|
static SceneCollection *collection_master_from_id(const ID *owner_id)
|
||||||
{
|
{
|
||||||
switch (GS(owner_id->name)) {
|
switch (GS(owner_id->name)) {
|
||||||
@@ -407,6 +411,82 @@ bool BKE_collections_object_remove(Main *bmain, ID *owner_id, Object *ob, const
|
|||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void layer_collection_sync(LayerCollection *lc_dst, LayerCollection *lc_src)
|
||||||
|
{
|
||||||
|
lc_dst->flag = lc_src->flag;
|
||||||
|
|
||||||
|
/* Pending: sync overrides. */
|
||||||
|
IDP_MergeGroup(lc_dst->properties, lc_src->properties, true);
|
||||||
|
|
||||||
|
/* Continue recursively. */
|
||||||
|
LayerCollection *lc_dst_nested, *lc_src_nested;
|
||||||
|
lc_src_nested = lc_src->layer_collections.first;
|
||||||
|
for (lc_dst_nested = lc_dst->layer_collections.first;
|
||||||
|
lc_dst_nested && lc_src_nested;
|
||||||
|
lc_dst_nested = lc_dst_nested->next, lc_src_nested = lc_src_nested->next)
|
||||||
|
{
|
||||||
|
layer_collection_sync(lc_dst_nested, lc_src_nested);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Leave only the master collection in, remove everything else.
|
||||||
|
* @param group
|
||||||
|
*/
|
||||||
|
static void collection_group_cleanup(Group *group)
|
||||||
|
{
|
||||||
|
/* Unlink all the LayerCollections. */
|
||||||
|
while (group->view_layer->layer_collections.last != NULL) {
|
||||||
|
BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.last);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove all the SceneCollections but the master. */
|
||||||
|
collection_free(group->collection, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a group from a collection
|
||||||
|
*
|
||||||
|
* Any ViewLayer that may have this the related SceneCollection linked is converted
|
||||||
|
* to a Group Collection.
|
||||||
|
*/
|
||||||
|
Group *BKE_collection_group_create(Main *bmain, Scene *scene, LayerCollection *lc_src)
|
||||||
|
{
|
||||||
|
SceneCollection *sc_dst, *sc_src = lc_src->scene_collection;
|
||||||
|
LayerCollection *lc_dst;
|
||||||
|
|
||||||
|
/* The master collection can't be converted. */
|
||||||
|
if (sc_src == BKE_collection_master(&scene->id)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a sub-collection of sc_dst is directly linked into a ViewLayer we can't convert. */
|
||||||
|
for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
|
||||||
|
for (LayerCollection *lc_child = view_layer->layer_collections.first; lc_child; lc_child = lc_child->next) {
|
||||||
|
if (is_collection_in_tree(lc_child->scene_collection, sc_src)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create new group with the same data as the original collection. */
|
||||||
|
Group *group = BKE_group_add(bmain, sc_src->name);
|
||||||
|
collection_group_cleanup(group);
|
||||||
|
|
||||||
|
sc_dst = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, sc_src->name);
|
||||||
|
BKE_collection_copy_data(sc_dst, sc_src, 0);
|
||||||
|
FOREACH_SCENE_COLLECTION(&group->id, sc_group)
|
||||||
|
{
|
||||||
|
sc_group->type = COLLECTION_TYPE_GROUP_INTERNAL;
|
||||||
|
}
|
||||||
|
FOREACH_SCENE_COLLECTION_END
|
||||||
|
|
||||||
|
lc_dst = BKE_collection_link(group->view_layer, sc_dst);
|
||||||
|
layer_collection_sync(lc_dst, lc_src);
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
/* Outliner drag and drop */
|
/* Outliner drag and drop */
|
||||||
|
|
||||||
|
@@ -664,6 +664,7 @@ typedef enum eOutliner_PropCollectionOps {
|
|||||||
OL_COLLECTION_OP_COLLECTION_NEW,
|
OL_COLLECTION_OP_COLLECTION_NEW,
|
||||||
OL_COLLECTION_OP_COLLECTION_DEL,
|
OL_COLLECTION_OP_COLLECTION_DEL,
|
||||||
OL_COLLECTION_OP_COLLECTION_UNLINK,
|
OL_COLLECTION_OP_COLLECTION_UNLINK,
|
||||||
|
OL_COLLECTION_OP_GROUP_CREATE,
|
||||||
} eOutliner_PropCollectionOps;
|
} eOutliner_PropCollectionOps;
|
||||||
|
|
||||||
static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
|
static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
|
||||||
@@ -878,6 +879,17 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
|
|||||||
TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */
|
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,
|
static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb,
|
||||||
@@ -1808,6 +1820,7 @@ static EnumPropertyItem prop_collection_op_none_types[] = {
|
|||||||
{OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"},
|
{OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"},
|
||||||
{OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink 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_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}
|
{0, NULL, 0, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -738,6 +738,32 @@ static void rna_LayerCollection_enable_set(
|
|||||||
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
|
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Group *rna_LayerCollection_create_group(
|
||||||
|
ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports)
|
||||||
|
{
|
||||||
|
Group *group;
|
||||||
|
Scene *scene = (Scene *)id;
|
||||||
|
SceneCollection *scene_collection = layer_collection->scene_collection;
|
||||||
|
|
||||||
|
/* The master collection can't be converted. */
|
||||||
|
if (scene_collection == BKE_collection_master(&scene->id)) {
|
||||||
|
BKE_report(reports, RPT_ERROR, "The master collection can't be converted to group");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
group = BKE_collection_group_create(bmain, scene, layer_collection);
|
||||||
|
if (group == NULL) {
|
||||||
|
BKE_reportf(reports, RPT_ERROR, "Failed to convert collection %s", scene_collection->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
static int rna_LayerCollections_active_collection_index_get(PointerRNA *ptr)
|
static int rna_LayerCollections_active_collection_index_get(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
ViewLayer *view_layer = (ViewLayer *)ptr->data;
|
ViewLayer *view_layer = (ViewLayer *)ptr->data;
|
||||||
@@ -2019,6 +2045,12 @@ static void rna_def_layer_collection(BlenderRNA *brna)
|
|||||||
parm = RNA_def_boolean(func, "value", 1, "Enable", "");
|
parm = RNA_def_boolean(func, "value", 1, "Enable", "");
|
||||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
|
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
|
||||||
|
|
||||||
|
func = RNA_def_function(srna, "create_group", "rna_LayerCollection_create_group");
|
||||||
|
RNA_def_function_ui_description(func, "Enable or disable a collection");
|
||||||
|
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
|
||||||
|
parm = RNA_def_pointer(func, "result", "Group", "", "Newly created Group");
|
||||||
|
RNA_def_function_return(func, parm);
|
||||||
|
|
||||||
/* Flags */
|
/* Flags */
|
||||||
prop = RNA_def_property(srna, "is_enabled", PROP_BOOLEAN, PROP_NONE);
|
prop = RNA_def_property(srna, "is_enabled", PROP_BOOLEAN, PROP_NONE);
|
||||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED);
|
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED);
|
||||||
|
@@ -87,6 +87,10 @@ VIEW_LAYER_TEST(evaluation_selectability_c)
|
|||||||
VIEW_LAYER_TEST(evaluation_selectability_d)
|
VIEW_LAYER_TEST(evaluation_selectability_d)
|
||||||
VIEW_LAYER_TEST(evaluation_selectability_e)
|
VIEW_LAYER_TEST(evaluation_selectability_e)
|
||||||
VIEW_LAYER_TEST(evaluation_selectability_f)
|
VIEW_LAYER_TEST(evaluation_selectability_f)
|
||||||
|
VIEW_LAYER_TEST(group_a)
|
||||||
|
VIEW_LAYER_TEST(group_b)
|
||||||
|
VIEW_LAYER_TEST(group_c)
|
||||||
|
VIEW_LAYER_TEST(group_d)
|
||||||
VIEW_LAYER_TEST(object_add_cylinder)
|
VIEW_LAYER_TEST(object_add_cylinder)
|
||||||
VIEW_LAYER_TEST(object_add_empty)
|
VIEW_LAYER_TEST(object_add_empty)
|
||||||
VIEW_LAYER_TEST(object_add_torus)
|
VIEW_LAYER_TEST(object_add_torus)
|
||||||
|
46
tests/python/view_layer/test_group_a.py
Normal file
46
tests/python/view_layer/test_group_a.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# ############################################################
|
||||||
|
# Importing - Same For All Render Layer Tests
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from view_layer_common import *
|
||||||
|
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
# Testing
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
class UnitTesting(ViewLayerTesting):
|
||||||
|
def test_group_create_basic(self):
|
||||||
|
"""
|
||||||
|
See if the creation of new groups is not crashing anything.
|
||||||
|
"""
|
||||||
|
import bpy
|
||||||
|
scene = bpy.context.scene
|
||||||
|
layer_collection = bpy.context.layer_collection
|
||||||
|
|
||||||
|
# Cleanup Viewport view layer
|
||||||
|
# technically this shouldn't be needed but
|
||||||
|
# for now we need it because depsgraph build all the view layers
|
||||||
|
# at once.
|
||||||
|
|
||||||
|
while len(scene.view_layers) > 1:
|
||||||
|
scene.view_layers.remove(scene.view_layers[1])
|
||||||
|
|
||||||
|
# create group
|
||||||
|
group = layer_collection.create_group()
|
||||||
|
|
||||||
|
# update depsgraph
|
||||||
|
scene.update()
|
||||||
|
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
# Main - Same For All Render Layer Tests
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
UnitTesting._extra_arguments = setup_extra_arguments(__file__)
|
||||||
|
unittest.main()
|
72
tests/python/view_layer/test_group_b.py
Normal file
72
tests/python/view_layer/test_group_b.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# ############################################################
|
||||||
|
# Importing - Same For All Render Layer Tests
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from view_layer_common import *
|
||||||
|
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
# Testing
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
class UnitTesting(ViewLayerTesting):
|
||||||
|
def test_group_create_basic(self):
|
||||||
|
"""
|
||||||
|
See if the creation of new groups is preserving visibility flags
|
||||||
|
from the original collections.
|
||||||
|
"""
|
||||||
|
import bpy
|
||||||
|
scene = bpy.context.scene
|
||||||
|
|
||||||
|
# clean slate
|
||||||
|
self.cleanup_tree()
|
||||||
|
|
||||||
|
master_collection = scene.master_collection
|
||||||
|
grandma = master_collection.collections.new('бабушка')
|
||||||
|
mom = grandma.collections.new('матушка')
|
||||||
|
|
||||||
|
child = bpy.data.objects.new("Child", None)
|
||||||
|
mom.objects.link(child)
|
||||||
|
|
||||||
|
grandma_layer_collection = scene.view_layers[0].collections.link(grandma)
|
||||||
|
mom_layer_collection = grandma_layer_collection.collections[0]
|
||||||
|
|
||||||
|
grandma_layer_collection.hide = False
|
||||||
|
grandma_layer_collection.hide = False
|
||||||
|
mom_layer_collection.hide = True
|
||||||
|
mom_layer_collection.hide_select = False
|
||||||
|
|
||||||
|
# update depsgraph
|
||||||
|
scene.update()
|
||||||
|
|
||||||
|
# create group
|
||||||
|
group = grandma_layer_collection.create_group()
|
||||||
|
|
||||||
|
# update depsgraph
|
||||||
|
scene.update()
|
||||||
|
|
||||||
|
# compare
|
||||||
|
self.assertEqual(len(group.view_layer.collections), 1)
|
||||||
|
grandma_group_layer = group.view_layer.collections[0]
|
||||||
|
|
||||||
|
self.assertEqual(grandma_group_layer.hide, False)
|
||||||
|
self.assertEqual(grandma_group_layer.hide_select, False)
|
||||||
|
|
||||||
|
self.assertEqual(len(grandma_group_layer.collections), 1)
|
||||||
|
mom_group_layer = grandma_group_layer.collections[0]
|
||||||
|
|
||||||
|
self.assertEqual(mom_group_layer.hide, True)
|
||||||
|
self.assertEqual(mom_group_layer.hide_select, False)
|
||||||
|
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
# Main - Same For All Render Layer Tests
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
UnitTesting._extra_arguments = setup_extra_arguments(__file__)
|
||||||
|
unittest.main()
|
56
tests/python/view_layer/test_group_c.py
Normal file
56
tests/python/view_layer/test_group_c.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# ############################################################
|
||||||
|
# Importing - Same For All Render Layer Tests
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from view_layer_common import *
|
||||||
|
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
# Testing
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
class UnitTesting(ViewLayerTesting):
|
||||||
|
def test_group_create_basic(self):
|
||||||
|
"""
|
||||||
|
More advanced creation of group from a collection not directly linked
|
||||||
|
to the scene layer.
|
||||||
|
"""
|
||||||
|
import bpy
|
||||||
|
scene = bpy.context.scene
|
||||||
|
|
||||||
|
# clean slate
|
||||||
|
self.cleanup_tree()
|
||||||
|
|
||||||
|
children = [bpy.data.objects.new("Child", None) for i in range(3)]
|
||||||
|
master_collection = scene.master_collection
|
||||||
|
|
||||||
|
grandma_scene_collection = master_collection.collections.new('Grand-Mother')
|
||||||
|
mom_scene_collection = grandma_scene_collection.collections.new('Mother')
|
||||||
|
|
||||||
|
grandma_scene_collection.objects.link(children[0])
|
||||||
|
mom_scene_collection.objects.link(children[1])
|
||||||
|
|
||||||
|
grandma_layer_collection = scene.view_layers[0].collections.link(grandma_scene_collection)
|
||||||
|
mom_layer_collection = grandma_layer_collection.collections[mom_scene_collection.name]
|
||||||
|
|
||||||
|
# update depsgraph
|
||||||
|
scene.update()
|
||||||
|
|
||||||
|
# create group
|
||||||
|
group = mom_layer_collection.create_group()
|
||||||
|
|
||||||
|
# update depsgraph
|
||||||
|
scene.update()
|
||||||
|
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
# Main - Same For All Render Layer Tests
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
UnitTesting._extra_arguments = setup_extra_arguments(__file__)
|
||||||
|
unittest.main()
|
76
tests/python/view_layer/test_group_d.py
Normal file
76
tests/python/view_layer/test_group_d.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# ############################################################
|
||||||
|
# Importing - Same For All Render Layer Tests
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from view_layer_common import *
|
||||||
|
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
# Testing
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
class UnitTesting(ViewLayerTesting):
|
||||||
|
def test_group_write_load(self):
|
||||||
|
"""
|
||||||
|
See if saving/loading is working for groups
|
||||||
|
"""
|
||||||
|
import bpy
|
||||||
|
scene = bpy.context.scene
|
||||||
|
layer_collection = bpy.context.layer_collection
|
||||||
|
|
||||||
|
while len(scene.view_layers) > 1:
|
||||||
|
scene.view_layers.remove(scene.view_layers[1])
|
||||||
|
|
||||||
|
# create group
|
||||||
|
group = layer_collection.create_group()
|
||||||
|
|
||||||
|
self.assertEqual(1, len(bpy.data.groups))
|
||||||
|
self.assertEqual(1, bpy.data.groups[0].users)
|
||||||
|
self.assertEqual(3, len(bpy.data.groups[0].objects))
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
with tempfile.TemporaryDirectory() as dirpath:
|
||||||
|
filepath = os.path.join(dirpath, 'layers.blend')
|
||||||
|
|
||||||
|
for i in range(3):
|
||||||
|
# save and re-open file
|
||||||
|
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath)
|
||||||
|
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath)
|
||||||
|
|
||||||
|
self.assertEqual(1, len(bpy.data.groups))
|
||||||
|
self.assertEqual(1, bpy.data.groups[0].users)
|
||||||
|
self.assertEqual(3, len(bpy.data.groups[0].objects))
|
||||||
|
|
||||||
|
|
||||||
|
# empty the group of objects
|
||||||
|
group = bpy.data.groups[0]
|
||||||
|
while group.objects:
|
||||||
|
group.view_layer.collections[0].collection.objects.unlink(group.objects[0])
|
||||||
|
|
||||||
|
# save and re-open file
|
||||||
|
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath)
|
||||||
|
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath)
|
||||||
|
|
||||||
|
self.assertEqual(1, len(bpy.data.groups))
|
||||||
|
self.assertEqual(0, bpy.data.groups[0].users)
|
||||||
|
self.assertEqual(0, len(bpy.data.groups[0].objects))
|
||||||
|
|
||||||
|
# save and re-open file
|
||||||
|
bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=filepath)
|
||||||
|
bpy.ops.wm.open_mainfile('EXEC_DEFAULT', filepath=filepath)
|
||||||
|
|
||||||
|
self.assertEqual(0, len(bpy.data.groups))
|
||||||
|
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
# Main - Same For All Render Layer Tests
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
UnitTesting._extra_arguments = setup_extra_arguments(__file__)
|
||||||
|
unittest.main()
|
Reference in New Issue
Block a user