Q: Using operator presets in a panel?

Hey there!
I’m trying to implement a panel in the tool shelf, that would enable the user to save, load and apply presets for any active operator, but due to being new to the Blender Python API, I’m struggling with it and would appreciate pointers in the right direction.

So, for example, if I use the translate operator and may have changed some values in the operator panel, I want to be able to save the used values via the familiar preset menu and apply them later on again, maybe to another object. The same should apply, if I use another operator like slide edge or bevel.

I found the classes AddPresetOperator and WM_MT_operator_presets in the presets.py located in the blender folder structure (e.g. blender-2.8/2.80/scripts/startup/bl_operators/presets.py), so naturally I assumed I could use them for my endeavor.

Here’s the code I have so far, but you can also find it in this repository:

import bpy

class OperatorPresetsPanel(bpy.types.Panel):
    """Creates a Panel in the TOOL_PROPS region of the Tool Shelf"""
    bl_label = "Operator Presets"
    bl_idname = "OBJECT_PT_operator_preset"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOL_PROPS'


    def draw(self, context):
        layout = self.layout

        if bpy.context.active_operator:
            row = layout.row(align=True)
            row.menu("WM_MT_operator_presets", text=bpy.types.WM_MT_operator_presets.bl_label)
            row.operator("wm.operator_preset_add", text="", icon="ZOOMIN")
            row.operator("wm.operator_preset_add", text="", icon="ZOOMOUT").remove_active = True
        else:
            row = layout.row(align=True)
            row.label(text="No Active Operator")


def register():
    bpy.utils.register_class(OperatorPresetsPanel)


def unregister():
    bpy.utils.unregister_class(OperatorPresetsPanel)
    
    
if __name__ == "__main__":
    register()

This is the related code in the presets.py:

class AddPresetOperator(AddPresetBase, Operator):
    """Add or remove an Operator Preset"""
    bl_idname = "wm.operator_preset_add"
    bl_label = "Operator Preset"
    preset_menu = "WM_MT_operator_presets"

    operator = StringProperty(
            name="Operator",
            maxlen=64,
            options={'HIDDEN', 'SKIP_SAVE'},
            )

    preset_defines = [
        "op = bpy.context.active_operator",
    ]

    @property
    def preset_subdir(self):
        return AddPresetOperator.operator_path(self.operator)

    @property
    def preset_values(self):
        properties_blacklist = Operator.bl_rna.properties.keys()

        prefix, suffix = self.operator.split("_OT_", 1)
        op = getattr(getattr(bpy.ops, prefix.lower()), suffix)
        operator_rna = op.get_rna().bl_rna
        del op

        ret = []
        for prop_id, prop in operator_rna.properties.items():
            if not (prop.is_hidden or prop.is_skip_save):
                if prop_id not in properties_blacklist:
                    ret.append("op.%s" % prop_id)

        return ret

    @staticmethod
    def operator_path(operator):
        import os

        prefix, suffix = operator.split("_OT_", 1)
        return os.path.join("operator", "%s.%s" % (prefix.lower(), suffix))


class WM_MT_operator_presets(Menu):
    bl_label = "Operator Presets"

    def draw(self, context):
        self.operator = context.active_operator.bl_idname

        # dummy 'default' menu item
        layout = self.layout
        layout.operator("wm.operator_defaults")
        layout.separator()

        Menu.draw_preset(self, context)

    @property
    def preset_subdir(self):
        return AddPresetOperator.operator_path(self.operator)

    preset_operator = "script.execute_preset"

The preset menu appears, but the dropdown says *Missing Paths*. Trying to save a preset fails. The problem appears to be that the operator member of AddPresetOperator and WM_MT_operator_presets doesn’t seem to hold a reference to the active operator which causes the split commands to fail which are used to determine the path.

If I use bpy.ops.wm.operator_preset_add(name="op_preset01", remove_active=False, operator="TRANSFORM_OT_translate") in the console, the preset gets saved with the latest used values in the according Folder and it will also show up in the preset menu.

A second issue is, that when I choose Restore Defaults or one of the manually saved presets from the dropdown, the values do reset, but they aren’t applied (operation is not redone with default values).

Can anyone please help me resolve the issues?