Commit: bab93fc3df9f92d535106711d48093315b11830f Author: Julian Eisel Date: Fri Jul 9 12:56:26 2021 +0200 Branches: temp-asset-browser-poselib-merge https://developer.blender.org/rBbab93fc3df9f92d535106711d48093315b11830f
Assets: Initial Asset List as part of the Asset System design Implements a basic, WIP version of the asset list. This is needed to give the asset view UI template asset reading and displaying functionality. See: * Asset System: Data Storage, Reading & UI Access - https://developer.blender.org/T88184 Especially the asset list internals should change. It uses the File/Asset Browser's `FileList` API, which isn't really meant for access from outside the File Browser. But as explained in T88184, it does a lot of the stuff we currently need, so we (Sybren Stüvel and I) decided to go this route for now. Work on a file-list rewrite which integrates well with the asset system started in the `asset-system-filelist` branch. Further includes: * Operator to reload the asset list. * New `bpy.types.AssetHandle.get_full_library_path()` function, which gets the full path of the asset via the asset-list. * Changes to preview loading to prevent the preview loading job to run eternally for asset views. File Browsers have this issue too, but should be fixed separately. =================================================================== M source/blender/editors/asset/CMakeLists.txt M source/blender/editors/asset/asset_edit.cc A source/blender/editors/asset/asset_list.cc M source/blender/editors/asset/asset_ops.cc M source/blender/editors/include/ED_asset.h M source/blender/editors/space_file/filelist.c M source/blender/editors/space_file/filelist.h M source/blender/editors/space_file/space_file.c M source/blender/editors/undo/ed_undo.c M source/blender/editors/util/ed_util.c M source/blender/editors/util/ed_util_ops.cc M source/blender/makesdna/DNA_asset_types.h M source/blender/makesrna/intern/rna_asset.c M source/blender/makesrna/intern/rna_space.c M source/blender/makesrna/intern/rna_workspace.c M source/blender/windowmanager/WM_types.h M source/blender/windowmanager/intern/wm_event_system.c M source/blender/windowmanager/intern/wm_init_exit.c =================================================================== diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt index 794e64fa420..d87879bea2a 100644 --- a/source/blender/editors/asset/CMakeLists.txt +++ b/source/blender/editors/asset/CMakeLists.txt @@ -31,11 +31,13 @@ set(INC_SYS set(SRC asset_edit.cc + asset_list.cc asset_ops.cc ) set(LIB bf_blenloader + bf_blenkernel ) blender_add_lib(bf_editor_asset "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/asset/asset_edit.cc b/source/blender/editors/asset/asset_edit.cc index 949dc1890ad..0937af0dbf1 100644 --- a/source/blender/editors/asset/asset_edit.cc +++ b/source/blender/editors/asset/asset_edit.cc @@ -18,10 +18,15 @@ * \ingroup edasset */ +#include <memory> +#include <string> + #include "BKE_asset.h" #include "BKE_context.h" #include "BKE_lib_id.h" +#include "BLO_readfile.h" + #include "DNA_ID.h" #include "DNA_asset_types.h" #include "DNA_space_types.h" @@ -32,6 +37,8 @@ #include "ED_asset.h" +using namespace blender; + bool ED_asset_mark_id(const bContext *C, ID *id) { if (id->asset_data) { @@ -47,6 +54,9 @@ bool ED_asset_mark_id(const bContext *C, ID *id) UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true); + /* Important for asset storage to update properly! */ + ED_assetlist_storage_tag_main_data_dirty(); + return true; } @@ -59,6 +69,9 @@ bool ED_asset_clear_id(ID *id) /* Don't clear fake user here, there's no guarantee that it was actually set by * #ED_asset_mark_id(), it might have been something/someone else. */ + /* Important for asset storage to update properly! */ + ED_assetlist_storage_tag_main_data_dirty(); + return true; } @@ -125,3 +138,18 @@ const char *ED_asset_handle_get_name(const AssetHandle *asset) { return asset->file_data->name; } + +void ED_asset_handle_get_full_library_path(const bContext *C, + const AssetLibraryReference *asset_library, + const AssetHandle *asset, + char r_full_lib_path[FILE_MAX_LIBEXTRA]) +{ + *r_full_lib_path = '\0'; + + std::string asset_path = ED_assetlist_asset_filepath_get(C, *asset_library, *asset); + if (asset_path.empty()) { + return; + } + + BLO_library_path_explode(asset_path.c_str(), r_full_lib_path, nullptr, nullptr); +} diff --git a/source/blender/editors/asset/asset_list.cc b/source/blender/editors/asset/asset_list.cc new file mode 100644 index 00000000000..1ea948d97d4 --- /dev/null +++ b/source/blender/editors/asset/asset_list.cc @@ -0,0 +1,637 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edasset + * + * Abstractions to manage runtime asset lists with a global cache for multiple UI elements to + * access. + * Internally this uses the #FileList API and structures from `filelist.c`. This is just because it + * contains most necessary logic already and there's not much time for a more long-term solution. + */ + +#include <optional> +#include <string> + +#include "BKE_asset.h" +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "BLI_function_ref.hh" +#include "BLI_hash.hh" +#include "BLI_map.hh" +#include "BLI_path_util.h" +#include "BLI_utility_mixins.hh" + +#include "DNA_asset_types.h" +#include "DNA_space_types.h" + +#include "BKE_preferences.h" + +#include "ED_asset.h" +#include "ED_fileselect.h" +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +/* XXX uses private header of file-space. */ +#include "../space_file/filelist.h" + +using namespace blender; + +/** + * Wrapper to add logic to the AssetLibraryReference DNA struct. + */ +class AssetLibraryReferenceWrapper { + const AssetLibraryReference reference_; + + public: + /* Intentionally not `explicit`, allow implicit conversion for convienience. Might have to be + * NOLINT */ + AssetLibraryReferenceWrapper(const AssetLibraryReference &reference); + ~AssetLibraryReferenceWrapper() = default; + + friend bool operator==(const AssetLibraryReferenceWrapper &a, + const AssetLibraryReferenceWrapper &b); + uint64_t hash() const; +}; + +AssetLibraryReferenceWrapper::AssetLibraryReferenceWrapper(const AssetLibraryReference &reference) + : reference_(reference) +{ +} + +bool operator==(const AssetLibraryReferenceWrapper &a, const AssetLibraryReferenceWrapper &b) +{ + return (a.reference_.type == b.reference_.type) && (a.reference_.type == ASSET_LIBRARY_CUSTOM) ? + (a.reference_.custom_library_index == b.reference_.custom_library_index) : + true; +} + +uint64_t AssetLibraryReferenceWrapper::hash() const +{ + uint64_t hash1 = DefaultHash<decltype(reference_.type)>{}(reference_.type); + if (reference_.type != ASSET_LIBRARY_CUSTOM) { + return hash1; + } + + uint64_t hash2 = DefaultHash<decltype(reference_.custom_library_index)>{}( + reference_.custom_library_index); + return hash1 ^ (hash2 * 33); /* Copied from DefaultHash for std::pair. */ +} + +/* -------------------------------------------------------------------- */ +/** \name Asset list API + * + * Internally re-uses #FileList from the File Browser. It does all the heavy lifting already. + * \{ */ + +/** + * RAII wrapper for `FileList` + */ +class FileListWrapper { + static void filelist_free_fn(FileList *list) + { + filelist_free(list); + MEM_freeN(list); + } + + std::unique_ptr<FileList, decltype(&filelist_free_fn)> file_list_; + + public: + explicit FileListWrapper(eFileSelectType filesel_type) + : file_list_(filelist_new(filesel_type), filelist_free_fn) + { + } + FileListWrapper(FileListWrapper &&other) = default; + FileListWrapper &operator=(FileListWrapper &&other) = default; + ~FileListWrapper() + { + /* Destructs the owned pointer. */ + file_list_ = nullptr; + } + + operator FileList *() const + { + return file_list_.get(); + } +}; + +class PreviewTimer { + /* Non-owning! The Window-Manager registers and owns this. */ + wmTimer *timer_ = nullptr; + + public: + void ensureRunning(const bContext *C) + { + if (!timer_) { + timer_ = WM_event_add_timer_notifier( + CTX_wm_manager(C), CTX_wm_window(C), NC_ASSET | ND_ASSET_LIST_PREVIEW, 0.01); + } + } + + void stop(const bContext *C) + { + if (timer_) { + WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), timer_); + timer_ = nullptr; + } + } +}; + +class AssetList : NonCopyable { + FileListWrapper filelist_; + AssetLibraryReference library_ref_; + PreviewTimer previews_timer_; + + public: + AssetList() = delete; + AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref); + AssetList(AssetList &&other) = default; + ~AssetList() = default; + + void setup(const AssetFilterSettings *filter_settings = nullptr); + void fetch(const bContext &C); + void ensurePreviewsJob(bContext *C); + void clear(bContext *C); + + bool needsRefetch() const; + void iterate(AssetListIterFn fn) const; + bool listen(const wmNotifier ¬ifier) const; + int size() const; + void tagMainDataDirty() const; + void remapID(ID *id_old, ID *id_new) const; + StringRef filepath() const; +}; + +AssetList::AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref) + : filelist_(filesel_type), library_ref_(asset_library_ref) +{ +} + +void AssetList::setup(const AssetFilterSettings *filter_settings) +{ + FileList *files = filelist_; + + /* TODO there should only be one (FileSelectAssetLibraryUID vs. AssetLibraryReference). */ + FileSelectAssetLibraryUID file_asset_lib_ref; + file_asset_lib_ref.type = library_ref_.type; + file_asset_lib_ref.custom_library_index = library_ref_.custom_library_index; + + bUserAssetLibrary *user_library = nullptr; + + /* Ensure valid repository, or fall-back to local one. */ + if (library_ref_.type == ASSET_LIBRARY_CUSTOM) { + BLI_assert(library_ref_.custom_library_index >= 0); + + user_library = BKE_preferences_asset_library_find_from_index( + &U, library_ref_.custom_library_index); + } + + /* Relevant bits from file_refresh(). */ + /* TODO pass options properly. */ + filelist_setrecursion(files, 1); + filelist_setsorting(files, FILE_SORT_ALPHA, false); + filelist_setlibrary(files, &file_asset_lib_ref); + /* TODO different filtering settings require the list to be reread. That's a no-go for when we + * want to allow showing the same asset library with different filter settings (as in, + * different ID types). The filelist needs to be made smarter somehow, maybe goes together with + * the plan to separate the view (preview caching, filtering, etc. ) from the data. */ + filelist_setfilter_options( + files, + filter_settings != nullptr, + true, + true, /* Just always hide parent, prefer to not add an extra user option for this. */ + FILE_TYPE_BLENDERLIB, + filter_settings ? filter_settings->id_types : FILTER_ID_ALL, + true, + "", + ""); + + char path[FILE_MAXDIR] = ""; + if (user_library) { + BLI_strncpy(path, user_library->path, sizeof(path)); + filelist_setdir(files, path); + } + else { + filelist_setdir(files, path); + } +} + +void AssetList::fetch(const bContext &C) +{ + FileList *files = filelist_; + + if (filelist_needs_force_reset(files)) { + filelist_readjob_stop(files, CTX_wm_manager(&C)); + filelist_clear(files); + } + + if (filelist_needs_reading(files)) { + if (!f @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
