diff options
Diffstat (limited to 'source/blender/editors/space_file')
-rw-r--r-- | source/blender/editors/space_file/asset_catalog_tree_view.cc | 31 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_draw.c | 11 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_ops.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_file/filelist.c | 354 | ||||
-rw-r--r-- | source/blender/editors/space_file/filelist.h | 2 | ||||
-rw-r--r-- | source/blender/editors/space_file/space_file.c | 26 |
6 files changed, 312 insertions, 114 deletions
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index 8906cf34288..c305a11daf4 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -21,8 +21,6 @@ * \ingroup spfile */ -#include "ED_fileselect.h" - #include "DNA_space_types.h" #include "BKE_asset.h" @@ -33,6 +31,9 @@ #include "BLT_translation.h" +#include "ED_asset.h" +#include "ED_fileselect.h" + #include "RNA_access.h" #include "UI_interface.h" @@ -52,7 +53,7 @@ using namespace blender::bke; namespace blender::ed::asset_browser { class AssetCatalogTreeView : public ui::AbstractTreeView { - bke::AssetCatalogService *catalog_service_; + ::AssetLibrary *asset_library_; /** The asset catalog tree this tree-view represents. */ bke::AssetCatalogTree *catalog_tree_; FileAssetSelectParams *params_; @@ -129,7 +130,7 @@ class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem { AssetCatalogTreeView::AssetCatalogTreeView(::AssetLibrary *library, FileAssetSelectParams *params, SpaceFile &space_file) - : catalog_service_(BKE_asset_library_get_catalog_service(library)), + : asset_library_(library), catalog_tree_(BKE_asset_library_get_catalog_tree(library)), params_(params), space_file_(space_file) @@ -218,7 +219,12 @@ void AssetCatalogTreeViewItem::on_activate() void AssetCatalogTreeViewItem::build_row(uiLayout &row) { - ui::BasicTreeViewItem::build_row(row); + if (catalog_item_.has_unsaved_changes()) { + uiItemL(&row, (label_ + "*").c_str(), icon); + } + else { + uiItemL(&row, label_.c_str(), icon); + } if (!is_hovered()) { return; @@ -353,12 +359,7 @@ bool AssetCatalogTreeViewItem::rename(StringRefNull new_name) const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>( get_tree_view()); - - AssetCatalogPath new_path = catalog_item_.catalog_path().parent(); - new_path = new_path / StringRef(new_name); - - tree_view.catalog_service_->undo_push(); - tree_view.catalog_service_->update_catalog_path(catalog_item_.get_catalog_id(), new_path); + ED_asset_catalog_rename(tree_view.asset_library_, catalog_item_.get_catalog_id(), new_name); return true; } @@ -369,6 +370,10 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row) ui::BasicTreeViewItem::build_row(row); PointerRNA *props; + + UI_but_extra_operator_icon_add( + (uiBut *)tree_row_button(), "ASSET_OT_catalogs_save", WM_OP_INVOKE_DEFAULT, ICON_FILE_TICK); + props = UI_but_extra_operator_icon_add( (uiBut *)tree_row_button(), "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD); /* No parent path to use the root level. */ @@ -470,7 +475,7 @@ void file_ensure_updated_catalog_filter_data( const AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service( asset_library); - if (filter_settings->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG) { + if (filter_settings->asset_catalog_visibility != FILE_SHOW_ASSETS_ALL_CATALOGS) { filter_settings->catalog_filter = std::make_unique<AssetCatalogFilter>( catalog_service->create_catalog_filter(filter_settings->asset_catalog_id)); } @@ -485,7 +490,7 @@ bool file_is_asset_visible_in_catalog_filter_settings( switch (filter_settings->asset_catalog_visibility) { case FILE_SHOW_ASSETS_WITHOUT_CATALOG: - return BLI_uuid_is_nil(asset_data->catalog_id); + return !filter_settings->catalog_filter->is_known(asset_data->catalog_id); case FILE_SHOW_ASSETS_FROM_CATALOG: return filter_settings->catalog_filter->contains(asset_data->catalog_id); case FILE_SHOW_ASSETS_ALL_CATALOGS: diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 9a46579780e..24b24eb81dd 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -465,6 +465,17 @@ static void file_draw_preview(const SpaceFile *sfile, UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); } + const bool is_current_main_data = filelist_file_get_id(file) != NULL; + if (is_current_main_data) { + /* Smaller, fainter icon at the top-right indicating that the file represents data from the + * current file (from current #Main in fact). */ + float icon_x, icon_y; + const uchar light[4] = {255, 255, 255, 255}; + icon_x = xco + ex - UI_UNIT_X; + icon_y = yco + ey - UI_UNIT_Y; + UI_icon_draw_ex(icon_x, icon_y, ICON_FILE_BLEND, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + } + /* Contrasting outline around some preview types. */ if (show_outline) { GPUVertFormat *format = immVertexFormat(); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d0f2a4fdc4c..f647e1d4e4f 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1449,7 +1449,7 @@ static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv ARegion *region = CTX_wm_region(C); SpaceFile *sfile = CTX_wm_space_file(C); - if (!file_highlight_set(sfile, region, event->x, event->y)) { + if (!file_highlight_set(sfile, region, event->xy[0], event->xy[1])) { return OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 773a321da5c..d329a8809c7 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -391,7 +391,7 @@ typedef struct FileList { eFileSelectType type; /* The library this list was created for. Stored here so we know when to re-read. */ AssetLibraryReference *asset_library_ref; - struct AssetLibrary *asset_library; + struct AssetLibrary *asset_library; /* Non-owning pointer. */ short flags; @@ -435,11 +435,14 @@ typedef struct FileList { /* FileList.flags */ enum { FL_FORCE_RESET = 1 << 0, - FL_IS_READY = 1 << 1, - FL_IS_PENDING = 1 << 2, - FL_NEED_SORTING = 1 << 3, - FL_NEED_FILTERING = 1 << 4, - FL_SORT_INVERT = 1 << 5, + /* Don't do a full reset (unless #FL_FORCE_RESET is also set), only reset files representing main + * data (assets from the current file/#Main). */ + FL_FORCE_RESET_MAIN_FILES = 1 << 1, + FL_IS_READY = 1 << 2, + FL_IS_PENDING = 1 << 3, + FL_NEED_SORTING = 1 << 4, + FL_NEED_FILTERING = 1 << 5, + FL_SORT_INVERT = 1 << 6, }; /* FileList.tags */ @@ -1375,6 +1378,11 @@ int ED_file_icon(const FileDirEntry *file) filelist_geticon_ex(file, NULL, false, false); } +static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry) +{ + return intern_entry->local_data.id != NULL; +} + /* ********** Main ********** */ static void parent_dir_until_exists_or_default_root(char *dir) @@ -1470,8 +1478,6 @@ static void filelist_direntryarr_free(FileDirEntryArr *array) #endif array->nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; array->nbr_entries_filtered = FILEDIR_NBR_ENTRIES_UNSET; - array->entry_idx_start = -1; - array->entry_idx_end = -1; } static void filelist_intern_entry_free(FileListInternEntry *entry) @@ -1505,6 +1511,26 @@ static void filelist_intern_free(FileListIntern *filelist_intern) MEM_SAFE_FREE(filelist_intern->filtered); } +/** + * \return the number of main files removed. + */ +static int filelist_intern_free_main_files(FileListIntern *filelist_intern) +{ + int removed_counter = 0; + LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) { + if (!filelist_intern_entry_is_main_file(entry)) { + continue; + } + + BLI_remlink(&filelist_intern->entries, entry); + filelist_intern_entry_free(entry); + removed_counter++; + } + + MEM_SAFE_FREE(filelist_intern->filtered); + return removed_counter; +} + static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata) { FileListEntryCache *cache = BLI_task_pool_user_data(pool); @@ -1805,6 +1831,7 @@ void filelist_settype(FileList *filelist, short type) filelist->read_job_fn = filelist_readjob_asset_library; filelist->prepare_filter_fn = prepare_filter_asset_library; filelist->filter_fn = is_filtered_asset_library; + filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA; break; case FILE_MAIN_ASSET: filelist->check_dir_fn = filelist_checkdir_main_assets; @@ -1823,6 +1850,12 @@ void filelist_settype(FileList *filelist, short type) filelist->flags |= FL_FORCE_RESET; } +static void filelist_clear_asset_library(FileList *filelist) +{ + /* The AssetLibraryService owns the AssetLibrary pointer, so no need for us to free it. */ + filelist->asset_library = NULL; +} + void filelist_clear_ex(struct FileList *filelist, const bool do_asset_library, const bool do_cache, @@ -1846,19 +1879,64 @@ void filelist_clear_ex(struct FileList *filelist, BLI_ghash_clear(filelist->selection_state, NULL, NULL); } - if (do_asset_library && (filelist->asset_library != NULL)) { - /* There is no way to refresh the catalogs stored by the AssetLibrary struct, so instead of - * "clearing" it, the entire struct is freed. It will be reallocated when needed. */ - BKE_asset_library_free(filelist->asset_library); - filelist->asset_library = NULL; + if (do_asset_library) { + filelist_clear_asset_library(filelist); } } -void filelist_clear(struct FileList *filelist) +static void filelist_clear_main_files(FileList *filelist, + const bool do_asset_library, + const bool do_cache, + const bool do_selection) +{ + if (!filelist || !(filelist->tags & FILELIST_TAGS_USES_MAIN_DATA)) { + return; + } + + filelist_tag_needs_filtering(filelist); + + if (do_cache) { + filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); + } + + const int removed_files = filelist_intern_free_main_files(&filelist->filelist_intern); + + filelist->filelist.nbr_entries -= removed_files; + filelist->filelist.nbr_entries_filtered = FILEDIR_NBR_ENTRIES_UNSET; + BLI_assert(filelist->filelist.nbr_entries > FILEDIR_NBR_ENTRIES_UNSET); + + if (do_selection && filelist->selection_state) { + BLI_ghash_clear(filelist->selection_state, NULL, NULL); + } + + if (do_asset_library) { + filelist_clear_asset_library(filelist); + } +} + +void filelist_clear(FileList *filelist) { filelist_clear_ex(filelist, true, true, true); } +/** + * A "smarter" version of #filelist_clear() that calls partial clearing based on the filelist + * force-reset flags. + */ +void filelist_clear_from_reset_tag(FileList *filelist) +{ + /* Do a full clear if needed. */ + if (filelist->flags & FL_FORCE_RESET) { + filelist_clear(filelist); + return; + } + + if (filelist->flags & FL_FORCE_RESET_MAIN_FILES) { + filelist_clear_main_files(filelist, false, true, false); + return; + } +} + void filelist_free(struct FileList *filelist) { if (!filelist) { @@ -1981,7 +2059,7 @@ void filelist_setrecursion(struct FileList *filelist, const int recursion_level) bool filelist_needs_force_reset(FileList *filelist) { - return (filelist->flags & FL_FORCE_RESET) != 0; + return (filelist->flags & (FL_FORCE_RESET | FL_FORCE_RESET_MAIN_FILES)) != 0; } void filelist_tag_force_reset(FileList *filelist) @@ -1989,6 +2067,14 @@ void filelist_tag_force_reset(FileList *filelist) filelist->flags |= FL_FORCE_RESET; } +void filelist_tag_force_reset_mainfiles(FileList *filelist) +{ + if (!(filelist->tags & FILELIST_TAGS_USES_MAIN_DATA)) { + return; + } + filelist->flags |= FL_FORCE_RESET_MAIN_FILES; +} + bool filelist_is_ready(struct FileList *filelist) { return (filelist->flags & FL_IS_READY) != 0; @@ -2718,9 +2804,10 @@ int ED_file_extension_icon(const char *path) } } -int filelist_needs_reading(struct FileList *filelist) +int filelist_needs_reading(FileList *filelist) { - return (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET); + return (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET) || + filelist_needs_force_reset(filelist); } uint filelist_entry_select_set(const FileList *filelist, @@ -3283,6 +3370,9 @@ typedef struct FileListReadJob { char main_name[FILE_MAX]; Main *current_main; struct FileList *filelist; + /** Set to request a partial read that only adds files representing #Main data (IDs). Used when + * #Main may have received changes of interest (e.g. asset removed or renamed). */ + bool only_main_data; /** Shallow copy of #filelist for thread-safe access. * @@ -3297,6 +3387,26 @@ typedef struct FileListReadJob { struct FileList *tmp_filelist; } FileListReadJob; +static void filelist_readjob_append_entries(FileListReadJob *job_params, + ListBase *from_entries, + int nbr_from_entries, + short *do_update) +{ + BLI_assert(BLI_listbase_count(from_entries) == nbr_from_entries); + if (nbr_from_entries <= 0) { + *do_update = false; + return; + } + + FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ + BLI_mutex_lock(&job_params->lock); + BLI_movelisttolist(&filelist->filelist.entries, from_entries); + filelist->filelist.nbr_entries += nbr_from_entries; + BLI_mutex_unlock(&job_params->lock); + + *do_update = true; +} + static bool filelist_readjob_should_recurse_into_entry(const int max_recursion, const bool is_lib, const int current_recursion_level, @@ -3333,11 +3443,11 @@ static bool filelist_readjob_should_recurse_into_entry(const int max_recursion, return true; } -static void filelist_readjob_do(const bool do_lib, - FileListReadJob *job_params, - const short *stop, - short *do_update, - float *progress) +static void filelist_readjob_recursive_dir_add_items(const bool do_lib, + FileListReadJob *job_params, + const short *stop, + short *do_update, + float *progress) { FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ ListBase entries = {0}; @@ -3349,13 +3459,6 @@ static void filelist_readjob_do(const bool do_lib, const int max_recursion = filelist->max_recursion; int nbr_done_dirs = 0, nbr_todo_dirs = 1; - // BLI_assert(filelist->filtered == NULL); - BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && - (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET)); - - /* A valid, but empty directory from now. */ - filelist->filelist.nbr_entries = 0; - todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__); td_dir = BLI_stack_push_r(todo_dirs); td_dir->level = 1; @@ -3443,16 +3546,7 @@ static void filelist_readjob_do(const bool do_lib, } } - if (nbr_entries) { - BLI_mutex_lock(&job_params->lock); - - *do_update = true; - - BLI_movelisttolist(&filelist->filelist.entries, &entries); - filelist->filelist.nbr_entries += nbr_entries; - - BLI_mutex_unlock(&job_params->lock); - } + filelist_readjob_append_entries(job_params, &entries, nbr_entries, do_update); nbr_done_dirs++; *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs; @@ -3469,6 +3563,24 @@ static void filelist_readjob_do(const bool do_lib, BLI_stack_free(todo_dirs); } +static void filelist_readjob_do(const bool do_lib, + FileListReadJob *job_params, + const short *stop, + short *do_update, + float *progress) +{ + FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ + + // BLI_assert(filelist->filtered == NULL); + BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && + (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET)); + + /* A valid, but empty directory from now. */ + filelist->filelist.nbr_entries = 0; + + filelist_readjob_recursive_dir_add_items(do_lib, job_params, stop, do_update, progress); +} + static void filelist_readjob_dir(FileListReadJob *job_params, short *stop, short *do_update, @@ -3506,57 +3618,41 @@ static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params { FileList *tmp_filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ - if (job_params->filelist->asset_library_ref != NULL) { - char library_root_path[FILE_MAX]; - filelist_asset_library_path(job_params, library_root_path); + *do_update = false; - /* Load asset catalogs, into the temp filelist for thread-safety. - * #filelist_readjob_endjob() will move it into the real filelist. */ - tmp_filelist->asset_library = BKE_asset_library_load(library_root_path); - *do_update = true; + if (job_params->filelist->asset_library_ref == NULL) { + return; + } + if (tmp_filelist->asset_library != NULL) { + /* Asset library already loaded. */ + return; } -} -static void filelist_readjob_asset_library(FileListReadJob *job_params, - short *stop, - short *do_update, - float *progress) -{ - filelist_readjob_load_asset_library_data(job_params, do_update); - filelist_readjob_lib(job_params, stop, do_update, progress); -} + char library_root_path[FILE_MAX]; + filelist_asset_library_path(job_params, library_root_path); -static void filelist_readjob_main(FileListReadJob *job_params, - short *stop, - short *do_update, - float *progress) -{ - /* TODO! */ - filelist_readjob_dir(job_params, stop, do_update, progress); + /* Load asset catalogs, into the temp filelist for thread-safety. + * #filelist_readjob_endjob() will move it into the real filelist. */ + tmp_filelist->asset_library = BKE_asset_library_load(library_root_path); + *do_update = true; } -/** - * \warning Acts on main, so NOT thread-safe! - */ -static void filelist_readjob_main_assets(FileListReadJob *job_params, - short *UNUSED(stop), - short *do_update, - float *UNUSED(progress)) +static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params, + short *UNUSED(stop), + short *do_update, + float *UNUSED(progress)) { FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ - BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && - (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET)); - - filelist_readjob_load_asset_library_data(job_params, do_update); - - /* A valid, but empty directory from now. */ - filelist->filelist.nbr_entries = 0; FileListInternEntry *entry; ListBase tmp_entries = {0}; ID *id_iter; int nbr_entries = 0; + /* Make sure no IDs are added/removed/reallocated in the main thread while this is running in + * parallel. */ + BKE_main_lock(job_params->current_main); + FOREACH_MAIN_ID_BEGIN (job_params->current_main, id_iter) { if (!id_iter->asset_data) { continue; @@ -3579,16 +3675,93 @@ static void filelist_readjob_main_assets(FileListReadJob *job_params, } FOREACH_MAIN_ID_END; + BKE_main_unlock(job_params->current_main); + if (nbr_entries) { *do_update = true; BLI_movelisttolist(&filelist->filelist.entries, &tmp_entries); filelist->filelist.nbr_entries += nbr_entries; - filelist->filelist.nbr_entries_filtered = filelist->filelist.entry_idx_start = - filelist->filelist.entry_idx_end = -1; + filelist->filelist.nbr_entries_filtered = -1; } } +/** + * Check if \a bmain is stored within the root path of \a filelist. This means either directly or + * in some nested directory. In other words, it checks if the \a filelist root path is contained in + * the path to \a bmain. + * This is irrespective of the recursion level displayed, it basically assumes unlimited recursion + * levels. + */ +static bool filelist_contains_main(const FileList *filelist, const Main *bmain) +{ + const char *main_path = BKE_main_blendfile_path(bmain); + return main_path[0] && BLI_path_contains(filelist->filelist.root, main_path); +} + +static void filelist_readjob_asset_library(FileListReadJob *job_params, + short *stop, + short *do_update, + float *progress) +{ + FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ + + BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && + (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET)); + + /* A valid, but empty file-list from now. */ + filelist->filelist.nbr_entries = 0; + + /* NOP if already read. */ + filelist_readjob_load_asset_library_data(job_params, do_update); + + if (filelist_contains_main(filelist, job_params->current_main)) { + filelist_readjob_main_assets_add_items(job_params, stop, do_update, progress); + } + if (!job_params->only_main_data) { + filelist_readjob_recursive_dir_add_items(true, job_params, stop, do_update, progress); + } +} + +static void filelist_readjob_main(FileListReadJob *job_params, + short *stop, + short *do_update, + float *progress) +{ + /* TODO! */ + filelist_readjob_dir(job_params, stop, do_update, progress); +} + +static void filelist_readjob_main_assets(FileListReadJob *job_params, + short *stop, + short *do_update, + float *progress) +{ + FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ + BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && + (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET)); + + filelist_readjob_load_asset_library_data(job_params, do_update); + + /* A valid, but empty file-list from now. */ + filelist->filelist.nbr_entries = 0; + + filelist_readjob_main_assets_add_items(job_params, stop, do_update, progress); +} + +/** + * Check if the read-job is requesting a partial reread of the file list only. + */ +static bool filelist_readjob_is_partial_read(const FileListReadJob *read_job) +{ + return read_job->only_main_data; +} + +/** + * \note This may trigger partial filelist reading. If the #FL_FORCE_RESET_MAIN_FILES flag is set, + * some current entries are kept and we just call the readjob to update the main files (see + * #FileListReadJob.only_main_data). + */ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress) { FileListReadJob *flrj = flrjv; @@ -3599,8 +3772,6 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update BLI_mutex_lock(&flrj->lock); BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist); - BLI_assert_msg(flrj->filelist->asset_library == NULL, - "Asset library should not yet be assigned at start of read job"); flrj->tmp_filelist = MEM_dupallocN(flrj->filelist); @@ -3609,7 +3780,12 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update flrj->tmp_filelist->filelist_intern.filtered = NULL; BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries); - filelist_uid_unset(&flrj->tmp_filelist->filelist_intern.curr_uid); + if (filelist_readjob_is_partial_read(flrj)) { + /* Don't unset the current UID on partial read, would give duplicates otherwise. */ + } + else { + filelist_uid_unset(&flrj->tmp_filelist->filelist_intern.curr_uid); + } flrj->tmp_filelist->libfiledata = NULL; memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache)); @@ -3622,6 +3798,11 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update flrj->tmp_filelist->read_job_fn(flrj, stop, do_update, progress); } +/** + * \note This may update for a partial filelist reading job. If the #FL_FORCE_RESET_MAIN_FILES flag + * is set, some current entries are kept and we just call the readjob to update the main + * files (see #FileListReadJob.only_main_data). + */ static void filelist_readjob_update(void *flrjv) { FileListReadJob *flrj = flrjv; @@ -3643,7 +3824,11 @@ static void filelist_readjob_update(void *flrjv) if (flrj->tmp_filelist->asset_library) { flrj->filelist->asset_library = flrj->tmp_filelist->asset_library; - flrj->tmp_filelist->asset_library = NULL; /* MUST be NULL to avoid double-free. */ + } + + /* Important for partial reads: Copy increased UID counter back to the real list. */ + if (flrj->tmp_filelist->filelist_intern.curr_uid > fl_intern->curr_uid) { + fl_intern->curr_uid = flrj->tmp_filelist->filelist_intern.curr_uid; } BLI_mutex_unlock(&flrj->lock); @@ -3708,8 +3893,11 @@ void filelist_readjob_start(FileList *filelist, const int space_notifier, const flrj->filelist = filelist; flrj->current_main = bmain; BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name)); + if ((filelist->flags & FL_FORCE_RESET_MAIN_FILES) && !(filelist->flags & FL_FORCE_RESET)) { + flrj->only_main_data = true; + } - filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY); + filelist->flags &= ~(FL_FORCE_RESET | FL_FORCE_RESET_MAIN_FILES | FL_IS_READY); filelist->flags |= FL_IS_PENDING; /* Init even for single threaded execution. Called functions use it. */ diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index c2c1211b81c..0048a349dca 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -96,6 +96,7 @@ void filelist_clear_ex(struct FileList *filelist, const bool do_asset_library, const bool do_cache, const bool do_selection); +void filelist_clear_from_reset_tag(struct FileList *filelist); void filelist_free(struct FileList *filelist); const char *filelist_dir(struct FileList *filelist); @@ -117,6 +118,7 @@ bool filelist_file_cache_block(struct FileList *filelist, const int index); bool filelist_needs_force_reset(struct FileList *filelist); void filelist_tag_force_reset(struct FileList *filelist); +void filelist_tag_force_reset_mainfiles(struct FileList *filelist); bool filelist_pending(struct FileList *filelist); bool filelist_needs_reset_on_main_changes(const struct FileList *filelist); bool filelist_is_ready(struct FileList *filelist); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index c8bca22c166..a875b7a2c12 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -43,6 +43,7 @@ #include "WM_message.h" #include "WM_types.h" +#include "ED_asset.h" #include "ED_fileselect.h" #include "ED_screen.h" #include "ED_space_api.h" @@ -303,15 +304,6 @@ static void file_ensure_valid_region_state(bContext *C, } } -/** - * Tag the space to recreate the file-list. - */ -static void file_tag_reset_list(ScrArea *area, SpaceFile *sfile) -{ - filelist_tag_force_reset(sfile->files); - ED_area_tag_refresh(area); -} - static void file_refresh(const bContext *C, ScrArea *area) { wmWindowManager *wm = CTX_wm_manager(C); @@ -326,7 +318,7 @@ static void file_refresh(const bContext *C, ScrArea *area) if (sfile->files && (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES) && filelist_needs_reset_on_main_changes(sfile->files)) { - filelist_tag_force_reset(sfile->files); + filelist_tag_force_reset_mainfiles(sfile->files); } sfile->tags &= ~FILE_TAG_REBUILD_MAIN_FILES; @@ -336,8 +328,9 @@ static void file_refresh(const bContext *C, ScrArea *area) } if (ED_fileselect_is_asset_browser(sfile)) { - /* Only poses supported as non-experimental right now. */ - params->filter_id = U.experimental.use_extended_asset_browser ? FILTER_ID_ALL : FILTER_ID_AC; + /* Ask the asset code for appropriate ID filter flags for the supported assets, and mask others + * out. */ + params->filter_id &= ED_asset_types_supported_as_filter_flags(); } filelist_settype(sfile->files, params->type); @@ -369,7 +362,7 @@ static void file_refresh(const bContext *C, ScrArea *area) if (filelist_needs_force_reset(sfile->files)) { filelist_readjob_stop(sfile->files, wm); - filelist_clear(sfile->files); + filelist_clear_from_reset_tag(sfile->files); } if (filelist_needs_reading(sfile->files)) { @@ -431,9 +424,8 @@ static void file_on_reload_callback_call(SpaceFile *sfile) static void file_reset_filelist_showing_main_data(ScrArea *area, SpaceFile *sfile) { if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { - /* Full refresh of the file list if local asset data was changed. Refreshing this view - * is cheap and users expect this to be updated immediately. */ - file_tag_reset_list(area, sfile); + filelist_tag_force_reset_mainfiles(sfile->files); + ED_area_tag_refresh(area); } } @@ -664,7 +656,7 @@ static void file_main_region_draw(const bContext *C, ARegion *region) /* on first read, find active file */ if (params->highlight_file == -1) { wmEvent *event = CTX_wm_window(C)->eventstate; - file_highlight_set(sfile, region, event->x, event->y); + file_highlight_set(sfile, region, event->xy[0], event->xy[1]); } if (!file_draw_hint_if_invalid(sfile, region)) { |