render_toolbox/properties.py
pullusb 0c6523049f Change conform behavior, now show individual items.
Add store/restore visibility  for items
2025-07-29 15:05:44 +02:00

213 lines
7.3 KiB
Python

import bpy
import os
from bpy.types import PropertyGroup
from bpy.props import (BoolProperty,
EnumProperty,
PointerProperty,
CollectionProperty,
StringProperty)
# region template props
class RT_PG_render_toolbox_props(PropertyGroup):
default_base_path : StringProperty(
name="Base Path Template",
description="Template for file output base path\
\nFolder containing subsequent filepath",
default="//render/{node_label}/",
# options={'SKIP_SAVE'}
)
## Multilayer base path : output on file instead of folder
default_multilayer_base_path : StringProperty(
name="Base Path Template",
description="Template for multilayer file output base paths\
\nOutput of the file sequence",
default="//render/{node_label}/{node_label}_",
# options={'SKIP_SAVE'}
)
### file slots (not used currently)
default_file_slot : StringProperty(
name="File Slot Template",
description="Template for file output file slots\
\nSubpath added to base path for file sequence",
default="{socket_name}/{socket_name}_",
# options={'SKIP_SAVE'}
)
## Multilayer's layer: layer name in EXR instead of subpath to file
default_multilayer_name : StringProperty(
name="Layer Name Template",
description="Template for multilayer file output layer names\
\nLayer name in EXR multilayer file",
default="{socket_name}",
# options={'SKIP_SAVE'}
)
# default_tech_pass_name : StringProperty(
# name="Tech Pass Name Template",
# description="Template for tech pass file output layer names\
# \nLayer name in EXR multilayer file",
# default="tech",
# # options={'SKIP_SAVE'}
# )
# default_crypto_name : StringProperty(
# name="Crypto Pass Name Template",
# description="Template for crypto pass file output layer names\
# \nLayer name in EXR multilayer file",
# default="crypto",
# # options={'SKIP_SAVE'}
# )
# endregion
# region visibility states
def name_search_callback(self, context, edit_text):
"""Search callback for collection names"""
## second arg is not displayed, can be and empty string...
if self.hierarchy_type == 'COLLECTION':
return [(c.name, '') for c in bpy.context.scene.collection.children_recursive if edit_text.lower() in c.name.lower()]
else:
return [(o.name, '') for o in bpy.context.scene.collection.all_objects if edit_text.lower() in o.name.lower()]
class RT_PG_render_toolbox_conform_props(PropertyGroup):
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'
)
## Utility prop : expose and control view layer hide state for active object
## just used for the update (actual bool value means nothing)
## can also use RT_PG_object_visibility from vis_conflict ops
## TODO: make an ops for this instead ?
# active_object_viewlayer_hide : BoolProperty(
# name="Active Object View Layer Hide",
# description="show / hide active object in current viewlayer",
# default=True,
# update=toggle_viewlayer_hide_state
# )
target_name: StringProperty(
name="Root Item",
description="Collection or object to target", # or object name # (useful for excluded collections)
default="",
search=name_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"),
('ALL', "All", "Affect both collections and objects")
],
default='ALL'
)
## Common object and collection
conform_selectability: BoolProperty(
name="Hide Select State",
description="Conform hide select select",
default=False
)
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=False
)
conform_render: BoolProperty(
name="Disable in Renders State",
description="Conform the camera icon (render visibility)",
default=False
)
## 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
)
# endregion
# region reset template functions
def reset_scene_path_templates():
## set default template from environment variable if available, or fallback to preferences defaults
prefs = bpy.context.preferences.addons[__package__].preferences
if not prefs.use_env_base_path_templates:
# set from preferences
bpy.context.scene.render_toolbox.default_base_path = prefs.base_path_template
bpy.context.scene.render_toolbox.default_multilayer_base_path = prefs.base_path_multilayer_template
return
# set from environment variables (fallback to preferences if not set)
exr_base_path_template = os.getenv('RENDERTOOLBOX_EXR_PATH_TEMPLATE')
if exr_base_path_template:
bpy.context.scene.render_toolbox.default_base_path = exr_base_path_template
else:
bpy.context.scene.render_toolbox.default_base_path = prefs.base_path_template
multilayer_base_path_template = os.getenv('RENDERTOOLBOX_MULTILAYER_PATH_TEMPLATE')
if multilayer_base_path_template:
bpy.context.scene.render_toolbox.default_multilayer_base_path = multilayer_base_path_template
else:
bpy.context.scene.render_toolbox.default_multilayer_base_path = prefs.base_path_multilayer_template
# endregion
# region register
classes = (
RT_PG_render_toolbox_props,
RT_PG_render_toolbox_conform_props,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Scene.render_toolbox = bpy.props.PointerProperty(type=RT_PG_render_toolbox_props)
bpy.types.ViewLayer.render_toolbox_conform = bpy.props.PointerProperty(type=RT_PG_render_toolbox_conform_props) # not stored, no need to unregister
def unregister():
del bpy.types.Scene.render_toolbox
for cls in reversed(classes):
bpy.utils.unregister_class(cls)