Newer
Older
# ##### BEGIN GPL LICENSE BLOCK #####
#
# 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 2
# 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, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# Copyright 2011, Ryan Inch
# For VARS
from . import internals
# For FUNCTIONS
mode_converter = {
'EDIT_MESH': 'EDIT',
'EDIT_CURVE': 'EDIT',
'EDIT_SURFACE': 'EDIT',
'EDIT_TEXT': 'EDIT',
'EDIT_ARMATURE': 'EDIT',
'EDIT_METABALL': 'EDIT',
'EDIT_LATTICE': 'EDIT',
'POSE': 'POSE',
'SCULPT': 'SCULPT',
'PAINT_WEIGHT': 'WEIGHT_PAINT',
'PAINT_VERTEX': 'VERTEX_PAINT',
'PAINT_TEXTURE': 'TEXTURE_PAINT',
'PARTICLE': 'PARTICLE_EDIT',
'OBJECT': 'OBJECT',
'PAINT_GPENCIL': 'PAINT_GPENCIL',
'EDIT_GPENCIL': 'EDIT_GPENCIL',
'SCULPT_GPENCIL': 'SCULPT_GPENCIL',
'WEIGHT_GPENCIL': 'WEIGHT_GPENCIL',
'VERTEX_GPENCIL': 'VERTEX_GPENCIL',
}
rto_path = {
"exclude": "exclude",
"select": "collection.hide_select",
"hide": "hide_viewport",
"disable": "collection.hide_viewport",
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
"render": "collection.hide_render",
"holdout": "holdout",
"indirect": "indirect_only",
}
set_off_on = {
"exclude": {
"off": True,
"on": False
},
"select": {
"off": True,
"on": False
},
"hide": {
"off": True,
"on": False
},
"disable": {
"off": True,
"on": False
},
"render": {
"off": True,
"on": False
},
"holdout": {
"off": False,
"on": True
},
"indirect": {
"off": False,
"on": True
}
}
get_off_on = {
False: {
"exclude": "on",
"select": "on",
"hide": "on",
"disable": "on",
"render": "on",
"holdout": "off",
"indirect": "off",
},
True: {
"exclude": "off",
"select": "off",
"hide": "off",
"disable": "off",
"render": "off",
"holdout": "on",
"indirect": "on",
}
}
def get_rto(layer_collection, rto):
if rto in ["exclude", "hide", "holdout", "indirect"]:
return getattr(layer_collection, rto_path[rto])
else:
collection = getattr(layer_collection, "collection")
return getattr(collection, rto_path[rto].split(".")[1])
def set_rto(layer_collection, rto, value):
if rto in ["exclude", "hide", "holdout", "indirect"]:
setattr(layer_collection, rto_path[rto], value)
else:
collection = getattr(layer_collection, "collection")
setattr(collection, rto_path[rto].split(".")[1], value)
def apply_to_children(parent, apply_function):
# works for both Collections & LayerCollections
child_lists = [parent.children]
while child_lists:
new_child_lists = []
for child_list in child_lists:
for child in child_list:
apply_function(child)
if child.children:
new_child_lists.append(child.children)
child_lists = new_child_lists
def isolate_rto(cls, self, view_layer, rto, *, children=False):
off = set_off_on[rto]["off"]
on = set_off_on[rto]["on"]
laycol_ptr = internals.layer_collections[self.name]["ptr"]
target = internals.rto_history[rto][view_layer]["target"]
history = internals.rto_history[rto][view_layer]["history"]
active_layer_collections = [x["ptr"] for x in internals.layer_collections.values()
if get_rto(x["ptr"], rto) == on]
# check if previous state should be restored
if cls.isolated and self.name == target:
# restore previous state
for x, item in enumerate(internals.layer_collections.values()):
set_rto(item["ptr"], rto, history[x])
# reset target and history
del internals.rto_history[rto][view_layer]
cls.isolated = False
# check if all RTOs should be activated
elif (len(active_layer_collections) == 1 and
active_layer_collections[0].name == self.name):
# activate all collections
for item in internals.layer_collections.values():
set_rto(item["ptr"], rto, on)
del internals.rto_history[rto][view_layer]
cls.isolated = False
else:
# isolate collection
internals.rto_history[rto][view_layer]["target"] = self.name
# reset history
history.clear()
# save state
for item in internals.layer_collections.values():
history.append(get_rto(item["ptr"], rto))
child_states = {}
if children:
# get child states
def get_child_states(layer_collection):
child_states[layer_collection.name] = get_rto(layer_collection, rto)
apply_to_children(laycol_ptr, get_child_states)
# isolate collection
for item in internals.layer_collections.values():
if item["name"] != laycol_ptr.name:
set_rto(item["ptr"], rto, off)
set_rto(laycol_ptr, rto, on)
if rto not in ["exclude", "holdout", "indirect"]:
laycol = internals.layer_collections[self.name]
set_rto(laycol["ptr"], rto, on)
laycol = laycol["parent"]
if children:
# restore child states
def restore_child_states(layer_collection):
set_rto(layer_collection, rto, child_states[layer_collection.name])
apply_to_children(laycol_ptr, restore_child_states)
else:
if children:
# restore child states
def restore_child_states(layer_collection):
set_rto(layer_collection, rto, child_states[layer_collection.name])
apply_to_children(laycol_ptr, restore_child_states)
elif rto == "exclude":
# deactivate all children
def deactivate_all_children(layer_collection):
set_rto(layer_collection, rto, True)
apply_to_children(laycol_ptr, deactivate_all_children)
cls.isolated = True
def toggle_children(self, view_layer, rto):
laycol_ptr = internals.layer_collections[self.name]["ptr"]
# clear rto history
del internals.rto_history[rto][view_layer]
internals.rto_history[rto+"_all"].pop(view_layer, None)
# toggle rto state
state = not get_rto(laycol_ptr, rto)
set_rto(laycol_ptr, rto, state)
def set_state(layer_collection):
set_rto(layer_collection, rto, state)
apply_to_children(laycol_ptr, set_state)
def activate_all_rtos(view_layer, rto):
off = set_off_on[rto]["off"]
on = set_off_on[rto]["on"]
history = internals.rto_history[rto+"_all"][view_layer]
# if not activated, activate all
if len(history) == 0:
keep_history = False
for item in reversed(list(internals.layer_collections.values())):
if get_rto(item["ptr"], rto) == off:
keep_history = True
history.append(get_rto(item["ptr"], rto))
set_rto(item["ptr"], rto, on)
if not keep_history:
history.clear()
history.reverse()
else:
for x, item in enumerate(internals.layer_collections.values()):
set_rto(item["ptr"], rto, history[x])
# clear rto history
del internals.rto_history[rto+"_all"][view_layer]
def invert_rtos(view_layer, rto):
if rto == "exclude":
orig_values = []
for item in internals.layer_collections.values():
orig_values.append(get_rto(item["ptr"], rto))
for x, item in enumerate(internals.layer_collections.values()):
set_rto(item["ptr"], rto, not orig_values[x])
else:
for item in internals.layer_collections.values():
set_rto(item["ptr"], rto, not get_rto(item["ptr"], rto))
# clear rto history
internals.rto_history[rto].pop(view_layer, None)
def copy_rtos(view_layer, rto):
if not internals.copy_buffer["RTO"]:
internals.copy_buffer["RTO"] = rto
for laycol in internals.layer_collections.values():
internals.copy_buffer["values"].append(get_off_on[
get_rto(laycol["ptr"], rto)
][
rto
]
)
for x, laycol in enumerate(internals.layer_collections.values()):
set_rto(laycol["ptr"],
rto,
set_off_on[rto][
internals.copy_buffer["values"][x]
# clear rto history
internals.rto_history[rto].pop(view_layer, None)
del internals.rto_history[rto+"_all"][view_layer]
internals.copy_buffer["RTO"] = ""
internals.copy_buffer["values"].clear()
def swap_rtos(view_layer, rto):
if not internals.swap_buffer["A"]["values"]:
internals.swap_buffer["A"]["RTO"] = rto
for laycol in internals.layer_collections.values():
internals.swap_buffer["A"]["values"].append(get_off_on[
get_rto(laycol["ptr"], rto)
][
rto
]
)
internals.swap_buffer["B"]["RTO"] = rto
for laycol in internals.layer_collections.values():
internals.swap_buffer["B"]["values"].append(get_off_on[
get_rto(laycol["ptr"], rto)
][
rto
]
)
for x, laycol in enumerate(internals.layer_collections.values()):
set_rto(laycol["ptr"], internals.swap_buffer["A"]["RTO"],
internals.swap_buffer["A"]["RTO"]
internals.swap_buffer["B"]["values"][x]
set_rto(laycol["ptr"], internals.swap_buffer["B"]["RTO"],
internals.swap_buffer["B"]["RTO"]
internals.swap_buffer["A"]["values"][x]
# clear rto history
swap_a = internals.swap_buffer["A"]["RTO"]
swap_b = internals.swap_buffer["B"]["RTO"]
internals.rto_history[swap_a].pop(view_layer, None)
internals.rto_history[swap_a+"_all"].pop(view_layer, None)
internals.rto_history[swap_b].pop(view_layer, None)
internals.rto_history[swap_b+"_all"].pop(view_layer, None)
internals.swap_buffer["A"]["RTO"] = ""
internals.swap_buffer["A"]["values"].clear()
internals.swap_buffer["B"]["RTO"] = ""
internals.swap_buffer["B"]["values"].clear()
if internals.copy_buffer["RTO"] == rto:
internals.copy_buffer["RTO"] = ""
internals.copy_buffer["values"].clear()
if internals.swap_buffer["A"]["RTO"] == rto:
internals.swap_buffer["A"]["RTO"] = ""
internals.swap_buffer["A"]["values"].clear()
internals.swap_buffer["B"]["RTO"] = ""
internals.swap_buffer["B"]["values"].clear()
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
def link_child_collections_to_parent(laycol, collection, parent_collection):
# store view layer RTOs for all children of the to be deleted collection
child_states = {}
def get_child_states(layer_collection):
child_states[layer_collection.name] = (layer_collection.exclude,
layer_collection.hide_viewport,
layer_collection.holdout,
layer_collection.indirect_only)
apply_to_children(laycol["ptr"], get_child_states)
# link any subcollections of the to be deleted collection to it's parent
for subcollection in collection.children:
if not subcollection.name in parent_collection.children:
parent_collection.children.link(subcollection)
# apply the stored view layer RTOs to the newly linked collections and their
# children
def restore_child_states(layer_collection):
state = child_states.get(layer_collection.name)
if state:
layer_collection.exclude = state[0]
layer_collection.hide_viewport = state[1]
layer_collection.holdout = state[2]
layer_collection.indirect_only = state[3]
apply_to_children(laycol["parent"]["ptr"], restore_child_states)
def remove_collection(laycol, collection, context):
# get selected row
cm = context.scene.collection_manager
selected_row_name = cm.cm_list_collection[cm.cm_list_index].name
# delete collection
bpy.data.collections.remove(collection)
# update references
internals.expanded.discard(laycol["name"])
if internals.expand_history["target"] == laycol["name"]:
internals.expand_history["target"] = ""
if laycol["name"] in internals.expand_history["history"]:
internals.expand_history["history"].remove(laycol["name"])
if internals.qcd_slots.contains(name=laycol["name"]):
internals.qcd_slots.del_slot(name=laycol["name"])
if laycol["name"] in internals.qcd_slots.overrides:
internals.qcd_slots.overrides.remove(laycol["name"])
for rto in internals.rto_history.values():
rto.clear()
# update tree view
update_property_group(context)
# update selected row
laycol = internals.layer_collections.get(selected_row_name, None)
if laycol:
cm.cm_list_index = laycol["row_index"]
elif len(cm.cm_list_collection) <= cm.cm_list_index:
cm.cm_list_index = len(cm.cm_list_collection) - 1
if cm.cm_list_index > -1:
name = cm.cm_list_collection[cm.cm_list_index].name
laycol = internals.layer_collections[name]
while not laycol["visible"]:
laycol = laycol["parent"]
cm.cm_list_index = laycol["row_index"]
def select_collection_objects(is_master_collection, collection_name, replace, nested, selection_state=None):
if bpy.context.mode != 'OBJECT':
return
target_collection = bpy.context.view_layer.layer_collection.collection
else:
laycol = internals.layer_collections[collection_name]
target_collection = laycol["ptr"].collection
if replace:
bpy.ops.object.select_all(action='DESELECT')
if selection_state == None:
selection_state = get_move_selection().isdisjoint(target_collection.objects)
def select_objects(collection):
for obj in collection.objects:
try:
obj.select_set(selection_state)
except RuntimeError:
pass
select_objects(target_collection)
if nested:
apply_to_children(target_collection, select_objects)
def set_exclude_state(target_layer_collection, state):
# get current child exclusion state
child_exclusion = []
def get_child_exclusion(layer_collection):
child_exclusion.append([layer_collection, layer_collection.exclude])
apply_to_children(target_layer_collection, get_child_exclusion)
# set exclusion
target_layer_collection.exclude = state
# set correct state for all children
for laycol in child_exclusion:
laycol[0].exclude = laycol[1]