Blender V4.3
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
15#include <optional>
16#include <string>
17
18#include "AS_asset_library.hh"
19
20#include "BKE_context.hh"
21#include "BKE_screen.hh"
22
23#include "BLI_map.hh"
24#include "BLI_string.h"
25#include "BLI_utility_mixins.hh"
26
27#include "DNA_space_types.h"
28
29#include "WM_api.hh"
30
31/* XXX uses private header of file-space. */
34
35#include "ED_asset_indexer.hh"
36#include "ED_asset_list.hh"
37#include "ED_fileselect.hh"
38#include "ED_screen.hh"
40
42
43/* -------------------------------------------------------------------- */
53 static void filelist_free_fn(FileList *list)
54 {
55 filelist_free(list);
56 MEM_freeN(list);
57 }
58
59 std::unique_ptr<FileList, decltype(&filelist_free_fn)> file_list_;
60
61 public:
62 explicit FileListWrapper(eFileSelectType filesel_type)
63 : file_list_(filelist_new(filesel_type), filelist_free_fn)
64 {
65 }
66 FileListWrapper(FileListWrapper &&other) = default;
69 {
70 /* Destructs the owned pointer. */
71 file_list_ = nullptr;
72 }
73
74 operator FileList *() const
75 {
76 return file_list_.get();
77 }
78};
79
81 /* Non-owning! The Window-Manager registers and owns this. */
82 wmTimer *timer_ = nullptr;
83
84 public:
85 void ensure_running(const bContext *C)
86 {
87 if (!timer_) {
90 }
91 }
92
93 void stop(const bContext *C)
94 {
95 if (timer_) {
97 timer_ = nullptr;
98 }
99 }
100};
101
103 FileListWrapper filelist_;
104 AssetLibraryReference library_ref_;
105 PreviewTimer previews_timer_;
106
107 public:
108 AssetList() = delete;
109 AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref);
110 AssetList(AssetList &&other) = default;
111 ~AssetList() = default;
112
113 static bool listen(const wmNotifier &notifier);
114
115 void setup();
116 void fetch(const bContext &C);
117 void update_previews(const bContext &C);
118 void clear(const bContext *C);
119
120 AssetHandle asset_get_by_index(int index) const;
121
122 void previews_job_update(const bContext *C);
123 bool needs_refetch() const;
124 bool is_loaded() const;
125 bool is_asset_preview_loading(const AssetHandle &asset) const;
129 FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn) const;
130 void iterate(AssetListIterFn fn) const;
131 int size() const;
132 void tag_main_data_dirty() const;
133 void remap_id(ID *id_old, ID *id_new) const;
134};
135
136AssetList::AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref)
137 : filelist_(filesel_type), library_ref_(asset_library_ref)
138{
139}
140
142{
143 FileList *files = filelist_;
144 std::string asset_lib_path = AS_asset_library_root_path_from_library_ref(library_ref_);
145
146 /* Relevant bits from file_refresh(). */
147 /* TODO pass options properly. */
150 filelist_setlibrary(files, &library_ref_);
152 files,
153 true,
154 true,
155 true, /* Just always hide parent, prefer to not add an extra user option for this. */
158 true,
159 "",
160 "");
162
163 const bool use_asset_indexer = !USER_EXPERIMENTAL_TEST(&U, no_asset_indexing);
165
166 char dirpath[FILE_MAX_LIBEXTRA] = "";
167 if (!asset_lib_path.empty()) {
168 STRNCPY(dirpath, asset_lib_path.c_str());
169 }
170 filelist_setdir(files, dirpath);
171}
172
174{
175 FileList *files = filelist_;
176
177 if (filelist_needs_force_reset(files)) {
180 }
181
182 if (filelist_needs_reading(files)) {
183 if (!filelist_pending(files)) {
185 }
186 }
187 filelist_sort(files);
188 filelist_filter(files);
189}
190
192{
193 if (filelist_cache_previews_enabled(filelist_)) {
194 /* Get newest loaded previews from the background thread queue. */
196 }
197 /* Update preview job, it might have to be stopped. */
198 this->previews_job_update(&C);
199}
200
202{
203 return filelist_needs_force_reset(filelist_) || filelist_needs_reading(filelist_);
204}
205
207{
208 return filelist_is_ready(filelist_);
209}
210
212{
213 /* Ensure previews are enabled. */
214 filelist_cache_previews_set(filelist_, true);
215
217 const_cast<FileDirEntry *>(asset.file_data)))
218 {
219 previews_timer_.ensure_running(&C);
220 }
221}
222
224{
225 return filelist_file_is_preview_pending(filelist_, asset.file_data);
226}
227
232
234 FunctionRef<bool(asset_system::AssetRepresentation &)> prefilter_fn) const
235{
236 FileList *files = filelist_;
237 int numfiles = filelist_files_ensure(files);
238
239 for (int i = 0; i < numfiles; i++) {
241 if (!asset) {
242 continue;
243 }
244
245 if (prefilter_fn && !prefilter_fn(*asset)) {
246 continue;
247 }
248
249 FileDirEntry *file = filelist_file(files, i);
250
251 AssetHandle asset_handle = {file};
252 if (!fn(asset_handle)) {
253 /* If the callback returns false, we stop iterating. */
254 break;
255 }
256 }
257}
258
260{
261 FileList *files = filelist_;
262 const int numfiles = filelist_files_ensure(files);
263
264 for (int i = 0; i < numfiles; i++) {
266 if (!asset) {
267 continue;
268 }
269
270 if (!fn(*asset)) {
271 break;
272 }
273 }
274}
275
277{
278 FileList *files = filelist_;
279
281 previews_timer_.stop(C);
282 return;
283 }
284
285 {
286 const bool previews_running = filelist_cache_previews_running(files) &&
288 if (previews_running) {
289 previews_timer_.ensure_running(C);
290 }
291 else {
292 /* Preview is not running, no need to keep generating update events! */
293 previews_timer_.stop(C);
294 }
295 }
296}
297
299{
300 /* Based on #ED_fileselect_clear() */
301
302 FileList *files = filelist_;
304 filelist_freelib(files);
305 filelist_clear(files);
307
309}
310
312{
313 return {filelist_file(filelist_, index)};
314}
315
319bool AssetList::listen(const wmNotifier &notifier)
320{
321 switch (notifier.category) {
322 case NC_ID: {
323 if (ELEM(notifier.action, NA_RENAME)) {
324 return true;
325 }
326 break;
327 }
328 case NC_ASSET:
330 return true;
331 }
332 if (ELEM(notifier.action, NA_ADDED, NA_REMOVED, NA_EDITED)) {
333 return true;
334 }
335 break;
336 }
337
338 return false;
339}
340
345{
346 return filelist_files_ensure(filelist_);
347}
348
350{
353 }
354}
355
356void AssetList::remap_id(ID * /*id_old*/, ID * /*id_new*/) const
357{
358 /* Trigger full re-fetch of the file list if main data was changed, don't even attempt remap
359 * pointers. We could give file list types a id-remap callback, but it's probably not worth it.
360 * Refreshing local file lists is relatively cheap. */
361 this->tag_main_data_dirty();
362}
363
366/* -------------------------------------------------------------------- */
374
379{
381 return global_storage;
382}
383
384static AssetList *lookup_list(const AssetLibraryReference &library_ref)
385{
386 return global_storage().lookup_ptr(library_ref);
387}
388
390{
391 for (AssetList &list : global_storage().values()) {
392 list.tag_main_data_dirty();
393 }
394}
395
396void storage_id_remap(ID *id_old, ID *id_new)
397{
398 for (AssetList &list : global_storage().values()) {
399 list.remap_id(id_old, id_new);
400 }
401}
402
403static std::optional<eFileSelectType> asset_library_reference_to_fileselect_type(
404 const AssetLibraryReference &library_reference)
405{
406 switch (eAssetLibraryType(library_reference.type)) {
411 return FILE_ASSET_LIBRARY;
413 return FILE_MAIN_ASSET;
414 }
415
416 return std::nullopt;
417}
418
419using is_new_t = bool;
420static std::tuple<AssetList &, is_new_t> ensure_list_storage(
421 const AssetLibraryReference &library_reference, eFileSelectType filesel_type)
422{
423 AssetListMap &storage = global_storage();
424
425 if (AssetList *list = storage.lookup_ptr(library_reference)) {
426 return {*list, false};
427 }
428 storage.add(library_reference, AssetList(filesel_type, library_reference));
429 return {storage.lookup(library_reference), true};
430}
431
435{
436 const wmNotifier *wmn = params->notifier;
437 ARegion *region = params->region;
438
439 switch (wmn->category) {
440 case NC_ASSET:
443 }
444 break;
445 }
446}
447
448/* -------------------------------------------------------------------- */
452void storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
453{
454 std::optional filesel_type = asset_library_reference_to_fileselect_type(*library_reference);
455 if (!filesel_type) {
456 return;
457 }
458
459 auto [list, is_new] = ensure_list_storage(*library_reference, *filesel_type);
460 if (is_new || list.needs_refetch()) {
461 list.setup();
462 list.fetch(*C);
463 }
464}
465
466bool is_loaded(const AssetLibraryReference *library_reference)
467{
468 AssetList *list = lookup_list(*library_reference);
469 if (!list) {
470 return false;
471 }
472 if (list->needs_refetch()) {
473 return false;
474 }
475 return list->is_loaded();
476}
477
478void previews_fetch(const AssetLibraryReference *library_reference, const bContext *C)
479{
480 AssetList *list = lookup_list(*library_reference);
481 if (list) {
482 list->update_previews(*C);
483 }
484}
485
486void clear(const AssetLibraryReference *library_reference, const bContext *C)
487{
488 AssetList *list = lookup_list(*library_reference);
489 if (list) {
490 list->clear(C);
491 }
492
494 LISTBASE_FOREACH (const wmWindow *, win, &wm->windows) {
495 const bScreen *screen = WM_window_get_active_screen(win);
496 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
497 /* Only needs to cover visible file/asset browsers, since others are already cleared through
498 * area exiting. */
499 if (area->spacetype == SPACE_FILE) {
500 SpaceFile *sfile = reinterpret_cast<SpaceFile *>(area->spacedata.first);
501 if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) {
502 if (sfile->asset_params && sfile->asset_params->asset_library_ref == *library_reference)
503 {
504 ED_fileselect_clear(wm, sfile);
505 }
506 }
507 }
508 }
509 }
510
511 /* Always clear the all library when clearing a nested one. */
512 if (library_reference->type != ASSET_LIBRARY_ALL) {
514 }
515}
516
518{
520 clear(&all_lib_ref, C);
521}
522
524{
525 return lookup_list(*library_reference) != nullptr;
526}
527
528void iterate(const AssetLibraryReference &library_reference,
531{
532 AssetList *list = lookup_list(library_reference);
533 if (list) {
534 list->iterate(fn, prefilter_fn);
535 }
536}
537
538void iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn)
539{
540 AssetList *list = lookup_list(library_reference);
541 if (list) {
542 list->iterate(fn);
543 }
544}
545
547 const AssetLibraryReference &library_reference)
548{
549 const AssetList *list = lookup_list(library_reference);
550 if (!list) {
551 return nullptr;
552 }
553 return list->asset_library();
554}
555
557 int asset_index)
558{
559 const AssetList *list = lookup_list(*library_reference);
560 return list->asset_get_by_index(asset_index);
561}
562
564 const AssetLibraryReference &library_reference, int asset_index)
565{
566 AssetHandle asset_handle = asset_handle_get_by_index(&library_reference, asset_index);
567 return reinterpret_cast<asset_system::AssetRepresentation *>(asset_handle.file_data->asset);
568}
569
570bool asset_image_is_loading(const AssetLibraryReference *library_reference,
571 const AssetHandle *asset_handle)
572{
573 const AssetList *list = lookup_list(*library_reference);
574 return list->is_asset_preview_loading(*asset_handle);
575}
576
578 const AssetLibraryReference *library_reference,
579 AssetHandle *asset_handle)
580{
581 AssetList *list = lookup_list(*library_reference);
582 list->ensure_asset_preview_requested(C, *asset_handle);
583}
584
585ImBuf *asset_image_get(const AssetHandle *asset_handle)
586{
587 ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data);
588 if (imbuf) {
589 return imbuf;
590 }
591
592 return filelist_geticon_image_ex(asset_handle->file_data);
593}
594
595bool listen(const wmNotifier *notifier)
596{
597 return AssetList::listen(*notifier);
598}
599
600int size(const AssetLibraryReference *library_reference)
601{
602 AssetList *list = lookup_list(*library_reference);
603 if (list) {
604 return list->size();
605 }
606 return -1;
607}
608
613
616} // namespace blender::ed::asset::list
std::string AS_asset_library_root_path_from_library_ref(const AssetLibraryReference &library_reference)
wmWindow * CTX_wm_window(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define LISTBASE_FOREACH(type, var, list)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define ELEM(...)
#define FILTER_ID_ALL
Definition DNA_ID.h:1206
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(wmWindowManager *wm, SpaceFile *sfile)
Definition filesel.cc:1289
void ED_region_tag_refresh_ui(ARegion *region)
Definition area.cc:662
#define ND_ASSET_LIST_READING
Definition WM_types.hh:516
#define NC_ID
Definition WM_types.hh:362
#define NA_ADDED
Definition WM_types.hh:552
#define NA_EDITED
Definition WM_types.hh:550
#define ND_ASSET_LIST_PREVIEW
Definition WM_types.hh:515
#define NC_ASSET
Definition WM_types.hh:371
#define NA_REMOVED
Definition WM_types.hh:553
#define ND_ASSET_LIST
Definition WM_types.hh:514
#define NA_RENAME
Definition WM_types.hh:554
unsigned int U
Definition btGjkEpa3.h:78
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:484
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
ValueIterator values() const
Definition BLI_map.hh:846
void clear_and_shrink()
Definition BLI_map.hh:1003
static bool listen(const wmNotifier &notifier)
AssetList(AssetList &&other)=default
AssetHandle asset_get_by_index(int index) const
void ensure_asset_preview_requested(const bContext &C, AssetHandle &asset)
void remap_id(ID *id_old, ID *id_new) const
asset_system::AssetLibrary * asset_library() const
void clear(const bContext *C)
void fetch(const bContext &C)
void iterate(AssetListHandleIterFn fn, FunctionRef< bool(asset_system::AssetRepresentation &)> prefilter_fn) const
void previews_job_update(const bContext *C)
bool is_asset_preview_loading(const AssetHandle &asset) const
void update_previews(const bContext &C)
FileListWrapper & operator=(FileListWrapper &&other)=default
FileListWrapper(eFileSelectType filesel_type)
Definition asset_list.cc:62
FileListWrapper(FileListWrapper &&other)=default
void ensure_running(const bContext *C)
Definition asset_list.cc:85
const FileIndexerType file_indexer_noop
void filelist_freelib(FileList *filelist)
Definition filelist.cc:2012
void filelist_tag_force_reset(FileList *filelist)
Definition filelist.cc:2120
void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
Definition filelist.cc:2641
blender::asset_system::AssetLibrary * filelist_asset_library(FileList *filelist)
Definition filelist.cc:2007
bool filelist_needs_force_reset(const FileList *filelist)
Definition filelist.cc:2115
bool filelist_file_is_preview_pending(const FileList *filelist, const FileDirEntry *file)
Definition filelist.cc:1160
void filelist_clear_from_reset_tag(FileList *filelist)
Definition filelist.cc:1970
void filelist_set_no_preview_auto_cache(FileList *filelist)
Definition filelist.cc:2110
bool filelist_pending(const FileList *filelist)
Definition filelist.cc:2138
bool filelist_cache_previews_running(FileList *filelist)
Definition filelist.cc:2729
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:1008
void filelist_free(FileList *filelist)
Definition filelist.cc:1984
void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
Definition filelist.cc:1111
asset_system::AssetRepresentation * filelist_entry_get_asset_representation(const FileList *filelist, const int index)
Definition filelist.cc:2318
bool filelist_cache_previews_done(FileList *filelist)
Definition filelist.cc:2736
void filelist_clear(FileList *filelist)
Definition filelist.cc:1965
void filelist_setdir(FileList *filelist, char dirpath[FILE_MAX_LIBEXTRA])
Definition filelist.cc:2085
void filelist_setrecursion(FileList *filelist, const int recursion_level)
Definition filelist.cc:2102
void filelist_setsorting(FileList *filelist, const short sort, bool invert_sort)
Definition filelist.cc:687
bool filelist_file_ensure_preview_requested(FileList *filelist, FileDirEntry *file)
Definition filelist.cc:1168
bool filelist_cache_previews_update(FileList *filelist)
Definition filelist.cc:2671
FileList * filelist_new(short type)
Definition filelist.cc:1833
ImBuf * filelist_file_getimage(const FileDirEntry *file)
Definition filelist.cc:1211
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
Definition filelist.cc:4327
bool filelist_cache_previews_enabled(const FileList *filelist)
Definition filelist.cc:2636
int filelist_needs_reading(const FileList *filelist)
Definition filelist.cc:2898
void filelist_filter(FileList *filelist)
Definition filelist.cc:952
void filelist_tag_force_reset_mainfiles(FileList *filelist)
Definition filelist.cc:2125
bool filelist_needs_reset_on_main_changes(const FileList *filelist)
Definition filelist.cc:2143
int filelist_files_ensure(FileList *filelist)
Definition filelist.cc:2148
void filelist_sort(FileList *filelist)
Definition filelist.cc:651
void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
Definition filelist.cc:1063
FileDirEntry * filelist_file(FileList *filelist, int index)
Definition filelist.cc:2265
bool filelist_is_ready(const FileList *filelist)
Definition filelist.cc:2133
void filelist_readjob_start(FileList *filelist, const int space_notifier, const bContext *C)
Definition filelist.cc:4265
ImBuf * filelist_geticon_image_ex(const FileDirEntry *file)
Definition filelist.cc:1225
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
AssetLibraryReference all_library_reference()
const FileIndexerType file_indexer_asset
void storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
void asset_preview_ensure_requested(const bContext &C, const AssetLibraryReference *library_reference, AssetHandle *asset_handle)
int size(const AssetLibraryReference *library_reference)
void storage_id_remap(ID *id_old, ID *id_new)
bool asset_image_is_loading(const AssetLibraryReference *library_reference, const AssetHandle *asset_handle)
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 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)
bool storage_has_list_for_library(const AssetLibraryReference *library_reference)
void clear_all_library(const bContext *C)
static AssetListMap & global_storage()
void iterate(const AssetLibraryReference &library_reference, AssetListHandleIterFn fn, FunctionRef< bool(asset_system::AssetRepresentation &)> prefilter_fn=nullptr)
bool is_loaded(const AssetLibraryReference *library_reference)
static AssetList * lookup_list(const AssetLibraryReference &library_ref)
asset_system::AssetRepresentation * asset_get_by_index(const AssetLibraryReference &library_reference, int asset_index)
AssetHandle asset_handle_get_by_index(const AssetLibraryReference *library_reference, int asset_index)
ImBuf * asset_image_get(const AssetHandle *asset_handle)
void asset_reading_region_listen_fn(const wmRegionListenerParams *params)
void previews_fetch(const AssetLibraryReference *library_reference, const bContext *C)
const struct FileDirEntry * file_data
AssetLibraryReference asset_library_ref
AssetRepresentationHandle * asset
Definition DNA_ID.h:413
FileAssetSelectParams * asset_params
unsigned int data
Definition WM_types.hh:325
unsigned int action
Definition WM_types.hh:325
unsigned int category
Definition WM_types.hh:325
void WM_main_add_notifier(uint type, void *reference)
wmTimer * WM_event_timer_add_notifier(wmWindowManager *wm, wmWindow *win, const uint type, const double time_step)
void WM_event_timer_remove_notifier(wmWindowManager *wm, wmWindow *win, wmTimer *timer)
bScreen * WM_window_get_active_screen(const wmWindow *win)