diff options
author | Ryan Inch <mythologylover75@gmail.com> | 2020-09-26 10:20:53 +0300 |
---|---|---|
committer | Ryan Inch <mythologylover75@gmail.com> | 2020-09-26 10:20:53 +0300 |
commit | bf176041da95d4b07d74727acb78f7cf6a46785e (patch) | |
tree | 23ac07c7a260172f8767c2f31c63404d9cf61870 | |
parent | 3d2076556a73af15779fc06630a3254fd584af02 (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__.py | 2 | ||||
-rw-r--r-- | object_collection_manager/internals.py | 16 | ||||
-rw-r--r-- | object_collection_manager/operator_utils.py | 46 | ||||
-rw-r--r-- | object_collection_manager/operators.py | 19 | ||||
-rw-r--r-- | object_collection_manager/qcd_init.py | 54 | ||||
-rw-r--r-- | object_collection_manager/qcd_operators.py | 483 | ||||
-rw-r--r-- | object_collection_manager/ui.py | 64 |
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() |