mirror of
https://github.com/blender/blender-addons.git
synced 2025-07-25 16:05:20 +00:00
1502 lines
48 KiB
Python
1502 lines
48 KiB
Python
# ##### 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
|
|
|
|
import bpy
|
|
|
|
from copy import deepcopy
|
|
|
|
from bpy.types import (
|
|
Operator,
|
|
)
|
|
|
|
from bpy.props import (
|
|
BoolProperty,
|
|
StringProperty,
|
|
IntProperty
|
|
)
|
|
|
|
# For VARS
|
|
from . import internals
|
|
|
|
# For FUNCTIONS
|
|
from .internals import (
|
|
update_property_group,
|
|
get_modifiers,
|
|
get_move_selection,
|
|
get_move_active,
|
|
update_qcd_header,
|
|
send_report,
|
|
)
|
|
|
|
from .operator_utils import (
|
|
apply_to_children,
|
|
isolate_rto,
|
|
toggle_children,
|
|
activate_all_rtos,
|
|
invert_rtos,
|
|
copy_rtos,
|
|
swap_rtos,
|
|
clear_copy,
|
|
clear_swap,
|
|
link_child_collections_to_parent,
|
|
remove_collection,
|
|
select_collection_objects,
|
|
set_exclude_state,
|
|
isolate_sel_objs_collections,
|
|
disable_sel_objs_collections,
|
|
)
|
|
|
|
from . import ui
|
|
|
|
class SetActiveCollection(Operator):
|
|
'''Set the active collection'''
|
|
bl_label = "Set Active Collection"
|
|
bl_idname = "view3d.set_active_collection"
|
|
bl_options = {'UNDO'}
|
|
|
|
is_master_collection: BoolProperty()
|
|
collection_name: StringProperty()
|
|
|
|
def execute(self, context):
|
|
if self.is_master_collection:
|
|
layer_collection = context.view_layer.layer_collection
|
|
|
|
else:
|
|
laycol = internals.layer_collections[self.collection_name]
|
|
layer_collection = laycol["ptr"]
|
|
|
|
# set selection to this row
|
|
cm = context.scene.collection_manager
|
|
cm.cm_list_index = laycol["row_index"]
|
|
|
|
context.view_layer.active_layer_collection = layer_collection
|
|
|
|
if context.view_layer.active_layer_collection != layer_collection:
|
|
self.report({'WARNING'}, "Can't set excluded collection as active")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class ExpandAllOperator(Operator):
|
|
'''Expand/Collapse all collections'''
|
|
bl_label = "Expand All Items"
|
|
bl_idname = "view3d.expand_all_items"
|
|
|
|
def execute(self, context):
|
|
if len(internals.expanded) > 0:
|
|
internals.expanded.clear()
|
|
context.scene.collection_manager.cm_list_index = 0
|
|
else:
|
|
for laycol in internals.layer_collections.values():
|
|
if laycol["ptr"].children:
|
|
internals.expanded.add(laycol["name"])
|
|
|
|
# clear expand history
|
|
internals.expand_history["target"] = ""
|
|
internals.expand_history["history"].clear()
|
|
|
|
# update tree view
|
|
update_property_group(context)
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class ExpandSublevelOperator(Operator):
|
|
bl_label = "Expand Sublevel Items"
|
|
bl_description = (
|
|
" * Ctrl+LMB - Expand/Collapse all sublevels\n"
|
|
" * Shift+LMB - Isolate tree/Restore\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.expand_sublevel"
|
|
|
|
expand: BoolProperty()
|
|
name: StringProperty()
|
|
index: IntProperty()
|
|
|
|
def invoke(self, context, event):
|
|
cls = ExpandSublevelOperator
|
|
|
|
modifiers = get_modifiers(event)
|
|
|
|
if modifiers == {"alt"}:
|
|
internals.expand_history["target"] = ""
|
|
internals.expand_history["history"].clear()
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
# expand/collapse all subcollections
|
|
expand = None
|
|
|
|
# check whether to expand or collapse
|
|
if self.name in internals.expanded:
|
|
internals.expanded.remove(self.name)
|
|
expand = False
|
|
else:
|
|
internals.expanded.add(self.name)
|
|
expand = True
|
|
|
|
# do expanding/collapsing
|
|
def set_expanded(layer_collection):
|
|
if expand:
|
|
internals.expanded.add(layer_collection.name)
|
|
else:
|
|
internals.expanded.discard(layer_collection.name)
|
|
|
|
apply_to_children(internals.layer_collections[self.name]["ptr"], set_expanded)
|
|
|
|
internals.expand_history["target"] = ""
|
|
internals.expand_history["history"].clear()
|
|
|
|
elif modifiers == {"shift"}:
|
|
def isolate_tree(current_laycol):
|
|
parent = current_laycol["parent"]
|
|
|
|
for laycol in parent["children"]:
|
|
if (laycol["name"] != current_laycol["name"]
|
|
and laycol["name"] in internals.expanded):
|
|
internals.expanded.remove(laycol["name"])
|
|
internals.expand_history["history"].append(laycol["name"])
|
|
|
|
if parent["parent"]:
|
|
isolate_tree(parent)
|
|
|
|
if self.name == internals.expand_history["target"]:
|
|
for item in internals.expand_history["history"]:
|
|
internals.expanded.add(item)
|
|
|
|
internals.expand_history["target"] = ""
|
|
internals.expand_history["history"].clear()
|
|
|
|
else:
|
|
internals.expand_history["target"] = ""
|
|
internals.expand_history["history"].clear()
|
|
|
|
isolate_tree(internals.layer_collections[self.name])
|
|
internals.expand_history["target"] = self.name
|
|
|
|
else:
|
|
# expand/collapse collection
|
|
if self.expand:
|
|
internals.expanded.add(self.name)
|
|
else:
|
|
internals.expanded.remove(self.name)
|
|
|
|
internals.expand_history["target"] = ""
|
|
internals.expand_history["history"].clear()
|
|
|
|
# set the selected row to the collection you're expanding/collapsing to
|
|
# preserve the tree view's scrolling
|
|
context.scene.collection_manager.cm_list_index = self.index
|
|
|
|
#update tree view
|
|
update_property_group(context)
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMSelectCollectionObjectsOperator(Operator):
|
|
bl_label = "Select All Objects in the Collection"
|
|
bl_description = (
|
|
" * LMB - Select all objects in collection.\n"
|
|
" * Shift+LMB - Add/Remove collection objects from selection.\n"
|
|
" * Ctrl+LMB - Isolate nested selection.\n"
|
|
" * Ctrl+Shift+LMB - Add/Remove nested from selection"
|
|
)
|
|
bl_idname = "view3d.select_collection_objects"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
is_master_collection: BoolProperty()
|
|
collection_name: StringProperty()
|
|
|
|
def invoke(self, context, event):
|
|
modifiers = get_modifiers(event)
|
|
|
|
if modifiers == {"shift"}:
|
|
select_collection_objects(
|
|
is_master_collection=self.is_master_collection,
|
|
collection_name=self.collection_name,
|
|
replace=False,
|
|
nested=False
|
|
)
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
select_collection_objects(
|
|
is_master_collection=self.is_master_collection,
|
|
collection_name=self.collection_name,
|
|
replace=True,
|
|
nested=True
|
|
)
|
|
|
|
elif modifiers == {"ctrl", "shift"}:
|
|
select_collection_objects(
|
|
is_master_collection=self.is_master_collection,
|
|
collection_name=self.collection_name,
|
|
replace=False,
|
|
nested=True
|
|
)
|
|
|
|
else:
|
|
select_collection_objects(
|
|
is_master_collection=self.is_master_collection,
|
|
collection_name=self.collection_name,
|
|
replace=True,
|
|
nested=False
|
|
)
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMSetCollectionOperator(Operator):
|
|
bl_label = "Set Object Collection"
|
|
bl_description = (
|
|
" * LMB - Move object to collection.\n"
|
|
" * Shift+LMB - Add/Remove object from collection"
|
|
)
|
|
bl_idname = "view3d.set_collection"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
is_master_collection: BoolProperty()
|
|
collection_name: StringProperty()
|
|
|
|
def invoke(self, context, event):
|
|
if self.is_master_collection:
|
|
target_collection = context.view_layer.layer_collection.collection
|
|
|
|
else:
|
|
laycol = internals.layer_collections[self.collection_name]
|
|
target_collection = laycol["ptr"].collection
|
|
|
|
selected_objects = get_move_selection()
|
|
active_object = get_move_active()
|
|
|
|
internals.move_triggered = True
|
|
|
|
if not selected_objects:
|
|
return {'CANCELLED'}
|
|
|
|
if event.shift:
|
|
# add objects to collection
|
|
|
|
# make sure there is an active object
|
|
if not active_object:
|
|
active_object = tuple(selected_objects)[0]
|
|
|
|
# check if in collection
|
|
if not active_object.name in target_collection.objects:
|
|
# add to collection
|
|
for obj in selected_objects:
|
|
if obj.name not in target_collection.objects:
|
|
target_collection.objects.link(obj)
|
|
|
|
else:
|
|
warnings = False
|
|
master_warning = False
|
|
|
|
# remove from collections
|
|
for obj in selected_objects:
|
|
if obj.name in target_collection.objects:
|
|
|
|
# disallow removing if only one
|
|
if len(obj.users_collection) == 1:
|
|
warnings = True
|
|
master_laycol = context.view_layer.layer_collection
|
|
master_collection = master_laycol.collection
|
|
|
|
if obj.name not in master_collection.objects:
|
|
master_collection.objects.link(obj)
|
|
|
|
else:
|
|
master_warning = True
|
|
continue
|
|
|
|
|
|
# remove from collection
|
|
target_collection.objects.unlink(obj)
|
|
|
|
if warnings:
|
|
if master_warning:
|
|
send_report(
|
|
"Error removing 1 or more objects from the Scene Collection.\n"
|
|
"Objects would be left without a collection."
|
|
)
|
|
self.report({"WARNING"},
|
|
"Error removing 1 or more objects from the Scene Collection."
|
|
" Objects would be left without a collection."
|
|
)
|
|
|
|
else:
|
|
self.report({"INFO"}, "1 or more objects moved to Scene Collection.")
|
|
|
|
|
|
else:
|
|
# move objects to collection
|
|
for obj in selected_objects:
|
|
if obj.name not in target_collection.objects:
|
|
target_collection.objects.link(obj)
|
|
|
|
# remove from all other collections
|
|
for collection in obj.users_collection:
|
|
if collection != target_collection:
|
|
collection.objects.unlink(obj)
|
|
|
|
# update the active object if needed
|
|
if not context.active_object:
|
|
try:
|
|
context.view_layer.objects.active = active_object
|
|
|
|
except RuntimeError: # object not in visible collection
|
|
pass
|
|
|
|
# update qcd header UI
|
|
update_qcd_header()
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMExcludeOperator(Operator):
|
|
bl_label = "[EC] Exclude from View Layer"
|
|
bl_description = (
|
|
" * Shift+LMB - Isolate/Restore.\n"
|
|
" * Shift+Ctrl+LMB - Isolate nested/Restore.\n"
|
|
" * Ctrl+LMB - Toggle nested.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.exclude_collection"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
name: StringProperty()
|
|
|
|
# static class var
|
|
isolated = False
|
|
|
|
def invoke(self, context, event):
|
|
cls = CMExcludeOperator
|
|
|
|
modifiers = get_modifiers(event)
|
|
view_layer = context.view_layer.name
|
|
orig_active_collection = context.view_layer.active_layer_collection
|
|
orig_active_object = context.view_layer.objects.active
|
|
laycol_ptr = internals.layer_collections[self.name]["ptr"]
|
|
|
|
if not view_layer in internals.rto_history["exclude"]:
|
|
internals.rto_history["exclude"][view_layer] = {"target": "", "history": []}
|
|
|
|
if modifiers == {"alt"}:
|
|
del internals.rto_history["exclude"][view_layer]
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"shift"}:
|
|
isolate_rto(cls, self, view_layer, "exclude")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
toggle_children(self, view_layer, "exclude")
|
|
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"ctrl", "shift"}:
|
|
isolate_rto(cls, self, view_layer, "exclude", children=True)
|
|
|
|
else:
|
|
# toggle exclusion
|
|
|
|
# reset exclude history
|
|
del internals.rto_history["exclude"][view_layer]
|
|
|
|
set_exclude_state(laycol_ptr, not laycol_ptr.exclude)
|
|
|
|
cls.isolated = False
|
|
|
|
# restore active collection
|
|
context.view_layer.active_layer_collection = orig_active_collection
|
|
|
|
# restore active object if possible
|
|
if orig_active_object:
|
|
if orig_active_object.name in context.view_layer.objects:
|
|
context.view_layer.objects.active = orig_active_object
|
|
|
|
# reset exclude all history
|
|
if view_layer in internals.rto_history["exclude_all"]:
|
|
del internals.rto_history["exclude_all"][view_layer]
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMUnExcludeAllOperator(Operator):
|
|
bl_label = "[EC Global] Exclude from View Layer"
|
|
bl_description = (
|
|
" * LMB - Enable all/Restore.\n"
|
|
" * Shift+LMB - Invert.\n"
|
|
" * Shift+Ctrl+LMB - Isolate collections w/ selected objects.\n"
|
|
" * Shift+Alt+LMB - Disable collections w/ selected objects.\n"
|
|
" * Ctrl+LMB - Copy/Paste RTOs.\n"
|
|
" * Ctrl+Alt+LMB - Swap RTOs.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.un_exclude_all_collections"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def invoke(self, context, event):
|
|
orig_active_collection = context.view_layer.active_layer_collection
|
|
orig_active_object = context.view_layer.objects.active
|
|
view_layer = context.view_layer.name
|
|
modifiers = get_modifiers(event)
|
|
|
|
if not view_layer in internals.rto_history["exclude_all"]:
|
|
internals.rto_history["exclude_all"][view_layer] = []
|
|
|
|
if modifiers == {"alt"}:
|
|
# clear all states
|
|
del internals.rto_history["exclude_all"][view_layer]
|
|
clear_copy("exclude")
|
|
clear_swap("exclude")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
copy_rtos(view_layer, "exclude")
|
|
|
|
elif modifiers == {"ctrl", "alt"}:
|
|
swap_rtos(view_layer, "exclude")
|
|
|
|
elif modifiers == {"shift"}:
|
|
invert_rtos(view_layer, "exclude")
|
|
|
|
elif modifiers == {"shift", "ctrl"}:
|
|
error = isolate_sel_objs_collections(view_layer, "exclude", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
elif modifiers == {"shift", "alt"}:
|
|
error = disable_sel_objs_collections(view_layer, "exclude", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
else:
|
|
activate_all_rtos(view_layer, "exclude")
|
|
|
|
# restore active collection
|
|
context.view_layer.active_layer_collection = orig_active_collection
|
|
|
|
# restore active object if possible
|
|
if orig_active_object:
|
|
if orig_active_object.name in context.view_layer.objects:
|
|
context.view_layer.objects.active = orig_active_object
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMRestrictSelectOperator(Operator):
|
|
bl_label = "[SS] Disable Selection"
|
|
bl_description = (
|
|
" * Shift+LMB - Isolate/Restore.\n"
|
|
" * Shift+Ctrl+LMB - Isolate nested/Restore.\n"
|
|
" * Ctrl+LMB - Toggle nested.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.restrict_select_collection"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
name: StringProperty()
|
|
|
|
# static class var
|
|
isolated = False
|
|
|
|
def invoke(self, context, event):
|
|
cls = CMRestrictSelectOperator
|
|
|
|
modifiers = get_modifiers(event)
|
|
view_layer = context.view_layer.name
|
|
laycol_ptr = internals.layer_collections[self.name]["ptr"]
|
|
|
|
if not view_layer in internals.rto_history["select"]:
|
|
internals.rto_history["select"][view_layer] = {"target": "", "history": []}
|
|
|
|
if modifiers == {"alt"}:
|
|
del internals.rto_history["select"][view_layer]
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"shift"}:
|
|
isolate_rto(cls, self, view_layer, "select")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
toggle_children(self, view_layer, "select")
|
|
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"ctrl", "shift"}:
|
|
isolate_rto(cls, self, view_layer, "select", children=True)
|
|
|
|
else:
|
|
# toggle selectable
|
|
|
|
# reset select history
|
|
del internals.rto_history["select"][view_layer]
|
|
|
|
# toggle selectability of collection
|
|
laycol_ptr.collection.hide_select = not laycol_ptr.collection.hide_select
|
|
|
|
cls.isolated = False
|
|
|
|
# reset select all history
|
|
if view_layer in internals.rto_history["select_all"]:
|
|
del internals.rto_history["select_all"][view_layer]
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMUnRestrictSelectAllOperator(Operator):
|
|
bl_label = "[SS Global] Disable Selection"
|
|
bl_description = (
|
|
" * LMB - Enable all/Restore.\n"
|
|
" * Shift+LMB - Invert.\n"
|
|
" * Shift+Ctrl+LMB - Isolate collections w/ selected objects.\n"
|
|
" * Shift+Alt+LMB - Disable collections w/ selected objects.\n"
|
|
" * Ctrl+LMB - Copy/Paste RTOs.\n"
|
|
" * Ctrl+Alt+LMB - Swap RTOs.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.un_restrict_select_all_collections"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def invoke(self, context, event):
|
|
view_layer = context.view_layer.name
|
|
modifiers = get_modifiers(event)
|
|
|
|
if not view_layer in internals.rto_history["select_all"]:
|
|
internals.rto_history["select_all"][view_layer] = []
|
|
|
|
if modifiers == {"alt"}:
|
|
# clear all states
|
|
del internals.rto_history["select_all"][view_layer]
|
|
clear_copy("select")
|
|
clear_swap("select")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
copy_rtos(view_layer, "select")
|
|
|
|
elif modifiers == {"ctrl", "alt"}:
|
|
swap_rtos(view_layer, "select")
|
|
|
|
elif modifiers == {"shift"}:
|
|
invert_rtos(view_layer, "select")
|
|
|
|
elif modifiers == {"shift", "ctrl"}:
|
|
error = isolate_sel_objs_collections(view_layer, "select", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
elif modifiers == {"shift", "alt"}:
|
|
error = disable_sel_objs_collections(view_layer, "select", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
else:
|
|
activate_all_rtos(view_layer, "select")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMHideOperator(Operator):
|
|
bl_label = "[VV] Hide in Viewport"
|
|
bl_description = (
|
|
" * Shift+LMB - Isolate/Restore.\n"
|
|
" * Shift+Ctrl+LMB - Isolate nested/Restore.\n"
|
|
" * Ctrl+LMB - Toggle nested.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.hide_collection"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
name: StringProperty()
|
|
|
|
# static class var
|
|
isolated = False
|
|
|
|
def invoke(self, context, event):
|
|
cls = CMHideOperator
|
|
|
|
modifiers = get_modifiers(event)
|
|
view_layer = context.view_layer.name
|
|
laycol_ptr = internals.layer_collections[self.name]["ptr"]
|
|
|
|
if not view_layer in internals.rto_history["hide"]:
|
|
internals.rto_history["hide"][view_layer] = {"target": "", "history": []}
|
|
|
|
if modifiers == {"alt"}:
|
|
del internals.rto_history["hide"][view_layer]
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"shift"}:
|
|
isolate_rto(cls, self, view_layer, "hide")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
toggle_children(self, view_layer, "hide")
|
|
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"ctrl", "shift"}:
|
|
isolate_rto(cls, self, view_layer, "hide", children=True)
|
|
|
|
else:
|
|
# toggle visible
|
|
|
|
# reset hide history
|
|
del internals.rto_history["hide"][view_layer]
|
|
|
|
# toggle view of collection
|
|
laycol_ptr.hide_viewport = not laycol_ptr.hide_viewport
|
|
|
|
cls.isolated = False
|
|
|
|
# reset hide all history
|
|
if view_layer in internals.rto_history["hide_all"]:
|
|
del internals.rto_history["hide_all"][view_layer]
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMUnHideAllOperator(Operator):
|
|
bl_label = "[VV Global] Hide in Viewport"
|
|
bl_description = (
|
|
" * LMB - Enable all/Restore.\n"
|
|
" * Shift+LMB - Invert.\n"
|
|
" * Shift+Ctrl+LMB - Isolate collections w/ selected objects.\n"
|
|
" * Shift+Alt+LMB - Disable collections w/ selected objects.\n"
|
|
" * Ctrl+LMB - Copy/Paste RTOs.\n"
|
|
" * Ctrl+Alt+LMB - Swap RTOs.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.un_hide_all_collections"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def invoke(self, context, event):
|
|
view_layer = context.view_layer.name
|
|
modifiers = get_modifiers(event)
|
|
|
|
if not view_layer in internals.rto_history["hide_all"]:
|
|
internals.rto_history["hide_all"][view_layer] = []
|
|
|
|
if modifiers == {"alt"}:
|
|
# clear all states
|
|
del internals.rto_history["hide_all"][view_layer]
|
|
clear_copy("hide")
|
|
clear_swap("hide")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
copy_rtos(view_layer, "hide")
|
|
|
|
elif modifiers == {"ctrl", "alt"}:
|
|
swap_rtos(view_layer, "hide")
|
|
|
|
elif modifiers == {"shift"}:
|
|
invert_rtos(view_layer, "hide")
|
|
|
|
elif modifiers == {"shift", "ctrl"}:
|
|
error = isolate_sel_objs_collections(view_layer, "hide", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
elif modifiers == {"shift", "alt"}:
|
|
error = disable_sel_objs_collections(view_layer, "hide", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
else:
|
|
activate_all_rtos(view_layer, "hide")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMDisableViewportOperator(Operator):
|
|
bl_label = "[DV] Disable in Viewports"
|
|
bl_description = (
|
|
" * Shift+LMB - Isolate/Restore.\n"
|
|
" * Shift+Ctrl+LMB - Isolate nested/Restore.\n"
|
|
" * Ctrl+LMB - Toggle nested.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.disable_viewport_collection"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
name: StringProperty()
|
|
|
|
# static class var
|
|
isolated = False
|
|
|
|
def invoke(self, context, event):
|
|
cls = CMDisableViewportOperator
|
|
|
|
modifiers = get_modifiers(event)
|
|
view_layer = context.view_layer.name
|
|
laycol_ptr = internals.layer_collections[self.name]["ptr"]
|
|
|
|
if not view_layer in internals.rto_history["disable"]:
|
|
internals.rto_history["disable"][view_layer] = {"target": "", "history": []}
|
|
|
|
if modifiers == {"alt"}:
|
|
del internals.rto_history["disable"][view_layer]
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"shift"}:
|
|
isolate_rto(cls, self, view_layer, "disable")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
toggle_children(self, view_layer, "disable")
|
|
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"ctrl", "shift"}:
|
|
isolate_rto(cls, self, view_layer, "disable", children=True)
|
|
|
|
else:
|
|
# toggle disable
|
|
|
|
# reset disable history
|
|
del internals.rto_history["disable"][view_layer]
|
|
|
|
# toggle disable of collection in viewport
|
|
laycol_ptr.collection.hide_viewport = not laycol_ptr.collection.hide_viewport
|
|
|
|
cls.isolated = False
|
|
|
|
# reset disable all history
|
|
if view_layer in internals.rto_history["disable_all"]:
|
|
del internals.rto_history["disable_all"][view_layer]
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMUnDisableViewportAllOperator(Operator):
|
|
bl_label = "[DV Global] Disable in Viewports"
|
|
bl_description = (
|
|
" * LMB - Enable all/Restore.\n"
|
|
" * Shift+LMB - Invert.\n"
|
|
" * Shift+Ctrl+LMB - Isolate collections w/ selected objects.\n"
|
|
" * Shift+Alt+LMB - Disable collections w/ selected objects.\n"
|
|
" * Ctrl+LMB - Copy/Paste RTOs.\n"
|
|
" * Ctrl+Alt+LMB - Swap RTOs.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.un_disable_viewport_all_collections"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def invoke(self, context, event):
|
|
view_layer = context.view_layer.name
|
|
modifiers = get_modifiers(event)
|
|
|
|
if not view_layer in internals.rto_history["disable_all"]:
|
|
internals.rto_history["disable_all"][view_layer] = []
|
|
|
|
if modifiers == {"alt"}:
|
|
# clear all states
|
|
del internals.rto_history["disable_all"][view_layer]
|
|
clear_copy("disable")
|
|
clear_swap("disable")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
copy_rtos(view_layer, "disable")
|
|
|
|
elif modifiers == {"ctrl", "alt"}:
|
|
swap_rtos(view_layer, "disable")
|
|
|
|
elif modifiers == {"shift"}:
|
|
invert_rtos(view_layer, "disable")
|
|
|
|
elif modifiers == {"shift", "ctrl"}:
|
|
error = isolate_sel_objs_collections(view_layer, "disable", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
elif modifiers == {"shift", "alt"}:
|
|
error = disable_sel_objs_collections(view_layer, "disable", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
else:
|
|
activate_all_rtos(view_layer, "disable")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMDisableRenderOperator(Operator):
|
|
bl_label = "[RR] Disable in Renders"
|
|
bl_description = (
|
|
" * Shift+LMB - Isolate/Restore.\n"
|
|
" * Shift+Ctrl+LMB - Isolate nested/Restore.\n"
|
|
" * Ctrl+LMB - Toggle nested.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.disable_render_collection"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
name: StringProperty()
|
|
|
|
# static class var
|
|
isolated = False
|
|
|
|
def invoke(self, context, event):
|
|
cls = CMDisableRenderOperator
|
|
|
|
modifiers = get_modifiers(event)
|
|
view_layer = context.view_layer.name
|
|
laycol_ptr = internals.layer_collections[self.name]["ptr"]
|
|
|
|
if not view_layer in internals.rto_history["render"]:
|
|
internals.rto_history["render"][view_layer] = {"target": "", "history": []}
|
|
|
|
|
|
if modifiers == {"alt"}:
|
|
del internals.rto_history["render"][view_layer]
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"shift"}:
|
|
isolate_rto(cls, self, view_layer, "render")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
toggle_children(self, view_layer, "render")
|
|
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"ctrl", "shift"}:
|
|
isolate_rto(cls, self, view_layer, "render", children=True)
|
|
|
|
else:
|
|
# toggle renderable
|
|
|
|
# reset render history
|
|
del internals.rto_history["render"][view_layer]
|
|
|
|
# toggle renderability of collection
|
|
laycol_ptr.collection.hide_render = not laycol_ptr.collection.hide_render
|
|
|
|
cls.isolated = False
|
|
|
|
# reset render all history
|
|
if view_layer in internals.rto_history["render_all"]:
|
|
del internals.rto_history["render_all"][view_layer]
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMUnDisableRenderAllOperator(Operator):
|
|
bl_label = "[RR Global] Disable in Renders"
|
|
bl_description = (
|
|
" * LMB - Enable all/Restore.\n"
|
|
" * Shift+LMB - Invert.\n"
|
|
" * Shift+Ctrl+LMB - Isolate collections w/ selected objects.\n"
|
|
" * Shift+Alt+LMB - Disable collections w/ selected objects.\n"
|
|
" * Ctrl+LMB - Copy/Paste RTOs.\n"
|
|
" * Ctrl+Alt+LMB - Swap RTOs.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.un_disable_render_all_collections"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def invoke(self, context, event):
|
|
view_layer = context.view_layer.name
|
|
modifiers = get_modifiers(event)
|
|
|
|
if not view_layer in internals.rto_history["render_all"]:
|
|
internals.rto_history["render_all"][view_layer] = []
|
|
|
|
if modifiers == {"alt"}:
|
|
# clear all states
|
|
del internals.rto_history["render_all"][view_layer]
|
|
clear_copy("render")
|
|
clear_swap("render")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
copy_rtos(view_layer, "render")
|
|
|
|
elif modifiers == {"ctrl", "alt"}:
|
|
swap_rtos(view_layer, "render")
|
|
|
|
elif modifiers == {"shift"}:
|
|
invert_rtos(view_layer, "render")
|
|
|
|
elif modifiers == {"shift", "ctrl"}:
|
|
error = isolate_sel_objs_collections(view_layer, "render", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
elif modifiers == {"shift", "alt"}:
|
|
error = disable_sel_objs_collections(view_layer, "render", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
else:
|
|
activate_all_rtos(view_layer, "render")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMHoldoutOperator(Operator):
|
|
bl_label = "[HH] Holdout"
|
|
bl_description = (
|
|
" * Shift+LMB - Isolate/Restore.\n"
|
|
" * Shift+Ctrl+LMB - Isolate nested/Restore.\n"
|
|
" * Ctrl+LMB - Toggle nested.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.holdout_collection"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
name: StringProperty()
|
|
|
|
# static class var
|
|
isolated = False
|
|
|
|
def invoke(self, context, event):
|
|
cls = CMHoldoutOperator
|
|
|
|
modifiers = get_modifiers(event)
|
|
view_layer = context.view_layer.name
|
|
laycol_ptr = internals.layer_collections[self.name]["ptr"]
|
|
|
|
if not view_layer in internals.rto_history["holdout"]:
|
|
internals.rto_history["holdout"][view_layer] = {"target": "", "history": []}
|
|
|
|
if modifiers == {"alt"}:
|
|
del internals.rto_history["holdout"][view_layer]
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"shift"}:
|
|
isolate_rto(cls, self, view_layer, "holdout")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
toggle_children(self, view_layer, "holdout")
|
|
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"ctrl", "shift"}:
|
|
isolate_rto(cls, self, view_layer, "holdout", children=True)
|
|
|
|
else:
|
|
# toggle holdout
|
|
|
|
# reset holdout history
|
|
del internals.rto_history["holdout"][view_layer]
|
|
|
|
# toggle holdout of collection in viewport
|
|
laycol_ptr.holdout = not laycol_ptr.holdout
|
|
|
|
cls.isolated = False
|
|
|
|
# reset holdout all history
|
|
if view_layer in internals.rto_history["holdout_all"]:
|
|
del internals.rto_history["holdout_all"][view_layer]
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMUnHoldoutAllOperator(Operator):
|
|
bl_label = "[HH Global] Holdout"
|
|
bl_description = (
|
|
" * LMB - Enable all/Restore.\n"
|
|
" * Shift+LMB - Invert.\n"
|
|
" * Shift+Ctrl+LMB - Isolate collections w/ selected objects.\n"
|
|
" * Shift+Alt+LMB - Disable collections w/ selected objects.\n"
|
|
" * Ctrl+LMB - Copy/Paste RTOs.\n"
|
|
" * Ctrl+Alt+LMB - Swap RTOs.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.un_holdout_all_collections"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def invoke(self, context, event):
|
|
view_layer = context.view_layer.name
|
|
modifiers = get_modifiers(event)
|
|
|
|
if not view_layer in internals.rto_history["holdout_all"]:
|
|
internals.rto_history["holdout_all"][view_layer] = []
|
|
|
|
if modifiers == {"alt"}:
|
|
# clear all states
|
|
del internals.rto_history["holdout_all"][view_layer]
|
|
clear_copy("holdout")
|
|
clear_swap("holdout")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
copy_rtos(view_layer, "holdout")
|
|
|
|
elif modifiers == {"ctrl", "alt"}:
|
|
swap_rtos(view_layer, "holdout")
|
|
|
|
elif modifiers == {"shift"}:
|
|
invert_rtos(view_layer, "holdout")
|
|
|
|
elif modifiers == {"shift", "ctrl"}:
|
|
error = isolate_sel_objs_collections(view_layer, "holdout", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
elif modifiers == {"shift", "alt"}:
|
|
error = disable_sel_objs_collections(view_layer, "holdout", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
else:
|
|
activate_all_rtos(view_layer, "holdout")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMIndirectOnlyOperator(Operator):
|
|
bl_label = "[IO] Indirect Only"
|
|
bl_description = (
|
|
" * Shift+LMB - Isolate/Restore.\n"
|
|
" * Shift+Ctrl+LMB - Isolate nested/Restore.\n"
|
|
" * Ctrl+LMB - Toggle nested.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.indirect_only_collection"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
name: StringProperty()
|
|
|
|
# static class var
|
|
isolated = False
|
|
|
|
def invoke(self, context, event):
|
|
cls = CMIndirectOnlyOperator
|
|
|
|
modifiers = get_modifiers(event)
|
|
view_layer = context.view_layer.name
|
|
laycol_ptr = internals.layer_collections[self.name]["ptr"]
|
|
|
|
if not view_layer in internals.rto_history["indirect"]:
|
|
internals.rto_history["indirect"][view_layer] = {"target": "", "history": []}
|
|
|
|
|
|
if modifiers == {"alt"}:
|
|
del internals.rto_history["indirect"][view_layer]
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"shift"}:
|
|
isolate_rto(cls, self, view_layer, "indirect")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
toggle_children(self, view_layer, "indirect")
|
|
|
|
cls.isolated = False
|
|
|
|
elif modifiers == {"ctrl", "shift"}:
|
|
isolate_rto(cls, self, view_layer, "indirect", children=True)
|
|
|
|
else:
|
|
# toggle indirect only
|
|
|
|
# reset indirect history
|
|
del internals.rto_history["indirect"][view_layer]
|
|
|
|
# toggle indirect only of collection
|
|
laycol_ptr.indirect_only = not laycol_ptr.indirect_only
|
|
|
|
cls.isolated = False
|
|
|
|
# reset indirect all history
|
|
if view_layer in internals.rto_history["indirect_all"]:
|
|
del internals.rto_history["indirect_all"][view_layer]
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMUnIndirectOnlyAllOperator(Operator):
|
|
bl_label = "[IO Global] Indirect Only"
|
|
bl_description = (
|
|
" * LMB - Enable all/Restore.\n"
|
|
" * Shift+LMB - Invert.\n"
|
|
" * Shift+Ctrl+LMB - Isolate collections w/ selected objects.\n"
|
|
" * Shift+Alt+LMB - Disable collections w/ selected objects.\n"
|
|
" * Ctrl+LMB - Copy/Paste RTOs.\n"
|
|
" * Ctrl+Alt+LMB - Swap RTOs.\n"
|
|
" * Alt+LMB - Discard history"
|
|
)
|
|
bl_idname = "view3d.un_indirect_only_all_collections"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def invoke(self, context, event):
|
|
view_layer = context.view_layer.name
|
|
modifiers = get_modifiers(event)
|
|
|
|
if not view_layer in internals.rto_history["indirect_all"]:
|
|
internals.rto_history["indirect_all"][view_layer] = []
|
|
|
|
if modifiers == {"alt"}:
|
|
# clear all states
|
|
del internals.rto_history["indirect_all"][view_layer]
|
|
clear_copy("indirect")
|
|
clear_swap("indirect")
|
|
|
|
elif modifiers == {"ctrl"}:
|
|
copy_rtos(view_layer, "indirect")
|
|
|
|
elif modifiers == {"ctrl", "alt"}:
|
|
swap_rtos(view_layer, "indirect")
|
|
|
|
elif modifiers == {"shift"}:
|
|
invert_rtos(view_layer, "indirect")
|
|
|
|
elif modifiers == {"shift", "ctrl"}:
|
|
error = isolate_sel_objs_collections(view_layer, "indirect", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
elif modifiers == {"shift", "alt"}:
|
|
error = disable_sel_objs_collections(view_layer, "indirect", "CM")
|
|
|
|
if error:
|
|
self.report({"WARNING"}, error)
|
|
return {'CANCELLED'}
|
|
|
|
else:
|
|
activate_all_rtos(view_layer, "indirect")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMRemoveCollectionOperator(Operator):
|
|
'''Remove Collection'''
|
|
bl_label = "Remove Collection"
|
|
bl_idname = "view3d.remove_collection"
|
|
bl_options = {'UNDO'}
|
|
|
|
collection_name: StringProperty()
|
|
|
|
def execute(self, context):
|
|
laycol = internals.layer_collections[self.collection_name]
|
|
collection = laycol["ptr"].collection
|
|
parent_collection = laycol["parent"]["ptr"].collection
|
|
|
|
|
|
# shift all objects in this collection to the parent collection
|
|
for obj in collection.objects:
|
|
if obj.name not in parent_collection.objects:
|
|
parent_collection.objects.link(obj)
|
|
|
|
|
|
# shift all child collections to the parent collection preserving view layer RTOs
|
|
if collection.children:
|
|
link_child_collections_to_parent(laycol, collection, parent_collection)
|
|
|
|
# remove collection, update references, and update tree view
|
|
remove_collection(laycol, collection, context)
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMRemoveEmptyCollectionsOperator(Operator):
|
|
bl_label = "Remove Empty Collections"
|
|
bl_idname = "view3d.remove_empty_collections"
|
|
bl_options = {'UNDO'}
|
|
|
|
without_objects: BoolProperty()
|
|
|
|
@classmethod
|
|
def description(cls, context, properties):
|
|
if properties.without_objects:
|
|
tooltip = (
|
|
"Purge All Collections Without Objects.\n"
|
|
"Deletes all collections that don't contain objects even if they have subcollections"
|
|
)
|
|
|
|
else:
|
|
tooltip = (
|
|
"Remove Empty Collections.\n"
|
|
"Delete collections that don't have any subcollections or objects"
|
|
)
|
|
|
|
return tooltip
|
|
|
|
def execute(self, context):
|
|
if self.without_objects:
|
|
empty_collections = [laycol["name"]
|
|
for laycol in internals.layer_collections.values()
|
|
if not laycol["ptr"].collection.objects]
|
|
else:
|
|
empty_collections = [laycol["name"]
|
|
for laycol in internals.layer_collections.values()
|
|
if not laycol["children"] and
|
|
not laycol["ptr"].collection.objects]
|
|
|
|
for name in empty_collections:
|
|
laycol = internals.layer_collections[name]
|
|
collection = laycol["ptr"].collection
|
|
parent_collection = laycol["parent"]["ptr"].collection
|
|
|
|
# link all child collections to the parent collection preserving view layer RTOs
|
|
if collection.children:
|
|
link_child_collections_to_parent(laycol, collection, parent_collection)
|
|
|
|
# remove collection, update references, and update tree view
|
|
remove_collection(laycol, collection, context)
|
|
|
|
self.report({"INFO"}, f"Removed {len(empty_collections)} collections")
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
rename = [False]
|
|
class CMNewCollectionOperator(Operator):
|
|
bl_label = "Add New Collection"
|
|
bl_idname = "view3d.add_collection"
|
|
bl_options = {'UNDO'}
|
|
|
|
child: BoolProperty()
|
|
|
|
@classmethod
|
|
def description(cls, context, properties):
|
|
if properties.child:
|
|
tooltip = (
|
|
"Add New SubCollection.\n"
|
|
"Add a new subcollection to the currently selected collection"
|
|
)
|
|
|
|
else:
|
|
tooltip = (
|
|
"Add New Collection.\n"
|
|
"Add a new collection as a sibling of the currently selected collection"
|
|
)
|
|
|
|
return tooltip
|
|
|
|
def execute(self, context):
|
|
new_collection = bpy.data.collections.new("New Collection")
|
|
cm = context.scene.collection_manager
|
|
|
|
# prevent adding collections when collections are filtered
|
|
# and the selection is ambiguous
|
|
if cm.cm_list_index == -1 and ui.CM_UL_items.filtering:
|
|
send_report("Cannot create new collection.\n"
|
|
"No collection is selected and collections are filtered."
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
if cm.cm_list_index > -1 and not ui.CM_UL_items.visible_items[cm.cm_list_index]:
|
|
send_report("Cannot create new collection.\n"
|
|
"The selected collection isn't visible."
|
|
)
|
|
return {'CANCELLED'}
|
|
|
|
|
|
# if there are collections
|
|
if len(cm.cm_list_collection) > 0:
|
|
if not cm.cm_list_index == -1:
|
|
# get selected collection
|
|
laycol = internals.layer_collections[cm.cm_list_collection[cm.cm_list_index].name]
|
|
|
|
# add new collection
|
|
if self.child:
|
|
laycol["ptr"].collection.children.link(new_collection)
|
|
internals.expanded.add(laycol["name"])
|
|
|
|
# update tree view property
|
|
update_property_group(context)
|
|
|
|
cm.cm_list_index = internals.layer_collections[new_collection.name]["row_index"]
|
|
|
|
else:
|
|
laycol["parent"]["ptr"].collection.children.link(new_collection)
|
|
|
|
# update tree view property
|
|
update_property_group(context)
|
|
|
|
cm.cm_list_index = internals.layer_collections[new_collection.name]["row_index"]
|
|
|
|
else:
|
|
context.scene.collection.children.link(new_collection)
|
|
|
|
# update tree view property
|
|
update_property_group(context)
|
|
|
|
cm.cm_list_index = internals.layer_collections[new_collection.name]["row_index"]
|
|
|
|
# if no collections add top level collection and select it
|
|
else:
|
|
context.scene.collection.children.link(new_collection)
|
|
|
|
# update tree view property
|
|
update_property_group(context)
|
|
|
|
cm.cm_list_index = 0
|
|
|
|
|
|
# set new collection to active
|
|
layer_collection = internals.layer_collections[new_collection.name]["ptr"]
|
|
context.view_layer.active_layer_collection = layer_collection
|
|
|
|
# show the new collection when collections are filtered.
|
|
ui.CM_UL_items.new_collections.append(new_collection.name)
|
|
|
|
global rename
|
|
rename[0] = True
|
|
|
|
# reset history
|
|
for rto in internals.rto_history.values():
|
|
rto.clear()
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMPhantomModeOperator(Operator):
|
|
'''Toggle Phantom Mode'''
|
|
bl_label = "Toggle Phantom Mode"
|
|
bl_idname = "view3d.toggle_phantom_mode"
|
|
|
|
def execute(self, context):
|
|
cm = context.scene.collection_manager
|
|
view_layer = context.view_layer
|
|
|
|
# enter Phantom Mode
|
|
if not cm.in_phantom_mode:
|
|
|
|
cm.in_phantom_mode = True
|
|
|
|
# save current visibility state
|
|
internals.phantom_history["view_layer"] = view_layer.name
|
|
|
|
def save_visibility_state(layer_collection):
|
|
internals.phantom_history["initial_state"][layer_collection.name] = {
|
|
"exclude": layer_collection.exclude,
|
|
"select": layer_collection.collection.hide_select,
|
|
"hide": layer_collection.hide_viewport,
|
|
"disable": layer_collection.collection.hide_viewport,
|
|
"render": layer_collection.collection.hide_render,
|
|
"holdout": layer_collection.holdout,
|
|
"indirect": layer_collection.indirect_only,
|
|
}
|
|
|
|
apply_to_children(view_layer.layer_collection, save_visibility_state)
|
|
|
|
# save current rto history
|
|
for rto, history, in internals.rto_history.items():
|
|
if history.get(view_layer.name, None):
|
|
internals.phantom_history[rto+"_history"] = deepcopy(history[view_layer.name])
|
|
|
|
|
|
|
|
else: # return to normal mode
|
|
def restore_visibility_state(layer_collection):
|
|
phantom_laycol = internals.phantom_history["initial_state"][layer_collection.name]
|
|
|
|
layer_collection.exclude = phantom_laycol["exclude"]
|
|
layer_collection.collection.hide_select = phantom_laycol["select"]
|
|
layer_collection.hide_viewport = phantom_laycol["hide"]
|
|
layer_collection.collection.hide_viewport = phantom_laycol["disable"]
|
|
layer_collection.collection.hide_render = phantom_laycol["render"]
|
|
layer_collection.holdout = phantom_laycol["holdout"]
|
|
layer_collection.indirect_only = phantom_laycol["indirect"]
|
|
|
|
apply_to_children(view_layer.layer_collection, restore_visibility_state)
|
|
|
|
|
|
# restore previous rto history
|
|
for rto, history, in internals.rto_history.items():
|
|
if view_layer.name in history:
|
|
del history[view_layer.name]
|
|
|
|
if internals.phantom_history[rto+"_history"]:
|
|
history[view_layer.name] = deepcopy(internals.phantom_history[rto+"_history"])
|
|
|
|
internals.phantom_history[rto+"_history"].clear()
|
|
|
|
cm.in_phantom_mode = False
|
|
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMApplyPhantomModeOperator(Operator):
|
|
'''Apply changes and quit Phantom Mode'''
|
|
bl_label = "Apply Phantom Mode"
|
|
bl_idname = "view3d.apply_phantom_mode"
|
|
|
|
def execute(self, context):
|
|
cm = context.scene.collection_manager
|
|
cm.in_phantom_mode = False
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMDisableObjectsOperator(Operator):
|
|
'''Disable selected objects in viewports'''
|
|
bl_label = "Disable Selected"
|
|
bl_idname = "view3d.disable_selected_objects"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
for obj in context.selected_objects:
|
|
obj.hide_viewport = True
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMDisableUnSelectedObjectsOperator(Operator):
|
|
'''Disable unselected objects in viewports'''
|
|
bl_label = "Disable Unselected"
|
|
bl_idname = "view3d.disable_unselected_objects"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
for obj in bpy.data.objects:
|
|
if obj in context.visible_objects and not obj in context.selected_objects:
|
|
obj.hide_viewport = True
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CMRestoreDisabledObjectsOperator(Operator):
|
|
'''Restore disabled objects in viewports'''
|
|
bl_label = "Restore Disabled Objects"
|
|
bl_idname = "view3d.restore_disabled_objects"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
for obj in bpy.data.objects:
|
|
if obj.hide_viewport:
|
|
obj.hide_viewport = False
|
|
obj.select_set(True)
|
|
|
|
return {'FINISHED'}
|