-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcollectionz.py
149 lines (120 loc) · 6.45 KB
/
collectionz.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# ##### BEGIN GPL LICENSE BLOCK #####
#
# Part of the "toolbox" repository
# Copyright (C) 2022 Cardboy0 (https://twitter.com/cardboy0)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
# for dealing with collections in general (but not viewlayer collections)
#
# You may ask yourself "why name it 'collectionz.py' with a z?"
# Because due to some very weird reasons, calling it 'collections.py' results in my VS code
# not being able to format code anymore, INCLUDING other files. It just disables it, I don't know why.
def link_object_to_collections(obj, collections, keep_links=False):
"""Links an object into one or multiple collections. By default also unlinks the obj from any other collections it's already in.
Parameters
----------
obj : bpy.types.Object
Object to link
collections : bpy.types.Collection or list
Collection(s) to link into. Know that the main collection of a scene is kinda special and located at Scene.collection
keep_links : bool
If True, the function will not unlink the obj from any collections it's already in.
"""
if isinstance(collections, list) == False:
collections = [collections]
# careful: Unlinking an object from all collections of the current scene makes it "disappear" and inactive.
# As such it's best to always have it linked to at least one collection in the current scene.
if keep_links == False:
collections_to_delete = list(obj.users_collection)
# link
for coll in collections:
if coll.objects.find(obj.name) == -1:
coll.objects.link(obj)
else:
# trying to link an object to a collection it's already linked to gives an error.
continue
if keep_links == False:
# unlink
# using the 'in' operator with a set is magnitudes faster than with a list.
collections = set(collections)
for coll in collections_to_delete:
if coll not in collections:
coll.objects.unlink(obj)
def link_collection_to_collections(coll, collections, keep_links=False):
""" "Clean" linking of a collection into one or multiple other collections, i.e. unlinking it from any other collections at the same time.
Parameters
----------
coll : bpy.types.Collection
Collection you want to link
collections : bpy.types.Collection or list
Collection(s) to link into. Know that the main collection of a scene is kinda special and located at Scene.collection
keep_links : bool
If True, the function will not unlink the collection from any collections it's already in.
"""
# Same as with linkObjectToCollections(), we should make sure that the collection never gets completely unlinked from its current scene (if it was linked in the first place).
if isinstance(collections, list) == False:
collections = set([collections])
else:
collections = set(collections)
if keep_links == False:
# Unlike objects, collections don't have a .users_collection property. This means we will have to do some searching.
# important: D.collections doesn't have ALL the collections, the master collections of each scene are not included and thus must be added manually
all_collections = set(bpy.data.collections)
for scene in bpy.data.scenes:
# adding the master collections
all_collections.add(scene.collection)
# search for parent collections so we can unlink them later
# this is a simple number, not a list or something similar
remaining_number_of_users = coll.users
delete_collections = []
for test_collection in all_collections:
if remaining_number_of_users == 0:
break # if we know that our collection has 3 users, we only need to search through all collections until we got 3 matches
if test_collection.children.find(coll.name) != -1:
remaining_number_of_users -= 1
delete_collections.append(test_collection)
for link_collection in collections:
# if it's already linked to this collection an error would appear
if link_collection.children.find(coll.name) == -1:
link_collection.children.link(coll)
if keep_links == False:
# using the 'in' operator with a set is magnitudes faster than with a list.
for parent in delete_collections:
if parent not in collections:
parent.children.unlink(coll)
def create_collection(context, name, parent_collection="MASTER", avoid_duplicates=False):
"""Create a new collection inside a specific parent collection.
Know that same as with objects, no two collections can have the same name and as such your chosen name may not be the actual one of this new collection.
Parameters
----------
name : str
The name of the collection to create
parent_collection : bpy.types.Collection or "MASTER", optional
The collection in which you want to create the new collection., by default "MASTER" (uses the main collection of the current scene).
avoid_duplicates : bool, optional
If True and a collection with the EXACT same name already exists in the parent collection, no new collection will be created. Does NOT check in any other collections., by default False
Returns
-------
bpy.types.Collection
The newly created collection (or if avoidDuplicates==True and an already existing collection was found, this collection)
"""
if parent_collection == "MASTER":
parent_collection = context.scene.collection
if avoid_duplicates == True:
index = parent_collection.children.find(name)
if index != -1:
return parent_collection.children[index]
new_collection = bpy.data.collections.new(name=name)
parent_collection.children.link(new_collection)
return new_collection