2

In the Blender preferences I would like to add paths to external resources, but I don't really know how to do it, I am aware that I can register a StringProperty property this way in the preferences:

class MyAddonPreferences(bpy.types.AddonPreferences):
bl_idname = __name__

path: bpy.props.StringProperty(name="PATH",subtype='DIR_PATH',description = '')

So I can access the path chosen by the user in this way:

preferences = bpy.context.preferences.addons[__name__].preferences
path = preferences.path

However, this is limiting if the resources can be multiple and chosen by the user. For example I would like to be able to add some other path of your choice with an "Add" or "Remove" button. Basically I'm trying to memorize some path in the addon preferences. I have no idea what the best way to do it is

Noob Cat
  • 1,222
  • 3
  • 20
  • 61
  • Hello Gorgious, I think you are partly right, the answer of @brockmann is very consistent with my question, while the one you pointed out to me is less consistent with my question, I think brockman's answer will be useful for many people as it is very specifies on this specific question. – Noob Cat Apr 25 '21 at 21:48
  • 2
    Agreed, I proposed the duplicate vote before the answer was posted. Cheers – Gorgious Apr 26 '21 at 07:47

1 Answers1

5

You would have to declare a CollectionProperty and assign its type to a previously declared PropertyGroup to hold multiple generic entries. Demo based on the code provided in the docs:

enter image description here

bl_info = {
    "name": "Example Add-on Preferences",
    "author": "Your Name Here",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "",
    "description": "Example Add-on",
    "warning": "",
    "doc_url": "",
    "tracker_url": "",
    "category": "Development",
}

import bpy from bpy.types import Operator, AddonPreferences, PropertyGroup from bpy.props import StringProperty, CollectionProperty

class CUSTOM_PG_filepaths(PropertyGroup): # name: bpy.props.StringProperty() path: bpy.props.StringProperty(subtype='FILE_PATH') display: bpy.props.BoolProperty()

class ExampleAddonPreferences(AddonPreferences): # this must match the add-on name, use 'package' # when defining this in a submodule of a python package. bl_idname = name

filepaths: CollectionProperty(
    name="File paths",
    type=CUSTOM_PG_filepaths)

def draw(self, context):
    layout = self.layout
    layout.label(text="This is a preferences view for our add-on")
    for i in self.filepaths:
        if i.display == True:
            layout.prop(i, "path")

filepath_list = { "geo": "//asset.obj", "anim": "//asset.fbx", "render": "//asset.exr" }

def register(): bpy.utils.register_class(CUSTOM_PG_filepaths) bpy.utils.register_class(ExampleAddonPreferences)

paths = bpy.context.preferences.addons[__name__].preferences.filepaths
if not paths:
    for key, value in filepath_list.items():
        item = paths.add()
        item.name = key
        item.path = value
        item.display = True


def unregister(): bpy.utils.unregister_class(ExampleAddonPreferences) bpy.utils.unregister_class(CUSTOM_PG_filepaths)

If you'd like to allow the user adding an arbitrary amount of filepaths, you can display the contents of the PropertyGroup in a custom UIList which will look like the material list, see:

Create an interface which is similar to the material list box


Alternatively you can just add a simple operator to add a new item:

enter image description here

class OBJECT_OT_addon_prefs_example(Operator):
    """Display example preferences"""
    bl_idname = "object.addon_prefs_example"
    bl_label = "Add-on Preferences Example"
    bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
    preferences = context.preferences
    addon_prefs = preferences.addons[__name__].preferences
    item = addon_prefs.filepaths.add()
    item.display = True

    self.report({'INFO'}, "New Filepath added")
    return {'FINISHED'}

brockmann
  • 12,613
  • 4
  • 50
  • 93
  • Great solution, I had in mind to use CollectionProperty, but I was not sure about it as I thought it would not remain stored, instead, by saving the preferences, all the added paths are saved in the preferences and therefore always available. I would like to give more points for this answer, it really was very helpful and coherent to my question. – Noob Cat Apr 25 '21 at 21:45