Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Inch <mythologylover75@gmail.com>2020-09-26 10:20:53 +0300
committerRyan Inch <mythologylover75@gmail.com>2020-09-26 10:20:53 +0300
commitbf176041da95d4b07d74727acb78f7cf6a46785e (patch)
tree23ac07c7a260172f8767c2f31c63404d9cf61870 /object_collection_manager
parent3d2076556a73af15779fc06630a3254fd584af02 (diff)
Collection Manager: Add QVT. Task: T69577
Add Quick View Toggles for influencing QCD setup, e.g. enable all slots. Fix bugs with QCD slot switching. Fix the active object sometimes getting lost when toggling slots.
Diffstat (limited to 'object_collection_manager')
-rw-r--r--object_collection_manager/__init__.py2
-rw-r--r--object_collection_manager/internals.py16
-rw-r--r--object_collection_manager/operator_utils.py46
-rw-r--r--object_collection_manager/operators.py19
-rw-r--r--object_collection_manager/qcd_init.py54
-rw-r--r--object_collection_manager/qcd_operators.py483
-rw-r--r--object_collection_manager/ui.py64
7 files changed, 627 insertions, 57 deletions
diff --git a/object_collection_manager/__init__.py b/object_collection_manager/__init__.py
index 72a279d1..792f5d1c 100644
--- a/object_collection_manager/__init__.py
+++ b/object_collection_manager/__init__.py
@@ -22,7 +22,7 @@ bl_info = {
"name": "Collection Manager",
"description": "Manage collections and their objects",
"author": "Ryan Inch",
- "version": (2, 14, 3),
+ "version": (2, 15, 0),
"blender": (2, 80, 0),
"location": "View3D - Object Mode (Shortcut - M)",
"warning": '', # used for warning icon and text in addons panel
diff --git a/object_collection_manager/internals.py b/object_collection_manager/internals.py
index 163e9804..34e66737 100644
--- a/object_collection_manager/internals.py
+++ b/object_collection_manager/internals.py
@@ -39,6 +39,7 @@ move_active = None
layer_collections = {}
collection_tree = []
collection_state = {}
+qcd_collection_state = {}
expanded = set()
row_index = 0
max_lvl = 0
@@ -60,6 +61,8 @@ rto_history = {
"indirect_all": {},
}
+qcd_history = {}
+
expand_history = {
"target": "",
"history": [],
@@ -131,6 +134,13 @@ class QCDSlots():
raise
+ def object_in_slots(self, obj):
+ for collection in obj.users_collection:
+ if self.contains(name=collection.name):
+ return True
+
+ return False
+
def get_data_for_blend(self):
return f"{self._slots.__repr__()}\n{self.overrides.__repr__()}"
@@ -584,8 +594,9 @@ def get_modifiers(event):
return set(modifiers)
-def generate_state():
+def generate_state(*, qcd=False):
global layer_collections
+ global qcd_slots
state = {
"name": [],
@@ -608,6 +619,9 @@ def generate_state():
state["holdout"].append(laycol["ptr"].holdout)
state["indirect"].append(laycol["ptr"].indirect_only)
+ if qcd:
+ state["qcd"] = dict(qcd_slots)
+
return state
diff --git a/object_collection_manager/operator_utils.py b/object_collection_manager/operator_utils.py
index 20c7dee7..2544b76b 100644
--- a/object_collection_manager/operator_utils.py
+++ b/object_collection_manager/operator_utils.py
@@ -31,6 +31,29 @@ from .internals import (
get_move_selection,
)
+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",
@@ -469,7 +492,7 @@ def remove_collection(laycol, collection, context):
cm.cm_list_index = laycol["row_index"]
-def select_collection_objects(is_master_collection, collection_name, replace, nested):
+def select_collection_objects(is_master_collection, collection_name, replace, nested, selection_state=None):
if is_master_collection:
target_collection = bpy.context.view_layer.layer_collection.collection
@@ -480,7 +503,8 @@ def select_collection_objects(is_master_collection, collection_name, replace, ne
if replace:
bpy.ops.object.select_all(action='DESELECT')
- selection_state = get_move_selection().isdisjoint(target_collection.objects)
+ if selection_state == None:
+ selection_state = get_move_selection().isdisjoint(target_collection.objects)
def select_objects(collection):
for obj in collection.objects:
@@ -493,3 +517,21 @@ def select_collection_objects(is_master_collection, collection_name, replace, ne
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]
diff --git a/object_collection_manager/operators.py b/object_collection_manager/operators.py
index 1e265e52..b18fc44a 100644
--- a/object_collection_manager/operators.py
+++ b/object_collection_manager/operators.py
@@ -66,6 +66,7 @@ from .operator_utils import (
link_child_collections_to_parent,
remove_collection,
select_collection_objects,
+ set_exclude_state,
)
class SetActiveCollection(Operator):
@@ -424,23 +425,7 @@ class CMExcludeOperator(Operator):
# reset exclude history
del rto_history["exclude"][view_layer]
-
- # get current child exclusion state
- child_exclusion = []
-
- def get_child_exclusion(layer_collection):
- child_exclusion.append([layer_collection, layer_collection.exclude])
-
- apply_to_children(laycol_ptr, get_child_exclusion)
-
-
- # toggle exclusion of collection
- laycol_ptr.exclude = not laycol_ptr.exclude
-
-
- # set correct state for all children
- for laycol in child_exclusion:
- laycol[0].exclude = laycol[1]
+ set_exclude_state(laycol_ptr, not laycol_ptr.exclude)
cls.isolated = False
diff --git a/object_collection_manager/qcd_init.py b/object_collection_manager/qcd_init.py
index 358d7617..035d62a0 100644
--- a/object_collection_manager/qcd_init.py
+++ b/object_collection_manager/qcd_init.py
@@ -16,10 +16,18 @@ addon_qcd_view_edit_mode_hotkey_keymaps = []
qcd_classes = (
qcd_move_widget.QCDMoveWidget,
+ qcd_operators.EnableAllQCDSlotsMeta,
+ qcd_operators.EnableAllQCDSlots,
+ qcd_operators.EnableAllQCDSlotsIsolated,
+ qcd_operators.DisableAllNonQCDSlots,
+ qcd_operators.DisableAllCollections,
+ qcd_operators.SelectAllQCDObjects,
+ qcd_operators.DiscardQCDHistory,
qcd_operators.MoveToQCDSlot,
qcd_operators.ViewQCDSlot,
qcd_operators.ViewMoveQCDSlot,
qcd_operators.RenumerateQCDSlots,
+ ui.EnableAllQCDSlotsMenu,
)
@@ -41,6 +49,13 @@ def load_internal_data(dummy):
internals.qcd_slots.load_blend_data(data)
+@persistent
+def load_pre_handler(dummy):
+ internals.qcd_collection_state.clear()
+ for key in list(internals.qcd_history.keys()):
+ del internals.qcd_history[key]
+
+
def register_qcd():
for cls in qcd_classes:
bpy.utils.register_class(cls)
@@ -60,6 +75,7 @@ def register_qcd():
bpy.app.handlers.save_pre.append(save_internal_data)
bpy.app.handlers.load_post.append(load_internal_data)
+ bpy.app.handlers.load_pre.append(load_pre_handler)
prefs = bpy.context.preferences.addons[__package__].preferences
@@ -114,6 +130,27 @@ def register_qcd_view_hotkeys():
kmi.properties.toggle = True
addon_qcd_view_hotkey_keymaps.append((km, kmi))
+ km = wm.keyconfigs.addon.keymaps.new(name=mode)
+ kmi = km.keymap_items.new('view3d.enable_all_qcd_slots', 'PLUS', 'PRESS', shift=True)
+ addon_qcd_view_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_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))
+
+ km = wm.keyconfigs.addon.keymaps.new(name=mode)
+ kmi = km.keymap_items.new('view3d.disable_all_collections', 'EQUAL', 'PRESS', alt=True, ctrl=True)
+ addon_qcd_view_hotkey_keymaps.append((km, kmi))
+
+ if mode == 'Object Mode':
+ km = wm.keyconfigs.addon.keymaps.new(name=mode)
+ kmi = km.keymap_items.new('view3d.select_all_qcd_objects', 'EQUAL', 'PRESS', alt=True)
+ addon_qcd_view_hotkey_keymaps.append((km, kmi))
+
def register_qcd_view_edit_mode_hotkeys():
wm = bpy.context.window_manager
@@ -156,6 +193,22 @@ def register_qcd_view_edit_mode_hotkeys():
kmi.properties.toggle = 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.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.enable_all_qcd_slots_isolated', 'PLUS', 'PRESS', shift=True, alt=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.disable_all_non_qcd_slots', 'PLUS', 'PRESS', shift=True, ctrl=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.disable_all_collections', 'EQUAL', 'PRESS', alt=True, ctrl=True)
+ addon_qcd_view_edit_mode_hotkey_keymaps.append((km, kmi))
+
km = wm.keyconfigs.addon.keymaps.new(name="Mesh")
kmi = km.keymap_items.new('wm.call_menu', 'ACCENT_GRAVE', 'PRESS')
@@ -173,6 +226,7 @@ def unregister_qcd():
bpy.app.handlers.save_pre.remove(save_internal_data)
bpy.app.handlers.load_post.remove(load_internal_data)
+ bpy.app.handlers.load_pre.remove(load_pre_handler)
for pcoll in ui.preview_collections.values():
bpy.utils.previews.remove(pcoll)
diff --git a/object_collection_manager/qcd_operators.py b/object_collection_manager/qcd_operators.py
index 6b5bce4a..f53fe6bc 100644
--- a/object_collection_manager/qcd_operators.py
+++ b/object_collection_manager/qcd_operators.py
@@ -35,8 +35,12 @@ from . import internals
from .internals import (
layer_collections,
rto_history,
+ qcd_history,
qcd_slots,
+ qcd_collection_state,
+ update_collection_tree,
update_property_group,
+ generate_state,
get_modifiers,
get_move_selection,
get_move_active,
@@ -44,10 +48,443 @@ from .internals import (
)
from .operator_utils import (
+ mode_converter,
apply_to_children,
select_collection_objects,
+ set_exclude_state,
)
+class LockedObjects():
+ def __init__(self):
+ self.objs = []
+ self.mode = ""
+
+def get_locked_objs(context):
+ # get objects not in object mode
+ locked = LockedObjects()
+ if context.mode == 'OBJECT':
+ return locked
+
+ if context.view_layer.objects.active:
+ active = context.view_layer.objects.active
+ locked.mode = mode_converter[context.mode]
+
+ for obj in context.view_layer.objects:
+ if obj.mode != 'OBJECT':
+ if obj.mode not in ['POSE', 'WEIGHT_PAINT'] or obj == active:
+ if obj.mode == active.mode:
+ locked.objs.append(obj)
+
+ return locked
+
+
+
+class QCDAllBase():
+ meta_op = False
+ meta_report = None
+
+ context = None
+ view_layer = ""
+ history = None
+ orig_active_collection = None
+ orig_active_object = None
+ locked = None
+
+ @classmethod
+ def init(cls, context):
+ cls.context = context
+ cls.orig_active_collection = context.view_layer.active_layer_collection
+ cls.view_layer = context.view_layer.name
+ cls.orig_active_object = context.view_layer.objects.active
+
+ if not cls.view_layer in qcd_history:
+ qcd_history[cls.view_layer] = []
+
+ cls.history = qcd_history[cls.view_layer]
+
+ cls.locked = get_locked_objs(context)
+
+ @classmethod
+ def apply_history(cls):
+ for x, item in enumerate(layer_collections.values()):
+ item["ptr"].exclude = cls.history[x]
+
+ # clear rto history
+ del qcd_history[cls.view_layer]
+
+ internals.qcd_collection_state.clear()
+ cls.history = None
+
+ @classmethod
+ def finalize(cls):
+ # restore active collection
+ cls.context.view_layer.active_layer_collection = cls.orig_active_collection
+
+ # restore active object if possible
+ if cls.orig_active_object:
+ if cls.orig_active_object.name in cls.context.view_layer.objects:
+ cls.context.view_layer.objects.active = cls.orig_active_object
+
+ # restore locked objects back to their original mode
+ # needed because of exclude child updates
+ if cls.context.view_layer.objects.active:
+ if cls.locked.objs:
+ bpy.ops.object.mode_set(mode=cls.locked.mode)
+
+ @classmethod
+ def clear(cls):
+
+ cls.context = None
+ cls.view_layer = ""
+ cls.history = None
+ cls.orig_active_collection = None
+ cls.orig_active_object = None
+ cls.locked = {}
+
+
+class EnableAllQCDSlotsMeta(Operator):
+ '''QCD All Meta Operator'''
+ bl_label = "Quick View Toggles"
+ bl_description = (
+ " * LMB - Enable all slots/Restore.\n"
+ " * Alt+LMB - Select all objects in QCD slots.\n"
+ " * LMB+Hold - Menu"
+ )
+ bl_idname = "view3d.enable_all_qcd_slots_meta"
+
+ def invoke(self, context, event):
+ global qcd_slots
+ global layer_collections
+ qab = QCDAllBase
+
+ modifiers = get_modifiers(event)
+
+ qab.meta_op = True
+
+ if modifiers == {"alt"}:
+ bpy.ops.view3d.select_all_qcd_objects()
+
+ else:
+ qab.init(context)
+
+ if not qab.history:
+ bpy.ops.view3d.enable_all_qcd_slots()
+
+ else:
+ qab.apply_history()
+ qab.finalize()
+
+
+ if qab.meta_report:
+ self.report({"INFO"}, qab.meta_report)
+ qab.meta_report = None
+
+ qab.meta_op = False
+
+
+ return {'FINISHED'}
+
+
+class EnableAllQCDSlots(Operator):
+ '''Toggles between the current state and all enabled'''
+ bl_label = "Enable All QCD Slots"
+ bl_idname = "view3d.enable_all_qcd_slots"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ def execute(self, context):
+ global qcd_slots
+ global layer_collections
+ qab = QCDAllBase
+
+ # validate qcd slots
+ if not dict(qcd_slots):
+ if qab.meta_op:
+ qab.meta_report = "No QCD slots."
+ else:
+ self.report({"INFO"}, "No QCD slots.")
+
+ return {'CANCELLED'}
+
+ qab.init(context)
+
+ if not qab.history:
+ keep_history = False
+
+ for laycol in layer_collections.values():
+ is_qcd_slot = qcd_slots.contains(name=laycol["name"])
+
+ qab.history.append(laycol["ptr"].exclude)
+
+ if is_qcd_slot and laycol["ptr"].exclude:
+ keep_history = True
+ set_exclude_state(laycol["ptr"], False)
+
+
+ if not keep_history:
+ # clear rto history
+ del qcd_history[qab.view_layer]
+ qab.clear()
+
+ if qab.meta_op:
+ qab.meta_report = "All QCD slots are already enabled."
+
+ else:
+ self.report({"INFO"}, "All QCD slots are already enabled.")
+
+ return {'CANCELLED'}
+
+ internals.qcd_collection_state.clear()
+ internals.qcd_collection_state.update(internals.generate_state(qcd=True))
+
+ else:
+ qab.apply_history()
+
+ qab.finalize()
+
+ return {'FINISHED'}
+
+class EnableAllQCDSlotsIsolated(Operator):
+ '''Toggles between the current state and all enabled (non-QCD collections disabled)'''
+ bl_label = "Enable All QCD Slots Isolated"
+ bl_idname = "view3d.enable_all_qcd_slots_isolated"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ def execute(self, context):
+ global qcd_slots
+ global layer_collections
+ qab = QCDAllBase
+
+ # validate qcd slots
+ if not dict(qcd_slots):
+ self.report({"INFO"}, "No QCD slots.")
+
+ return {'CANCELLED'}
+
+ qab.init(context)
+
+ if qab.locked.objs and not qcd_slots.object_in_slots(qab.orig_active_object):
+ # clear rto history
+ del qcd_history[qab.view_layer]
+ qab.clear()
+
+ self.report({"WARNING"}, "Cannot execute. The active object would be lost.")
+
+ return {'CANCELLED'}
+
+ if not qab.history:
+ keep_history = False
+
+ for laycol in layer_collections.values():
+ is_qcd_slot = qcd_slots.contains(name=laycol["name"])
+
+ qab.history.append(laycol["ptr"].exclude)
+
+ if is_qcd_slot and laycol["ptr"].exclude:
+ keep_history = True
+ set_exclude_state(laycol["ptr"], False)
+
+ if not is_qcd_slot and not laycol["ptr"].exclude:
+ keep_history = True
+ set_exclude_state(laycol["ptr"], True)
+
+
+ if not keep_history:
+ # clear rto history
+ del qcd_history[qab.view_layer]
+ qab.clear()
+
+ self.report({"INFO"}, "All QCD slots are already enabled and isolated.")
+ return {'CANCELLED'}
+
+ internals.qcd_collection_state.clear()
+ internals.qcd_collection_state.update(internals.generate_state(qcd=True))
+
+ else:
+ qab.apply_history()
+
+ qab.finalize()
+
+ return {'FINISHED'}
+
+class DisableAllNonQCDSlots(Operator):
+ '''Toggles between the current state and all non-QCD collections disabled'''
+ bl_label = "Disable All Non QCD Slots"
+ bl_idname = "view3d.disable_all_non_qcd_slots"
+ bl_options = {'REGISTER', 'UNDO'}
+
+
+ def execute(self, context):
+ global qcd_slots
+ global layer_collections
+ qab = QCDAllBase
+
+ # validate qcd slots
+ if not dict(qcd_slots):
+ self.report({"INFO"}, "No QCD slots.")
+
+ return {'CANCELLED'}
+
+ qab.init(context)
+
+ if qab.locked.objs and not qcd_slots.object_in_slots(qab.orig_active_object):
+ # clear rto history
+ del qcd_history[qab.view_layer]
+ qab.clear()
+
+ self.report({"WARNING"}, "Cannot execute. The active object would be lost.")
+
+ return {'CANCELLED'}
+
+ if not qab.history:
+ keep_history = False
+
+ for laycol in layer_collections.values():
+ is_qcd_slot = qcd_slots.contains(name=laycol["name"])
+
+ qab.history.append(laycol["ptr"].exclude)
+
+ if not is_qcd_slot and not laycol["ptr"].exclude:
+ keep_history = True
+ set_exclude_state(laycol["ptr"], True)
+
+ if not keep_history:
+ # clear rto history
+ del qcd_history[qab.view_layer]
+ qab.clear()
+
+ self.report({"INFO"}, "All non QCD slots are already disabled.")
+ return {'CANCELLED'}
+
+ internals.qcd_collection_state.clear()
+ internals.qcd_collection_state.update(internals.generate_state(qcd=True))
+
+ else:
+ qab.apply_history()
+
+ qab.finalize()
+
+ return {'FINISHED'}
+
+
+class DisableAllCollections(Operator):
+ '''Toggles between the current state and all collections disabled'''
+ bl_label = "Disable All collections"
+ bl_idname = "view3d.disable_all_collections"
+ bl_options = {'REGISTER', 'UNDO'}
+
+
+ def execute(self, context):
+ global qcd_slots
+ global layer_collections
+ qab = QCDAllBase
+
+ qab.init(context)
+
+ if qab.locked.objs:
+ # clear rto history
+ del qcd_history[qab.view_layer]
+ qab.clear()
+
+ self.report({"WARNING"}, "Cannot execute. The active object would be lost.")
+
+ return {'CANCELLED'}
+
+ if not qab.history:
+ for laycol in layer_collections.values():
+
+ qab.history.append(laycol["ptr"].exclude)
+
+ if all(qab.history): # no collections are enabled
+ # clear rto history
+ del qcd_history[qab.view_layer]
+ qab.clear()
+
+ self.report({"INFO"}, "All collections are already disabled.")
+ return {'CANCELLED'}
+
+ for laycol in layer_collections.values():
+ laycol["ptr"].exclude = True
+
+ internals.qcd_collection_state.clear()
+ internals.qcd_collection_state.update(internals.generate_state(qcd=True))
+
+ else:
+ qab.apply_history()
+
+ qab.finalize()
+
+ return {'FINISHED'}
+
+
+class SelectAllQCDObjects(Operator):
+ '''Select all objects in QCD slots'''
+ bl_label = "Select All QCD Objects"
+ bl_idname = "view3d.select_all_qcd_objects"
+ bl_options = {'REGISTER', 'UNDO'}
+
+
+ def execute(self, context):
+ global qcd_slots
+ global layer_collections
+ qab = QCDAllBase
+
+ if context.mode != 'OBJECT':
+ return {'CANCELLED'}
+
+ if not context.selectable_objects:
+ if qab.meta_op:
+ qab.meta_report = "No objects present to select."
+
+ else:
+ self.report({"INFO"}, "No objects present to select.")
+
+ return {'CANCELLED'}
+
+ orig_selected_objects = context.selected_objects
+
+ bpy.ops.object.select_all(action='DESELECT')
+
+ for slot, collection_name in qcd_slots:
+ select_collection_objects(
+ is_master_collection=False,
+ collection_name=collection_name,
+ replace=False,
+ nested=False,
+ selection_state=True
+ )
+
+ if context.selected_objects == orig_selected_objects:
+ for slot, collection_name in qcd_slots:
+ select_collection_objects(
+ is_master_collection=False,
+ collection_name=collection_name,
+ replace=False,
+ nested=False,
+ selection_state=False
+ )
+
+
+ return {'FINISHED'}
+
+
+class DiscardQCDHistory(Operator):
+ '''Discard QCD History'''
+ bl_label = "Discard History"
+ bl_idname = "view3d.discard_qcd_history"
+
+ def execute(self, context):
+ global qcd_slots
+ global layer_collections
+ qab = QCDAllBase
+
+ view_layer = context.view_layer.name
+
+ if view_layer in qcd_history:
+ del qcd_history[view_layer]
+ qab.clear()
+
+ return {'FINISHED'}
+
class MoveToQCDSlot(Operator):
'''Move object(s) to QCD slot'''
@@ -209,46 +646,25 @@ class ViewQCDSlot(Operator):
return {'CANCELLED'}
- # get objects not in object mode
- locked_active_obj = context.view_layer.objects.active
- locked_objs = []
- locked_objs_mode = ""
- for obj in context.view_layer.objects:
- if obj.mode != 'OBJECT':
- if obj.mode not in ['POSE', 'WEIGHT_PAINT'] or obj == locked_active_obj:
- locked_objs.append(obj)
- locked_objs_mode = obj.mode
+ orig_active_object = context.view_layer.objects.active
+ locked = get_locked_objs(context)
if self.toggle:
# check if slot can be toggled off.
if not qcd_laycol.exclude:
- for obj in qcd_laycol.collection.objects:
- if obj.mode != 'OBJECT':
- if obj.mode not in ['POSE', 'WEIGHT_PAINT'] or obj == locked_active_obj:
- return {'CANCELLED'}
-
- # get current child exclusion state
- child_exclusion = []
-
- def get_child_exclusion(layer_collection):
- child_exclusion.append([layer_collection, layer_collection.exclude])
-
- apply_to_children(qcd_laycol, get_child_exclusion)
+ if not set(locked.objs).isdisjoint(qcd_laycol.collection.objects):
+ return {'CANCELLED'}
# toggle exclusion of qcd_laycol
- qcd_laycol.exclude = not qcd_laycol.exclude
-
- # set correct state for all children
- for laycol in child_exclusion:
- laycol[0].exclude = laycol[1]
+ set_exclude_state(qcd_laycol, not qcd_laycol.exclude)
else:
# exclude all collections
for laycol in layer_collections.values():
if laycol["name"] != qcd_laycol.name:
# prevent exclusion if locked objects in this collection
- if set(locked_objs).isdisjoint(laycol["ptr"].collection.objects):
+ if set(locked.objs).isdisjoint(laycol["ptr"].collection.objects):
laycol["ptr"].exclude = True
else:
laycol["ptr"].exclude = False
@@ -259,21 +675,22 @@ class ViewQCDSlot(Operator):
# exclude all children
def exclude_all_children(layer_collection):
# prevent exclusion if locked objects in this collection
- if set(locked_objs).isdisjoint(layer_collection.collection.objects):
+ if set(locked.objs).isdisjoint(layer_collection.collection.objects):
layer_collection.exclude = True
else:
layer_collection.exclude = False
apply_to_children(qcd_laycol, exclude_all_children)
+ if orig_active_object:
+ if orig_active_object.name in context.view_layer.objects:
+ context.view_layer.objects.active = orig_active_object
# restore locked objects back to their original mode
# needed because of exclude child updates
- if locked_objs:
- context.view_layer.objects.active = locked_active_obj
-
- if context.view_layer.objects.active:
- bpy.ops.object.mode_set(mode=locked_objs_mode)
+ if context.view_layer.objects.active:
+ if locked.objs:
+ bpy.ops.object.mode_set(mode=locked.mode)
# set layer as active layer collection
context.view_layer.active_layer_collection = qcd_laycol
diff --git a/object_collection_manager/ui.py b/object_collection_manager/ui.py
index 4c1eb077..8d7acc30 100644
--- a/object_collection_manager/ui.py
+++ b/object_collection_manager/ui.py
@@ -35,10 +35,12 @@ from bpy.props import (
from .internals import (
collection_tree,
collection_state,
+ qcd_collection_state,
expanded,
get_max_lvl,
layer_collections,
rto_history,
+ qcd_history,
expand_history,
phantom_history,
copy_buffer,
@@ -52,6 +54,10 @@ from .internals import (
update_qcd_header,
)
+from .qcd_operators import (
+ QCDAllBase,
+)
+
preview_collections = {}
last_icon_theme_text = None
@@ -842,18 +848,70 @@ class SpecialsMenu(Menu):
prop.without_objects = True
+class EnableAllQCDSlotsMenu(Menu):
+ bl_label = "Global QCD Slot Actions"
+ bl_idname = "VIEW3D_MT_CM_qcd_enable_all_menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("view3d.enable_all_qcd_slots")
+ layout.operator("view3d.enable_all_qcd_slots_isolated")
+
+ layout.separator()
+
+ layout.operator("view3d.disable_all_non_qcd_slots")
+ layout.operator("view3d.disable_all_collections")
+
+ if context.mode == 'OBJECT':
+ layout.separator()
+ layout.operator("view3d.select_all_qcd_objects")
+
+ layout.separator()
+
+ layout.operator("view3d.discard_qcd_history")
+
+
def view3d_header_qcd_slots(self, context):
+ global qcd_collection_state
+
+ update_collection_tree(context)
+
+ view_layer = context.view_layer
+
layout = self.layout
idx = 1
- split = layout.split()
+ if qcd_collection_state:
+ view_layer = context.view_layer
+ new_state = generate_state(qcd=True)
+
+ if (new_state["name"] != qcd_collection_state["name"]
+ or new_state["exclude"] != qcd_collection_state["exclude"]
+ or new_state["exclude"] != qcd_collection_state["exclude"]
+ or new_state["qcd"] != qcd_collection_state["qcd"]):
+ if view_layer.name in qcd_history:
+ del qcd_history[view_layer.name]
+ qcd_collection_state.clear()
+ QCDAllBase.clear()
+
+
+ main_row = layout.row(align=True)
+ current_qcd_history = qcd_history.get(context.view_layer.name, [])
+
+ main_row.operator_menu_hold("view3d.enable_all_qcd_slots_meta",
+ text="",
+ icon='HIDE_OFF',
+ depress=bool(current_qcd_history),
+ menu="VIEW3D_MT_CM_qcd_enable_all_menu")
+
+
+ split = main_row.split()
col = split.column(align=True)
row = col.row(align=True)
row.scale_y = 0.5
- update_collection_tree(context)
-
selected_objects = get_move_selection()
active_object = get_move_active()