render_toolbox/operators/conform_collection_hierarchy.py
2025-07-24 14:46:22 +02:00

181 lines
6.7 KiB
Python

import bpy
from bpy.types import Operator
from bpy.props import (BoolProperty,
EnumProperty,
PointerProperty,
CollectionProperty,
StringProperty)
from .. import fn
def collection_search_callback(self, context, edit_text):
"""Search callback for collection names"""
## second arg is not displayed, can be and empty string...
return [(c.name, str(c.session_uid)) for c in bpy.context.scene.collection.children_recursive if edit_text.lower() in c.name.lower()]
class RT_OT_conform_collection_hierarchy(Operator):
bl_idname = "rt.conform_collection_hierarchy"
bl_label = "Conform Collection Hierarchy"
bl_description = "Chek and conform collection visibility hierarchy settings\
\nCan affect collection, objects or both"
bl_options = {"REGISTER", "UNDO"}
hierarchy_type: EnumProperty(
name="Hierarchy Type",
description="Choose whether to conform object hierarchy or collection hierarchy",
items=[
('COLLECTION', "Collection Hierarchy", "Conform collection hierarchy")
('OBJECT', "Object Hierarchy", "Conform object hierarchy"),
],
default='COLLECTION'
)
target_collection: StringProperty(
name="Target Collecton",
description="Collection to target", # or object name # (useful for excluded collections)
default="",
search=collection_search_callback
## basic collection fetch:
# search=lambda self, context, edit_text: [(c.name, '') for c in bpy.context.scene.collection.children_recursive if edit_text.lower() in c.name.lower()]
)
affect_target: EnumProperty(
name="Affect Target",
description="Choose whether to affect collections, objects, or both",
items=[
('COLLECTION', "Collection", "Affect collections only"),
('OBJECT', "Object", "Affect objects only"),
('BOTH', "Both", "Affect both collections and objects")
],
default='BOTH'
)
## Common object and collection
conform_selectability: BoolProperty(
name="Hide Select State",
description="Conform hide select select",
default=True
)
conform_viewlayer: BoolProperty(
name="Hide in Viewlayer State",
description="Conform viewlayer temporary hide",
default=True
)
conform_viewport: BoolProperty(
name="Disable in Viewports State",
description="Conform the monitor icon (global viewport disable)",
default=True
)
conform_render: BoolProperty(
name="Disable in Renders State",
description="Conform the camera icon (render visibility)",
default=True
)
## Specific to collections
conform_exclude: BoolProperty(
name="Exclude View Layer State",
description="Conform the exclude from view layer",
default=True
)
conform_holdout: BoolProperty(
name="Holdout State",
description="Conform Collection Holdout State",
default=True
)
conform_use_indirect: BoolProperty(
name="Indirect Only State",
description="Conform Collection Indirect Only",
default=True
)
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self, width=400)
def draw(self, context):
layout = self.layout
# if self.hierarchy_type == 'COLLECTION':
layout.prop(self, "Get Collection by name")
layout.prop(self, "affect_target", text="Target Items")
# layout.prop(self, "target_name", text="Target Collection")
## Works with 'children' (root hierarchy), but not with 'children_recursive'
# layout.prop_search(self, "target_name", bpy.context.scene.collection, "children", text="Target Collection")
target_collection = None
if not self.target_collection:
target_collection = context.collection
return
if not self.target_collection:
layout.label(text="Select a collection or search by name", icon='INFO')
return
root_col = next((c for c in context.scene.collection.children_recursive if c.name == target_collection), None)
if not root_col:
layout.label(text=f"Error: Collection '{target_collection}' not found", icon='ERROR')
return
vlc_root = fn.get_view_layer_collection(root_col)
if not vlc_root:
layout.label(text=f"Error: Viewlayer Collection '{target_collection}' not found", icon='ERROR')
return
## TODO: Show current state of the selected root collection
col = layout.column(align=True)
row = layout.row(align=True)
row.prop(vlc_root, "exclude", text="", emboss=False)
row.prop(root_col, "hide_select", text="", emboss=False)
row.prop(vlc_root, "hide_viewport", text="", emboss=False)
row.prop(root_col, "hide_viewport", text="", emboss=False)
row.prop(root_col, "hide_render", text="", emboss=False)
row.prop(vlc_root, "holdout", text="", emboss=False)
row.prop(vlc_root, "indirect_only", text="", emboss=False)
col = layout.column(align=True)
col.label(text="Parameter To Conform:")
row = col.row(align=True)
## Same order, greyout unused options
collec_row = row.row(align=True)
collec_row.prop(self, "conform_exclude", text="", icon='CHECKBOX_HLT') # Exclude from View Layer
collec_row.active = self.affect_target != 'OBJECT'
## Object and collections
row.prop(self, "conform_selectability", text="", icon='RESTRICT_SELECT_OFF') # Hide Select
row.prop(self, "conform_viewlayer", text="", icon='HIDE_OFF') # Hide in current viewlayer (eye)
row.prop(self, "conform_viewport", text="", icon='RESTRICT_VIEW_OFF') # Disable in Viewports
row.prop(self, "conform_render", text="", icon='RESTRICT_RENDER_OFF') # Disable in Renders
## Specific to collections
collec_row = row.row(align=True)
collec_row.prop(self, "conform_holdout", text="", icon='HOLDOUT_OFF') # Holdout
collec_row.prop(self, "conform_use_indirect", text="", icon='INDIRECT_ONLY_OFF') # Indirect Only
collec_row.active = self.affect_target != 'OBJECT'
## TODO: Show live wich object / collection are affected by the conformation action when executed.
sub_vlc = fn.get_collection_children_recursive(vlc_root)
def execute(self, context):
return {'FINISHED'}
# endregion
def register():
bpy.utils.register_class(RT_OT_conform_collection_hierarchy)
def unregister():
bpy.utils.unregister_class(RT_OT_conform_collection_hierarchy)