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:
authorJulian Eisel <julian@blender.org>2020-12-14 15:50:36 +0300
committerJulian Eisel <julian@blender.org>2020-12-15 19:03:48 +0300
commit70474e1a7cc45a1b1cc08d39b3e472c88c8d3225 (patch)
tree1f973b96e0b6c78e4b30e4413517a994e59ff744
parente413c80371c1714d80262034d0e83b4e10e6cbe5 (diff)
Asset System: Prepare File Browser backend for the Asset Browser
The Asset Browser will be a sub-editor of the File Browser. This prepares the File Browser code for that. **File-Lists** * Support loading assets with metadata read from external files into the file-list. * New main based file-list type, for the "Current File" asset library. * Refresh file-list when switching between browse modes or asset libraries. * Support empty file-lists (asset library with no assets). * Store file previews as icons, so scripts can reference them via icon-id. See previous commit. **Space Data** * Introduce "browse mode" to differeniate between file and asset browsing. * Add `FileAssetSelectParams` to `SpaceFile`, with `FileSelectParams` as base. Makes sure data is separated between asset and file browsing when switching between them. The active params can be obtained through `ED_fileselect_get_active_params()`. * `FileAssetSelectParams` stores the currently visible asset library ID. * Introduce file history abstraction so file and asset browsing can keep a separate history (previous and next directories). **General** * Option to only show asset data-blocks while file browsing (not exposed here). * Add "active_file" context member, so scripts can get and display info about the active file. * Add "active_id" context member, so `ED_OT_lib_id_load_custom_preview` can set a custom ID preview. (Only for "Current File" asset library) * Expose some of `FileDirEntry` in RNA as (non-editable). That way scripts can obtain name, preview icon and asset-data. Part of the first Asset Browser milestone. Check the #asset_browser_milestone_1 project milestone on developer.blender.org. Differential Revision: https://developer.blender.org/D9724 Reviewed by: Bastien Montagne
-rw-r--r--source/blender/blenkernel/intern/screen.c11
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/editors/include/ED_fileselect.h7
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c9
-rw-r--r--source/blender/editors/space_file/filelist.c655
-rw-r--r--source/blender/editors/space_file/filelist.h19
-rw-r--r--source/blender/editors/space_file/filesel.c188
-rw-r--r--source/blender/editors/space_file/space_file.c139
-rw-r--r--source/blender/makesdna/DNA_space_types.h125
-rw-r--r--source/blender/makesrna/RNA_access.h2
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_space.c241
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c2
14 files changed, 1159 insertions, 242 deletions
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index ae817c46931..52c41c9fd05 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -1266,6 +1266,9 @@ static void write_area_regions(BlendWriter *writer, ScrArea *area)
if (sfile->params) {
BLO_write_struct(writer, FileSelectParams, sfile->params);
}
+ if (sfile->asset_params) {
+ BLO_write_struct(writer, FileAssetSelectParams, sfile->asset_params);
+ }
}
else if (sl->spacetype == SPACE_SEQ) {
BLO_write_struct(writer, SpaceSeq, sl);
@@ -1663,11 +1666,14 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
* plus, it isn't saved to files yet!
*/
sfile->folders_prev = sfile->folders_next = NULL;
+ BLI_listbase_clear(&sfile->folder_histories);
sfile->files = NULL;
sfile->layout = NULL;
sfile->op = NULL;
sfile->previews_timer = NULL;
+ sfile->tags = 0;
BLO_read_data_address(reader, &sfile->params);
+ BLO_read_data_address(reader, &sfile->asset_params);
}
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
@@ -1751,8 +1757,11 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr
}
break;
}
- case SPACE_FILE:
+ case SPACE_FILE: {
+ SpaceFile *sfile = (SpaceFile *)sl;
+ sfile->tags |= FILE_TAG_REBUILD_MAIN_FILES;
break;
+ }
case SPACE_ACTION: {
SpaceAction *saction = (SpaceAction *)sl;
bDopeSheet *ads = &saction->ads;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index a3e793038f7..bccc7150523 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2751,6 +2751,7 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
SpaceFile *sfile = (SpaceFile *)sl;
sfile->op = NULL;
sfile->previews_timer = NULL;
+ sfile->tags = FILE_TAG_REBUILD_MAIN_FILES;
}
else if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index a5a8df916d6..3288cf11cb0 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -29,6 +29,7 @@ extern "C" {
struct ARegion;
struct FileSelectParams;
+struct FileAssetSelectParams;
struct Scene;
struct ScrArea;
struct SpaceFile;
@@ -103,14 +104,14 @@ struct rcti;
struct FileSelectParams *ED_fileselect_ensure_active_params(struct SpaceFile *sfile);
struct FileSelectParams *ED_fileselect_get_active_params(const struct SpaceFile *sfile);
+struct FileSelectParams *ED_fileselect_get_file_params(const struct SpaceFile *sfile);
+struct FileAssetSelectParams *ED_fileselect_get_asset_params(const struct SpaceFile *sfile);
void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
void ED_fileselect_params_to_userdef(struct SpaceFile *sfile,
const int temp_win_size[],
const bool is_maximized);
-void ED_fileselect_reset_params(struct SpaceFile *sfile);
-
void ED_fileselect_init_layout(struct SpaceFile *sfile, struct ARegion *region);
FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, struct ARegion *region);
@@ -142,6 +143,8 @@ void ED_fileselect_exit(struct wmWindowManager *wm,
struct Scene *owner_scene,
struct SpaceFile *sfile);
+bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile);
+
void ED_fileselect_window_params_get(const struct wmWindow *win,
int win_size[2],
bool *is_maximized);
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index b459c02d9e5..a0e02681e0e 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -90,6 +90,7 @@ void file_sfile_to_operator(struct Main *bmain, struct wmOperator *op, struct Sp
void file_operator_to_sfile(struct Main *bmain, struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
+void fileselect_refresh_params(struct SpaceFile *sfile);
void fileselect_file_set(SpaceFile *sfile, const int index);
bool file_attribute_column_type_enabled(const FileSelectParams *params,
FileAttributeColumnType column);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index b98348307f3..8af84f65ced 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -930,6 +930,7 @@ void FILE_OT_select_all(wmOperatorType *ot)
/* Note we could get rid of this one, but it's used by some addon so...
* Does not hurt keeping it around for now. */
+/* TODO disallow bookmark editing in assets mode? */
static int bookmark_select_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -1836,10 +1837,6 @@ static int file_previous_exec(bContext *C, wmOperator *UNUSED(op))
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
if (params) {
- if (!sfile->folders_next) {
- sfile->folders_next = folderlist_new();
- }
-
folderlist_pushdir(sfile->folders_next, params->dir);
folderlist_popdir(sfile->folders_prev, params->dir);
folderlist_pushdir(sfile->folders_next, params->dir);
@@ -1874,10 +1871,6 @@ static int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
if (params) {
- if (!sfile->folders_next) {
- sfile->folders_next = folderlist_new();
- }
-
folderlist_pushdir(sfile->folders_prev, params->dir);
folderlist_popdir(sfile->folders_next, params->dir);
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index e87142a7096..5dc5f741ac3 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -53,13 +53,17 @@
# include "BLI_winstuff.h"
#endif
+#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_main_idmap.h"
#include "BLO_readfile.h"
+#include "DNA_asset_types.h"
#include "DNA_space_types.h"
#include "ED_datafiles.h"
@@ -82,6 +86,8 @@
#include "filelist.h"
+#define FILEDIR_NBR_ENTRIES_UNSET -1
+
/* ----------------- FOLDERLIST (previous/next) -------------- */
typedef struct FolderList {
@@ -89,12 +95,6 @@ typedef struct FolderList {
char *foldername;
} FolderList;
-ListBase *folderlist_new(void)
-{
- ListBase *p = MEM_callocN(sizeof(*p), __func__);
- return p;
-}
-
void folderlist_popdir(struct ListBase *folderlist, char *dir)
{
const char *prev_dir;
@@ -117,6 +117,10 @@ void folderlist_popdir(struct ListBase *folderlist, char *dir)
void folderlist_pushdir(ListBase *folderlist, const char *dir)
{
+ if (!dir[0]) {
+ return;
+ }
+
struct FolderList *folder, *previous_folder;
previous_folder = folderlist->last;
@@ -153,7 +157,7 @@ int folderlist_clear_next(struct SpaceFile *sfile)
struct FolderList *folder;
/* if there is no folder_next there is nothing we can clear */
- if (!sfile->folders_next) {
+ if (BLI_listbase_is_empty(sfile->folders_next)) {
return 0;
}
@@ -180,23 +184,79 @@ void folderlist_free(ListBase *folderlist)
}
}
-ListBase *folderlist_duplicate(ListBase *folderlist)
+static ListBase folderlist_duplicate(ListBase *folderlist)
{
+ ListBase folderlistn = {NULL};
- if (folderlist) {
- ListBase *folderlistn = MEM_callocN(sizeof(*folderlistn), __func__);
- FolderList *folder;
+ BLI_duplicatelist(&folderlistn, folderlist);
+
+ for (FolderList *folder = folderlistn.first; folder; folder = folder->next) {
+ folder->foldername = MEM_dupallocN(folder->foldername);
+ }
+ return folderlistn;
+}
- BLI_duplicatelist(folderlistn, folderlist);
+/* ----------------- Folder-History (wraps/owns file list above) -------------- */
- for (folder = folderlistn->first; folder; folder = folder->next) {
- folder->foldername = MEM_dupallocN(folder->foldername);
+static FileFolderHistory *folder_history_find(const SpaceFile *sfile, eFileBrowse_Mode browse_mode)
+{
+ LISTBASE_FOREACH (FileFolderHistory *, history, &sfile->folder_histories) {
+ if (history->browse_mode == browse_mode) {
+ return history;
}
- return folderlistn;
}
+
return NULL;
}
+void folder_history_list_ensure_for_active_browse_mode(SpaceFile *sfile)
+{
+ FileFolderHistory *history = folder_history_find(sfile, sfile->browse_mode);
+
+ if (!history) {
+ history = MEM_callocN(sizeof(*history), __func__);
+ history->browse_mode = sfile->browse_mode;
+ BLI_addtail(&sfile->folder_histories, history);
+ }
+
+ sfile->folders_next = &history->folders_next;
+ sfile->folders_prev = &history->folders_prev;
+}
+
+static void folder_history_entry_free(SpaceFile *sfile, FileFolderHistory *history)
+{
+ if (sfile->folders_prev == &history->folders_prev) {
+ sfile->folders_prev = NULL;
+ }
+ if (sfile->folders_next == &history->folders_next) {
+ sfile->folders_next = NULL;
+ }
+ folderlist_free(&history->folders_prev);
+ folderlist_free(&history->folders_next);
+ BLI_freelinkN(&sfile->folder_histories, history);
+}
+
+void folder_history_list_free(SpaceFile *sfile)
+{
+ LISTBASE_FOREACH_MUTABLE (FileFolderHistory *, history, &sfile->folder_histories) {
+ folder_history_entry_free(sfile, history);
+ }
+}
+
+ListBase folder_history_list_duplicate(ListBase *listbase)
+{
+ ListBase histories = {NULL};
+
+ LISTBASE_FOREACH (FileFolderHistory *, history, listbase) {
+ FileFolderHistory *history_new = MEM_dupallocN(history);
+ history_new->folders_prev = folderlist_duplicate(&history->folders_prev);
+ history_new->folders_next = folderlist_duplicate(&history->folders_next);
+ BLI_addtail(&histories, history_new);
+ }
+
+ return histories;
+}
+
/* ------------------FILELIST------------------------ */
typedef struct FileListInternEntry {
@@ -216,6 +276,24 @@ typedef struct FileListInternEntry {
/** not strictly needed, but used during sorting, avoids to have to recompute it there... */
char *name;
+ /**
+ * This is data from the current main, represented by this file. It's crucial that this is
+ * updated correctly on undo, redo and file reading (without UI). The space is responsible to
+ * take care of that.
+ */
+ struct {
+ /** When showing local IDs (FILE_MAIN, FILE_MAIN_ASSET), the ID this file entry represents. */
+ ID *id;
+
+ /* For the few file types that have the preview already in memory. For others, there's delayed
+ * preview reading from disk. Non-owning pointer. */
+ PreviewImage *preview_image;
+ } local_data;
+
+ /** When the file represents an asset read from another file, it is stored here.
+ * Owning pointer. */
+ AssetMetaData *imported_asset_data;
+
/** Defined in BLI_fileops.h */
eFileAttributes attributes;
BLI_stat_t st;
@@ -267,7 +345,11 @@ typedef struct FileListEntryPreview {
char path[FILE_MAX];
uint flags;
int index;
- ImBuf *img;
+ /* Some file types load the memory from runtime data, not from disk. We just wait until it's done
+ * generating (BKE_previewimg_is_finished()). */
+ PreviewImage *in_memory_preview;
+
+ int icon_id;
} FileListEntryPreview;
/* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing
@@ -290,11 +372,16 @@ enum {
FLF_HIDE_DOT = 1 << 1,
FLF_HIDE_PARENT = 1 << 2,
FLF_HIDE_LIB_DIR = 1 << 3,
+ FLF_ASSETS_ONLY = 1 << 4,
};
typedef struct FileList {
FileDirEntryArr filelist;
+ eFileSelectType type;
+ /* The library this list was created for. Stored here so we know when to re-read. */
+ FileSelectAssetLibraryUID *asset_library;
+
short flags;
short sort;
@@ -324,10 +411,13 @@ typedef struct FileList {
bool (*checkdirf)(struct FileList *, char *, const bool);
/* Fill filelist (to be called by read job). */
- void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
+ void (*read_jobf)(
+ Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
/* Filter an entry of current filelist. */
bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *);
+
+ short tags; /* FileListTags */
} FileList;
/* FileList.flags */
@@ -340,6 +430,14 @@ enum {
FL_SORT_INVERT = 1 << 5,
};
+/* FileList.tags */
+enum FileListTags {
+ /** The file list has references to main data (IDs) and needs special care. */
+ FILELIST_TAGS_USES_MAIN_DATA = (1 << 0),
+ /** The file list type is not thread-safe. */
+ FILELIST_TAGS_NO_THREADS = (1 << 2),
+};
+
#define SPECIAL_IMG_SIZE 256
#define SPECIAL_IMG_ROWS 1
#define SPECIAL_IMG_COLS 7
@@ -357,24 +455,34 @@ enum {
static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX];
-static void filelist_readjob_main(FileList *filelist,
+static void filelist_readjob_main(Main *current_main,
+ FileList *filelist,
const char *main_name,
short *stop,
short *do_update,
float *progress,
ThreadMutex *lock);
-static void filelist_readjob_lib(FileList *filelist,
+static void filelist_readjob_lib(Main *current_main,
+ FileList *filelist,
const char *main_name,
short *stop,
short *do_update,
float *progress,
ThreadMutex *lock);
-static void filelist_readjob_dir(FileList *filelist,
+static void filelist_readjob_dir(Main *current_main,
+ FileList *filelist,
const char *main_name,
short *stop,
short *do_update,
float *progress,
ThreadMutex *lock);
+static void filelist_readjob_main_assets(Main *current_main,
+ FileList *filelist,
+ const char *main_name,
+ short *stop,
+ short *do_update,
+ float *progress,
+ ThreadMutex *lock);
/* helper, could probably go in BKE actually? */
static int groupname_to_code(const char *group);
@@ -694,6 +802,11 @@ static bool is_filtered_hidden(const char *filename,
return true;
}
#endif
+ /* For data-blocks (but not the group directories), check the asset-only filter. */
+ if (!(file->typeflag & FILE_TYPE_DIR) && (file->typeflag & FILE_TYPE_BLENDERLIB) &&
+ (filter->flags & FLF_ASSETS_ONLY) && !(file->typeflag & FILE_TYPE_ASSET)) {
+ return true;
+ }
return false;
}
@@ -737,51 +850,61 @@ static bool is_filtered_file(FileListInternEntry *file,
return is_filtered;
}
-static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
+static bool is_filtered_id_file(const FileListInternEntry *file,
+ const char *id_group,
+ const char *name,
+ const FileListFilter *filter)
{
- bool is_filtered;
- char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
-
- BLI_join_dirfile(path, sizeof(path), root, file->relpath);
-
- if (BLO_library_path_explode(path, dir, &group, &name)) {
- is_filtered = !is_filtered_hidden(file->relpath, filter, file);
- if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
- /* We only check for types if some type are enabled in filtering. */
- if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
- if (file->typeflag & FILE_TYPE_DIR) {
- if (file->typeflag &
- (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
- if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
- is_filtered = false;
- }
- }
- else {
- if (!(filter->filter & FILE_TYPE_FOLDER)) {
- is_filtered = false;
- }
+ bool is_filtered = !is_filtered_hidden(file->relpath, filter, file);
+ if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
+ /* We only check for types if some type are enabled in filtering. */
+ if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
+ if (file->typeflag & FILE_TYPE_DIR) {
+ if (file->typeflag &
+ (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
+ if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
+ is_filtered = false;
}
}
- if (is_filtered && group) {
- if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
+ else {
+ if (!(filter->filter & FILE_TYPE_FOLDER)) {
is_filtered = false;
}
- else {
- uint64_t filter_id = groupname_to_filter_id(group);
- if (!(filter_id & filter->filter_id)) {
- is_filtered = false;
- }
- }
}
}
- /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
- if (is_filtered && (filter->filter_search[0] != '\0')) {
- if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
+ if (is_filtered && id_group) {
+ if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
is_filtered = false;
}
+ else {
+ uint64_t filter_id = groupname_to_filter_id(id_group);
+ if (!(filter_id & filter->filter_id)) {
+ is_filtered = false;
+ }
+ }
+ }
+ }
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
+ if (is_filtered && (filter->filter_search[0] != '\0')) {
+ if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
+ is_filtered = false;
}
}
}
+
+ return is_filtered;
+}
+
+static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
+{
+ bool is_filtered;
+ char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
+
+ BLI_join_dirfile(path, sizeof(path), root, file->relpath);
+
+ if (BLO_library_path_explode(path, dir, &group, &name)) {
+ is_filtered = is_filtered_id_file(file, group, name, filter);
+ }
else {
is_filtered = is_filtered_file(file, root, filter);
}
@@ -796,6 +919,14 @@ static bool is_filtered_main(FileListInternEntry *file,
return !is_filtered_hidden(file->relpath, filter, file);
}
+static bool is_filtered_main_assets(FileListInternEntry *file,
+ const char *UNUSED(dir),
+ FileListFilter *filter)
+{
+ /* "Filtered" means *not* being filtered out... So return true if the file should be visible. */
+ return is_filtered_id_file(file, file->relpath, file->name, filter);
+}
+
static void filelist_filter_clear(FileList *filelist)
{
filelist->flags |= FL_NEED_FILTERING;
@@ -807,7 +938,7 @@ void filelist_filter(FileList *filelist)
const int num_files = filelist->filelist.nbr_entries;
FileListInternEntry **filtered_tmp, *file;
- if (filelist->filelist.nbr_entries == 0) {
+ if (ELEM(filelist->filelist.nbr_entries, FILEDIR_NBR_ENTRIES_UNSET, 0)) {
return;
}
@@ -858,6 +989,7 @@ void filelist_setfilter_options(FileList *filelist,
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)
{
@@ -875,6 +1007,10 @@ void filelist_setfilter_options(FileList *filelist,
filelist->filter_data.flags ^= FLF_HIDE_PARENT;
update = true;
}
+ if (((filelist->filter_data.flags & FLF_ASSETS_ONLY) != 0) != (filter_assets_only != 0)) {
+ filelist->filter_data.flags ^= FLF_ASSETS_ONLY;
+ update = true;
+ }
if (filelist->filter_data.filter != filter) {
filelist->filter_data.filter = filter;
update = true;
@@ -903,6 +1039,50 @@ void filelist_setfilter_options(FileList *filelist,
}
}
+/**
+ * Checks two libraries for equality.
+ * \return True if the libraries match.
+ */
+static bool filelist_compare_asset_libraries(const FileSelectAssetLibraryUID *library_a,
+ const FileSelectAssetLibraryUID *library_b)
+{
+ if (library_a->type != library_b->type) {
+ return false;
+ }
+ if (library_a->type == FILE_ASSET_LIBRARY_CUSTOM) {
+ return STREQ(library_a->custom_library_identifier, library_b->custom_library_identifier);
+ }
+
+ return true;
+}
+
+/**
+ * \param asset_library: May be NULL to unset the library.
+ */
+void filelist_setlibrary(FileList *filelist, const FileSelectAssetLibraryUID *asset_library)
+{
+ /* Unset if needed. */
+ if (!asset_library) {
+ if (filelist->asset_library) {
+ MEM_SAFE_FREE(filelist->asset_library);
+ filelist->flags |= FL_FORCE_RESET;
+ }
+ return;
+ }
+
+ if (!filelist->asset_library) {
+ filelist->asset_library = MEM_mallocN(sizeof(*filelist->asset_library),
+ "filelist asset library");
+ *filelist->asset_library = *asset_library;
+
+ filelist->flags |= FL_FORCE_RESET;
+ }
+ else if (!filelist_compare_asset_libraries(filelist->asset_library, asset_library)) {
+ *filelist->asset_library = *asset_library;
+ filelist->flags |= FL_FORCE_RESET;
+ }
+}
+
/* ********** Icon/image helpers ********** */
void filelist_init_icons(void)
@@ -960,7 +1140,12 @@ ImBuf *filelist_getimage(struct FileList *filelist, const int index)
{
FileDirEntry *file = filelist_geticon_get_file(filelist, index);
- return file->image;
+ return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL;
+}
+
+ImBuf *filelist_file_getimage(const FileDirEntry *file)
+{
+ return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL;
}
static ImBuf *filelist_geticon_image_ex(FileDirEntry *file)
@@ -993,7 +1178,7 @@ static int filelist_geticon_ex(FileDirEntry *file,
const bool is_main,
const bool ignore_libdir)
{
- const int typeflag = file->typeflag;
+ const eFileSel_File_Types typeflag = file->typeflag;
if ((typeflag & FILE_TYPE_DIR) &&
!(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) {
@@ -1160,6 +1345,14 @@ static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const
return filelist_checkdir_lib(filelist, r_dir, do_change);
}
+static bool filelist_checkdir_main_assets(struct FileList *UNUSED(filelist),
+ char *UNUSED(r_dir),
+ const bool UNUSED(do_change))
+{
+ /* Main is always valid. */
+ return true;
+}
+
static void filelist_entry_clear(FileDirEntry *entry)
{
if (entry->name) {
@@ -1174,8 +1367,9 @@ static void filelist_entry_clear(FileDirEntry *entry)
if (entry->redirection_path) {
MEM_freeN(entry->redirection_path);
}
- if (entry->image) {
- IMB_freeImBuf(entry->image);
+ if (entry->preview_icon_id) {
+ BKE_icon_delete(entry->preview_icon_id);
+ entry->preview_icon_id = 0;
}
/* For now, consider FileDirEntryRevision::poin as not owned here,
* so no need to do anything about it */
@@ -1232,8 +1426,8 @@ static void filelist_direntryarr_free(FileDirEntryArr *array)
#else
BLI_assert(BLI_listbase_is_empty(&array->entries));
#endif
- array->nbr_entries = 0;
- array->nbr_entries_filtered = -1;
+ 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;
}
@@ -1249,6 +1443,10 @@ static void filelist_intern_entry_free(FileListInternEntry *entry)
if (entry->name) {
MEM_freeN(entry->name);
}
+ /* If we own the asset-data (it was generated from external file data), free it. */
+ if (entry->imported_asset_data) {
+ BKE_asset_metadata_free(&entry->imported_asset_data);
+ }
MEM_freeN(entry);
}
@@ -1272,37 +1470,52 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
FileListEntryPreview *preview = preview_taskdata->preview;
ThumbSource source = 0;
+ bool done = false;
// printf("%s: Start (%d)...\n", __func__, threadid);
- // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
- BLI_assert(preview->flags &
- (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
- FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
-
- if (preview->flags & FILE_TYPE_IMAGE) {
- source = THB_SOURCE_IMAGE;
- }
- else if (preview->flags &
- (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
- source = THB_SOURCE_BLEND;
- }
- else if (preview->flags & FILE_TYPE_MOVIE) {
- source = THB_SOURCE_MOVIE;
- }
- else if (preview->flags & FILE_TYPE_FTFONT) {
- source = THB_SOURCE_FONT;
+ if (preview->in_memory_preview) {
+ if (BKE_previewimg_is_finished(preview->in_memory_preview, ICON_SIZE_PREVIEW)) {
+ ImBuf *imbuf = BKE_previewimg_to_imbuf(preview->in_memory_preview, ICON_SIZE_PREVIEW);
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ done = true;
+ }
}
+ else {
+ // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ BLI_assert(preview->flags &
+ (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
+ FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
- IMB_thumb_path_lock(preview->path);
- /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate in
- * case user switch to a bigger preview size. */
- preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source);
- IMB_thumb_path_unlock(preview->path);
+ if (preview->flags & FILE_TYPE_IMAGE) {
+ source = THB_SOURCE_IMAGE;
+ }
+ else if (preview->flags &
+ (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
+ source = THB_SOURCE_BLEND;
+ }
+ else if (preview->flags & FILE_TYPE_MOVIE) {
+ source = THB_SOURCE_MOVIE;
+ }
+ else if (preview->flags & FILE_TYPE_FTFONT) {
+ source = THB_SOURCE_FONT;
+ }
+
+ IMB_thumb_path_lock(preview->path);
+ /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
+ * in case user switch to a bigger preview size. */
+ ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source);
+ IMB_thumb_path_unlock(preview->path);
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
- /* That way task freeing function won't free th preview, since it does not own it anymore. */
- atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL);
- BLI_thread_queue_push(cache->previews_done, preview);
+ done = true;
+ }
+
+ if (done) {
+ /* That way task freeing function won't free th preview, since it does not own it anymore. */
+ atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL);
+ BLI_thread_queue_push(cache->previews_done, preview);
+ }
// printf("%s: End (%d)...\n", __func__, threadid);
}
@@ -1315,8 +1528,8 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void
/* preview_taskdata->preview is atomically set to NULL once preview has been processed and sent
* to previews_done queue. */
if (preview != NULL) {
- if (preview->img) {
- IMB_freeImBuf(preview->img);
+ if (preview->icon_id) {
+ BKE_icon_delete(preview->icon_id);
}
MEM_freeN(preview);
}
@@ -1342,8 +1555,8 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache)
while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) {
// printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path,
// preview->img);
- if (preview->img) {
- IMB_freeImBuf(preview->img);
+ if (preview->icon_id) {
+ BKE_icon_delete(preview->icon_id);
}
MEM_freeN(preview);
}
@@ -1374,10 +1587,11 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
BLI_assert(cache->flags & FLC_PREVIEWS_ACTIVE);
- if (!entry->image && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) &&
+ if (!entry->preview_icon_id && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) &&
(entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) {
FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
+ FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
if (entry->redirection_path) {
BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
@@ -1389,7 +1603,8 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
preview->index = index;
preview->flags = entry->typeflag;
- preview->img = NULL;
+ preview->in_memory_preview = intern_entry->local_data.preview_image;
+ preview->icon_id = 0;
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
filelist_cache_preview_ensure_running(cache);
@@ -1497,25 +1712,45 @@ FileList *filelist_new(short type)
p->selection_state = BLI_ghash_new(
BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__);
+ p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
+ filelist_settype(p, type);
- switch (type) {
+ return p;
+}
+
+void filelist_settype(FileList *filelist, short type)
+{
+ if (filelist->type == type) {
+ return;
+ }
+
+ filelist->type = type;
+ filelist->tags = 0;
+ switch (filelist->type) {
case FILE_MAIN:
- p->checkdirf = filelist_checkdir_main;
- p->read_jobf = filelist_readjob_main;
- p->filterf = is_filtered_main;
+ filelist->checkdirf = filelist_checkdir_main;
+ filelist->read_jobf = filelist_readjob_main;
+ filelist->filterf = is_filtered_main;
break;
case FILE_LOADLIB:
- p->checkdirf = filelist_checkdir_lib;
- p->read_jobf = filelist_readjob_lib;
- p->filterf = is_filtered_lib;
+ filelist->checkdirf = filelist_checkdir_lib;
+ filelist->read_jobf = filelist_readjob_lib;
+ filelist->filterf = is_filtered_lib;
+ break;
+ case FILE_MAIN_ASSET:
+ filelist->checkdirf = filelist_checkdir_main_assets;
+ filelist->read_jobf = filelist_readjob_main_assets;
+ filelist->filterf = is_filtered_main_assets;
+ filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA | FILELIST_TAGS_NO_THREADS;
break;
default:
- p->checkdirf = filelist_checkdir_dir;
- p->read_jobf = filelist_readjob_dir;
- p->filterf = is_filtered_file;
+ filelist->checkdirf = filelist_checkdir_dir;
+ filelist->read_jobf = filelist_readjob_dir;
+ filelist->filterf = is_filtered_file;
break;
}
- return p;
+
+ filelist->flags |= FL_FORCE_RESET;
}
void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection)
@@ -1560,6 +1795,8 @@ void filelist_free(struct FileList *filelist)
filelist->selection_state = NULL;
}
+ MEM_SAFE_FREE(filelist->asset_library);
+
memset(&filelist->filter_data, 0, sizeof(filelist->filter_data));
filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING);
@@ -1580,7 +1817,7 @@ BlendHandle *filelist_lib(struct FileList *filelist)
static const char *fileentry_uiname(const char *root,
const char *relpath,
- const int typeflag,
+ const eFileSel_File_Types typeflag,
char *buff)
{
char *name = NULL;
@@ -1624,11 +1861,12 @@ bool filelist_is_dir(struct FileList *filelist, const char *path)
*/
void filelist_setdir(struct FileList *filelist, char *r_dir)
{
+ const bool allow_invalid = filelist->asset_library != NULL;
BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir);
- const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true);
- BLI_assert(is_valid_path);
+ const bool is_valid_path = filelist->checkdirf(filelist, r_dir, !allow_invalid);
+ BLI_assert(is_valid_path || allow_invalid);
UNUSED_VARS_NDEBUG(is_valid_path);
if (!STREQ(filelist->filelist.root, r_dir)) {
@@ -1645,11 +1883,16 @@ void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
}
}
-bool filelist_force_reset(struct FileList *filelist)
+bool filelist_needs_force_reset(FileList *filelist)
{
return (filelist->flags & FL_FORCE_RESET) != 0;
}
+void filelist_tag_force_reset(FileList *filelist)
+{
+ filelist->flags |= FL_FORCE_RESET;
+}
+
bool filelist_is_ready(struct FileList *filelist)
{
return (filelist->flags & FL_IS_READY) != 0;
@@ -1660,6 +1903,11 @@ bool filelist_pending(struct FileList *filelist)
return (filelist->flags & FL_IS_PENDING) != 0;
}
+bool filelist_needs_reset_on_main_changes(const FileList *filelist)
+{
+ return (filelist->tags & FILELIST_TAGS_USES_MAIN_DATA) != 0;
+}
+
/**
* Limited version of full update done by space_file's file_refresh(),
* to be used by operators and such.
@@ -1668,7 +1916,7 @@ bool filelist_pending(struct FileList *filelist)
*/
int filelist_files_ensure(FileList *filelist)
{
- if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) {
+ if (!filelist_needs_force_reset(filelist) || !filelist_needs_reading(filelist)) {
filelist_sort(filelist);
filelist_filter(filelist);
}
@@ -1701,6 +1949,17 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
if (entry->redirection_path) {
ret->redirection_path = BLI_strdup(entry->redirection_path);
}
+ ret->id = entry->local_data.id;
+ ret->asset_data = entry->imported_asset_data ? entry->imported_asset_data : NULL;
+ if (ret->id && (ret->asset_data == NULL)) {
+ ret->asset_data = ret->id->asset_data;
+ }
+ /* For some file types the preview is already available. */
+ if (entry->local_data.preview_image &&
+ BKE_previewimg_is_finished(entry->local_data.preview_image, ICON_SIZE_PREVIEW)) {
+ ImBuf *ibuf = BKE_previewimg_to_imbuf(entry->local_data.preview_image, ICON_SIZE_PREVIEW);
+ ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
+ }
BLI_addtail(&cache->cached_entries, ret);
return ret;
}
@@ -1770,7 +2029,7 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename)
{
int fidx = -1;
- if (filelist->filelist.nbr_entries_filtered < 0) {
+ if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
return fidx;
}
@@ -1788,9 +2047,17 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename)
return -1;
}
+/**
+ * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET.
+ */
+ID *filelist_file_get_id(const FileDirEntry *file)
+{
+ return file->id;
+}
+
FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4])
{
- if (filelist->filelist.nbr_entries_filtered < 0) {
+ if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
return NULL;
}
@@ -2147,15 +2414,17 @@ bool filelist_cache_previews_update(FileList *filelist)
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
- if (preview->img) {
+ if (preview->icon_id) {
/* Due to asynchronous process, a preview for a given image may be generated several times,
* i.e. entry->image may already be set at this point. */
- if (entry && !entry->image) {
- entry->image = preview->img;
+ if (entry && !entry->preview_icon_id) {
+ /* Move ownership over icon. */
+ entry->preview_icon_id = preview->icon_id;
+ preview->icon_id = 0;
changed = true;
}
else {
- IMB_freeImBuf(preview->img);
+ BKE_icon_delete(preview->icon_id);
}
}
else if (entry) {
@@ -2313,9 +2582,9 @@ int ED_file_extension_icon(const char *path)
}
}
-int filelist_empty(struct FileList *filelist)
+int filelist_needs_reading(struct FileList *filelist)
{
- return (filelist->filelist.nbr_entries == 0);
+ return (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET);
}
uint filelist_entry_select_set(const FileList *filelist,
@@ -2564,8 +2833,8 @@ static int filelist_readjob_list_dir(const char *root,
static int filelist_readjob_list_lib(const char *root, ListBase *entries, const bool skip_currpar)
{
FileListInternEntry *entry;
- LinkNode *ln, *names;
- int i, nnames, idcode = 0, nbr_entries = 0;
+ LinkNode *ln, *names = NULL, *datablock_infos = NULL;
+ int i, nitems, idcode = 0, nbr_entries = 0;
char dir[FILE_MAX_LIBEXTRA], *group;
bool ok;
@@ -2587,11 +2856,11 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
* and freed in filelist_entry_free. */
if (group) {
idcode = groupname_to_code(group);
- names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames);
+ datablock_infos = BLO_blendhandle_get_datablock_info(libfiledata, idcode, &nitems);
}
else {
names = BLO_blendhandle_get_linkable_groups(libfiledata);
- nnames = BLI_linklist_count(names);
+ nitems = BLI_linklist_count(names);
}
BLO_blendhandle_close(libfiledata);
@@ -2604,12 +2873,18 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
nbr_entries++;
}
- for (i = 0, ln = names; i < nnames; i++, ln = ln->next) {
- const char *blockname = ln->link;
+ for (i = 0, ln = (datablock_infos ? datablock_infos : names); i < nitems; i++, ln = ln->next) {
+ struct BLODataBlockInfo *info = datablock_infos ? ln->link : NULL;
+ const char *blockname = info ? info->name : ln->link;
entry = MEM_callocN(sizeof(*entry), __func__);
entry->relpath = BLI_strdup(blockname);
entry->typeflag |= FILE_TYPE_BLENDERLIB;
+ if (info && info->asset_data) {
+ entry->typeflag |= FILE_TYPE_ASSET;
+ /* Moves ownership! */
+ entry->imported_asset_data = info->asset_data;
+ }
if (!(group && idcode)) {
entry->typeflag |= FILE_TYPE_DIR;
entry->blentype = groupname_to_code(blockname);
@@ -2621,7 +2896,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
nbr_entries++;
}
- BLI_linklist_freeN(names);
+ BLI_linklist_freeN(datablock_infos ? datablock_infos : names);
return nbr_entries;
}
@@ -2820,7 +3095,10 @@ static void filelist_readjob_do(const bool do_lib,
// BLI_assert(filelist->filtered == NULL);
BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) &&
- (filelist->filelist.nbr_entries == 0));
+ (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);
@@ -2932,7 +3210,8 @@ static void filelist_readjob_do(const bool do_lib,
BLI_stack_free(todo_dirs);
}
-static void filelist_readjob_dir(FileList *filelist,
+static void filelist_readjob_dir(Main *UNUSED(current_main),
+ FileList *filelist,
const char *main_name,
short *stop,
short *do_update,
@@ -2942,7 +3221,8 @@ static void filelist_readjob_dir(FileList *filelist,
filelist_readjob_do(false, filelist, main_name, stop, do_update, progress, lock);
}
-static void filelist_readjob_lib(FileList *filelist,
+static void filelist_readjob_lib(Main *UNUSED(current_main),
+ FileList *filelist,
const char *main_name,
short *stop,
short *do_update,
@@ -2952,7 +3232,8 @@ static void filelist_readjob_lib(FileList *filelist,
filelist_readjob_do(true, filelist, main_name, stop, do_update, progress, lock);
}
-static void filelist_readjob_main(FileList *filelist,
+static void filelist_readjob_main(Main *current_main,
+ FileList *filelist,
const char *main_name,
short *stop,
short *do_update,
@@ -2960,12 +3241,67 @@ static void filelist_readjob_main(FileList *filelist,
ThreadMutex *lock)
{
/* TODO! */
- filelist_readjob_dir(filelist, main_name, stop, do_update, progress, lock);
+ filelist_readjob_dir(current_main, filelist, main_name, stop, do_update, progress, lock);
+}
+
+/**
+ * \warning Acts on main, so NOT thread-safe!
+ */
+static void filelist_readjob_main_assets(Main *current_main,
+ FileList *filelist,
+ const char *UNUSED(main_name),
+ short *UNUSED(stop),
+ short *do_update,
+ float *UNUSED(progress),
+ ThreadMutex *UNUSED(lock))
+{
+ 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;
+
+ FileListInternEntry *entry;
+ ListBase tmp_entries = {0};
+ ID *id_iter;
+ int nbr_entries = 0;
+
+ FOREACH_MAIN_ID_BEGIN (current_main, id_iter) {
+ if (!id_iter->asset_data) {
+ continue;
+ }
+
+ const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name));
+
+ entry = MEM_callocN(sizeof(*entry), __func__);
+ entry->relpath = BLI_strdup(id_code_name);
+ entry->name = BLI_strdup(id_iter->name + 2);
+ entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_ASSET;
+ entry->blentype = GS(id_iter->name);
+ *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32(
+ (uint32_t *)filelist->filelist_intern.curr_uuid, 1);
+ entry->local_data.preview_image = BKE_asset_metadata_preview_get_from_id(id_iter->asset_data,
+ id_iter);
+ entry->local_data.id = id_iter;
+ nbr_entries++;
+ BLI_addtail(&tmp_entries, entry);
+ }
+ FOREACH_MAIN_ID_END;
+
+ 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;
+ }
}
typedef struct FileListReadJob {
ThreadMutex lock;
char main_name[FILE_MAX];
+ Main *current_main;
struct FileList *filelist;
/** XXX We may use a simpler struct here... just a linked list and root path? */
struct FileList *tmp_filelist;
@@ -2985,7 +3321,7 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update
flrj->tmp_filelist = MEM_dupallocN(flrj->filelist);
BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries);
- flrj->tmp_filelist->filelist.nbr_entries = 0;
+ flrj->tmp_filelist->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
flrj->tmp_filelist->filelist_intern.filtered = NULL;
BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries);
@@ -2996,11 +3332,17 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update
flrj->tmp_filelist->libfiledata = NULL;
memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache));
flrj->tmp_filelist->selection_state = NULL;
+ flrj->tmp_filelist->asset_library = NULL;
BLI_mutex_unlock(&flrj->lock);
- flrj->tmp_filelist->read_jobf(
- flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock);
+ flrj->tmp_filelist->read_jobf(flrj->current_main,
+ flrj->tmp_filelist,
+ flrj->main_name,
+ stop,
+ do_update,
+ progress,
+ &flrj->lock);
}
static void filelist_readjob_update(void *flrjv)
@@ -3015,7 +3357,7 @@ static void filelist_readjob_update(void *flrjv)
BLI_mutex_lock(&flrj->lock);
- if (flrj->tmp_filelist->filelist.nbr_entries) {
+ if (flrj->tmp_filelist->filelist.nbr_entries > 0) {
/* We just move everything out of 'thread context' into final list. */
new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries;
BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries);
@@ -3033,7 +3375,7 @@ static void filelist_readjob_update(void *flrjv)
/* if no new_nbr_entries, this is NOP */
BLI_movelisttolist(&fl_intern->entries, &new_entries);
- flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries;
+ flrj->filelist->filelist.nbr_entries = MAX2(nbr_entries, 0) + new_nbr_entries;
}
static void filelist_readjob_endjob(void *flrjv)
@@ -3074,30 +3416,51 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
wmJob *wm_job;
FileListReadJob *flrj;
+ if (!filelist_is_dir(filelist, filelist->filelist.root)) {
+ return;
+ }
+
/* prepare job data */
flrj = MEM_callocN(sizeof(*flrj), __func__);
flrj->filelist = filelist;
+ flrj->current_main = bmain;
BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name));
filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY);
filelist->flags |= FL_IS_PENDING;
+ /* Init even for single threaded execution. Called functions use it. */
BLI_mutex_init(&flrj->lock);
- /* setup job */
- wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- CTX_data_scene(C),
- "Listing Dirs...",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_FILESEL_READDIR);
- WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free);
- WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST);
- WM_jobs_callbacks(
- wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob);
-
- /* start the job */
- WM_jobs_start(CTX_wm_manager(C), wm_job);
+ if (filelist->tags & FILELIST_TAGS_NO_THREADS) {
+ short dummy_stop = false;
+ short dummy_do_update = false;
+ float dummy_progress = 0.0f;
+
+ /* Single threaded execution. Just directly call the callbacks. */
+ filelist_readjob_startjob(flrj, &dummy_stop, &dummy_do_update, &dummy_progress);
+ filelist_readjob_endjob(flrj);
+ filelist_readjob_free(flrj);
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
+ return;
+ }
+ else {
+ /* setup job */
+ wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ CTX_data_scene(C),
+ "Listing Dirs...",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_FILESEL_READDIR);
+ WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free);
+ WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST);
+ WM_jobs_callbacks(
+ wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob);
+
+ /* start the job */
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
}
void filelist_readjob_stop(wmWindowManager *wm, Scene *owner_scene)
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 4b8cc052382..59bd5bb50d7 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -30,6 +30,7 @@ extern "C" {
struct BlendHandle;
struct FileList;
struct FileSelection;
+struct FileSelectAssetLibraryUID;
struct wmWindowManager;
struct FileDirEntry;
@@ -46,14 +47,16 @@ typedef enum FileCheckType {
CHECK_ALL = 3,
} FileCheckType;
-struct ListBase *folderlist_new(void);
void folderlist_free(struct ListBase *folderlist);
-struct ListBase *folderlist_duplicate(ListBase *folderlist);
void folderlist_popdir(struct ListBase *folderlist, char *dir);
void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
const char *folderlist_peeklastdir(struct ListBase *folderlist);
int folderlist_clear_next(struct SpaceFile *sfile);
+void folder_history_list_ensure_for_active_browse_mode(struct SpaceFile *sfile);
+void folder_history_list_free(struct SpaceFile *sfile);
+struct ListBase folder_history_list_duplicate(struct ListBase *listbase);
+
void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort);
void filelist_sort(struct FileList *filelist);
@@ -63,17 +66,22 @@ void filelist_setfilter_options(struct FileList *filelist,
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);
void filelist_filter(struct FileList *filelist);
+void filelist_setlibrary(struct FileList *filelist,
+ const struct FileSelectAssetLibraryUID *asset_library);
void filelist_init_icons(void);
void filelist_free_icons(void);
struct ImBuf *filelist_getimage(struct FileList *filelist, const int index);
+struct ImBuf *filelist_file_getimage(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index);
int filelist_geticon(struct FileList *filelist, const int index, const bool is_main);
struct FileList *filelist_new(short type);
+void filelist_settype(struct FileList *filelist, short type);
void filelist_clear(struct FileList *filelist);
void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection);
void filelist_free(struct FileList *filelist);
@@ -83,15 +91,18 @@ bool filelist_is_dir(struct FileList *filelist, const char *path);
void filelist_setdir(struct FileList *filelist, char *r_dir);
int filelist_files_ensure(struct FileList *filelist);
-int filelist_empty(struct FileList *filelist);
+int filelist_needs_reading(struct FileList *filelist);
FileDirEntry *filelist_file(struct FileList *filelist, int index);
int filelist_file_findpath(struct FileList *filelist, const char *file);
+struct ID *filelist_file_get_id(const struct FileDirEntry *file);
FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]);
void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size);
bool filelist_file_cache_block(struct FileList *filelist, const int index);
-bool filelist_force_reset(struct FileList *filelist);
+bool filelist_needs_force_reset(struct FileList *filelist);
+void filelist_tag_force_reset(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);
unsigned int filelist_entry_select_set(const struct FileList *filelist,
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 6e933e53a8f..2c66bd39e0a 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -56,7 +56,9 @@
#include "BKE_appdir.h"
#include "BKE_context.h"
+#include "BKE_idtype.h"
#include "BKE_main.h"
+#include "BKE_preferences.h"
#include "BLF_api.h"
@@ -77,14 +79,66 @@
#define VERTLIST_MAJORCOLUMN_WIDTH (25 * UI_UNIT_X)
-FileSelectParams *ED_fileselect_get_active_params(const SpaceFile *sfile)
+static void fileselect_initialize_params_common(SpaceFile *sfile, FileSelectParams *params)
{
- if (!sfile) {
- /* Sometimes called in poll before space type was checked. */
- return NULL;
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+
+ /* operator has no setting for this */
+ params->active_file = -1;
+
+ if (!params->dir[0]) {
+ if (blendfile_path[0] != '\0') {
+ BLI_split_dir_part(blendfile_path, params->dir, sizeof(params->dir));
+ }
+ else {
+ const char *doc_path = BKE_appdir_folder_default();
+ if (doc_path) {
+ BLI_strncpy(params->dir, doc_path, sizeof(params->dir));
+ }
+ }
}
- return sfile->params;
+ folder_history_list_ensure_for_active_browse_mode(sfile);
+ folderlist_pushdir(sfile->folders_prev, params->dir);
+
+ /* Switching thumbnails needs to recalc layout T28809. */
+ if (sfile->layout) {
+ sfile->layout->dirty = true;
+ }
+}
+
+static void fileselect_ensure_updated_asset_params(SpaceFile *sfile)
+{
+ BLI_assert(sfile->browse_mode == FILE_BROWSE_MODE_ASSETS);
+ BLI_assert(sfile->op == NULL);
+
+ FileAssetSelectParams *asset_params = sfile->asset_params;
+
+ if (!asset_params) {
+ asset_params = sfile->asset_params = MEM_callocN(sizeof(*asset_params),
+ "FileAssetSelectParams");
+ asset_params->base_params.details_flags = U_default.file_space_data.details_flags;
+ asset_params->asset_library.type = FILE_ASSET_LIBRARY_LOCAL;
+ }
+
+ FileSelectParams *base_params = &asset_params->base_params;
+ base_params->file[0] = '\0';
+ base_params->filter_glob[0] = '\0';
+ /* TODO this way of using filters to form categories is notably slower than specifying a
+ * "group" to read. That's because all types are read and filtering is applied afterwards. Would
+ * be nice if we could lazy-read individual groups. */
+ base_params->flag |= U_default.file_space_data.flag | FILE_ASSETS_ONLY | FILE_FILTER;
+ base_params->flag &= ~FILE_DIRSEL_ONLY;
+ base_params->filter |= FILE_TYPE_BLENDERLIB;
+ base_params->filter_id = FILTER_ID_OB | FILTER_ID_GR;
+ base_params->display = FILE_IMGDISPLAY;
+ base_params->sort = FILE_SORT_ALPHA;
+ base_params->recursion_level = 1;
+ /* 'SMALL' size by default. More reasonable since this is typically used as regular editor,
+ * space is more of an issue here. */
+ base_params->thumbnail_size = 96;
+
+ fileselect_initialize_params_common(sfile, base_params);
}
/**
@@ -92,6 +146,8 @@ FileSelectParams *ED_fileselect_get_active_params(const SpaceFile *sfile)
* the previously used settings to be used here rather than overriding them */
static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
{
+ BLI_assert(sfile->browse_mode == FILE_BROWSE_MODE_FILES);
+
FileSelectParams *params;
wmOperator *op = sfile->op;
@@ -297,42 +353,102 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
params->filter_glob[0] = '\0';
}
- /* operator has no setting for this */
- params->active_file = -1;
+ fileselect_initialize_params_common(sfile, params);
- /* initialize the list with previous folders */
- if (!sfile->folders_prev) {
- sfile->folders_prev = folderlist_new();
- }
+ return params;
+}
- if (!params->dir[0]) {
- if (blendfile_path[0] != '\0') {
- BLI_split_dir_part(blendfile_path, params->dir, sizeof(params->dir));
- }
- else {
- const char *doc_path = BKE_appdir_folder_default();
- if (doc_path) {
- BLI_strncpy(params->dir, doc_path, sizeof(params->dir));
+/**
+ * If needed, create and return the file select parameters for the active browse mode.
+ */
+FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile)
+{
+ switch ((eFileBrowse_Mode)sfile->browse_mode) {
+ case FILE_BROWSE_MODE_FILES:
+ if (!sfile->params) {
+ fileselect_ensure_updated_file_params(sfile);
}
- }
+ return sfile->params;
+ case FILE_BROWSE_MODE_ASSETS:
+ if (!sfile->asset_params) {
+ fileselect_ensure_updated_asset_params(sfile);
+ }
+ return &sfile->asset_params->base_params;
}
- folderlist_pushdir(sfile->folders_prev, params->dir);
+ BLI_assert(!"Invalid browse mode set in file space.");
+ return NULL;
+}
- /* Switching thumbnails needs to recalc layout T28809. */
- if (sfile->layout) {
- sfile->layout->dirty = true;
+/**
+ * Get the file select parameters for the active browse mode.
+ */
+FileSelectParams *ED_fileselect_get_active_params(const SpaceFile *sfile)
+{
+ if (!sfile) {
+ /* Sometimes called in poll before space type was checked. */
+ return NULL;
}
- return params;
+ switch ((eFileBrowse_Mode)sfile->browse_mode) {
+ case FILE_BROWSE_MODE_FILES:
+ return sfile->params;
+ case FILE_BROWSE_MODE_ASSETS:
+ return (FileSelectParams *)sfile->asset_params;
+ }
+
+ BLI_assert(!"Invalid browse mode set in file space.");
+ return NULL;
}
-FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile)
+FileSelectParams *ED_fileselect_get_file_params(const SpaceFile *sfile)
{
- if (!sfile->params) {
- fileselect_ensure_updated_file_params(sfile);
+ return (sfile->browse_mode == FILE_BROWSE_MODE_FILES) ? sfile->params : NULL;
+}
+
+FileAssetSelectParams *ED_fileselect_get_asset_params(const SpaceFile *sfile)
+{
+ return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) ? sfile->asset_params : NULL;
+}
+
+static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params)
+{
+ FileSelectAssetLibraryUID *library = &asset_params->asset_library;
+ FileSelectParams *base_params = &asset_params->base_params;
+ bUserAssetLibrary *user_library = NULL;
+
+ /* Ensure valid repo, or fall-back to local one. */
+ if (library->type == FILE_ASSET_LIBRARY_CUSTOM) {
+ user_library = BKE_preferences_asset_library_find_from_name(
+ &U, library->custom_library_identifier);
+ if (!user_library) {
+ library->type = FILE_ASSET_LIBRARY_LOCAL;
+ }
+ }
+
+ switch (library->type) {
+ case FILE_ASSET_LIBRARY_LOCAL:
+ base_params->dir[0] = '\0';
+ break;
+ case FILE_ASSET_LIBRARY_CUSTOM:
+ BLI_assert(user_library);
+ BLI_strncpy(base_params->dir, user_library->path, sizeof(base_params->dir));
+ break;
}
- return sfile->params;
+ base_params->type = (library->type == FILE_ASSET_LIBRARY_LOCAL) ? FILE_MAIN_ASSET : FILE_LOADLIB;
+}
+
+void fileselect_refresh_params(SpaceFile *sfile)
+{
+ FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
+ if (asset_params) {
+ fileselect_refresh_asset_params(asset_params);
+ }
+}
+
+bool ED_fileselect_is_asset_browser(const SpaceFile *sfile)
+{
+ return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS);
}
/* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA
@@ -371,6 +487,8 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
wmOperator *op = sfile->op;
UserDef_FileSpaceData *sfile_udata = &U.file_space_data;
+ BLI_assert(sfile->browse_mode == FILE_BROWSE_MODE_FILES);
+
FileSelectParams *params = fileselect_ensure_updated_file_params(sfile);
if (!op) {
return;
@@ -438,15 +556,6 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile,
}
}
-void ED_fileselect_reset_params(SpaceFile *sfile)
-{
- FileSelectParams *params = ED_fileselect_get_active_params(sfile);
- params->type = FILE_UNIX;
- params->flag = 0;
- params->title[0] = '\0';
- params->active_file = -1;
-}
-
/**
* Sets FileSelectParams->file (name of selected file)
*/
@@ -1046,8 +1155,7 @@ void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfil
sfile->op = NULL;
}
- folderlist_free(sfile->folders_prev);
- folderlist_free(sfile->folders_next);
+ folder_history_list_free(sfile);
if (sfile->files) {
ED_fileselect_clear(wm, owner_scene, sfile);
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index c72ca58abba..f1d72387791 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -35,6 +35,8 @@
#include "BKE_screen.h"
#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_message.h"
@@ -149,22 +151,10 @@ static void file_free(SpaceLink *sl)
sfile->files = NULL;
}
- if (sfile->folders_prev) {
- folderlist_free(sfile->folders_prev);
- MEM_freeN(sfile->folders_prev);
- sfile->folders_prev = NULL;
- }
-
- if (sfile->folders_next) {
- folderlist_free(sfile->folders_next);
- MEM_freeN(sfile->folders_next);
- sfile->folders_next = NULL;
- }
+ folder_history_list_free(sfile);
- if (sfile->params) {
- MEM_freeN(sfile->params);
- sfile->params = NULL;
- }
+ MEM_SAFE_FREE(sfile->params);
+ MEM_SAFE_FREE(sfile->asset_params);
if (sfile->layout) {
MEM_freeN(sfile->layout);
@@ -205,19 +195,20 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
sfilen->previews_timer = NULL;
sfilen->smoothscroll_timer = NULL;
+ FileSelectParams *active_params_old = ED_fileselect_get_active_params(sfileo);
+ if (active_params_old) {
+ sfilen->files = filelist_new(active_params_old->type);
+ filelist_setdir(sfilen->files, active_params_old->dir);
+ }
+
if (sfileo->params) {
- sfilen->files = filelist_new(sfileo->params->type);
sfilen->params = MEM_dupallocN(sfileo->params);
- filelist_setdir(sfilen->files, sfilen->params->dir);
}
-
- if (sfileo->folders_prev) {
- sfilen->folders_prev = folderlist_duplicate(sfileo->folders_prev);
+ if (sfileo->asset_params) {
+ sfilen->asset_params = MEM_dupallocN(sfileo->asset_params);
}
- if (sfileo->folders_next) {
- sfilen->folders_next = folderlist_duplicate(sfileo->folders_next);
- }
+ sfilen->folder_histories = folder_history_list_duplicate(&sfileo->folder_histories);
if (sfileo->layout) {
sfilen->layout = MEM_dupallocN(sfileo->layout);
@@ -265,24 +256,42 @@ 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);
wmWindow *win = CTX_wm_window(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_ensure_active_params(sfile);
+ FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
struct FSMenu *fsmenu = ED_fsmenu_get();
- if (!sfile->folders_prev) {
- sfile->folders_prev = folderlist_new();
+ fileselect_refresh_params(sfile);
+ folder_history_list_ensure_for_active_browse_mode(sfile);
+
+ if (sfile->files && (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES) &&
+ filelist_needs_reset_on_main_changes(sfile->files)) {
+ filelist_tag_force_reset(sfile->files);
}
+ sfile->tags &= ~FILE_TAG_REBUILD_MAIN_FILES;
+
if (!sfile->files) {
sfile->files = filelist_new(params->type);
params->highlight_file = -1; /* added this so it opens nicer (ton) */
}
+ filelist_settype(sfile->files, params->type);
filelist_setdir(sfile->files, params->dir);
filelist_setrecursion(sfile->files, params->recursion_level);
filelist_setsorting(sfile->files, params->sort, params->flag & FILE_SORT_INVERT);
+ filelist_setlibrary(sfile->files, asset_params ? &asset_params->asset_library : NULL);
filelist_setfilter_options(
sfile->files,
(params->flag & FILE_FILTER) != 0,
@@ -290,6 +299,7 @@ static void file_refresh(const bContext *C, ScrArea *area)
true, /* Just always hide parent, prefer to not add an extra user option for this. */
params->filter,
params->filter_id,
+ (params->flag & FILE_ASSETS_ONLY) != 0,
params->filter_glob,
params->filter_search);
@@ -300,12 +310,12 @@ static void file_refresh(const bContext *C, ScrArea *area)
sfile->bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir);
sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir);
- if (filelist_force_reset(sfile->files)) {
+ if (filelist_needs_force_reset(sfile->files)) {
filelist_readjob_stop(wm, CTX_data_scene(C));
filelist_clear(sfile->files);
}
- if (filelist_empty(sfile->files)) {
+ if (filelist_needs_reading(sfile->files)) {
if (!filelist_pending(sfile->files)) {
filelist_readjob_start(sfile->files, C);
}
@@ -365,6 +375,14 @@ static void file_listener(wmWindow *UNUSED(win),
break;
}
break;
+ case NC_ASSET: {
+ 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);
+ }
+ break;
+ }
}
}
@@ -442,6 +460,22 @@ static void file_main_region_message_subscribe(const struct bContext *UNUSED(C),
}
}
+static bool file_main_region_needs_refresh_before_draw(SpaceFile *sfile)
+{
+ /* Needed, because filelist is not initialized on loading */
+ if (!sfile->files || filelist_needs_reading(sfile->files)) {
+ return true;
+ }
+
+ /* File reading tagged the space because main data changed that may require a filelist reset. */
+ if (filelist_needs_reset_on_main_changes(sfile->files) &&
+ (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES)) {
+ return true;
+ }
+
+ return false;
+}
+
static void file_main_region_draw(const bContext *C, ARegion *region)
{
/* draw entirely, view changes should be handled here */
@@ -450,8 +484,7 @@ static void file_main_region_draw(const bContext *C, ARegion *region)
View2D *v2d = &region->v2d;
- /* Needed, because filelist is not initialized on loading */
- if (!sfile->files || filelist_empty(sfile->files)) {
+ if (file_main_region_needs_refresh_before_draw(sfile)) {
file_refresh(C, NULL);
}
@@ -681,6 +714,52 @@ static void file_dropboxes(void)
WM_dropbox_add(lb, "FILE_OT_filepath_drop", filepath_drop_poll, filepath_drop_copy);
}
+const char *file_context_dir[] = {"active_file", "active_id", NULL};
+
+static int /*eContextResult*/ file_context(const bContext *C,
+ const char *member,
+ bContextDataResult *result)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+
+ BLI_assert(!ED_area_is_global(CTX_wm_area(C)));
+
+ if (CTX_data_dir(member)) {
+ CTX_data_dir_set(result, file_context_dir);
+ return CTX_RESULT_OK;
+ }
+ else if (CTX_data_equals(member, "active_file")) {
+ FileDirEntry *file = filelist_file(sfile->files, params->active_file);
+ CTX_data_pointer_set(result, &screen->id, &RNA_FileSelectEntry, file);
+ return CTX_RESULT_OK;
+ }
+ else if (CTX_data_equals(member, "active_id")) {
+ const FileDirEntry *file = filelist_file(sfile->files, params->active_file);
+
+ ID *id = filelist_file_get_id(file);
+ if (id) {
+ CTX_data_id_pointer_set(result, id);
+ }
+ return CTX_RESULT_OK;
+ }
+ return CTX_RESULT_MEMBER_NOT_FOUND;
+}
+
+static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *UNUSED(new_id))
+{
+ SpaceFile *sfile = (SpaceFile *)sl;
+
+ /* If the file shows main data (IDs), tag it for reset. */
+ if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) {
+ /* Full refresh of the file list if main data was changed, don't even attempt remap pointers.
+ * We could give file list types a id-remap callback, but it's probably not worth it.
+ * Refreshing local file lists is relatively cheap. */
+ file_tag_reset_list(area, sfile);
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_file(void)
{
@@ -700,6 +779,8 @@ void ED_spacetype_file(void)
st->operatortypes = file_operatortypes;
st->keymap = file_keymap;
st->dropboxes = file_dropboxes;
+ st->context = file_context;
+ st->id_remap = file_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 6fd112628a1..e07f085d356 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -664,6 +664,23 @@ typedef enum eSpaceSeq_OverlayType {
/** \name File Selector
* \{ */
+/**
+ * Information to identify a asset library. May be either one of the predefined types (current
+ * 'Main', builtin library, project library), or a custom type as defined in the Preferences.
+ *
+ * If the type is set to #FILE_ASSET_LIBRARY_CUSTOM, idname must have the name to identify the
+ * custom library. Otherwise idname is not used.
+ */
+typedef struct FileSelectAssetLibraryUID {
+ short type;
+ char _pad[6];
+ /**
+ * If showing a custom asset library (#FILE_ASSET_LIBRARY_CUSTOM), this name has to be set to
+ * define which. Can be empty otherwise.
+ */
+ char custom_library_identifier[64]; /* MAX_NAME */
+} FileSelectAssetLibraryUID;
+
/* Config and Input for File Selector */
typedef struct FileSelectParams {
/** Title, also used for the text of the execute button. */
@@ -708,6 +725,7 @@ typedef struct FileSelectParams {
/** Details toggles (file size, creation date, etc.) */
char details_flags;
char _pad2[3];
+
/** Filter when (flags & FILE_FILTER) is true. */
int filter;
@@ -723,6 +741,32 @@ typedef struct FileSelectParams {
/* XXX --- end unused -- */
} FileSelectParams;
+/**
+ * File selection parameters for asset browsing mode, with #FileSelectParams as base.
+ */
+typedef struct FileAssetSelectParams {
+ FileSelectParams base_params;
+
+ FileSelectAssetLibraryUID asset_library;
+} FileAssetSelectParams;
+
+/**
+ * A wrapper to store previous and next folder lists (#FolderList) for a specific browse mode
+ * (#eFileBrowse_Mode).
+ */
+typedef struct FileFolderHistory {
+ struct FileFolderLists *next, *prev;
+
+ /** The browse mode this prev/next folder-lists are created for. */
+ char browse_mode; /* eFileBrowse_Mode */
+ char _pad[7];
+
+ /** Holds the list of previous directories to show. */
+ ListBase folders_prev;
+ /** Holds the list of next directories (pushed from previous) to show. */
+ ListBase folders_next;
+} FileFolderHistory;
+
/* File Browser */
typedef struct SpaceFile {
SpaceLink *next, *prev;
@@ -733,20 +777,42 @@ typedef struct SpaceFile {
char _pad0[6];
/* End 'SpaceLink' header. */
- char _pad1[4];
+ /** Is this a File Browser or an Asset Browser? */
+ char browse_mode; /* eFileBrowse_Mode */
+ char _pad1[1];
+
+ short tags;
+
int scroll_offset;
- /** Config and input for file select. */
- struct FileSelectParams *params;
+ /** Config and input for file select. One for each browse-mode, to keep them independent. */
+ FileSelectParams *params;
+ FileAssetSelectParams *asset_params;
- /** Holds the list of files to show. */
+ void *_pad2;
+
+ /**
+ * Holds the list of files to show.
+ * Currently recreated when browse-mode changes. Could be per browse-mode to avoid refreshes.
+ */
struct FileList *files;
- /** Holds the list of previous directories to show. */
+ /**
+ * Holds the list of previous directories to show. Owned by `folder_histories` below.
+ */
ListBase *folders_prev;
- /** Holds the list of next directories (pushed from previous) to show. */
+ /**
+ * Holds the list of next directories (pushed from previous) to show. Owned by
+ * `folder_histories` below.
+ */
ListBase *folders_next;
+ /**
+ * This actually owns the prev/next folder-lists above. On browse-mode change, the lists of the
+ * new mode get assigned to the above.
+ */
+ ListBase folder_histories; /* FileFolderHistory */
+
/* operator that is invoking fileselect
* op->exec() will be called on the 'Load' button.
* if operator provides op->cancel(), then this will be invoked
@@ -763,6 +829,30 @@ typedef struct SpaceFile {
short systemnr, system_bookmarknr;
} SpaceFile;
+/* SpaceFile.browse_mode (File Space Browsing Mode) */
+typedef enum eFileBrowse_Mode {
+ /* Regular Blender File Browser */
+ FILE_BROWSE_MODE_FILES = 0,
+ /* Asset Browser */
+ FILE_BROWSE_MODE_ASSETS = 1,
+} eFileBrowse_Mode;
+
+typedef enum eFileAssetLibrary_Type {
+ /* For the future. Display assets bundled with Blender by default. */
+ // FILE_ASSET_LIBRARY_BUNDLED = 0,
+ /** Display assets from the current session (current "Main"). */
+ FILE_ASSET_LIBRARY_LOCAL = 1,
+ /* For the future. Display assets for the current project. */
+ // FILE_ASSET_LIBRARY_PROJECT = 2,
+
+ /** Display assets from custom asset libraries, as defined in the preferences
+ * (#bUserAssetLibrary). The name will be taken from #FileSelectParams.asset_library.idname
+ * then.
+ * In RNA, we add the index of the custom library to this to identify it by index. So keep
+ * this last! */
+ FILE_ASSET_LIBRARY_CUSTOM = 100,
+} eFileAssetLibrary_Type;
+
/* FileSelectParams.display */
enum eFileDisplayType {
/** Internal (not exposed to users): Keep whatever display type was used during the last File
@@ -792,6 +882,13 @@ enum eFileSortType {
FILE_SORT_SIZE = 4,
};
+/* SpaceFile.tags */
+enum eFileTags {
+ /** Tag the space as having to update files representing or containing main data. Must be set
+ * after file read and undo/redo. */
+ FILE_TAG_REBUILD_MAIN_FILES = (1 << 0),
+};
+
/* FileSelectParams.details_flags */
enum eFileDetails {
FILE_DETAILS_SIZE = (1 << 0),
@@ -810,6 +907,7 @@ enum eFileDetails {
typedef enum eFileSelectType {
FILE_LOADLIB = 1,
FILE_MAIN = 2,
+ FILE_MAIN_ASSET = 3,
FILE_UNIX = 8,
FILE_BLENDER = 8, /* don't display relative paths */
@@ -842,6 +940,7 @@ typedef enum eFileSel_Params_Flag {
FILE_SORT_INVERT = (1 << 11),
FILE_HIDE_TOOL_PROPS = (1 << 12),
FILE_CHECK_EXISTING = (1 << 13),
+ FILE_ASSETS_ONLY = (1 << 14),
} eFileSel_Params_Flag;
/* sfile->params->rename_flag */
@@ -885,6 +984,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_USD = (1 << 18),
FILE_TYPE_VOLUME = (1 << 19),
+ FILE_TYPE_ASSET = (1 << 28),
/** An FS directory (i.e. S_ISDIR on its path is true). */
FILE_TYPE_DIR = (1 << 30),
FILE_TYPE_BLENDERLIB = (1u << 31),
@@ -985,9 +1085,16 @@ typedef struct FileDirEntry {
/** Optional argument for shortcuts, aliases etc. */
char *redirection_path;
- /** TODO: make this a real ID pointer? */
- void *poin;
- struct ImBuf *image;
+ /** When showing local IDs (FILE_MAIN, FILE_MAIN_ASSET), ID this file represents. Note comment
+ * for FileListInternEntry.local_data, the same applies here! */
+ ID *id;
+ /** If this file represents an asset, its asset data is here. Note that we may show assets of
+ * external files in which case this is set but not the id above.
+ * Note comment for FileListInternEntry.local_data, the same applies here! */
+ struct AssetMetaData *asset_data;
+
+ /* The icon_id for the preview image. */
+ int preview_icon_id;
/* Tags are for info only, most of filtering is done in asset engine. */
char **tags;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 0b0895f9db0..aaa948dbff6 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -253,7 +253,9 @@ extern StructRNA RNA_FModifierPython;
extern StructRNA RNA_FModifierStepped;
extern StructRNA RNA_FaceMap;
extern StructRNA RNA_FieldSettings;
+extern StructRNA RNA_FileAssetSelectParams;
extern StructRNA RNA_FileBrowserFSMenuEntry;
+extern StructRNA RNA_FileSelectEntry;
extern StructRNA RNA_FileSelectParams;
extern StructRNA RNA_FloatAttribute;
extern StructRNA RNA_FloatAttributeValue;
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index a94466e30c2..69bd6142cad 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -56,6 +56,7 @@ extern const EnumPropertyItem rna_enum_mesh_select_mode_items[];
extern const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[];
extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[];
extern const EnumPropertyItem rna_enum_space_graph_mode_items[];
+extern const EnumPropertyItem rna_enum_space_file_browse_mode_items[];
extern const EnumPropertyItem rna_enum_space_sequencer_view_type_items[];
extern const EnumPropertyItem rna_enum_space_type_items[];
extern const EnumPropertyItem rna_enum_space_image_mode_items[];
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 36dbb1c78cc..4b39858026c 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -170,6 +170,12 @@ const EnumPropertyItem rna_enum_space_sequencer_view_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_space_file_browse_mode_items[] = {
+ {FILE_BROWSE_MODE_FILES, "FILES", ICON_FILEBROWSER, "File Browser", ""},
+ {FILE_BROWSE_MODE_ASSETS, "ASSETS", ICON_ASSET_MANAGER, "Asset Browser", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#define SACT_ITEM_DOPESHEET \
{ \
SACTCONT_DOPESHEET, "DOPESHEET", ICON_ACTION, "Dope Sheet", "Edit all keyframes in scene" \
@@ -504,6 +510,7 @@ static const EnumPropertyItem rna_enum_curve_display_handle_items[] = {
# include "BKE_layer.h"
# include "BKE_nla.h"
# include "BKE_paint.h"
+# include "BKE_preferences.h"
# include "BKE_scene.h"
# include "BKE_screen.h"
# include "BKE_workspace.h"
@@ -2462,13 +2469,159 @@ static PointerRNA rna_FileSelectParams_filter_id_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_FileSelectIDFilter, ptr->data);
}
+static int rna_FileAssetSelectParams_asset_library_get(PointerRNA *ptr)
+{
+ FileAssetSelectParams *params = ptr->data;
+ /* Just an extra sanity check to ensure this isn't somehow called for RNA_FileSelectParams. */
+ BLI_assert(ptr->type == &RNA_FileAssetSelectParams);
+
+ /* Simple case: Predefined repo, just set the value. */
+ if (params->asset_library.type < FILE_ASSET_LIBRARY_CUSTOM) {
+ return params->asset_library.type;
+ }
+
+ /* Note that the path isn't checked for validity here. If an invalid library path is used, the
+ * Asset Browser can give a nice hint on what's wrong. */
+ const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_name(
+ &U, params->asset_library.custom_library_identifier);
+ const int index = BKE_preferences_asset_library_get_index(&U, user_library);
+ if (index > -1) {
+ return FILE_ASSET_LIBRARY_CUSTOM + index;
+ }
+
+ BLI_assert(0);
+ return FILE_ASSET_LIBRARY_LOCAL;
+}
+
+static void rna_FileAssetSelectParams_asset_library_set(PointerRNA *ptr, int value)
+{
+ FileAssetSelectParams *params = ptr->data;
+
+ /* Simple case: Predefined repo, just set the value. */
+ if (value < FILE_ASSET_LIBRARY_CUSTOM) {
+ params->asset_library.type = value;
+ params->asset_library.custom_library_identifier[0] = '\0';
+ BLI_assert(ELEM(value, FILE_ASSET_LIBRARY_LOCAL));
+ return;
+ }
+
+ const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
+ &U, value - FILE_ASSET_LIBRARY_CUSTOM);
+
+ /* Note that the path isn't checked for validity here. If an invalid library path is used, the
+ * Asset Browser can give a nice hint on what's wrong. */
+ const bool is_valid = (user_library->name[0] && user_library->path[0]);
+ if (user_library && is_valid) {
+ BLI_strncpy(params->asset_library.custom_library_identifier,
+ user_library->name,
+ sizeof(params->asset_library.custom_library_identifier));
+ params->asset_library.type = FILE_ASSET_LIBRARY_CUSTOM;
+ }
+}
+
+static const EnumPropertyItem *rna_FileAssetSelectParams_asset_library_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ const EnumPropertyItem predefined_items[] = {
+ /* For the future. */
+ // {FILE_ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
+ {FILE_ASSET_LIBRARY_LOCAL,
+ "LOCAL",
+ ICON_BLENDER,
+ "Current File",
+ "Show the assets currently available in this Blender session"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ /* Add separator if needed. */
+ if (!BLI_listbase_is_empty(&U.asset_libraries)) {
+ const EnumPropertyItem sepr = {0, "", 0, "Custom", NULL};
+ RNA_enum_item_add(&item, &totitem, &sepr);
+ }
+
+ int i = 0;
+ for (bUserAssetLibrary *user_library = U.asset_libraries.first; user_library;
+ user_library = user_library->next, i++) {
+ /* Note that the path itself isn't checked for validity here. If an invalid library path is
+ * used, the Asset Browser can give a nice hint on what's wrong. */
+ const bool is_valid = (user_library->name[0] && user_library->path[0]);
+ if (!is_valid) {
+ continue;
+ }
+
+ /* Use library path as description, it's a nice hint for users. */
+ EnumPropertyItem tmp = {FILE_ASSET_LIBRARY_CUSTOM + i,
+ user_library->name,
+ ICON_NONE,
+ user_library->name,
+ user_library->path};
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+
+ if (totitem) {
+ const EnumPropertyItem sepr = {0, "", 0, "Built-in", NULL};
+ RNA_enum_item_add(&item, &totitem, &sepr);
+ }
+
+ /* Add predefined items. */
+ RNA_enum_items_add(&item, &totitem, predefined_items);
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+ return item;
+}
+
+static void rna_FileBrowser_FileSelectEntry_name_get(PointerRNA *ptr, char *value)
+{
+ const FileDirEntry *entry = ptr->data;
+ strcpy(value, entry->name);
+}
+
+static int rna_FileBrowser_FileSelectEntry_name_length(PointerRNA *ptr)
+{
+ const FileDirEntry *entry = ptr->data;
+ return (int)strlen(entry->name);
+}
+
+static int rna_FileBrowser_FileSelectEntry_preview_icon_id_get(PointerRNA *ptr)
+{
+ const FileDirEntry *entry = ptr->data;
+ return entry->preview_icon_id;
+}
+
+static PointerRNA rna_FileBrowser_FileSelectEntry_asset_data_get(PointerRNA *ptr)
+{
+ const FileDirEntry *entry = ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_AssetMetaData, entry->asset_data);
+}
+
+static StructRNA *rna_FileBrowser_params_typef(PointerRNA *ptr)
+{
+ SpaceFile *sfile = ptr->data;
+ FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+
+ if (params == ED_fileselect_get_file_params(sfile)) {
+ return &RNA_FileSelectParams;
+ }
+ if (params == (void *)ED_fileselect_get_asset_params(sfile)) {
+ return &RNA_FileAssetSelectParams;
+ }
+
+ BLI_assert(!"Could not identify file select parameters");
+ return NULL;
+}
+
static PointerRNA rna_FileBrowser_params_get(PointerRNA *ptr)
{
SpaceFile *sfile = ptr->data;
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ StructRNA *params_struct = rna_FileBrowser_params_typef(ptr);
- if (params) {
- return rna_pointer_inherit_refine(ptr, &RNA_FileSelectParams, params);
+ if (params && params_struct) {
+ return rna_pointer_inherit_refine(ptr, params_struct, params);
}
return rna_pointer_inherit_refine(ptr, NULL, NULL);
@@ -2784,6 +2937,14 @@ static void rna_FileBrowser_FSMenuRecent_active_range(
rna_FileBrowser_FSMenu_active_range(ptr, min, max, softmin, softmax, FS_CATEGORY_RECENT);
}
+static void rna_SpaceFileBrowser_browse_mode_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ ScrArea *area = rna_area_from_space(ptr);
+ ED_area_tag_refresh(area);
+}
+
#else
static const EnumPropertyItem dt_uv_items[] = {
@@ -5794,6 +5955,44 @@ static void rna_def_fileselect_idfilter(BlenderRNA *brna)
}
}
+static void rna_def_fileselect_entry(BlenderRNA *brna)
+{
+ PropertyRNA *prop;
+ StructRNA *srna = RNA_def_struct(brna, "FileSelectEntry", NULL);
+ RNA_def_struct_sdna(srna, "FileDirEntry");
+ RNA_def_struct_ui_text(srna, "File Select Entry", "A file viewable in the File Browser");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop,
+ "rna_FileBrowser_FileSelectEntry_name_get",
+ "rna_FileBrowser_FileSelectEntry_name_length",
+ NULL);
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_int(
+ srna,
+ "preview_icon_id",
+ 0,
+ INT_MIN,
+ INT_MAX,
+ "Icon ID",
+ "Unique integer identifying the preview of this file as an icon (zero means invalid)",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_int_funcs(
+ prop, "rna_FileBrowser_FileSelectEntry_preview_icon_id_get", NULL, NULL);
+
+ prop = RNA_def_property(srna, "asset_data", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "AssetMetaData");
+ RNA_def_property_pointer_funcs(
+ prop, "rna_FileBrowser_FileSelectEntry_asset_data_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(
+ prop, "Asset Data", "Asset data, valid if the file represents an asset");
+}
+
static void rna_def_fileselect_params(BlenderRNA *brna)
{
StructRNA *srna;
@@ -5966,6 +6165,12 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_BLENDER, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ prop = RNA_def_property(srna, "use_filter_asset_only", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_ASSETS_ONLY);
+ RNA_def_property_ui_text(
+ prop, "Only Assets", "Hide .blend files items that are not data-blocks with asset metadata");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
prop = RNA_def_property(srna, "filter_id", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "FileSelectIDFilter");
@@ -5997,6 +6202,25 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
+static void rna_def_fileselect_asset_params(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "FileAssetSelectParams", "FileSelectParams");
+ RNA_def_struct_ui_text(
+ srna, "Asset Select Parameters", "Settings for the file selection in Asset Browser mode");
+
+ prop = RNA_def_property(srna, "asset_library", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, DummyRNA_NULL_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_FileAssetSelectParams_asset_library_get",
+ "rna_FileAssetSelectParams_asset_library_set",
+ "rna_FileAssetSelectParams_asset_library_itemf");
+ RNA_def_property_ui_text(prop, "Asset Library", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+}
+
static void rna_def_filemenu_entry(BlenderRNA *brna)
{
StructRNA *srna;
@@ -6050,9 +6274,18 @@ static void rna_def_space_filebrowser(BlenderRNA *brna)
rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_TOOLS) | (1 << RGN_TYPE_UI));
+ prop = RNA_def_property(srna, "browse_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_space_file_browse_mode_items);
+ RNA_def_property_ui_text(
+ prop,
+ "Browsing Mode",
+ "Type of the File Editor view (regular file browsing or asset browsing)");
+ RNA_def_property_update(prop, 0, "rna_SpaceFileBrowser_browse_mode_update");
+
prop = RNA_def_property(srna, "params", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "FileSelectParams");
- RNA_def_property_pointer_funcs(prop, "rna_FileBrowser_params_get", NULL, NULL, NULL);
+ RNA_def_property_pointer_funcs(
+ prop, "rna_FileBrowser_params_get", NULL, "rna_FileBrowser_params_typef", NULL);
RNA_def_property_ui_text(
prop, "Filebrowser Parameter", "Parameters and Settings for the Filebrowser");
@@ -6800,7 +7033,9 @@ void RNA_def_space(BlenderRNA *brna)
rna_def_space_image(brna);
rna_def_space_sequencer(brna);
rna_def_space_text(brna);
+ rna_def_fileselect_entry(brna);
rna_def_fileselect_params(brna);
+ rna_def_fileselect_asset_params(brna);
rna_def_fileselect_idfilter(brna);
rna_def_filemenu_entry(brna);
rna_def_space_filebrowser(brna);
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 631a4d23eb5..fa658a5cdec 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -198,6 +198,8 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
ot->srna, "filter_blenlib", (filter & FILE_TYPE_BLENDERLIB) != 0, "Filter Blender IDs", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* TODO asset only filter? */
+
prop = RNA_def_int(
ot->srna,
"filemode",