diff --git a/scripts/modules/addon_utils.py b/scripts/modules/addon_utils.py index 3b87ea09e64..360f59ab258 100644 --- a/scripts/modules/addon_utils.py +++ b/scripts/modules/addon_utils.py @@ -69,7 +69,7 @@ def _paths_with_extension_repos(): for repo in _preferences.filepaths.extension_repos: if not repo.enabled: continue - dirpath = repo.directory_or_default + dirpath = repo.directory if not os.path.isdir(dirpath): continue addon_paths.append((dirpath, "%s.%s" % (_ext_base_pkg_idname, repo.module))) @@ -774,7 +774,7 @@ def _extension_dirpath_from_preferences(): for repo in _preferences.filepaths.extension_repos: if not repo.enabled: continue - repos_dict[repo.module] = repo.directory_or_default + repos_dict[repo.module] = repo.directory return repos_dict diff --git a/scripts/modules/bpy_types.py b/scripts/modules/bpy_types.py index d7faf00135a..dd5cbd2b49c 100644 --- a/scripts/modules/bpy_types.py +++ b/scripts/modules/bpy_types.py @@ -1316,10 +1316,10 @@ class UserExtensionRepo(StructRNA): __slots__ = () @property - def directory_or_default(self): + def directory(self): """Return ``directory`` or a default path derived from the users scripts path.""" - if directory := self.directory: - return directory + if self.use_custom_directory: + return self.custom_directory import os import bpy return os.path.join(bpy.utils.user_resource('SCRIPTS', path="extensions"), self.module) diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index 60bf05d714c..8467d1e0570 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -1603,6 +1603,15 @@ class USERPREF_UL_extension_repos(UIList): elif self.layout_type == 'GRID': layout.alignment = 'CENTER' layout.prop(repo, "name", text="", emboss=False) + + # Show an error icon if this repository has unusable settings. + if repo.enabled: + if ( + (repo.use_custom_directory and repo.custom_directory == "") or + (repo.use_remote_path and repo.remote_path == "") + ): + layout.label(text="", icon='ERROR') + layout.prop(repo, "enabled", text="", emboss=False, icon='CHECKBOX_HLT' if repo.enabled else 'CHECKBOX_DEHLT') @@ -2049,8 +2058,8 @@ class USERPREF_PT_extensions_repos(Panel): ) col = row.column(align=True) - col.operator("preferences.extension_repo_add", text="", icon='ADD') - props = col.operator("preferences.extension_repo_remove", text="", icon='REMOVE') + col.operator_menu_enum("preferences.extension_repo_add", "type", text="", icon='ADD') + props = col.operator_menu_enum("preferences.extension_repo_remove", "type", text="", icon='REMOVE') props.index = active_library_index try: @@ -2063,10 +2072,29 @@ class USERPREF_PT_extensions_repos(Panel): layout.separator() - layout.prop(active_repo, "remote_path") + layout.prop(active_repo, "use_remote_path", text="Use Remote URL") + row = layout.row() + if active_repo.use_remote_path: + if active_repo.remote_path == "": + row.alert = True + else: + row.active = False + row.prop(active_repo, "remote_path", text="") if layout_panel := self._panel_layout_kludge(layout, text="Advanced"): - layout_panel.prop(active_repo, "directory") + + layout_panel.prop(active_repo, "use_custom_directory") + + row = layout_panel.row() + if active_repo.use_custom_directory: + if active_repo.custom_directory == "": + row.alert = True + else: + row.active = False + row.prop(active_repo, "custom_directory", text="") + + layout_panel.separator() + row = layout_panel.row() row.prop(active_repo, "use_cache") row.prop(active_repo, "module") diff --git a/source/blender/blenkernel/BKE_preferences.h b/source/blender/blenkernel/BKE_preferences.h index 6a4e8987caa..fec295c8d13 100644 --- a/source/blender/blenkernel/BKE_preferences.h +++ b/source/blender/blenkernel/BKE_preferences.h @@ -82,7 +82,7 @@ void BKE_preferences_asset_library_default_add(struct UserDef *userdef) ATTR_NON bUserExtensionRepo *BKE_preferences_extension_repo_add(UserDef *userdef, const char *name, const char *module, - const char *dirpath); + const char *custom_dirpath); void BKE_preferences_extension_repo_remove(UserDef *userdef, bUserExtensionRepo *repo); void BKE_preferences_extension_repo_name_set(UserDef *userdef, @@ -92,7 +92,11 @@ void BKE_preferences_extension_repo_module_set(UserDef *userdef, bUserExtensionRepo *repo, const char *module); -void BKE_preferences_extension_repo_path_set(bUserExtensionRepo *repo, const char *path); +void BKE_preferences_extension_repo_custom_dirpath_set(bUserExtensionRepo *repo, const char *path); +void BKE_preferences_extension_repo_dirpath_get(const bUserExtensionRepo *repo, + char *dirpath, + int dirpath_maxncpy); + bUserExtensionRepo *BKE_preferences_extension_repo_find_index(const UserDef *userdef, int index); bUserExtensionRepo *BKE_preferences_extension_repo_find_by_module(const UserDef *userdef, const char *module); diff --git a/source/blender/blenkernel/intern/preferences.cc b/source/blender/blenkernel/intern/preferences.cc index cf33818713f..88bc0d78407 100644 --- a/source/blender/blenkernel/intern/preferences.cc +++ b/source/blender/blenkernel/intern/preferences.cc @@ -159,7 +159,7 @@ static size_t strncpy_py_module(char *dst, const char *src, const size_t dst_max bUserExtensionRepo *BKE_preferences_extension_repo_add(UserDef *userdef, const char *name, const char *module, - const char *dirpath) + const char *custom_dirpath) { bUserExtensionRepo *repo = DNA_struct_default_alloc(bUserExtensionRepo); BLI_addtail(&userdef->extension_repos, repo); @@ -171,9 +171,9 @@ bUserExtensionRepo *BKE_preferences_extension_repo_add(UserDef *userdef, BKE_preferences_extension_repo_module_set(userdef, repo, module); /* Set the directory. */ - STRNCPY(repo->dirpath, dirpath); - BLI_path_normalize(repo->dirpath); - BLI_path_slash_rstrip(repo->dirpath); + STRNCPY(repo->custom_dirpath, custom_dirpath); + BLI_path_normalize(repo->custom_dirpath); + BLI_path_slash_rstrip(repo->custom_dirpath); /* While not a strict rule, ignored paths that already exist, * * pointing to the same path is going to logical problems with package-management. */ @@ -181,8 +181,8 @@ bUserExtensionRepo *BKE_preferences_extension_repo_add(UserDef *userdef, if (repo == repo_iter) { continue; } - if (BLI_path_cmp(repo->dirpath, repo_iter->dirpath) == 0) { - repo->dirpath[0] = '\0'; + if (BLI_path_cmp(repo->custom_dirpath, repo_iter->custom_dirpath) == 0) { + repo->custom_dirpath[0] = '\0'; break; } } @@ -228,9 +228,29 @@ void BKE_preferences_extension_repo_module_set(UserDef *userdef, sizeof(repo->module)); } -void BKE_preferences_extension_repo_path_set(bUserExtensionRepo *repo, const char *path) +void BKE_preferences_extension_repo_custom_dirpath_set(bUserExtensionRepo *repo, const char *path) { - STRNCPY(repo->dirpath, path); + STRNCPY(repo->custom_dirpath, path); +} + +void BKE_preferences_extension_repo_dirpath_get(const bUserExtensionRepo *repo, + char *dirpath, + const int dirpath_maxncpy) +{ + if (repo->flag & USER_EXTENSION_REPO_FLAG_USE_CUSTOM_DIRECTORY) { + BLI_strncpy(dirpath, repo->custom_dirpath, dirpath_maxncpy); + return; + } + + char subdir[16 + sizeof(bUserExtensionRepo::module)]; + BLI_string_join(subdir, sizeof(subdir), "extensions", SEP_STR, repo->module); + const std::optional path = BKE_appdir_folder_id(BLENDER_USER_SCRIPTS, subdir); + if (path.has_value()) { + BLI_strncpy(dirpath, path.value().c_str(), dirpath_maxncpy); + } + else { + dirpath[0] = '\0'; + } } bUserExtensionRepo *BKE_preferences_extension_repo_find_index(const UserDef *userdef, int index) diff --git a/source/blender/editors/space_userpref/CMakeLists.txt b/source/blender/editors/space_userpref/CMakeLists.txt index ec89b79795e..b144f36295c 100644 --- a/source/blender/editors/space_userpref/CMakeLists.txt +++ b/source/blender/editors/space_userpref/CMakeLists.txt @@ -6,6 +6,7 @@ set(INC ../include ../../blenkernel ../../blenloader + ../../blentranslation ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_userpref/userpref_ops.cc b/source/blender/editors/space_userpref/userpref_ops.cc index a339284c5e9..23e7fd948e3 100644 --- a/source/blender/editors/space_userpref/userpref_ops.cc +++ b/source/blender/editors/space_userpref/userpref_ops.cc @@ -7,6 +7,7 @@ */ #include +#include #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -15,6 +16,7 @@ #ifdef WIN32 # include "BLI_winstuff.h" #endif +#include "BLI_fileops.h" #include "BLI_path_util.h" #include "BKE_callbacks.h" @@ -24,6 +26,8 @@ #include "BKE_report.h" +#include "BLT_translation.h" + #include "RNA_access.hh" #include "RNA_define.hh" #include "RNA_types.hh" @@ -238,21 +242,42 @@ static void PREFERENCES_OT_asset_library_remove(wmOperatorType *ot) /** \name Add Extension Repository Operator * \{ */ +enum class bUserExtensionRepoAddType { + Online = 0, + Local = 1, +}; + static int preferences_extension_repo_add_exec(bContext *C, wmOperator *op) { - char name[FILE_MAXFILE]; - char directory[FILE_MAX]; + const bUserExtensionRepoAddType repo_type = bUserExtensionRepoAddType( + RNA_enum_get(op->ptr, "type")); Main *bmain = CTX_data_main(C); BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_PRE); - RNA_string_get(op->ptr, "directory", directory); - BLI_path_slash_rstrip(directory); + char name[sizeof(bUserExtensionRepo::name)]; + char custom_directory[FILE_MAX] = ""; - BLI_path_split_file_part(directory, name, sizeof(name)); + const bool use_custom_directory = RNA_boolean_get(op->ptr, "use_custom_directory"); + RNA_string_get(op->ptr, "name", name); - const char *module = name; - bUserExtensionRepo *new_repo = BKE_preferences_extension_repo_add(&U, name, module, directory); + if (use_custom_directory) { + RNA_string_get(op->ptr, "custom_directory", custom_directory); + BLI_path_slash_rstrip(custom_directory); + } + + const char *module = custom_directory[0] ? BLI_path_basename(custom_directory) : name; + bUserExtensionRepo *new_repo = BKE_preferences_extension_repo_add( + &U, name, module, custom_directory); + + if (use_custom_directory) { + new_repo->flag |= USER_EXTENSION_REPO_FLAG_USE_CUSTOM_DIRECTORY; + } + + if (repo_type == bUserExtensionRepoAddType::Online) { + RNA_string_get(op->ptr, "remote_path", new_repo->remote_path); + new_repo->flag |= USER_EXTENSION_REPO_FLAG_USE_REMOTE_PATH; + } /* Activate new repository in the UI for further setup. */ U.active_extension_repo = BLI_findindex(&U.extension_repos, new_repo); @@ -266,16 +291,49 @@ static int preferences_extension_repo_add_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int preferences_extension_repo_add_invoke(bContext *C, - wmOperator *op, - const wmEvent * /*event*/) +static int preferences_extension_repo_add_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (!RNA_struct_property_is_set(op->ptr, "directory")) { - WM_event_add_fileselect(C, op); - return OPERATOR_RUNNING_MODAL; + const bUserExtensionRepoAddType repo_type = bUserExtensionRepoAddType( + RNA_enum_get(op->ptr, "type")); + PropertyRNA *prop_name = RNA_struct_find_property(op->ptr, "name"); + if (!RNA_property_is_set(op->ptr, prop_name)) { + const char *name_default = nullptr; + if (repo_type == bUserExtensionRepoAddType::Online) { + name_default = "Online Repository"; + } + else { + name_default = "User Repository"; + } + RNA_property_string_set(op->ptr, prop_name, name_default); } - return preferences_extension_repo_add_exec(C, op); + return WM_operator_props_popup_confirm(C, op, event); +} + +static bool preferences_extension_repo_add_poll_property(const bContext * /*C*/, + wmOperator *op, + const PropertyRNA *prop) +{ + PointerRNA *ptr = op->ptr; + + const char *prop_id = RNA_property_identifier(prop); + const bUserExtensionRepoAddType repo_type = bUserExtensionRepoAddType(RNA_enum_get(ptr, "type")); + + /* Only show remote_path for remote repositories. */ + if (STREQ(prop_id, "remote_path")) { + if (repo_type != bUserExtensionRepoAddType::Online) { + return false; + } + } + + if (STREQ(prop_id, "custom_directory")) { + if (!RNA_boolean_get(ptr, "use_custom_directory")) { + return false; + } + } + + /* Else, show it! */ + return true; } static void PREFERENCES_OT_extension_repo_add(wmOperatorType *ot) @@ -284,18 +342,52 @@ static void PREFERENCES_OT_extension_repo_add(wmOperatorType *ot) ot->idname = "PREFERENCES_OT_extension_repo_add"; ot->description = "Add a directory to be used as a local extension repository"; - ot->exec = preferences_extension_repo_add_exec; ot->invoke = preferences_extension_repo_add_invoke; + ot->exec = preferences_extension_repo_add_exec; + ot->poll_property = preferences_extension_repo_add_poll_property; - ot->flag = OPTYPE_INTERNAL; + ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER; - WM_operator_properties_filesel(ot, - FILE_TYPE_FOLDER, - FILE_SPECIAL, - FILE_OPENFILE, - WM_FILESEL_DIRECTORY, - FILE_DEFAULTDISPLAY, - FILE_SORT_DEFAULT); + static const EnumPropertyItem repo_type_items[] = { + {int(bUserExtensionRepoAddType::Online), + "ONLINE", + ICON_WORLD, + "Add Online Repository", + "Add a repository referencing an remote repository " + "with support for listing and updating extensions"}, + {int(bUserExtensionRepoAddType::Local), + "LOCAL", + ICON_DISK_DRIVE, + "Add Local Repository", + "Add a repository managed manually without referencing an external repository"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + PropertyRNA *prop; + + prop = RNA_def_string(ot->srna, "name", nullptr, sizeof(bUserExtensionRepo::name), "Name", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_string( + ot->srna, "remote_path", nullptr, sizeof(bUserExtensionRepo::remote_path), "URL", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_boolean(ot->srna, "use_custom_directory", false, "Custom Directory", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + /* WARNING: `RNA_def_string_dir_path` should be used but the file selector crashes from + * #WM_operator_props_popup_confirm as it closes the popup before showing the file-selector. */ + prop = RNA_def_string(ot->srna, + "custom_directory", + nullptr, + sizeof(bUserExtensionRepo::remote_path), + "Directory", + ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + ot->prop = RNA_def_enum( + ot->srna, "type", repo_type_items, 0, "Type", "The kind of repository to add"); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE | PROP_HIDDEN); } /** \} */ @@ -304,6 +396,11 @@ static void PREFERENCES_OT_extension_repo_add(wmOperatorType *ot) /** \name Remove Extension Repository Operator * \{ */ +enum class bUserExtensionRepoRemoveType { + RepoOnly = 0, + RepoWithDirectory = 1, +}; + static bool preferences_extension_repo_remove_poll(bContext *C) { if (BLI_listbase_is_empty(&U.extension_repos)) { @@ -313,9 +410,49 @@ static bool preferences_extension_repo_remove_poll(bContext *C) return true; } +static int preferences_extension_repo_remove_invoke(bContext *C, + wmOperator *op, + const wmEvent * /*event*/) +{ + const int index = RNA_int_get(op->ptr, "index"); + bUserExtensionRepoRemoveType repo_type = bUserExtensionRepoRemoveType( + RNA_enum_get(op->ptr, "type")); + bUserExtensionRepo *repo = static_cast( + BLI_findlink(&U.extension_repos, index)); + + if (!repo) { + return OPERATOR_CANCELLED; + } + std::string message; + if (repo_type == bUserExtensionRepoRemoveType::RepoWithDirectory) { + char dirpath[FILE_MAX]; + BKE_preferences_extension_repo_dirpath_get(repo, dirpath, sizeof(dirpath)); + + if (dirpath[0]) { + message = fmt::format(IFACE_("Remove all files in \"{}\"."), dirpath); + } + else { + message = IFACE_("Remove, local files not found."); + repo_type = bUserExtensionRepoRemoveType::RepoOnly; + } + } + else { + message = IFACE_("Remove, keeping local files."); + } + + const char *confirm_text = (repo_type == bUserExtensionRepoRemoveType::RepoWithDirectory) ? + IFACE_("Remove Repository & Files") : + IFACE_("Remove Repository"); + + return WM_operator_confirm_ex( + C, op, nullptr, message.c_str(), confirm_text, ALERT_ICON_WARNING, true); +} + static int preferences_extension_repo_remove_exec(bContext *C, wmOperator *op) { const int index = RNA_int_get(op->ptr, "index"); + const bUserExtensionRepoRemoveType repo_type = bUserExtensionRepoRemoveType( + RNA_enum_get(op->ptr, "type")); bUserExtensionRepo *repo = static_cast( BLI_findlink(&U.extension_repos, index)); if (!repo) { @@ -325,6 +462,19 @@ static int preferences_extension_repo_remove_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_PRE); + if (repo_type == bUserExtensionRepoRemoveType::RepoWithDirectory) { + char dirpath[FILE_MAX]; + BKE_preferences_extension_repo_dirpath_get(repo, dirpath, sizeof(dirpath)); + if (dirpath[0] && BLI_is_dir(dirpath)) { + if (BLI_delete(dirpath, true, true) != 0) { + BKE_reportf(op->reports, + RPT_ERROR, + "Error removing directory: %s", + errno ? strerror(errno) : "unknown"); + } + } + } + BKE_preferences_extension_repo_remove(&U, repo); const int count_remaining = BLI_listbase_count(&U.extension_repos); /* Update active repo index to be in range. */ @@ -345,12 +495,27 @@ static void PREFERENCES_OT_extension_repo_remove(wmOperatorType *ot) ot->idname = "PREFERENCES_OT_extension_repo_remove"; ot->description = "Remove an extension repository"; + ot->invoke = preferences_extension_repo_remove_invoke; ot->exec = preferences_extension_repo_remove_exec; ot->poll = preferences_extension_repo_remove_poll; ot->flag = OPTYPE_INTERNAL; + static const EnumPropertyItem repo_type_items[] = { + {int(bUserExtensionRepoRemoveType::RepoOnly), "REPO_ONLY", 0, "Remove Repository"}, + {int(bUserExtensionRepoRemoveType::RepoWithDirectory), + "REPO_AND_DIRECTORY", + 0, + "Remove Repository & Files", + "Delete all associated local files when removing"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); + + ot->prop = RNA_def_enum( + ot->srna, "type", repo_type_items, 0, "Type", "Method for removing the repository"); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE | PROP_HIDDEN); } /** \} */ diff --git a/source/blender/makesdna/DNA_userdef_defaults.h b/source/blender/makesdna/DNA_userdef_defaults.h index f4da9e4191b..6bd35d28ce0 100644 --- a/source/blender/makesdna/DNA_userdef_defaults.h +++ b/source/blender/makesdna/DNA_userdef_defaults.h @@ -33,7 +33,7 @@ { \ .name = {'\0'}, \ .module = {'\0'}, \ - .dirpath = {'\0'}, \ + .custom_dirpath = {'\0'}, \ .remote_path = {'\0'}, \ .flag = 0, \ } diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 7761ef6aafc..53a66012f99 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -627,8 +627,8 @@ typedef struct bUserExtensionRepo { * The "local" directory where extensions are stored. * When unset, use `{BLENDER_USER_SCRIPTS}/extensions/{bUserExtensionRepo::module}`. */ - char dirpath[1024]; /* FILE_MAX */ - char remote_path[1024]; /* FILE_MAX */ + char custom_dirpath[1024]; /* FILE_MAX */ + char remote_path[1024]; /* FILE_MAX */ int flag; char _pad0[4]; @@ -638,6 +638,8 @@ typedef enum eUserExtensionRepo_Flag { /** Maintain disk cache. */ USER_EXTENSION_REPO_FLAG_NO_CACHE = 1 << 0, USER_EXTENSION_REPO_FLAG_DISABLED = 1 << 1, + USER_EXTENSION_REPO_FLAG_USE_CUSTOM_DIRECTORY = 1 << 2, + USER_EXTENSION_REPO_FLAG_USE_REMOTE_PATH = 1 << 3, } eUserExtensionRepo_Flag; typedef struct SolidLight { diff --git a/source/blender/makesrna/intern/rna_userdef.cc b/source/blender/makesrna/intern/rna_userdef.cc index dd631353f22..44f4f336c94 100644 --- a/source/blender/makesrna/intern/rna_userdef.cc +++ b/source/blender/makesrna/intern/rna_userdef.cc @@ -378,17 +378,36 @@ static void rna_userdef_extension_repo_directory_set(PointerRNA *ptr, const char Main *bmain = G.main; bUserExtensionRepo *repo = (bUserExtensionRepo *)ptr->data; BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_PRE); - BKE_preferences_extension_repo_path_set(repo, value); + BKE_preferences_extension_repo_custom_dirpath_set(repo, value); + BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_POST); +} + +static void rna_userdef_extension_repo_generic_flag_set_impl(PointerRNA *ptr, + const bool value, + const int flag) +{ + Main *bmain = G.main; + bUserExtensionRepo *repo = (bUserExtensionRepo *)ptr->data; + BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_PRE); + SET_FLAG_FROM_TEST(repo->flag, value, flag); BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_POST); } static void rna_userdef_extension_repo_enabled_set(PointerRNA *ptr, bool value) { - Main *bmain = G.main; - bUserExtensionRepo *repo = (bUserExtensionRepo *)ptr->data; - BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_PRE); - SET_FLAG_FROM_TEST(repo->flag, !value, USER_EXTENSION_REPO_FLAG_DISABLED); - BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_POST); + rna_userdef_extension_repo_generic_flag_set_impl(ptr, !value, USER_EXTENSION_REPO_FLAG_DISABLED); +} + +static void rna_userdef_extension_repo_use_custom_directory_set(PointerRNA *ptr, bool value) +{ + rna_userdef_extension_repo_generic_flag_set_impl( + ptr, value, USER_EXTENSION_REPO_FLAG_USE_CUSTOM_DIRECTORY); +} + +static void rna_userdef_extension_repo_use_remote_path_set(PointerRNA *ptr, bool value) +{ + rna_userdef_extension_repo_generic_flag_set_impl( + ptr, value, USER_EXTENSION_REPO_FLAG_USE_REMOTE_PATH); } static void rna_userdef_script_autoexec_update(Main * /*bmain*/, @@ -489,16 +508,22 @@ static void rna_userdef_asset_library_remove(ReportList *reports, PointerRNA *pt static bUserExtensionRepo *rna_userdef_extension_repo_new(const char *name, const char *module, - const char *directory, + const char *custom_directory, const char *remote_path) { Main *bmain = G.main; BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_PRE); bUserExtensionRepo *repo = BKE_preferences_extension_repo_add( - &U, name ? name : "", module ? module : "", directory ? directory : ""); + &U, name ? name : "", module ? module : "", custom_directory ? custom_directory : ""); + if (remote_path) { STRNCPY(repo->remote_path, remote_path); + repo->flag |= USER_EXTENSION_REPO_FLAG_USE_REMOTE_PATH; + } + + if (repo->custom_dirpath[0]) { + repo->flag |= USER_EXTENSION_REPO_FLAG_USE_CUSTOM_DIRECTORY; } BKE_callback_exec_null(bmain, BKE_CB_EVT_EXTENSION_REPOS_UPDATE_POST); @@ -6615,12 +6640,9 @@ static void rna_def_userdef_filepaths_extension_repo(BlenderRNA *brna) RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_userdef_extension_repo_module_set"); 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, nullptr, "dirpath"); - RNA_def_property_ui_text(prop, - "Local Directory", - "The local directory containing extensions. " - "When unset, a path is used based on the user scripts path"); + prop = RNA_def_property(srna, "custom_directory", PROP_STRING, PROP_DIRPATH); + RNA_def_property_string_sdna(prop, nullptr, "custom_dirpath"); + RNA_def_property_ui_text(prop, "Custom Directory", "The local directory containing extensions"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_EDITOR_FILEBROWSER); RNA_def_property_string_funcs( prop, nullptr, nullptr, "rna_userdef_extension_repo_directory_set"); @@ -6646,6 +6668,19 @@ static void rna_def_userdef_filepaths_extension_repo(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag", USER_EXTENSION_REPO_FLAG_DISABLED); RNA_def_property_ui_text(prop, "Enabled", "Enable the repository"); RNA_def_property_boolean_funcs(prop, nullptr, "rna_userdef_extension_repo_enabled_set"); + + prop = RNA_def_property(srna, "use_custom_directory", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "flag", USER_EXTENSION_REPO_FLAG_USE_CUSTOM_DIRECTORY); + RNA_def_property_ui_text( + prop, "Custom Directory", "Manually set the path for extensions to be stored"); + RNA_def_property_boolean_funcs( + prop, nullptr, "rna_userdef_extension_repo_use_custom_directory_set"); + + prop = RNA_def_property(srna, "use_remote_path", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "flag", USER_EXTENSION_REPO_FLAG_USE_REMOTE_PATH); + RNA_def_property_ui_text(prop, "Use Remote", "Synchonize the repository with a remote URL/path"); + RNA_def_property_boolean_funcs(prop, nullptr, "rna_userdef_extension_repo_use_remote_path_set"); } static void rna_def_userdef_script_directory(BlenderRNA *brna) @@ -6760,8 +6795,12 @@ static void rna_def_userdef_extension_repos_collection(BlenderRNA *brna, Propert RNA_def_string(func, "name", nullptr, sizeof(bUserExtensionRepo::name), "Name", ""); RNA_def_string(func, "module", nullptr, sizeof(bUserExtensionRepo::module), "Module", ""); - RNA_def_string( - func, "directory", nullptr, sizeof(bUserExtensionRepo::dirpath), "Directories", ""); + RNA_def_string(func, + "custom_directory", + nullptr, + sizeof(bUserExtensionRepo::custom_dirpath), + "Custom Directory", + ""); RNA_def_string( func, "remote_path", nullptr, sizeof(bUserExtensionRepo::remote_path), "Remote Path", "");