1
$\begingroup$

I am currently working on an Add-on that makes use of the Preset system. As outlined here, Presets in an Operator can easily be defined using the bl_options = {'PRESET'} set. Those presets are then stored in BlenderPrefsLocation\scripts\presets\operator, named after the operator they refer to. Fine.

What I'd like to do is: Operator A has created a preset called file.A. From operator B, I'd like to re-use said preset. The property structure matches, so technically it would be possible.

At the moment, my only way of achieving this is to duplicate the folder file.A, and name it file.B, but I'd need to repeat this every time a preset is created.

$\endgroup$
1
$\begingroup$

Leveraging the preset system

A while back when doing some addon maintenance, changed the preset code for the add curve extra objects addon for 2.7x. In particular add curve spirals.

Can leverage off the existing preset code to emulate the 'PRESET' option. This way can choose what goes in the preset, what folder to save in, the menu and the operator to execute the preset.

Code snippets from /2.79/scripts/addons/add_curve_extra_objects/add_curve_spirals.py

Firstly there is an add preset base base class to inherit

from bl_operators.presets import AddPresetBase

The operator that creates the presets, notice can set the subdir here, defines in the script, and what properties to save in the preset. It is also associated with a menu.

class CURVE_EXTRAS_OT_spirals_presets(AddPresetBase, Operator):
    bl_idname = "curve_extras.spiral_presets"
    bl_label = "Spirals"
    bl_description = "Spirals Presets"
    preset_menu = "OBJECT_MT_spiral_curve_presets"
    preset_subdir = "curve_extras/curve.spirals"

    preset_defines = [
            "op = bpy.context.active_operator",
            ]
    preset_values = [
            "op.spiral_type",
            "op.curve_type",
            "op.spiral_direction",
            "op.turns",
            "op.steps",
            "op.radius",
            "op.dif_z",
            "op.dif_radius",
            "op.B_force",
            "op.inner_radius",
            "op.dif_inner_radius",
            "op.cycles",
            "op.curves_number",
            "op.touch",
            ]

its associated menu class. The bpy.types.Menu class has a 'draw_preset(..)` class method that draws the menu from the files in the presets folder. The default preset execute operator, which runs the code within the preset file setting the props is assigned as the operator of each menu item.

class OBJECT_MT_spiral_curve_presets(Menu):
    '''Presets for curve.spiral'''
    bl_label = "Spiral Curve Presets"
    bl_idname = "OBJECT_MT_spiral_curve_presets"
    preset_subdir = "curve_extras/curve.spirals"
    preset_operator = "script.execute_preset"

    draw = bpy.types.Menu.draw_preset

In the draw method of the operator that the presets are for

def draw(self, context):
    layout = self.layout
    col = layout.column_flow(align=True)

    col.label("Presets:")

    row = col.row(align=True)
    row.menu("OBJECT_MT_spiral_curve_presets",
             text=bpy.types.OBJECT_MT_spiral_curve_presets.bl_label)
    row.operator("curve_extras.spiral_presets", text="", icon='ZOOMIN')
    op = row.operator("curve_extras.spiral_presets", text="", icon='ZOOMOUT')
    op.remove_active = True

With this set up presets are being saved to or loaded from the defined folder. This way if your operators A and B have similar (same) structure can draw their presets from the same folder.

Also Look for code in addon prefs in __init__.py to convert from the old preset locations to new presets.

$\endgroup$
  • $\begingroup$ nice, will test this hopefully today $\endgroup$ – aliasguru Mar 18 at 14:37
  • $\begingroup$ this almost works. The functionality is there, the presets are shared. The only problem I face is that this preset system seems to ignore an environment variable I set (BLENDER_USER_SCRIPTS) on Blender 2.80. It saves and loads the presets from C:\Users\USERNAME\AppData\Roaming\Blender Foundation\Blender\2.80\scripts\presets instead of my custom scripts path $\endgroup$ – aliasguru Mar 18 at 16:48
  • $\begingroup$ I've tried using os.path.join(os.path.dirname(os.path.abspath(__file__)) , 'my_addon') to work around it, but absolute paths are not allowed it seems. Is there a magic flag I missed? $\endgroup$ – aliasguru Mar 18 at 16:49
  • 1
    $\begingroup$ Rusty on this. Pretty sure all the pertinent code is available as python in bl_operators.presets . Is expected path set via EV same as bpy.utils.script_path_user() and or showing in bpy.utils.script_paths("presets") ? $\endgroup$ – batFINGER Mar 18 at 17:13
  • $\begingroup$ Was just browsing class AddPresetBase: from release/scripts/startup/bl_operators in the Blender source code. There they construct the file path from bpy.utils.user_resource('SCRIPTS', target_path, create=True) which technically would yield the correct path (it does so when run from a blender console). Not sure why this fails on inheritance. $\endgroup$ – aliasguru Mar 18 at 17:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.