Using Blender’s presets in Python

19.10.2018 @ Tutorials(Addon, Blender, Python)

Looking to add support for presets in your addon? Read on to find out how!

There’s a built-in presets system in Blender used for operators and panels. The good news is that it’s Python based and easy to use. Presets are Python files that manually set values. When you select a preset in the menu that particular script is read from disk and run. Adding/removing presets involves creating or deleting py files from the presets folder. This is handled for us, but you might want to keep it mind for other things (like packaging presets). The presets folder is inside your personal Blender scripts folder. 

Linux~/.config/blender/2.79/scripts/presets/
Mac/Users/{user}/Library/Application/Support/Blender/2.79/scripts/presets/
WindowsC:\Documents and Settings\%username%\Application Data\Blender Foundation\Blender\2.79\scripts\presets\

Unfortunately there’s no way of importing/exporting presets yet other than manually copying files (or making an operator that does that). Also note that the built-in presets system only includes the menu we often see on top of operators and panels. If you want to have images, thumbnails and other advanced features you will have to roll your own system.

For operators

Adding presets to operators is as simple as it gets. Just add the PRESET to the bl_options set and you’re done.

class My_OP(Operator):
    bl_idname = "my.operator"
    bl_label = 'My Cool OP'
    bl_options = {'PRESET'}

Blender will add the preset menu to the operator UI for you. It will even create a folder for them in the presets directory! (note that you need to save at least one preset for that)

For panels

Using the presets system on panels only takes a bit more work. It also brings some extra flexibility on the UI.

First we have to decide where to save the presets. This could be your addons name, or a category with your addon as a subfolder. For this example let’s use ‘object/my_presets’. The full path would then
be ~/.config/blender/2.79/scripts/presets/object/my_presets/.

Next we need to make an operator to add/remove presets. Let’s bring the AddPresetsBase mixin into the mix (hah!).

from bl_operators.presets import AddPresetBase

class OT_AddMyPreset(AddPresetBase, Operator):
    bl_idname = 'my.add_preset'
    bl_label = 'Add A preset'
    preset_menu = 'MT_MyPresets'

    # Common variable used for all preset values
    preset_defines = [
                        'obj = bpy.context.object',
                        'scene = bpy.context.scene'
                     ]

    # Properties to store in the preset
    preset_values = [
                        'obj.show_axis',
                        'obj.show_name',
                        'obj.show_bounds',
                        'scene.world'
                    ]

    # Directory to store the presets
    preset_subdir = 'object/my_presets'

There’s no need to add an execute() or invoke() function in this case, since the mixin implements them. If you want to take a peek at the code behind this magic you can find it in [BLENDER_FOLDER]/bin/2.79/scripts/startup/bl_operators/presets.py We can also use this operator to remove presets by setting remove_active to True.

The meaty part of this code are the preset_defines and preset_values properties. The first list lets you declare variables common to all the preset’s values. This is only for convenience. It saves you from typing bpy.blah.bla over and over. The second list are the actual values that will be saved in the preset. With the operator done and ready, we now have to make a class for the menu and add everything to the panel.

class MT_MyPresets(Menu):
    bl_label = 'My Presets'
    preset_subdir = 'object/my_presets'
    preset_operator = 'script.execute_preset'
    draw = Menu.draw_preset

    # [...]
    # This code goes in the panel's draw()

    row = layout.row(align=True)
    row.menu('MT_MyPresets', text='Presets')
    row.operator('my.add_preset', text='', icon='ZOOMIN')
    row.operator('my.add_preset', text='',
                  icon='ZOOMOUT').remove_active = True

Don’t change the preset_operator and draw lines. These the lines make it look and work like a presets menu.

Packaging presets

There’s no “official” way of packaging presets with addons. But since they are just files we can easily do this ourselves. The process goes like this: First check if the presets folder exists, if it doesn’t that means this is the first time the addon is enabled. In that case copy the addon files from the addon folder to the presets folder. If it does exist we can assume the presets have already been installed (in which case we don’t do anything).

We can do all this in the register() function.

import os
import shutils

# [...]

my_presets = os.path.join(presets_folder, 'object', 'my_presets')

if not os.path.isdir(my_presets):
    # makedirs() will also create all the parent folders (like "object")
    os.makedirs(my_presets)

    # Get a list of all the files in your bundled presets folder
    files = os.listdir(my_bundled_presets)

    # Copy them
    [shutil.copy2(os.path.join(my_bundled_presets, f), my_presets)
     for f in files]

That’s all there is to know about Blender’s presets system. Well, at least for the 2.7x series. The system is getting some love in 2.80 (mostly UI). Hopefully there will be more improvements over the 2.8x series.

All the posts you can read

8 Comments

  1. Rombout Versluijs(1 week ago)

    NIce man! I have done this recently and hacked parts of this into my addon i made for rigify. Though your version of adding presets is way simpler than what i did. My addon makes it possible to save rigify setups and rigify presets.

    1. Diego Gangl(1 week ago)

      Hey, awesome! Did you roll your own system or did you build it on top of the builtin?

  2. Rusty(1 week ago)

    The path for Windows 10

    C:\Users\%username%\AppData\Roaming\Blender Foundation\Blender\2.79\scripts\presets

  3. Rusty(1 week ago)

    Addendum to my previous post. If you want to modifiy an existing preset, one that came with blender, they’re in

    C:\Program Files\Blender Foundation\Blender\2.79\scripts\presets

    Also note that in the path C:\Users\%username%\AppData\Roaming\Blender Foundation\Blender\2.79\scripts\presets

    If you haven’t changed the setting in Windows to display hidden files the directory AppData is hidden.

  4. Campbell Barton(1 week ago)

    Note: the example that uses Menu.draw_preset isn’t correct, you’re meant to subclass PresetMenu instead.

    1. Diego Gangl(6 days ago)

      Hey, thanks but is that class available on 2.7x? I only found it in the 2.8 branch

  5. CampbellBarton(6 days ago)

    Ah, you’re right, should have checked the master branch.

    1. Diego Gangl(5 days ago)

      Np, I’ll make a note to update this when 2.8 comes out with all the new goodness

Leave a Reply

Your email address will not be published.