Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_file')
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc31
-rw-r--r--source/blender/editors/space_file/file_draw.c11
-rw-r--r--source/blender/editors/space_file/file_ops.c2
-rw-r--r--source/blender/editors/space_file/filelist.c354
-rw-r--r--source/blender/editors/space_file/filelist.h2
-rw-r--r--source/blender/editors/space_file/space_file.c26
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)) {