diff options
author | Ryan Inch <mythologylover75@gmail.com> | 2020-04-06 00:08:02 +0300 |
---|---|---|
committer | Ryan Inch <mythologylover75@gmail.com> | 2020-04-06 00:08:02 +0300 |
commit | 5c9aaca64d7c54aaa09684d64542c59b896c5f11 (patch) | |
tree | f0ff51cec5b70e5a91d0a6318d086025944f32d7 | |
parent | ba19a9a74770a39fb23d96a99a0abe30d154a8f2 (diff) |
Collection Manager: Update Move Operator. Task: T69577
Updates the Collection Manager's Move Operator with improvements
developed for QCD.
-rw-r--r-- | object_collection_manager/__init__.py | 23 | ||||
-rw-r--r-- | object_collection_manager/internals.py | 27 | ||||
-rw-r--r-- | object_collection_manager/operators.py | 74 | ||||
-rw-r--r-- | object_collection_manager/qcd_init.py | 20 | ||||
-rw-r--r-- | object_collection_manager/qcd_operators.py | 32 | ||||
-rw-r--r-- | object_collection_manager/ui.py | 18 |
6 files changed, 128 insertions, 66 deletions
diff --git a/object_collection_manager/__init__.py b/object_collection_manager/__init__.py index 2aa38c5b..1f3fdef1 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,4,12), + "version": (2,5,0), "blender": (2, 80, 0), "location": "View3D - Object Mode (Shortcut - M)", "warning": '', # used for warning icon and text in addons panel @@ -52,6 +52,7 @@ else: from . import preferences import bpy +from bpy.app.handlers import persistent from bpy.types import PropertyGroup from bpy.props import ( CollectionProperty, @@ -108,7 +109,19 @@ classes = ( CollectionManagerProperties, ) +@persistent +def depsgraph_update_post_handler(dummy): + if internals.move_triggered: + internals.move_triggered = False + return + internals.move_selection.clear() + internals.move_active = None + +@persistent +def undo_redo_post_handler(dummy): + internals.move_selection.clear() + internals.move_active = None def register(): for cls in classes: @@ -122,6 +135,10 @@ def register(): kmi = km.keymap_items.new('view3d.collection_manager', 'M', 'PRESS') addon_keymaps.append((km, kmi)) + bpy.app.handlers.depsgraph_update_post.append(depsgraph_update_post_handler) + bpy.app.handlers.undo_post.append(undo_redo_post_handler) + bpy.app.handlers.redo_post.append(undo_redo_post_handler) + if bpy.context.preferences.addons[__package__].preferences.enable_qcd: qcd_init.register_qcd() @@ -132,6 +149,10 @@ def unregister(): for cls in classes: bpy.utils.unregister_class(cls) + bpy.app.handlers.depsgraph_update_post.remove(depsgraph_update_post_handler) + bpy.app.handlers.undo_post.remove(undo_redo_post_handler) + bpy.app.handlers.redo_post.remove(undo_redo_post_handler) + del bpy.types.Scene.collection_manager # remove keymaps when add-on is deactivated diff --git a/object_collection_manager/internals.py b/object_collection_manager/internals.py index 292d8cfd..594756c9 100644 --- a/object_collection_manager/internals.py +++ b/object_collection_manager/internals.py @@ -32,6 +32,10 @@ from bpy.props import ( IntProperty, ) +move_triggered = False +move_selection = [] +move_active = None + layer_collections = {} collection_tree = [] collection_state = {} @@ -186,6 +190,7 @@ def update_col_name(self, context): self.last_name = self.name + def update_qcd_slot(self, context): global qcd_slots @@ -357,6 +362,7 @@ def get_modifiers(event): return set(modifiers) + def generate_state(): global layer_collections @@ -380,6 +386,27 @@ def generate_state(): return state +def get_move_selection(): + global move_selection + + if not move_selection: + move_selection = [obj.name for obj in bpy.context.selected_objects] + + return [bpy.data.objects[name] for name in move_selection] + + +def get_move_active(): + 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 [obj.name for obj in get_move_selection()]: + move_active = None + + return bpy.data.objects[move_active] if move_active else None + class CMSendReport(Operator): bl_label = "Send Report" diff --git a/object_collection_manager/operators.py b/object_collection_manager/operators.py index 30cf17a9..1094e578 100644 --- a/object_collection_manager/operators.py +++ b/object_collection_manager/operators.py @@ -32,12 +32,16 @@ from bpy.props import ( IntProperty ) +from . import internals + from .internals import ( expanded, layer_collections, qcd_slots, update_property_group, get_modifiers, + get_move_selection, + get_move_active, send_report, ) @@ -187,30 +191,74 @@ class CMSetCollectionOperator(Operator): collection_name: StringProperty() def invoke(self, context, event): - collection = layer_collections[self.collection_name]["ptr"].collection + laycol = layer_collections[self.collection_name] + target_collection = laycol["ptr"].collection + + selected_objects = get_move_selection() + active_object = get_move_active() + + internals.move_triggered = True + + if not selected_objects: + return {'CANCELLED'} if event.shift: - # add object to collection + # add objects to collection + + # make sure there is an active object + if not active_object: + active_object = selected_objects[0] # check if in collection - if context.active_object.name not in collection.objects: + if not active_object.name in target_collection.objects: # add to collection - bpy.ops.object.link_to_collection(collection_index=self.collection_index) + for obj in selected_objects: + if obj.name not in target_collection.objects: + target_collection.objects.link(obj) else: - # check and disallow removing from all collections - for obj in context.selected_objects: - if len(obj.users_collection) == 1: - send_report("Error removing 1 or more objects from this collection.\nObjects would be left without a collection") + errors = False + + # remove from collections + for obj in selected_objects: + if obj.name in target_collection.objects: + + # disallow removing if only one + if len(obj.users_collection) == 1: + errors = True + continue + + # remove from collection + target_collection.objects.unlink(obj) - return {'FINISHED'} + if errors: + send_report("Error removing 1 or more objects from this collection.\nObjects would be left without a collection") - # remove from collection - bpy.ops.collection.objects_remove(collection=collection.name) else: - # move object to collection - bpy.ops.object.move_to_collection(collection_index=self.collection_index) + # move objects to collection + for obj in selected_objects: + if obj.name not in target_collection.objects: + target_collection.objects.link(obj) + + # remove from all other collections + for collection in obj.users_collection: + if collection.name != target_collection.name: + collection.objects.unlink(obj) + + # update the active object if needed + if not context.active_object: + try: + context.view_layer.objects.active = active_object + + except RuntimeError: # object not in visible collection + pass + + # update qcd header UI + cm = bpy.context.scene.collection_manager + cm.update_header.clear() + new_update_header = cm.update_header.add() + new_update_header.name = "updated" return {'FINISHED'} diff --git a/object_collection_manager/qcd_init.py b/object_collection_manager/qcd_init.py index 87cbcd16..0bef6e44 100644 --- a/object_collection_manager/qcd_init.py +++ b/object_collection_manager/qcd_init.py @@ -21,20 +21,6 @@ qcd_classes = ( ) @persistent -def depsgraph_update_post_handler(dummy): - if qcd_operators.move_triggered: - qcd_operators.move_triggered = False - return - - qcd_operators.move_selection.clear() - qcd_operators.move_active = None - -@persistent -def undo_redo_post_handler(dummy): - qcd_operators.move_selection.clear() - qcd_operators.move_active = None - -@persistent def save_internal_data(dummy): cm = bpy.context.scene.collection_manager @@ -66,9 +52,6 @@ def register_qcd(): kmi = km.keymap_items.new('view3d.qcd_move_widget', 'V', 'PRESS') addon_qcd_keymaps.append((km, kmi)) - bpy.app.handlers.depsgraph_update_post.append(depsgraph_update_post_handler) - bpy.app.handlers.undo_post.append(undo_redo_post_handler) - bpy.app.handlers.redo_post.append(undo_redo_post_handler) bpy.app.handlers.save_pre.append(save_internal_data) bpy.app.handlers.load_post.append(load_internal_data) @@ -122,9 +105,6 @@ def unregister_qcd(): for cls in qcd_classes: bpy.utils.unregister_class(cls) - bpy.app.handlers.depsgraph_update_post.remove(depsgraph_update_post_handler) - bpy.app.handlers.undo_post.remove(undo_redo_post_handler) - bpy.app.handlers.redo_post.remove(undo_redo_post_handler) bpy.app.handlers.save_pre.remove(save_internal_data) bpy.app.handlers.load_post.remove(load_internal_data) diff --git a/object_collection_manager/qcd_operators.py b/object_collection_manager/qcd_operators.py index 98d3b455..a7a6079e 100644 --- a/object_collection_manager/qcd_operators.py +++ b/object_collection_manager/qcd_operators.py @@ -30,39 +30,19 @@ from bpy.props import ( IntProperty ) +from . import internals + from .internals import ( layer_collections, qcd_slots, update_property_group, get_modifiers, + get_move_selection, + get_move_active ) from .operators import rto_history -move_triggered = False -move_selection = [] -move_active = None - -def get_move_selection(): - global move_selection - - if not move_selection: - move_selection = [obj.name for obj in bpy.context.selected_objects] - - return [bpy.data.objects[name] for name in move_selection] - -def get_move_active(): - 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 [obj.name for obj in get_move_selection()]: - move_active = None - - return bpy.data.objects[move_active] if move_active else None - class MoveToQCDSlot(Operator): '''Move object(s) to QCD slot''' @@ -76,11 +56,11 @@ class MoveToQCDSlot(Operator): def execute(self, context): global qcd_slots global layer_collections - global move_triggered selected_objects = get_move_selection() active_object = get_move_active() - move_triggered = True + internals.move_triggered = True + qcd_laycol = None slot_name = qcd_slots.get_name(self.slot) diff --git a/object_collection_manager/ui.py b/object_collection_manager/ui.py index a90a619f..2209f18f 100644 --- a/object_collection_manager/ui.py +++ b/object_collection_manager/ui.py @@ -36,6 +36,8 @@ from .internals import ( update_collection_tree, update_property_group, generate_state, + get_move_selection, + get_move_active ) from .operators import ( @@ -46,8 +48,6 @@ from .operators import ( phantom_history, ) -from . import qcd_operators - preview_collections = {} last_icon_theme_text = None @@ -353,6 +353,8 @@ class CM_UL_items(UIList): view_layer = context.view_layer laycol = layer_collections[item.name] collection = laycol["ptr"].collection + selected_objects = get_move_selection() + active_object = get_move_active() split = layout.split(factor=0.96) row = split.row(align=True) @@ -409,9 +411,13 @@ class CM_UL_items(UIList): icon = 'MESH_CUBE' - if len(context.selected_objects) > 0 and context.active_object: - if context.active_object.name in collection.objects: + if selected_objects: + if active_object and active_object.name in collection.objects: icon = 'SNAP_VOLUME' + + elif not set(selected_objects).isdisjoint(collection.objects): + icon = 'STICKY_UVS_LOC' + else: row_setcol.enabled = False @@ -588,8 +594,8 @@ def view3d_header_qcd_slots(self, context): if qcd_slot_name: qcd_laycol = layer_collections[qcd_slot_name]["ptr"] collection_objects = qcd_laycol.collection.objects - selected_objects = qcd_operators.get_move_selection() - active_object = qcd_operators.get_move_active() + selected_objects = get_move_selection() + active_object = get_move_active() icon_value = 0 |