Python: Support multiple custom script directories in Preferences
Makes it possible to select multiple custom script directories in Preferences > File Paths, replacing the single Scripts path option. Each of these directories supports the regular script directory layout with a startup file (or files?), add-ons, modules and presets. When installing an add-on, the script directory can be chosen. NOTE: Deprecates the `bpy.types.PreferencesFilePaths.script_directory` property, and replaces `bpy.utils.script_path_pref` with `bpy.utils.script_paths_pref`. Pull Request: https://projects.blender.org/blender/blender/pulls/104876
This commit is contained in:
parent
dc402a8b96
commit
ba25023d22
@ -34,7 +34,7 @@ const UserDef U_default = {
|
||||
.renderdir = "//",
|
||||
.render_cachedir = "",
|
||||
.textudir = "//",
|
||||
.pythondir = "",
|
||||
.script_directories = {NULL, NULL},
|
||||
.sounddir = "//",
|
||||
.i18ndir = "",
|
||||
.image_editor = "",
|
||||
|
@ -30,7 +30,6 @@ __all__ = (
|
||||
"previews",
|
||||
"resource_path",
|
||||
"script_path_user",
|
||||
"script_path_pref",
|
||||
"script_paths",
|
||||
"smpte_from_frame",
|
||||
"smpte_from_seconds",
|
||||
@ -340,10 +339,14 @@ def script_path_user():
|
||||
return _os.path.normpath(path) if path else None
|
||||
|
||||
|
||||
def script_path_pref():
|
||||
"""returns the user preference or None"""
|
||||
path = _preferences.filepaths.script_directory
|
||||
return _os.path.normpath(path) if path else None
|
||||
def script_paths_pref():
|
||||
"""Returns a list of user preference script directories."""
|
||||
paths = []
|
||||
for script_directory in _preferences.filepaths.script_directories:
|
||||
directory = script_directory.directory
|
||||
if directory:
|
||||
paths.append(_os.path.normpath(directory))
|
||||
return paths
|
||||
|
||||
|
||||
def script_paths(*, subdir=None, user_pref=True, check_all=False, use_user=True):
|
||||
@ -384,9 +387,6 @@ def script_paths(*, subdir=None, user_pref=True, check_all=False, use_user=True)
|
||||
if use_user:
|
||||
base_paths.append(path_user)
|
||||
|
||||
if user_pref:
|
||||
base_paths.append(script_path_pref())
|
||||
|
||||
scripts = []
|
||||
for path in base_paths:
|
||||
if not path:
|
||||
|
@ -88,7 +88,9 @@ def write_sysinfo(filepath):
|
||||
for p in bpy.utils.script_paths():
|
||||
output.write("\t%r\n" % p)
|
||||
output.write("user scripts: %r\n" % (bpy.utils.script_path_user()))
|
||||
output.write("pref scripts: %r\n" % (bpy.utils.script_path_pref()))
|
||||
output.write("pref scripts:\n")
|
||||
for p in bpy.utils.script_paths_pref():
|
||||
output.write("\t%r\n" % p)
|
||||
output.write("datafiles: %r\n" % (bpy.utils.user_resource('DATAFILES')))
|
||||
output.write("config: %r\n" % (bpy.utils.user_resource('CONFIG')))
|
||||
output.write("scripts : %r\n" % (bpy.utils.user_resource('SCRIPTS')))
|
||||
|
@ -587,12 +587,18 @@ class PREFERENCES_OT_addon_install(Operator):
|
||||
description="Remove existing add-ons with the same ID",
|
||||
default=True,
|
||||
)
|
||||
|
||||
def _target_path_items(_self, context):
|
||||
paths = context.preferences.filepaths
|
||||
return (
|
||||
('DEFAULT', "Default", ""),
|
||||
None,
|
||||
*[(item.name, item.name, "") for index, item in enumerate(paths.script_directories) if item.directory],
|
||||
)
|
||||
|
||||
target: EnumProperty(
|
||||
name="Target Path",
|
||||
items=(
|
||||
('DEFAULT', "Default", ""),
|
||||
('PREFS', "Preferences", ""),
|
||||
),
|
||||
items=_target_path_items,
|
||||
)
|
||||
|
||||
filepath: StringProperty(
|
||||
@ -626,9 +632,11 @@ class PREFERENCES_OT_addon_install(Operator):
|
||||
# Don't use `bpy.utils.script_paths(path="addons")` because we may not be able to write to it.
|
||||
path_addons = bpy.utils.user_resource('SCRIPTS', path="addons", create=True)
|
||||
else:
|
||||
path_addons = context.preferences.filepaths.script_directory
|
||||
if path_addons:
|
||||
path_addons = os.path.join(path_addons, "addons")
|
||||
paths = context.preferences.filepaths
|
||||
for script_directory in paths.script_directories:
|
||||
if script_directory.name == self.target:
|
||||
path_addons = os.path.join(script_directory.directory, "addons")
|
||||
break
|
||||
|
||||
if not path_addons:
|
||||
self.report({'ERROR'}, "Failed to get add-ons path")
|
||||
@ -1139,6 +1147,60 @@ class PREFERENCES_OT_studiolight_show(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class PREFERENCES_OT_script_directory_new(Operator):
|
||||
bl_idname = "preferences.script_directory_add"
|
||||
bl_label = "Add Python Script Directory"
|
||||
|
||||
directory: StringProperty(
|
||||
subtype='DIR_PATH',
|
||||
)
|
||||
filter_folder: BoolProperty(
|
||||
name="Filter Folders",
|
||||
default=True,
|
||||
options={'HIDDEN'},
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
import os
|
||||
|
||||
script_directories = context.preferences.filepaths.script_directories
|
||||
|
||||
new_dir = script_directories.new()
|
||||
# Assign path selected via file browser.
|
||||
new_dir.directory = self.directory
|
||||
new_dir.name = os.path.basename(self.directory.rstrip(os.sep))
|
||||
|
||||
assert context.preferences.is_dirty == True
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, _event):
|
||||
wm = context.window_manager
|
||||
|
||||
wm.fileselect_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
class PREFERENCES_OT_script_directory_remove(Operator):
|
||||
bl_idname = "preferences.script_directory_remove"
|
||||
bl_label = "Remove Python Script Directory"
|
||||
|
||||
index: IntProperty(
|
||||
name="Index",
|
||||
description="Index of the script directory to remove",
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
script_directories = context.preferences.filepaths.script_directories
|
||||
for search_index, script_directory in enumerate(script_directories):
|
||||
if search_index == self.index:
|
||||
script_directories.remove(script_directory)
|
||||
break
|
||||
|
||||
assert context.preferences.is_dirty == True
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
classes = (
|
||||
PREFERENCES_OT_addon_disable,
|
||||
PREFERENCES_OT_addon_enable,
|
||||
@ -1164,4 +1226,6 @@ classes = (
|
||||
PREFERENCES_OT_studiolight_uninstall,
|
||||
PREFERENCES_OT_studiolight_copy_settings,
|
||||
PREFERENCES_OT_studiolight_show,
|
||||
PREFERENCES_OT_script_directory_new,
|
||||
PREFERENCES_OT_script_directory_remove,
|
||||
)
|
||||
|
@ -1333,11 +1333,52 @@ class USERPREF_PT_file_paths_data(FilePathsPanel, Panel):
|
||||
col = self.layout.column()
|
||||
col.prop(paths, "font_directory", text="Fonts")
|
||||
col.prop(paths, "texture_directory", text="Textures")
|
||||
col.prop(paths, "script_directory", text="Scripts")
|
||||
col.prop(paths, "sound_directory", text="Sounds")
|
||||
col.prop(paths, "temporary_directory", text="Temporary Files")
|
||||
|
||||
|
||||
class USERPREF_PT_file_paths_script_directories(FilePathsPanel, Panel):
|
||||
bl_label = "Script Directories"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
paths = context.preferences.filepaths
|
||||
|
||||
if len(paths.script_directories) == 0:
|
||||
layout.operator("preferences.script_directory_add", text="Add", icon='ADD')
|
||||
return
|
||||
|
||||
layout.use_property_split = False
|
||||
layout.use_property_decorate = False
|
||||
|
||||
box = layout.box()
|
||||
split = box.split(factor=0.35)
|
||||
name_col = split.column()
|
||||
path_col = split.column()
|
||||
|
||||
row = name_col.row(align=True) # Padding
|
||||
row.separator()
|
||||
row.label(text="Name")
|
||||
|
||||
row = path_col.row(align=True) # Padding
|
||||
row.separator()
|
||||
row.label(text="Path")
|
||||
|
||||
row.operator("preferences.script_directory_add", text="", icon='ADD', emboss=False)
|
||||
|
||||
for i, script_directory in enumerate(paths.script_directories):
|
||||
row = name_col.row()
|
||||
row.alert = not script_directory.name
|
||||
row.prop(script_directory, "name", text="")
|
||||
|
||||
row = path_col.row()
|
||||
subrow = row.row()
|
||||
subrow.alert = not script_directory.directory
|
||||
subrow.prop(script_directory, "directory", text="")
|
||||
row.operator("preferences.script_directory_remove", text="", icon='X', emboss=False).index = i
|
||||
|
||||
|
||||
class USERPREF_PT_file_paths_render(FilePathsPanel, Panel):
|
||||
bl_label = "Render"
|
||||
|
||||
@ -1878,7 +1919,7 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
|
||||
if not user_addon_paths:
|
||||
for path in (
|
||||
bpy.utils.script_path_user(),
|
||||
bpy.utils.script_path_pref(),
|
||||
*bpy.utils.script_paths_pref(),
|
||||
):
|
||||
if path is not None:
|
||||
user_addon_paths.append(os.path.join(path, "addons"))
|
||||
@ -1910,7 +1951,7 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
|
||||
|
||||
addon_user_dirs = tuple(
|
||||
p for p in (
|
||||
os.path.join(prefs.filepaths.script_directory, "addons"),
|
||||
*[os.path.join(pref_p, "addons") for pref_p in bpy.utils.script_path_user()],
|
||||
bpy.utils.user_resource('SCRIPTS', path="addons"),
|
||||
)
|
||||
if p
|
||||
@ -2457,6 +2498,7 @@ classes = (
|
||||
USERPREF_PT_theme_strip_colors,
|
||||
|
||||
USERPREF_PT_file_paths_data,
|
||||
USERPREF_PT_file_paths_script_directories,
|
||||
USERPREF_PT_file_paths_render,
|
||||
USERPREF_PT_file_paths_applications,
|
||||
USERPREF_PT_file_paths_development,
|
||||
|
@ -25,7 +25,7 @@ extern "C" {
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 4
|
||||
#define BLENDER_FILE_SUBVERSION 5
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
@ -296,6 +296,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
|
||||
}
|
||||
|
||||
BLI_freelistN(&userdef->autoexec_paths);
|
||||
BLI_freelistN(&userdef->script_directories);
|
||||
BLI_freelistN(&userdef->asset_libraries);
|
||||
|
||||
BLI_freelistN(&userdef->uistyles);
|
||||
|
@ -3700,6 +3700,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
|
||||
BLO_read_list(reader, &user->user_menus);
|
||||
BLO_read_list(reader, &user->addons);
|
||||
BLO_read_list(reader, &user->autoexec_paths);
|
||||
BLO_read_list(reader, &user->script_directories);
|
||||
BLO_read_list(reader, &user->asset_libraries);
|
||||
|
||||
LISTBASE_FOREACH (wmKeyMap *, keymap, &user->user_keymaps) {
|
||||
|
@ -31,8 +31,12 @@
|
||||
|
||||
#include "BLO_readfile.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "GPU_platform.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "readfile.h" /* Own include. */
|
||||
|
||||
#include "WM_types.h"
|
||||
@ -798,6 +802,17 @@ void blo_do_versions_userdef(UserDef *userdef)
|
||||
}
|
||||
}
|
||||
|
||||
if (!USER_VERSION_ATLEAST(306, 5)) {
|
||||
if (userdef->pythondir_legacy[0]) {
|
||||
bUserScriptDirectory *script_dir = MEM_callocN(sizeof(*script_dir),
|
||||
"Versioning user script path");
|
||||
|
||||
STRNCPY(script_dir->dir_path, userdef->pythondir_legacy);
|
||||
STRNCPY(script_dir->name, DATA_("Untitled"));
|
||||
BLI_addhead(&userdef->script_directories, script_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
@ -922,6 +922,10 @@ static void write_userdef(BlendWriter *writer, const UserDef *userdef)
|
||||
BLO_write_struct(writer, bPathCompare, path_cmp);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (const bUserScriptDirectory *, script_dir, &userdef->script_directories) {
|
||||
BLO_write_struct(writer, bUserScriptDirectory, script_dir);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (const bUserAssetLibrary *, asset_library_ref, &userdef->asset_libraries) {
|
||||
BLO_write_struct(writer, bUserAssetLibrary, asset_library_ref);
|
||||
}
|
||||
|
@ -1033,7 +1033,14 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
|
||||
|
||||
FS_UDIR_PATH(U.fontdir, ICON_FILE_FONT)
|
||||
FS_UDIR_PATH(U.textudir, ICON_FILE_IMAGE)
|
||||
FS_UDIR_PATH(U.pythondir, ICON_FILE_SCRIPT)
|
||||
LISTBASE_FOREACH (bUserScriptDirectory *, script_dir, &U.script_directories) {
|
||||
fsmenu_insert_entry(fsmenu,
|
||||
FS_CATEGORY_OTHER,
|
||||
script_dir->dir_path,
|
||||
script_dir->name,
|
||||
ICON_FILE_SCRIPT,
|
||||
FS_INSERT_LAST);
|
||||
}
|
||||
FS_UDIR_PATH(U.sounddir, ICON_FILE_SOUND)
|
||||
FS_UDIR_PATH(U.tempdir, ICON_TEMP)
|
||||
|
||||
|
@ -679,6 +679,17 @@ typedef struct UserDef_Experimental {
|
||||
#define USER_EXPERIMENTAL_TEST(userdef, member) \
|
||||
(((userdef)->flag & USER_DEVELOPER_UI) && ((userdef)->experimental).member)
|
||||
|
||||
/**
|
||||
* Container to store multiple directory paths and a name for each as a #ListBase.
|
||||
*/
|
||||
typedef struct bUserScriptDirectory {
|
||||
struct bUserScriptDirectory *next, *prev;
|
||||
|
||||
/** Name must be unique. */
|
||||
char name[64]; /* MAX_NAME */
|
||||
char dir_path[768]; /* FILE_MAXDIR */
|
||||
} bUserScriptDirectory;
|
||||
|
||||
typedef struct UserDef {
|
||||
DNA_DEFINE_CXX_METHODS(UserDef)
|
||||
|
||||
@ -703,22 +714,8 @@ typedef struct UserDef {
|
||||
/** 768 = FILE_MAXDIR. */
|
||||
char render_cachedir[768];
|
||||
char textudir[768];
|
||||
/**
|
||||
* Optional user location for scripts.
|
||||
*
|
||||
* This supports the same layout as Blender's scripts directory `scripts`.
|
||||
*
|
||||
* \note Unlike most paths, changing this is not fully supported at run-time,
|
||||
* requiring a restart to properly take effect. Supporting this would cause complications as
|
||||
* the script path can contain `startup`, `addons` & `modules` etc. properly unwinding the
|
||||
* Python environment to the state it _would_ have been in gets complicated.
|
||||
*
|
||||
* Although this is partially supported as the `sys.path` is refreshed when loading preferences.
|
||||
* This is done to support #PREFERENCES_OT_copy_prev which is available to the user when they
|
||||
* launch with a new version of Blender. In this case setting the script path on top of
|
||||
* factory settings will work without problems.
|
||||
*/
|
||||
char pythondir[768];
|
||||
/* Deprecated, use #UserDef.script_directories instead. */
|
||||
char pythondir_legacy[768] DNA_DEPRECATED;
|
||||
char sounddir[768];
|
||||
char i18ndir[768];
|
||||
/** 1024 = FILE_MAX. */
|
||||
@ -790,6 +787,22 @@ typedef struct UserDef {
|
||||
struct ListBase user_keyconfig_prefs;
|
||||
struct ListBase addons;
|
||||
struct ListBase autoexec_paths;
|
||||
/**
|
||||
* Optional user locations for Python scripts.
|
||||
*
|
||||
* This supports the same layout as Blender's scripts directory `scripts`.
|
||||
*
|
||||
* \note Unlike most paths, changing this is not fully supported at run-time,
|
||||
* requiring a restart to properly take effect. Supporting this would cause complications as
|
||||
* the script path can contain `startup`, `addons` & `modules` etc. properly unwinding the
|
||||
* Python environment to the state it _would_ have been in gets complicated.
|
||||
*
|
||||
* Although this is partially supported as the `sys.path` is refreshed when loading preferences.
|
||||
* This is done to support #PREFERENCES_OT_copy_prev which is available to the user when they
|
||||
* launch with a new version of Blender. In this case setting the script path on top of
|
||||
* factory settings will work without problems.
|
||||
*/
|
||||
ListBase script_directories; /* #bUserScriptDirectory */
|
||||
/** #bUserMenu. */
|
||||
struct ListBase user_menus;
|
||||
/** #bUserAssetLibrary */
|
||||
|
@ -148,6 +148,7 @@ DNA_STRUCT_RENAME_ELEM(ThemeSpace, scrubbing_background, time_scrub_background)
|
||||
DNA_STRUCT_RENAME_ELEM(ThemeSpace, show_back_grad, background_type)
|
||||
DNA_STRUCT_RENAME_ELEM(UVProjectModifierData, num_projectors, projectors_num)
|
||||
DNA_STRUCT_RENAME_ELEM(UserDef, gp_manhattendist, gp_manhattandist)
|
||||
DNA_STRUCT_RENAME_ELEM(UserDef, pythondir, pythondir_legacy)
|
||||
DNA_STRUCT_RENAME_ELEM(VFont, name, filepath)
|
||||
DNA_STRUCT_RENAME_ELEM(View3D, far, clip_end)
|
||||
DNA_STRUCT_RENAME_ELEM(View3D, near, clip_start)
|
||||
|
@ -150,6 +150,7 @@ static const EnumPropertyItem rna_enum_preference_gpu_backend_items[] = {
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
# include "BLI_math_vector.h"
|
||||
# include "BLI_string_utils.h"
|
||||
|
||||
# include "DNA_object_types.h"
|
||||
# include "DNA_screen_types.h"
|
||||
@ -344,6 +345,52 @@ static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain),
|
||||
USERDEF_TAG_DIRTY;
|
||||
}
|
||||
|
||||
static void rna_userdef_script_directory_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
bUserScriptDirectory *script_dir = ptr->data;
|
||||
bool value_invalid = false;
|
||||
|
||||
if (!value[0]) {
|
||||
value_invalid = true;
|
||||
}
|
||||
if (STREQ(value, "DEFAULT")) {
|
||||
value_invalid = true;
|
||||
}
|
||||
|
||||
if (value_invalid) {
|
||||
value = DATA_("Untitled");
|
||||
}
|
||||
|
||||
BLI_strncpy_utf8(script_dir->name, value, sizeof(script_dir->name));
|
||||
BLI_uniquename(&U.script_directories,
|
||||
script_dir,
|
||||
value,
|
||||
'.',
|
||||
offsetof(bUserScriptDirectory, name),
|
||||
sizeof(script_dir->name));
|
||||
}
|
||||
|
||||
static bUserScriptDirectory *rna_userdef_script_directory_new(void)
|
||||
{
|
||||
bUserScriptDirectory *script_dir = MEM_callocN(sizeof(*script_dir), __func__);
|
||||
BLI_addtail(&U.script_directories, script_dir);
|
||||
USERDEF_TAG_DIRTY;
|
||||
return script_dir;
|
||||
}
|
||||
|
||||
static void rna_userdef_script_directory_remove(ReportList *reports, PointerRNA *ptr)
|
||||
{
|
||||
bUserScriptDirectory *script_dir = ptr->data;
|
||||
if (BLI_findindex(&U.script_directories, script_dir) == -1) {
|
||||
BKE_report(reports, RPT_ERROR, "Script directory not found");
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_freelinkN(&U.script_directories, script_dir);
|
||||
RNA_POINTER_INVALIDATE(ptr);
|
||||
USERDEF_TAG_DIRTY;
|
||||
}
|
||||
|
||||
static void rna_userdef_load_ui_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
|
||||
{
|
||||
UserDef *userdef = (UserDef *)ptr->data;
|
||||
@ -6212,6 +6259,57 @@ static void rna_def_userdef_filepaths_asset_library(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_script_directory(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna = RNA_def_struct(brna, "ScriptDirectory", NULL);
|
||||
RNA_def_struct_sdna(srna, "bUserScriptDirectory");
|
||||
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
|
||||
RNA_def_struct_ui_text(srna, "Python Scripts Directory", "");
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Name", "Identifier for the Python scripts directory");
|
||||
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_userdef_script_directory_name_set");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH);
|
||||
RNA_def_property_string_sdna(prop, NULL, "dir_path");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Python Scripts Directory",
|
||||
"Alternate script path, matching the default layout with sub-directories: startup, add-ons, "
|
||||
"modules, and presets (requires restart)");
|
||||
/* TODO: editing should reset sys.path! */
|
||||
}
|
||||
|
||||
static void rna_def_userdef_script_directory_collection(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
{
|
||||
StructRNA *srna;
|
||||
FunctionRNA *func;
|
||||
PropertyRNA *parm;
|
||||
|
||||
RNA_def_property_srna(cprop, "ScriptDirectoryCollection");
|
||||
srna = RNA_def_struct(brna, "ScriptDirectoryCollection", NULL);
|
||||
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
|
||||
RNA_def_struct_ui_text(srna, "Python Scripts Directories", "");
|
||||
|
||||
func = RNA_def_function(srna, "new", "rna_userdef_script_directory_new");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF);
|
||||
RNA_def_function_ui_description(func, "Add a new python script directory");
|
||||
/* return type */
|
||||
parm = RNA_def_pointer(func, "script_directory", "ScriptDirectory", "", "");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "remove", "rna_userdef_script_directory_remove");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
|
||||
RNA_def_function_ui_description(func, "Remove a python script directory");
|
||||
parm = RNA_def_pointer(func, "script_directory", "ScriptDirectory", "", "");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
|
||||
}
|
||||
|
||||
static void rna_def_userdef_filepaths(BlenderRNA *brna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
@ -6311,14 +6409,12 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
|
||||
"Render Output Directory",
|
||||
"The default directory for rendering output, for new scenes");
|
||||
|
||||
prop = RNA_def_property(srna, "script_directory", PROP_STRING, PROP_DIRPATH);
|
||||
RNA_def_property_string_sdna(prop, NULL, "pythondir");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Python Scripts Directory",
|
||||
"Alternate script path, matching the default layout with subdirectories: "
|
||||
"`startup`, `addons`, `modules`, and `presets` (requires restart)");
|
||||
/* TODO: editing should reset sys.path! */
|
||||
rna_def_userdef_script_directory(brna);
|
||||
|
||||
prop = RNA_def_property(srna, "script_directories", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "ScriptDirectory");
|
||||
RNA_def_property_ui_text(prop, "Python Scripts Directory", "");
|
||||
rna_def_userdef_script_directory_collection(brna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "i18n_branches_directory", PROP_STRING, PROP_DIRPATH);
|
||||
RNA_def_property_string_sdna(prop, NULL, "i18ndir");
|
||||
|
Loading…
x
Reference in New Issue
Block a user