Collection Manager: Add ops for selected objects. Task: T69577
Add operators to isolate/disable the collections of selected objects.
This commit is contained in:
parent
589d13408a
commit
47820f66c2
|
@ -22,7 +22,7 @@ bl_info = {
|
|||
"name": "Collection Manager",
|
||||
"description": "Manage collections and their objects",
|
||||
"author": "Ryan Inch",
|
||||
"version": (2, 18, 5),
|
||||
"version": (2, 19, 0),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "View3D - Object Mode (Shortcut - M)",
|
||||
"warning": '', # used for warning icon and text in addons panel
|
||||
|
|
|
@ -638,14 +638,14 @@ def get_move_selection(*, names_only=False):
|
|||
return {obj for obj in bpy.data.objects if obj.name in move_selection}
|
||||
|
||||
|
||||
def get_move_active():
|
||||
def get_move_active(*, always=False):
|
||||
global move_active
|
||||
global move_selection
|
||||
|
||||
if not move_active:
|
||||
move_active = getattr(bpy.context.view_layer.objects.active, "name", None)
|
||||
|
||||
if move_active not in get_move_selection(names_only=True):
|
||||
if not always and move_active not in get_move_selection(names_only=True):
|
||||
move_active = None
|
||||
|
||||
return bpy.data.objects[move_active] if move_active else None
|
||||
|
|
|
@ -26,6 +26,7 @@ from . import internals
|
|||
from .internals import (
|
||||
update_property_group,
|
||||
get_move_selection,
|
||||
get_move_active,
|
||||
)
|
||||
|
||||
mode_converter = {
|
||||
|
@ -244,6 +245,122 @@ def isolate_rto(cls, self, view_layer, rto, *, children=False):
|
|||
cls.isolated = True
|
||||
|
||||
|
||||
def isolate_sel_objs_collections(view_layer, rto, caller, *, use_active=False):
|
||||
selected_objects = get_move_selection()
|
||||
|
||||
if use_active:
|
||||
selected_objects.add(get_move_active(always=True))
|
||||
|
||||
if not selected_objects:
|
||||
return "No selected objects"
|
||||
|
||||
off = set_off_on[rto]["off"]
|
||||
on = set_off_on[rto]["on"]
|
||||
|
||||
if caller == "CM":
|
||||
history = internals.rto_history[rto+"_all"][view_layer]
|
||||
|
||||
elif caller == "QCD":
|
||||
history = internals.qcd_history[view_layer]
|
||||
|
||||
|
||||
# if not isolated, isolate collections of selected objects
|
||||
if len(history) == 0:
|
||||
keep_history = False
|
||||
|
||||
# save history and isolate RTOs
|
||||
for item in internals.layer_collections.values():
|
||||
history.append(get_rto(item["ptr"], rto))
|
||||
rto_state = off
|
||||
|
||||
# check if any of the selected objects are in the collection
|
||||
if not set(selected_objects).isdisjoint(item["ptr"].collection.objects):
|
||||
rto_state = on
|
||||
|
||||
if history[-1] != rto_state:
|
||||
keep_history = True
|
||||
|
||||
if rto == "exclude":
|
||||
set_exclude_state(item["ptr"], rto_state)
|
||||
|
||||
else:
|
||||
set_rto(item["ptr"], rto, rto_state)
|
||||
|
||||
# activate all parents if needed
|
||||
if rto_state == on and rto not in ["holdout", "indirect"]:
|
||||
laycol = item["parent"]
|
||||
while laycol["id"] != 0:
|
||||
set_rto(laycol["ptr"], rto, on)
|
||||
laycol = laycol["parent"]
|
||||
|
||||
|
||||
if not keep_history:
|
||||
history.clear()
|
||||
|
||||
return "Collection already isolated"
|
||||
|
||||
|
||||
else:
|
||||
for x, item in enumerate(internals.layer_collections.values()):
|
||||
set_rto(item["ptr"], rto, history[x])
|
||||
|
||||
# clear history
|
||||
if caller == "CM":
|
||||
del internals.rto_history[rto+"_all"][view_layer]
|
||||
|
||||
elif caller == "QCD":
|
||||
del internals.qcd_history[view_layer]
|
||||
|
||||
|
||||
def disable_sel_objs_collections(view_layer, rto, caller):
|
||||
off = set_off_on[rto]["off"]
|
||||
on = set_off_on[rto]["on"]
|
||||
selected_objects = get_move_selection()
|
||||
|
||||
if caller == "CM":
|
||||
history = internals.rto_history[rto+"_all"][view_layer]
|
||||
|
||||
elif caller == "QCD":
|
||||
history = internals.qcd_history[view_layer]
|
||||
|
||||
|
||||
if not selected_objects and not history:
|
||||
# clear history
|
||||
if caller == "CM":
|
||||
del internals.rto_history[rto+"_all"][view_layer]
|
||||
|
||||
elif caller == "QCD":
|
||||
del internals.qcd_history[view_layer]
|
||||
|
||||
return "No selected objects"
|
||||
|
||||
# if not disabled, disable collections of selected objects
|
||||
if len(history) == 0:
|
||||
# save history and disable RTOs
|
||||
for item in internals.layer_collections.values():
|
||||
history.append(get_rto(item["ptr"], rto))
|
||||
|
||||
# check if any of the selected objects are in the collection
|
||||
if not set(selected_objects).isdisjoint(item["ptr"].collection.objects):
|
||||
if rto == "exclude":
|
||||
set_exclude_state(item["ptr"], off)
|
||||
|
||||
else:
|
||||
set_rto(item["ptr"], rto, off)
|
||||
|
||||
|
||||
else:
|
||||
for x, item in enumerate(internals.layer_collections.values()):
|
||||
set_rto(item["ptr"], rto, history[x])
|
||||
|
||||
# clear history
|
||||
if caller == "CM":
|
||||
del internals.rto_history[rto+"_all"][view_layer]
|
||||
|
||||
elif caller == "QCD":
|
||||
del internals.qcd_history[view_layer]
|
||||
|
||||
|
||||
def toggle_children(self, view_layer, rto):
|
||||
laycol_ptr = internals.layer_collections[self.name]["ptr"]
|
||||
# clear rto history
|
||||
|
|
|
@ -59,6 +59,8 @@ from .operator_utils import (
|
|||
remove_collection,
|
||||
select_collection_objects,
|
||||
set_exclude_state,
|
||||
isolate_sel_objs_collections,
|
||||
disable_sel_objs_collections,
|
||||
)
|
||||
|
||||
from . import ui
|
||||
|
@ -441,6 +443,8 @@ class CMUnExcludeAllOperator(Operator):
|
|||
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"
|
||||
|
@ -472,6 +476,20 @@ class CMUnExcludeAllOperator(Operator):
|
|||
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")
|
||||
|
||||
|
@ -550,6 +568,8 @@ class CMUnRestrictSelectAllOperator(Operator):
|
|||
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"
|
||||
|
@ -579,6 +599,20 @@ class CMUnRestrictSelectAllOperator(Operator):
|
|||
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")
|
||||
|
||||
|
@ -649,6 +683,8 @@ class CMUnHideAllOperator(Operator):
|
|||
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"
|
||||
|
@ -678,6 +714,20 @@ class CMUnHideAllOperator(Operator):
|
|||
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")
|
||||
|
||||
|
@ -748,6 +798,8 @@ class CMUnDisableViewportAllOperator(Operator):
|
|||
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"
|
||||
|
@ -777,6 +829,20 @@ class CMUnDisableViewportAllOperator(Operator):
|
|||
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")
|
||||
|
||||
|
@ -848,6 +914,8 @@ class CMUnDisableRenderAllOperator(Operator):
|
|||
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"
|
||||
|
@ -877,6 +945,20 @@ class CMUnDisableRenderAllOperator(Operator):
|
|||
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")
|
||||
|
||||
|
@ -947,6 +1029,8 @@ class CMUnHoldoutAllOperator(Operator):
|
|||
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"
|
||||
|
@ -976,6 +1060,20 @@ class CMUnHoldoutAllOperator(Operator):
|
|||
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")
|
||||
|
||||
|
@ -1047,6 +1145,8 @@ class CMUnIndirectOnlyAllOperator(Operator):
|
|||
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"
|
||||
|
@ -1076,6 +1176,20 @@ class CMUnIndirectOnlyAllOperator(Operator):
|
|||
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")
|
||||
|
||||
|
|
|
@ -50,6 +50,8 @@ qcd_classes = (
|
|||
qcd_operators.EnableAllQCDSlotsMeta,
|
||||
qcd_operators.EnableAllQCDSlots,
|
||||
qcd_operators.EnableAllQCDSlotsIsolated,
|
||||
qcd_operators.IsolateSelectedObjectsCollections,
|
||||
qcd_operators.DisableSelectedObjectsCollections,
|
||||
qcd_operators.DisableAllNonQCDSlots,
|
||||
qcd_operators.DisableAllCollections,
|
||||
qcd_operators.SelectAllQCDObjects,
|
||||
|
@ -169,6 +171,14 @@ def register_qcd_view_hotkeys():
|
|||
kmi = km.keymap_items.new('view3d.enable_all_qcd_slots_isolated', 'PLUS', 'PRESS', shift=True, alt=True)
|
||||
addon_qcd_view_hotkey_keymaps.append((km, kmi))
|
||||
|
||||
km = wm.keyconfigs.addon.keymaps.new(name=mode)
|
||||
kmi = km.keymap_items.new('view3d.isolate_selected_objects_collections', 'EQUAL', 'PRESS')
|
||||
addon_qcd_view_hotkey_keymaps.append((km, kmi))
|
||||
|
||||
km = wm.keyconfigs.addon.keymaps.new(name=mode)
|
||||
kmi = km.keymap_items.new('view3d.disable_selected_objects_collections', 'MINUS', 'PRESS')
|
||||
addon_qcd_view_hotkey_keymaps.append((km, kmi))
|
||||
|
||||
km = wm.keyconfigs.addon.keymaps.new(name=mode)
|
||||
kmi = km.keymap_items.new('view3d.disable_all_non_qcd_slots', 'PLUS', 'PRESS', shift=True, ctrl=True)
|
||||
addon_qcd_view_hotkey_keymaps.append((km, kmi))
|
||||
|
@ -228,6 +238,10 @@ def register_qcd_view_edit_mode_hotkeys():
|
|||
kmi = km.keymap_items.new('view3d.enable_all_qcd_slots', 'PLUS', 'PRESS', shift=True)
|
||||
addon_qcd_view_edit_mode_hotkey_keymaps.append((km, kmi))
|
||||
|
||||
km = wm.keyconfigs.addon.keymaps.new(name=mode)
|
||||
kmi = km.keymap_items.new('view3d.isolate_selected_objects_collections', 'EQUAL', 'PRESS')
|
||||
addon_qcd_view_edit_mode_hotkey_keymaps.append((km, kmi))
|
||||
|
||||
km = wm.keyconfigs.addon.keymaps.new(name=mode)
|
||||
kmi = km.keymap_items.new('view3d.enable_all_qcd_slots_isolated', 'PLUS', 'PRESS', shift=True, alt=True)
|
||||
addon_qcd_view_edit_mode_hotkey_keymaps.append((km, kmi))
|
||||
|
|
|
@ -48,6 +48,8 @@ from .operator_utils import (
|
|||
apply_to_children,
|
||||
select_collection_objects,
|
||||
set_exclude_state,
|
||||
isolate_sel_objs_collections,
|
||||
disable_sel_objs_collections,
|
||||
)
|
||||
|
||||
class LockedObjects():
|
||||
|
@ -134,7 +136,7 @@ class QCDAllBase():
|
|||
cls.history = None
|
||||
cls.orig_active_collection = None
|
||||
cls.orig_active_object = None
|
||||
cls.locked = {}
|
||||
cls.locked = None
|
||||
|
||||
|
||||
class EnableAllQCDSlotsMeta(Operator):
|
||||
|
@ -308,6 +310,66 @@ class EnableAllQCDSlotsIsolated(Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
class IsolateSelectedObjectsCollections(Operator):
|
||||
'''Isolate collections (via EC) that contain the selected objects'''
|
||||
bl_label = "Isolate Selected Objects Collections"
|
||||
bl_idname = "view3d.isolate_selected_objects_collections"
|
||||
|
||||
def execute(self, context):
|
||||
qab = QCDAllBase
|
||||
qab.init(context)
|
||||
|
||||
use_active = bool(context.mode != 'OBJECT')
|
||||
|
||||
# isolate
|
||||
error = isolate_sel_objs_collections(qab.view_layer, "exclude", "QCD", use_active=use_active)
|
||||
|
||||
if error:
|
||||
qab.clear()
|
||||
self.report({"WARNING"}, error)
|
||||
return {'CANCELLED'}
|
||||
|
||||
qab.finalize()
|
||||
|
||||
internals.qcd_collection_state.clear()
|
||||
internals.qcd_collection_state.update(internals.generate_state(qcd=True))
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class DisableSelectedObjectsCollections(Operator):
|
||||
'''Disable all collections that contain the selected objects'''
|
||||
bl_label = "Disable Selected Objects Collections"
|
||||
bl_idname = "view3d.disable_selected_objects_collections"
|
||||
|
||||
def execute(self, context):
|
||||
qab = QCDAllBase
|
||||
qab.init(context)
|
||||
|
||||
if qab.locked.objs:
|
||||
# clear rto history
|
||||
del internals.qcd_history[qab.view_layer]
|
||||
qab.clear()
|
||||
|
||||
self.report({"WARNING"}, "Can only be executed in Object Mode")
|
||||
return {'CANCELLED'}
|
||||
|
||||
# disable
|
||||
error = disable_sel_objs_collections(qab.view_layer, "exclude", "QCD")
|
||||
|
||||
if error:
|
||||
qab.clear()
|
||||
self.report({"WARNING"}, error)
|
||||
return {'CANCELLED'}
|
||||
|
||||
qab.finalize()
|
||||
|
||||
internals.qcd_collection_state.clear()
|
||||
internals.qcd_collection_state.update(internals.generate_state(qcd=True))
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class DisableAllNonQCDSlots(Operator):
|
||||
'''Toggles between the current state and all non-QCD collections disabled'''
|
||||
bl_label = "Disable All Non QCD Slots"
|
||||
|
|
|
@ -905,6 +905,12 @@ class EnableAllQCDSlotsMenu(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("view3d.isolate_selected_objects_collections")
|
||||
if context.mode == 'OBJECT':
|
||||
layout.operator("view3d.disable_selected_objects_collections")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("view3d.disable_all_non_qcd_slots")
|
||||
layout.operator("view3d.disable_all_collections")
|
||||
|
||||
|
|
Loading…
Reference in New Issue