Blender V4.5
asset_list.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14
15#include <optional>
16#include <string>
17
18#include "AS_asset_library.hh"
20
21#include "BKE_context.hh"
22#include "BKE_main.hh"
23#include "BKE_screen.hh"
24
25#include "BLI_listbase.h"
26#include "BLI_map.hh"
27#include "BLI_string.h"
28#include "BLI_utility_mixins.hh"
29
30#include "DNA_space_types.h"
31
32#include "WM_api.hh"
33
34/* XXX uses private header of file-space. */
37
38#include "ED_asset_handle.hh"
39#include "ED_asset_indexer.hh"
40#include "ED_asset_list.hh"
41#include "ED_fileselect.hh"
42#include "ED_screen.hh"
44
46
47/* -------------------------------------------------------------------- */
52
57 static void filelist_free_fn(FileList *list)
58 {
60 }
61
62 std::unique_ptr<FileList, decltype(&filelist_free_fn)> file_list_;
63
64 public:
65 explicit FileListWrapper(eFileSelectType filesel_type)
66 : file_list_(filelist_new(filesel_type), filelist_free_fn)
67 {
68 }
69 FileListWrapper(FileListWrapper &&other) = default;
72 {
73 /* Destructs the owned pointer. */
74 file_list_ = nullptr;
75 }
76
77 operator FileList *() const
78 {
79 return file_list_.get();
80 }
81};
82
84 FileListWrapper filelist_;
85 AssetLibraryReference library_ref_;
86
87 public:
88 AssetList() = delete;
89 AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref);
90 AssetList(AssetList &&other) = default;
91 ~AssetList() = default;
92
93 static bool listen(const wmNotifier &notifier);
94
95 void setup();
96 void fetch(const bContext &C);
97 void ensure_blocking(const bContext &C);
100
102
103 bool needs_refetch() const;
104 bool is_loaded() const;
106 void iterate(AssetListIndexIterFn fn) const;
107 void iterate(AssetListIterFn fn) const;
108 int size() const;
109 void tag_main_data_dirty() const;
110 void remap_id(ID *id_old, ID *id_new) const;
111};
112
113AssetList::AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref)
114 : filelist_(filesel_type), library_ref_(asset_library_ref)
115{
116}
117
119{
120 FileList *files = filelist_;
121 std::string asset_lib_path = AS_asset_library_root_path_from_library_ref(library_ref_);
122
123 /* Relevant bits from file_refresh(). */
124 /* TODO pass options properly. */
127 filelist_setlibrary(files, &library_ref_);
129 files,
130 true,
131 true,
132 true, /* Just always hide parent, prefer to not add an extra user option for this. */
135 true,
136 "",
137 "");
138
139 const bool use_asset_indexer = !USER_EXPERIMENTAL_TEST(&U, no_asset_indexing);
141
142 char dirpath[FILE_MAX_LIBEXTRA] = "";
143 if (!asset_lib_path.empty()) {
144 STRNCPY(dirpath, asset_lib_path.c_str());
145 }
146 filelist_setdir(files, dirpath);
147}
148
150{
151 FileList *files = filelist_;
152
153 if (filelist_needs_force_reset(files)) {
156 }
157
158 if (filelist_needs_reading(files)) {
159 if (!filelist_pending(files)) {
161 }
162 }
163 filelist_sort(files);
164 filelist_filter(files);
165}
166
168{
169 FileList *files = filelist_;
170
171 if (filelist_needs_force_reset(files)) {
173 }
174
175 if (filelist_needs_reading(files)) {
177 }
178
179 filelist_sort(files);
180 filelist_filter(files);
181}
182
184{
185 return filelist_needs_force_reset(filelist_) || filelist_needs_reading(filelist_);
186}
187
189{
190 return filelist_is_ready(filelist_);
191}
192
197
199{
200 FileList *files = filelist_;
201 int numfiles = filelist_files_ensure(files);
202
203 for (int i = 0; i < numfiles; i++) {
205 if (!asset) {
206 continue;
207 }
208
209 if (!fn(*asset, i)) {
210 /* If the callback returns false, we stop iterating. */
211 break;
212 }
213 }
214}
215
217{
218 FileList *files = filelist_;
219 const int numfiles = filelist_files_ensure(files);
220
221 for (int i = 0; i < numfiles; i++) {
223 if (!asset) {
224 continue;
225 }
226
227 if (!fn(*asset)) {
228 break;
229 }
230 }
231}
232
234{
235 /* Based on #ED_fileselect_clear() */
236
237 FileList *files = filelist_;
239 filelist_freelib(files);
240 filelist_clear(files);
242
244}
245
247{
248 /* Based on #ED_fileselect_clear_main_assets() */
249
250 FileList *files = filelist_;
252 filelist_freelib(files);
256
258}
259
261{
262 return {filelist_file(filelist_, index)};
263}
264
268bool AssetList::listen(const wmNotifier &notifier)
269{
270 switch (notifier.category) {
271 case NC_ID: {
272 if (ELEM(notifier.action, NA_RENAME)) {
273 return true;
274 }
275 break;
276 }
277 case NC_ASSET:
279 return true;
280 }
281 if (ELEM(notifier.action, NA_ADDED, NA_REMOVED, NA_EDITED)) {
282 return true;
283 }
284 break;
285 }
286
287 return false;
288}
289
294{
295 return filelist_files_ensure(filelist_);
296}
297
299{
302 }
303}
304
305void AssetList::remap_id(ID * /*id_old*/, ID * /*id_new*/) const
306{
307 /* Trigger full re-fetch of the file list if main data was changed, don't even attempt remap
308 * pointers. We could give file list types a id-remap callback, but it's probably not worth it.
309 * Refreshing local file lists is relatively cheap. */
310 this->tag_main_data_dirty();
311}
312
314
315/* -------------------------------------------------------------------- */
318
319static void clear(const AssetLibraryReference *library_reference, wmWindowManager *wm);
320static void on_save_post(Main *main, PointerRNA **pointers, int num_pointers, void *arg);
321
326
339
344{
345 static GlobalStorage global_storage;
346 return global_storage.list_map;
347}
348
349static AssetList *lookup_list(const AssetLibraryReference &library_ref)
350{
351 return libraries_map().lookup_ptr(library_ref);
352}
353
355{
356 for (AssetList &list : libraries_map().values()) {
357 list.tag_main_data_dirty();
358 }
359}
360
361void storage_id_remap(ID *id_old, ID *id_new)
362{
363 for (AssetList &list : libraries_map().values()) {
364 list.remap_id(id_old, id_new);
365 }
366}
367
368static std::optional<eFileSelectType> asset_library_reference_to_fileselect_type(
369 const AssetLibraryReference &library_reference)
370{
371 switch (eAssetLibraryType(library_reference.type)) {
376 return FILE_ASSET_LIBRARY;
378 return FILE_MAIN_ASSET;
379 }
380
381 return std::nullopt;
382}
383
384using is_new_t = bool;
385static std::tuple<AssetList &, is_new_t> ensure_list_storage(
386 const AssetLibraryReference &library_reference, eFileSelectType filesel_type)
387{
388 AssetListMap &storage = libraries_map();
389
390 if (AssetList *list = storage.lookup_ptr(library_reference)) {
391 return {*list, false};
392 }
393 storage.add(library_reference, AssetList(filesel_type, library_reference));
394 return {storage.lookup(library_reference), true};
395}
396
398
400{
401 const wmNotifier *wmn = params->notifier;
402 ARegion *region = params->region;
403
404 switch (wmn->category) {
405 case NC_ASSET:
408 }
409 break;
410 }
411}
412
413static void on_save_post(Main *main,
414 PointerRNA ** /*pointers*/,
415 int /*num_pointers*/,
416 void * /*arg*/)
417{
418 wmWindowManager *wm = static_cast<wmWindowManager *>(main->wm.first);
419 const AssetLibraryReference current_file_library =
421 clear(&current_file_library, wm);
422}
423
424/* -------------------------------------------------------------------- */
427
428void storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
429{
430 std::optional filesel_type = asset_library_reference_to_fileselect_type(*library_reference);
431 if (!filesel_type) {
432 return;
433 }
434
435 auto [list, is_new] = ensure_list_storage(*library_reference, *filesel_type);
436 if (is_new || list.needs_refetch()) {
437 list.setup();
438 list.fetch(*C);
439 }
440}
441
442void storage_fetch_blocking(const AssetLibraryReference &library_reference, const bContext &C)
443{
444 std::optional filesel_type = asset_library_reference_to_fileselect_type(library_reference);
445 if (!filesel_type) {
446 /* TODO: Warn? */
447 return;
448 }
449
450 auto [list, is_new] = ensure_list_storage(library_reference, *filesel_type);
451 if (is_new || list.needs_refetch()) {
452 list.setup();
453 list.ensure_blocking(C);
454 }
455}
456
457bool is_loaded(const AssetLibraryReference *library_reference)
458{
459 AssetList *list = lookup_list(*library_reference);
460 if (!list) {
461 return false;
462 }
463 if (list->needs_refetch()) {
464 return false;
465 }
466 return list->is_loaded();
467}
468
470 const AssetLibraryReference &library_reference,
471 const wmWindowManager *wm,
472 const FunctionRef<void(SpaceFile &sfile)> fn)
473{
474 LISTBASE_FOREACH (const wmWindow *, win, &wm->windows) {
475 const bScreen *screen = WM_window_get_active_screen(win);
476 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
477 /* Only needs to cover visible file/asset browsers, since others are already cleared through
478 * area exiting. */
479 if (area->spacetype == SPACE_FILE) {
480 SpaceFile *sfile = reinterpret_cast<SpaceFile *>(area->spacedata.first);
481 if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) {
482 if (sfile->asset_params && sfile->asset_params->asset_library_ref == library_reference) {
483 fn(*sfile);
484 }
485 }
486 }
487 }
488 }
489}
490
491void clear(const AssetLibraryReference *library_reference, wmWindowManager *wm)
492{
493 AssetList *list = lookup_list(*library_reference);
494 if (list) {
495 list->clear(wm);
496 }
497
498 /* Only needs to cover visible file/asset browsers, since others are already cleared through area
499 * exiting. */
501 *library_reference, wm, [&](SpaceFile &sfile) { ED_fileselect_clear(wm, &sfile); });
502
503 /* Always clear the all library when clearing a nested one. */
504 if (library_reference->type != ASSET_LIBRARY_ALL) {
506 AssetList *all_lib_list = lookup_list(all_lib_ref);
507
508 /* If the cleared nested library is the current file one, only clear current file assets. */
509 if (library_reference->type == ASSET_LIBRARY_LOCAL) {
510 if (all_lib_list) {
511 all_lib_list->clear_current_file_assets(wm);
512 }
513
515 all_lib_ref, wm, [&](SpaceFile &sfile) { ED_fileselect_clear_main_assets(wm, &sfile); });
516 }
517 else {
518 if (all_lib_list) {
519 all_lib_list->clear(wm);
520 }
521
523 all_lib_ref, wm, [&](SpaceFile &sfile) { ED_fileselect_clear(wm, &sfile); });
524 }
525 }
526}
527
528void clear(const AssetLibraryReference *library_reference, const bContext *C)
529{
530 clear(library_reference, CTX_wm_manager(C));
531}
532
534{
536 clear(&all_lib_ref, CTX_wm_manager(C));
537}
538
540{
541 return lookup_list(*library_reference) != nullptr;
542}
543
545 const bContext *C)
546{
547 bool has_asset_browser = false;
549 *library_reference, CTX_wm_manager(C), [&](SpaceFile & /*sfile*/) {
550 has_asset_browser = true;
551 });
552
553 return has_asset_browser;
554}
555
557{
558 AssetList *list = lookup_list(library_reference);
559 if (list) {
560 list->iterate(fn);
561 }
562}
563
564void iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn)
565{
566 AssetList *list = lookup_list(library_reference);
567 if (list) {
568 list->iterate(fn);
569 }
570}
571
573 const AssetLibraryReference &library_reference)
574{
575 const AssetList *list = lookup_list(library_reference);
576 if (!list) {
577 return nullptr;
578 }
579 return list->asset_library();
580}
581
583 int asset_index)
584{
585 const AssetList *list = lookup_list(*library_reference);
586 return list->asset_get_by_index(asset_index);
587}
588
590 const AssetLibraryReference &library_reference, int asset_index)
591{
592 AssetHandle asset_handle = asset_handle_get_by_index(&library_reference, asset_index);
593 return reinterpret_cast<asset_system::AssetRepresentation *>(asset_handle.file_data->asset);
594}
595
596bool listen(const wmNotifier *notifier)
597{
598 return AssetList::listen(*notifier);
599}
600
601int size(const AssetLibraryReference *library_reference)
602{
603 AssetList *list = lookup_list(*library_reference);
604 if (list) {
605 return list->size();
606 }
607 return -1;
608}
609
611{
613}
614
616
617} // namespace blender::ed::asset::list
std::string AS_asset_library_root_path_from_library_ref(const AssetLibraryReference &library_reference)
Main runtime representation of an asset.
void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
Definition callbacks.cc:74
@ BKE_CB_EVT_SAVE_POST
wmWindowManager * CTX_wm_manager(const bContext *C)
#define LISTBASE_FOREACH(type, var, list)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define ELEM(...)
eAssetLibraryType
@ ASSET_LIBRARY_CUSTOM
@ ASSET_LIBRARY_ESSENTIALS
@ ASSET_LIBRARY_LOCAL
@ ASSET_LIBRARY_ALL
@ FILE_SORT_ASSET_CATALOG
eFileSelectType
@ FILE_ASSET_LIBRARY
@ FILE_MAIN_ASSET
@ FILE_ASSET_LIBRARY_ALL
@ FILE_TYPE_BLENDERLIB
@ SPACE_FILE
@ FILE_BROWSE_MODE_ASSETS
#define FILE_MAX_LIBEXTRA
#define FILE_SELECT_MAX_RECURSIONS
#define USER_EXPERIMENTAL_TEST(userdef, member)
void ED_fileselect_clear_main_assets(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1312
void ED_fileselect_clear(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1298
void ED_region_tag_refresh_ui(ARegion *region)
Definition area.cc:668
#define C
Definition RandGen.cpp:29
#define ND_ASSET_LIST_READING
Definition WM_types.hh:547
#define NC_ID
Definition WM_types.hh:392
#define NA_ADDED
Definition WM_types.hh:583
#define NA_EDITED
Definition WM_types.hh:581
#define ND_ASSET_LIST_PREVIEW
Definition WM_types.hh:546
#define NC_ASSET
Definition WM_types.hh:401
#define NA_REMOVED
Definition WM_types.hh:584
#define ND_ASSET_LIST
Definition WM_types.hh:545
#define NA_RENAME
Definition WM_types.hh:585
#define U
void clear()
Definition BLI_map.hh:1038
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
NonCopyable(const NonCopyable &other)=delete
static bool listen(const wmNotifier &notifier)
AssetList(AssetList &&other)=default
AssetHandle asset_get_by_index(int index) const
void remap_id(ID *id_old, ID *id_new) const
asset_system::AssetLibrary * asset_library() const
void iterate(AssetListIndexIterFn fn) const
void fetch(const bContext &C)
void clear(wmWindowManager *wm)
void clear_current_file_assets(wmWindowManager *wm)
void ensure_blocking(const bContext &C)
FileListWrapper & operator=(FileListWrapper &&other)=default
FileListWrapper(eFileSelectType filesel_type)
Definition asset_list.cc:65
FileListWrapper(FileListWrapper &&other)=default
const FileIndexerType file_indexer_noop
void filelist_freelib(FileList *filelist)
Definition filelist.cc:2002
void filelist_tag_force_reset(FileList *filelist)
Definition filelist.cc:2105
blender::asset_system::AssetLibrary * filelist_asset_library(FileList *filelist)
Definition filelist.cc:1997
bool filelist_needs_force_reset(const FileList *filelist)
Definition filelist.cc:2100
void filelist_readjob_blocking_run(FileList *filelist, int space_notifier, const bContext *C)
Definition filelist.cc:4322
void filelist_clear_from_reset_tag(FileList *filelist)
Definition filelist.cc:1958
bool filelist_pending(const FileList *filelist)
Definition filelist.cc:2128
void filelist_setfilter_options(FileList *filelist, const bool do_filter, const bool hide_dot, const bool hide_parent, const uint64_t filter, const uint64_t filter_id, const bool filter_assets_only, const char *filter_glob, const char *filter_search)
Definition filelist.cc:1011
void filelist_free(FileList *filelist)
Definition filelist.cc:1972
void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
Definition filelist.cc:1114
asset_system::AssetRepresentation * filelist_entry_get_asset_representation(const FileList *filelist, const int index)
Definition filelist.cc:2308
void filelist_clear(FileList *filelist)
Definition filelist.cc:1953
void filelist_setdir(FileList *filelist, char dirpath[FILE_MAX_LIBEXTRA])
Definition filelist.cc:2075
void filelist_tag_reload_asset_library(FileList *filelist)
Definition filelist.cc:2118
void filelist_setrecursion(FileList *filelist, const int recursion_level)
Definition filelist.cc:2092
void filelist_setsorting(FileList *filelist, const short sort, bool invert_sort)
Definition filelist.cc:685
FileList * filelist_new(short type)
Definition filelist.cc:1815
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
Definition filelist.cc:4327
int filelist_needs_reading(const FileList *filelist)
Definition filelist.cc:2878
void filelist_filter(FileList *filelist)
Definition filelist.cc:955
void filelist_tag_force_reset_mainfiles(FileList *filelist)
Definition filelist.cc:2110
bool filelist_needs_reset_on_main_changes(const FileList *filelist)
Definition filelist.cc:2133
int filelist_files_ensure(FileList *filelist)
Definition filelist.cc:2138
void filelist_sort(FileList *filelist)
Definition filelist.cc:649
void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
Definition filelist.cc:1066
FileDirEntry * filelist_file(FileList *filelist, int index)
Definition filelist.cc:2255
bool filelist_is_ready(const FileList *filelist)
Definition filelist.cc:2123
void filelist_readjob_start(FileList *filelist, const int space_notifier, const bContext *C)
Definition filelist.cc:4317
#define main()
#define FILTER_ID_ALL
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
AssetLibraryReference all_library_reference()
AssetLibraryReference current_file_library_reference()
const FileIndexerType file_indexer_asset
void storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
int size(const AssetLibraryReference *library_reference)
void storage_id_remap(ID *id_old, ID *id_new)
bool has_asset_browser_storage_for_library(const AssetLibraryReference *library_reference, const bContext *C)
static void on_save_post(Main *main, PointerRNA **pointers, int num_pointers, void *arg)
static std::tuple< AssetList &, is_new_t > ensure_list_storage(const AssetLibraryReference &library_reference, eFileSelectType filesel_type)
asset_system::AssetLibrary * library_get_once_available(const AssetLibraryReference &library_reference)
void storage_fetch_blocking(const AssetLibraryReference &library_reference, const bContext &C)
void clear(const AssetLibraryReference *library_reference, const bContext *C)
bool listen(const wmNotifier *notifier)
static std::optional< eFileSelectType > asset_library_reference_to_fileselect_type(const AssetLibraryReference &library_reference)
void clear_all_library(const bContext *C)
bool has_list_storage_for_library(const AssetLibraryReference *library_reference)
bool is_loaded(const AssetLibraryReference *library_reference)
static AssetList * lookup_list(const AssetLibraryReference &library_ref)
Map< AssetLibraryReference, AssetList > AssetListMap
asset_system::AssetRepresentation * asset_get_by_index(const AssetLibraryReference &library_reference, int asset_index)
static void foreach_visible_asset_browser_showing_library(const AssetLibraryReference &library_reference, const wmWindowManager *wm, const FunctionRef< void(SpaceFile &sfile)> fn)
FunctionRef< bool(asset_system::AssetRepresentation &)> AssetListIterFn
FunctionRef< bool(asset_system::AssetRepresentation &, int asset_index)> AssetListIndexIterFn
AssetHandle asset_handle_get_by_index(const AssetLibraryReference *library_reference, int asset_index)
void iterate(const AssetLibraryReference &library_reference, AssetListIndexIterFn fn)
static AssetListMap & libraries_map()
void asset_reading_region_listen_fn(const wmRegionListenerParams *params)
const struct FileDirEntry * file_data
AssetLibraryReference asset_library_ref
AssetRepresentationHandle * asset
Definition DNA_ID.h:404
FileAssetSelectParams * asset_params
ListBase areabase
unsigned int data
Definition WM_types.hh:355
unsigned int action
Definition WM_types.hh:355
unsigned int category
Definition WM_types.hh:355
i
Definition text_draw.cc:230
void WM_main_add_notifier(uint type, void *reference)
bScreen * WM_window_get_active_screen(const wmWindow *win)