From 4feebf0a060c4d06a72eb8969a58a744d5e2f9e1 Mon Sep 17 00:00:00 2001 From: pullusb Date: Fri, 25 Jul 2025 10:55:04 +0200 Subject: [PATCH] Add preferences with default templates with option to set them from env (falling back to prefs) at startup change default templates to use label instead of name --- __init__.py | 3 +- operators/outputs_setup.py | 2 +- operators/utility.py | 16 +++---- preferences.py | 91 ++++++++++++++++++++++++++++++++++++++ properties.py | 23 +++++++--- 5 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 preferences.py diff --git a/__init__.py b/__init__.py index 5a74912..4c27b3e 100755 --- a/__init__.py +++ b/__init__.py @@ -14,12 +14,13 @@ bl_info = { from . import properties from . import operators from . import ui +from . import preferences modules = ( properties, operators, ui, - # prefs, + preferences, ) def register(): diff --git a/operators/outputs_setup.py b/operators/outputs_setup.py index dae85ab..e5d7613 100755 --- a/operators/outputs_setup.py +++ b/operators/outputs_setup.py @@ -402,7 +402,7 @@ class RT_OT_create_output_layers(bpy.types.Operator): row.prop(self, 'use_base_path_templates') if self.use_base_path_templates: - row.operator("rt.set_env_settings", text='', icon='FILE_REFRESH') + row.operator("rt.reset_path_templates", text='', icon='FILE_REFRESH') row.separator() row.operator("rt.info_note", text='', icon='INFO').text = """Format the base path using templates. diff --git a/operators/utility.py b/operators/utility.py index ea77067..84b8575 100644 --- a/operators/utility.py +++ b/operators/utility.py @@ -87,24 +87,24 @@ class RT_OT_info_note(Operator): return {"FINISHED"} # Not registered yet -class RT_set_env_settings(bpy.types.Operator): - """manually reset environnement settings""" - bl_idname = "rt.set_env_settings" - bl_label = "Reset Templates From Env" - bl_description = "Reset Render Toolbox templates from environment variables" +class RT_reset_path_templates(bpy.types.Operator): + """manually reset template to preferences or env settings""" + bl_idname = "rt.reset_path_templates" + bl_label = "Reset Render Toolbox Templates" + bl_description = "Reset Render Toolbox templates from preferences or environment variables if applicable" bl_options = {"REGISTER", "UNDO", "INTERNAL"} # mode : bpy.props.StringProperty(default='ALL', options={'SKIP_SAVE'}) # 'HIDDEN', def execute(self, context): - from ..properties import set_env_properties - set_env_properties() + from ..properties import reset_scene_path_templates + reset_scene_path_templates() return {'FINISHED'} classes = ( RT_OT_select_object_by_name, RT_OT_info_note, -RT_set_env_settings, +RT_reset_path_templates, ) diff --git a/preferences.py b/preferences.py new file mode 100644 index 0000000..c9519b0 --- /dev/null +++ b/preferences.py @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +import bpy +import os + +from bpy.props import (FloatProperty, + BoolProperty, + EnumProperty, + StringProperty, + IntProperty, + PointerProperty, + FloatVectorProperty) + +from bpy.app.handlers import persistent + +# region Preferences + +class RT_prefs(bpy.types.AddonPreferences): + bl_idname = __package__ + + use_env_base_path_templates : BoolProperty( + name="Use Environment Base Path Templates", + description="Use environmenet variables to set base path for file output templates\ + \nFollowing env variable are available:\ + \nRENDERTOOLBOX_EXR_PATH_TEMPLATE fo single base path file output\ + \nRENDERTOOLBOX_MULTILAYER_PATH_TEMPLATE for multilayer base path file output", + default=True, + ) + + base_path_template: StringProperty( + name="Base Path Template", + description="Template for base paths", + default="//render/{node_label}/", + ) + + base_path_multilayer_template: StringProperty( + name="Base Path Multilayer Template", + description="Template for base paths of multilayer files", + default="//render/{node_label}/{node_label}_", + ) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + layout.prop(self, "use_env_base_path_templates", text="Use Environment Base Path Templates") + col = layout.column() + # col.active = not self.use_env_base_path_templates + col.prop(self, "base_path_template", text="Base Path Template") + col.prop(self, "base_path_multilayer_template", text="Base Path Multilayer Template") + + if self.use_env_base_path_templates: + col.separator() + col.label(text="Environment variables will override above templates if set", icon='INFO') + # col.label(text="RENDERTOOLBOX_EXR_PATH_TEMPLATE for single base path file output") + # col.label(text="RENDERTOOLBOX_MULTILAYER_PATH_TEMPLATE for multilayer base path file output") + col.label(text'If environment variables are not found, preferences will be used instead') + + +# region Handlers + +@persistent +def set_render_toolbox_settings(dummy): + ## Handler for prefs to scene properties replications + prefs = bpy.context.preferences.addons[__package__].preferences + reset_scene_path_templates() + +# region Register + +classes = ( + RT_prefs, +) + +def register(): + for cls in classes: + bpy.utils.register_class(cls) + + # prefs = bpy.context.preferences.addons[__package__].preferences + + if not 'set_render_toolbox_settings' in [hand.__name__ for hand in bpy.app.handlers.load_post]: + bpy.app.handlers.load_post.append(set_render_toolbox_settings) + +def unregister(): + if not 'set_render_toolbox_settings' in [hand.__name__ for hand in bpy.app.handlers.load_post]: + bpy.app.handlers.load_post.remove(set_render_toolbox_settings) + + for cls in reversed(classes): + bpy.utils.unregister_class(cls) + +# endregion \ No newline at end of file diff --git a/properties.py b/properties.py index ef60dcb..90a0bba 100644 --- a/properties.py +++ b/properties.py @@ -10,7 +10,7 @@ class RT_PG_render_toolbox_props(PropertyGroup): name="Base Path Template", description="Template for file output base path\ \nFolder containing subsequent filepath", - default="//render/{node_name}/", + default="//render/{node_label}/", # options={'SKIP_SAVE'} ) @@ -19,7 +19,7 @@ class RT_PG_render_toolbox_props(PropertyGroup): name="Base Path Template", description="Template for multilayer file output base paths\ \nOutput of the file sequence", - default="//render/{node_name}/{node_name}_", + default="//render/{node_label}/{node_label}_", # options={'SKIP_SAVE'} ) @@ -58,15 +58,28 @@ class RT_PG_render_toolbox_props(PropertyGroup): # # options={'SKIP_SAVE'} # ) -def set_env_properties(): - ## set default template from environment variable if available +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 + classes = ( RT_PG_render_toolbox_props, @@ -77,7 +90,7 @@ def register(): bpy.utils.register_class(cls) bpy.types.Scene.render_toolbox = bpy.props.PointerProperty(type=RT_PG_render_toolbox_props) - # set_env_properties() # restricted context error when trying assignation here (probably need handler) + # reset_scene_path_templates() # restricted context error when trying assignation here (probably need handler) def unregister(): del bpy.types.Scene.render_toolbox