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:
Diffstat (limited to 'object_collection_manager/operators.py')
-rw-r--r--object_collection_manager/operators.py391
1 files changed, 327 insertions, 64 deletions
diff --git a/object_collection_manager/operators.py b/object_collection_manager/operators.py
index 54f9596b..1e265e52 100644
--- a/object_collection_manager/operators.py
+++ b/object_collection_manager/operators.py
@@ -63,6 +63,9 @@ from .operator_utils import (
swap_rtos,
clear_copy,
clear_swap,
+ link_child_collections_to_parent,
+ remove_collection,
+ select_collection_objects,
)
class SetActiveCollection(Operator):
@@ -71,11 +74,11 @@ class SetActiveCollection(Operator):
bl_idname = "view3d.set_active_collection"
bl_options = {'UNDO'}
- collection_index: IntProperty()
+ is_master_collection: BoolProperty()
collection_name: StringProperty()
def execute(self, context):
- if self.collection_index == -1:
+ if self.is_master_collection:
layer_collection = context.view_layer.layer_collection
else:
@@ -98,7 +101,6 @@ class ExpandAllOperator(Operator):
'''Expand/Collapse all collections'''
bl_label = "Expand All Items"
bl_idname = "view3d.expand_all_items"
- bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
global expand_history
@@ -129,7 +131,6 @@ class ExpandSublevelOperator(Operator):
" * Alt+LMB - Discard history"
)
bl_idname = "view3d.expand_sublevel"
- bl_options = {'REGISTER', 'UNDO'}
expand: BoolProperty()
name: StringProperty()
@@ -215,6 +216,58 @@ class ExpandSublevelOperator(Operator):
return {'FINISHED'}
+class CMSelectCollectionObjectsOperator(Operator):
+ bl_label = "Select All Objects in the Collection"
+ bl_description = (
+ " * LMB - Select all objects in collection.\n"
+ " * Shift+LMB - Add/Remove collection objects from selection.\n"
+ " * Ctrl+LMB - Isolate nested selection.\n"
+ " * Ctrl+Shift+LMB - Add/Remove nested from selection"
+ )
+ bl_idname = "view3d.select_collection_objects"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ is_master_collection: BoolProperty()
+ collection_name: StringProperty()
+
+ def invoke(self, context, event):
+ modifiers = get_modifiers(event)
+
+ if modifiers == {"shift"}:
+ select_collection_objects(
+ is_master_collection=self.is_master_collection,
+ collection_name=self.collection_name,
+ replace=False,
+ nested=False
+ )
+
+ elif modifiers == {"ctrl"}:
+ select_collection_objects(
+ is_master_collection=self.is_master_collection,
+ collection_name=self.collection_name,
+ replace=True,
+ nested=True
+ )
+
+ elif modifiers == {"ctrl", "shift"}:
+ select_collection_objects(
+ is_master_collection=self.is_master_collection,
+ collection_name=self.collection_name,
+ replace=False,
+ nested=True
+ )
+
+ else:
+ select_collection_objects(
+ is_master_collection=self.is_master_collection,
+ collection_name=self.collection_name,
+ replace=True,
+ nested=False
+ )
+
+ return {'FINISHED'}
+
+
class CMSetCollectionOperator(Operator):
bl_label = "Set Object Collection"
bl_description = (
@@ -224,11 +277,11 @@ class CMSetCollectionOperator(Operator):
bl_idname = "view3d.set_collection"
bl_options = {'REGISTER', 'UNDO'}
- collection_index: IntProperty()
+ is_master_collection: BoolProperty()
collection_name: StringProperty()
def invoke(self, context, event):
- if self.collection_index == 0:
+ if self.is_master_collection:
target_collection = context.view_layer.layer_collection.collection
else:
@@ -248,7 +301,7 @@ class CMSetCollectionOperator(Operator):
# make sure there is an active object
if not active_object:
- active_object = selected_objects[0]
+ active_object = tuple(selected_objects)[0]
# check if in collection
if not active_object.name in target_collection.objects:
@@ -856,6 +909,211 @@ class CMUnDisableRenderAllOperator(Operator):
return {'FINISHED'}
+class CMHoldoutOperator(Operator):
+ bl_label = "[HH] Holdout"
+ bl_description = (
+ " * Shift+LMB - Isolate/Restore.\n"
+ " * Shift+Ctrl+LMB - Isolate nested/Restore.\n"
+ " * Ctrl+LMB - Toggle nested.\n"
+ " * Alt+LMB - Discard history"
+ )
+ bl_idname = "view3d.holdout_collection"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ name: StringProperty()
+
+ # static class var
+ isolated = False
+
+ def invoke(self, context, event):
+ global rto_history
+ cls = CMHoldoutOperator
+
+ modifiers = get_modifiers(event)
+ view_layer = context.view_layer.name
+ laycol_ptr = layer_collections[self.name]["ptr"]
+
+ if not view_layer in rto_history["holdout"]:
+ rto_history["holdout"][view_layer] = {"target": "", "history": []}
+
+ if modifiers == {"alt"}:
+ del rto_history["holdout"][view_layer]
+ cls.isolated = False
+
+ elif modifiers == {"shift"}:
+ isolate_rto(cls, self, view_layer, "holdout")
+
+ elif modifiers == {"ctrl"}:
+ toggle_children(self, view_layer, "holdout")
+
+ cls.isolated = False
+
+ elif modifiers == {"ctrl", "shift"}:
+ isolate_rto(cls, self, view_layer, "holdout", children=True)
+
+ else:
+ # toggle holdout
+
+ # reset holdout history
+ del rto_history["holdout"][view_layer]
+
+ # toggle holdout of collection in viewport
+ laycol_ptr.holdout = not laycol_ptr.holdout
+
+ cls.isolated = False
+
+ # reset holdout all history
+ if view_layer in rto_history["holdout_all"]:
+ del rto_history["holdout_all"][view_layer]
+
+ return {'FINISHED'}
+
+
+class CMUnHoldoutAllOperator(Operator):
+ bl_label = "[HH Global] Holdout"
+ bl_description = (
+ " * LMB - Enable all/Restore.\n"
+ " * Shift+LMB - Invert.\n"
+ " * Ctrl+LMB - Copy/Paste RTOs.\n"
+ " * Ctrl+Alt+LMB - Swap RTOs.\n"
+ " * Alt+LMB - Discard history"
+ )
+ bl_idname = "view3d.un_holdout_all_collections"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ def invoke(self, context, event):
+ global rto_history
+
+ view_layer = context.view_layer.name
+ modifiers = get_modifiers(event)
+
+ if not view_layer in rto_history["holdout_all"]:
+ rto_history["holdout_all"][view_layer] = []
+
+ if modifiers == {"alt"}:
+ # clear all states
+ del rto_history["holdout_all"][view_layer]
+ clear_copy("holdout")
+ clear_swap("holdout")
+
+ elif modifiers == {"ctrl"}:
+ copy_rtos(view_layer, "holdout")
+
+ elif modifiers == {"ctrl", "alt"}:
+ swap_rtos(view_layer, "holdout")
+
+ elif modifiers == {"shift"}:
+ invert_rtos(view_layer, "holdout")
+
+ else:
+ activate_all_rtos(view_layer, "holdout")
+
+ return {'FINISHED'}
+
+
+class CMIndirectOnlyOperator(Operator):
+ bl_label = "[IO] Indirect Only"
+ bl_description = (
+ " * Shift+LMB - Isolate/Restore.\n"
+ " * Shift+Ctrl+LMB - Isolate nested/Restore.\n"
+ " * Ctrl+LMB - Toggle nested.\n"
+ " * Alt+LMB - Discard history"
+ )
+ bl_idname = "view3d.indirect_only_collection"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ name: StringProperty()
+
+ # static class var
+ isolated = False
+
+ def invoke(self, context, event):
+ global rto_history
+ cls = CMIndirectOnlyOperator
+
+ modifiers = get_modifiers(event)
+ view_layer = context.view_layer.name
+ laycol_ptr = layer_collections[self.name]["ptr"]
+
+ if not view_layer in rto_history["indirect"]:
+ rto_history["indirect"][view_layer] = {"target": "", "history": []}
+
+
+ if modifiers == {"alt"}:
+ del rto_history["indirect"][view_layer]
+ cls.isolated = False
+
+ elif modifiers == {"shift"}:
+ isolate_rto(cls, self, view_layer, "indirect")
+
+ elif modifiers == {"ctrl"}:
+ toggle_children(self, view_layer, "indirect")
+
+ cls.isolated = False
+
+ elif modifiers == {"ctrl", "shift"}:
+ isolate_rto(cls, self, view_layer, "indirect", children=True)
+
+ else:
+ # toggle indirect only
+
+ # reset indirect history
+ del rto_history["indirect"][view_layer]
+
+ # toggle indirect only of collection
+ laycol_ptr.indirect_only = not laycol_ptr.indirect_only
+
+ cls.isolated = False
+
+ # reset indirect all history
+ if view_layer in rto_history["indirect_all"]:
+ del rto_history["indirect_all"][view_layer]
+
+ return {'FINISHED'}
+
+
+class CMUnIndirectOnlyAllOperator(Operator):
+ bl_label = "[IO Global] Indirect Only"
+ bl_description = (
+ " * LMB - Enable all/Restore.\n"
+ " * Shift+LMB - Invert.\n"
+ " * Ctrl+LMB - Copy/Paste RTOs.\n"
+ " * Ctrl+Alt+LMB - Swap RTOs.\n"
+ " * Alt+LMB - Discard history"
+ )
+ bl_idname = "view3d.un_indirect_only_all_collections"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ def invoke(self, context, event):
+ global rto_history
+
+ view_layer = context.view_layer.name
+ modifiers = get_modifiers(event)
+
+ if not view_layer in rto_history["indirect_all"]:
+ rto_history["indirect_all"][view_layer] = []
+
+ if modifiers == {"alt"}:
+ # clear all states
+ del rto_history["indirect_all"][view_layer]
+ clear_copy("indirect")
+ clear_swap("indirect")
+
+ elif modifiers == {"ctrl"}:
+ copy_rtos(view_layer, "indirect")
+
+ elif modifiers == {"ctrl", "alt"}:
+ swap_rtos(view_layer, "indirect")
+
+ elif modifiers == {"shift"}:
+ invert_rtos(view_layer, "indirect")
+
+ else:
+ activate_all_rtos(view_layer, "indirect")
+
+ return {'FINISHED'}
+
+
class CMRemoveCollectionOperator(Operator):
'''Remove Collection'''
bl_label = "Remove Collection"
@@ -869,12 +1127,9 @@ class CMRemoveCollectionOperator(Operator):
global expand_history
global qcd_slots
- cm = context.scene.collection_manager
-
laycol = layer_collections[self.collection_name]
collection = laycol["ptr"].collection
parent_collection = laycol["parent"]["ptr"].collection
- selected_row_name = cm.cm_list_collection[cm.cm_list_index].name
# shift all objects in this collection to the parent collection
@@ -885,77 +1140,69 @@ class CMRemoveCollectionOperator(Operator):
# shift all child collections to the parent collection preserving view layer RTOs
if collection.children:
- # store view layer RTOs for all children of the to be deleted collection
- child_states = {}
- def get_child_states(layer_collection):
- child_states[layer_collection.name] = (layer_collection.exclude,
- layer_collection.hide_viewport,
- layer_collection.holdout,
- layer_collection.indirect_only)
-
- apply_to_children(laycol["ptr"], get_child_states)
-
- # link any subcollections of the to be deleted collection to it's parent
- for subcollection in collection.children:
- parent_collection.children.link(subcollection)
-
- # apply the stored view layer RTOs to the newly linked collections and their
- # children
- def restore_child_states(layer_collection):
- state = child_states.get(layer_collection.name)
+ link_child_collections_to_parent(laycol, collection, parent_collection)
- if state:
- layer_collection.exclude = state[0]
- layer_collection.hide_viewport = state[1]
- layer_collection.holdout = state[2]
- layer_collection.indirect_only = state[3]
+ # remove collection, update references, and update tree view
+ remove_collection(laycol, collection, context)
- apply_to_children(laycol["parent"]["ptr"], restore_child_states)
-
-
- # remove collection, update expanded, and update tree view
- bpy.data.collections.remove(collection)
- expanded.discard(self.collection_name)
+ return {'FINISHED'}
- if expand_history["target"] == self.collection_name:
- expand_history["target"] = ""
- if self.collection_name in expand_history["history"]:
- expand_history["history"].remove(self.collection_name)
+class CMRemoveEmptyCollectionsOperator(Operator):
+ bl_label = "Remove Empty Collections"
+ bl_idname = "view3d.remove_empty_collections"
+ bl_options = {'UNDO'}
- update_property_group(context)
+ without_objects: BoolProperty()
+ @classmethod
+ def description(cls, context, properties):
+ if properties.without_objects:
+ tooltip = (
+ "Purge All Collections Without Objects.\n"
+ "Deletes all collections that don't contain objects even if they have subcollections"
+ )
- # update selected row
- laycol = layer_collections.get(selected_row_name, None)
- if laycol:
- cm.cm_list_index = laycol["row_index"]
+ else:
+ tooltip = (
+ "Remove Empty Collections.\n"
+ "Delete collections that don't have any subcollections or objects"
+ )
- elif len(cm.cm_list_collection) == cm.cm_list_index:
- cm.cm_list_index -= 1
+ return tooltip
- if cm.cm_list_index > -1:
- name = cm.cm_list_collection[cm.cm_list_index].name
- laycol = layer_collections[name]
- while not laycol["visible"]:
- laycol = laycol["parent"]
+ def execute(self, context):
+ global rto_history
+ global expand_history
+ global qcd_slots
- cm.cm_list_index = laycol["row_index"]
+ if self.without_objects:
+ empty_collections = [laycol["name"]
+ for laycol in layer_collections.values()
+ if not laycol["ptr"].collection.objects]
+ else:
+ empty_collections = [laycol["name"]
+ for laycol in layer_collections.values()
+ if not laycol["children"] and
+ not laycol["ptr"].collection.objects]
+ for name in empty_collections:
+ laycol = layer_collections[name]
+ collection = laycol["ptr"].collection
+ parent_collection = laycol["parent"]["ptr"].collection
- # update qcd
- if qcd_slots.contains(name=self.collection_name):
- qcd_slots.del_slot(name=self.collection_name)
+ # link all child collections to the parent collection preserving view layer RTOs
+ if collection.children:
+ link_child_collections_to_parent(laycol, collection, parent_collection)
- if self.collection_name in qcd_slots.overrides:
- qcd_slots.overrides.remove(self.collection_name)
+ # remove collection, update references, and update tree view
+ remove_collection(laycol, collection, context)
- # reset history
- for rto in rto_history.values():
- rto.clear()
+ self.report({"INFO"}, f"Removed {len(empty_collections)} collections")
return {'FINISHED'}
+
rename = [False]
class CMNewCollectionOperator(Operator):
bl_label = "Add New Collection"
@@ -1070,6 +1317,8 @@ class CMPhantomModeOperator(Operator):
"hide": layer_collection.hide_viewport,
"disable": layer_collection.collection.hide_viewport,
"render": layer_collection.collection.hide_render,
+ "holdout": layer_collection.holdout,
+ "indirect": layer_collection.indirect_only,
}
apply_to_children(view_layer.layer_collection, save_visibility_state)
@@ -1090,6 +1339,8 @@ class CMPhantomModeOperator(Operator):
layer_collection.hide_viewport = phantom_laycol["hide"]
layer_collection.collection.hide_viewport = phantom_laycol["disable"]
layer_collection.collection.hide_render = phantom_laycol["render"]
+ layer_collection.holdout = phantom_laycol["holdout"]
+ layer_collection.indirect_only = phantom_laycol["indirect"]
apply_to_children(view_layer.layer_collection, restore_visibility_state)
@@ -1108,3 +1359,15 @@ class CMPhantomModeOperator(Operator):
return {'FINISHED'}
+
+
+class CMApplyPhantomModeOperator(Operator):
+ '''Apply changes and quit Phantom Mode'''
+ bl_label = "Apply Phantom Mode"
+ bl_idname = "view3d.apply_phantom_mode"
+
+ def execute(self, context):
+ cm = context.scene.collection_manager
+ cm.in_phantom_mode = False
+
+ return {'FINISHED'}