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
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.
-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()