From fe35551df2d874d51073b1dc4a582a1962255949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 5 Mar 2021 15:00:56 +0100 Subject: Asset Browser Space API: add `activate_asset_by_id()` function Add an RNA function `activate_asset_by_id(asset_id: ID, deferred: bool)` to the File Browser space type, which intended to be used to activate an asset's entry as identified by its `ID *`. Calling it changes the active asset, but only if the given ID can actually be found. The activation can be deferred (by passing `deferred=True`) until the next refresh operation has finished. This is necessary when an asset has just been added, as it will be loaded by the filebrowser in a background job. Reviewed By: Severin Differential Revision: https://developer.blender.org/D10549 --- source/blender/blenkernel/intern/screen.c | 1 + source/blender/editors/include/ED_fileselect.h | 7 +++ source/blender/editors/space_file/file_intern.h | 15 +++++++ source/blender/editors/space_file/filelist.c | 11 ++--- source/blender/editors/space_file/filelist.h | 2 + source/blender/editors/space_file/filesel.c | 60 +++++++++++++++++++++++++ source/blender/editors/space_file/space_file.c | 51 ++++++++++++++++++--- source/blender/makesdna/DNA_space_types.h | 5 +++ source/blender/makesrna/intern/rna_internal.h | 1 + source/blender/makesrna/intern/rna_space.c | 2 + source/blender/makesrna/intern/rna_space_api.c | 21 +++++++++ source/blender/windowmanager/WM_types.h | 1 + 12 files changed, 166 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 8b911143668..623f3a349d8 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1681,6 +1681,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) sfile->op = NULL; sfile->previews_timer = NULL; sfile->tags = 0; + sfile->runtime = NULL; BLO_read_data_address(reader, &sfile->params); BLO_read_data_address(reader, &sfile->asset_params); } diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 7538dac1354..983ae94b637 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -145,6 +145,13 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile); bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile); +struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile); + +/* Activate the file that corresponds to the given ID. + * Pass deferred=true to wait for the next refresh before activating. */ +void ED_fileselect_activate_by_id(struct SpaceFile *sfile, + struct ID *asset_id, + const bool deferred); void ED_fileselect_window_params_get(const struct wmWindow *win, int win_size[2], diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 56fb588776e..deb32812f44 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -112,6 +112,21 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v); void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params); +typedef void *onReloadFnData; +typedef void (*onReloadFn)(struct SpaceFile *space_data, onReloadFnData custom_data); +typedef struct SpaceFile_Runtime { + /* Called once after the file browser has reloaded. Reset to NULL after calling. + * Use file_on_reload_callback_register() to register a callback. */ + onReloadFn on_reload; + onReloadFnData on_reload_custom_data; +} SpaceFile_Runtime; + +/* Register an on-reload callback function. Note that there can only be one such function at a + * time; registering a new one will overwrite the previous one. */ +void file_on_reload_callback_register(struct SpaceFile *sfile, + onReloadFn callback, + onReloadFnData custom_data); + /* file_panels.c */ void file_tool_props_region_panels_register(struct ARegionType *art); void file_execute_region_panels_register(struct ARegionType *art); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 33c37875372..518fc777c67 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1990,9 +1990,7 @@ static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry) filelist_entry_free(entry); } -static FileDirEntry *filelist_file_ex(struct FileList *filelist, - const int index, - const bool use_request) +FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request) { FileDirEntry *ret = NULL, *old; FileListEntryCache *cache = &filelist->filelist_cache; @@ -3464,7 +3462,7 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) filelist_readjob_endjob(flrj); filelist_readjob_free(flrj); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED, NULL); return; } @@ -3476,7 +3474,10 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) 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_timer(wm_job, + 0.01, + NC_SPACE | ND_SPACE_FILE_LIST, + NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED); WM_jobs_callbacks( wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 16984bb6e43..7eecd7a05de 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -93,6 +93,8 @@ void filelist_setdir(struct FileList *filelist, char *r_dir); int filelist_files_ensure(struct FileList *filelist); int filelist_needs_reading(struct FileList *filelist); FileDirEntry *filelist_file(struct FileList *filelist, int index); +FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request); + 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]); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 6917893ab5f..7015ca970a3 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -454,6 +454,66 @@ bool ED_fileselect_is_asset_browser(const SpaceFile *sfile) return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS); } +struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile) +{ + if (!ED_fileselect_is_asset_browser(sfile)) { + return NULL; + } + + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + const FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return NULL; + } + + return filelist_file_get_id(file); +} + +static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data) +{ + ID *asset_id = (ID *)custom_data; + ED_fileselect_activate_by_id(sfile, asset_id, false); +} + +void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred) +{ + if (!ED_fileselect_is_asset_browser(sfile)) { + return; + } + + /* If there are filelist operations running now ("pending" true) or soon ("force reset" true), + * there is a fair chance that the to-be-activated ID will only be present after these operations + * have completed. Defer activation until then. */ + if (deferred || filelist_pending(sfile->files) || filelist_needs_force_reset(sfile->files)) { + /* This should be thread-safe, as this function is likely called from the main thread, and + * notifiers (which cause a call to the on-reload callback function) are handled on the main + * thread as well. */ + file_on_reload_callback_register(sfile, on_reload_activate_by_id, asset_id); + return; + } + + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + struct FileList *files = sfile->files; + + const int num_files_filtered = filelist_files_ensure(files); + for (int file_index = 0; file_index < num_files_filtered; ++file_index) { + const FileDirEntry *file = filelist_file_ex(files, file_index, false); + + if (filelist_file_get_id(file) != asset_id) { + filelist_entry_select_set(files, file, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); + continue; + } + + params->active_file = file_index; + filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + + /* Keep looping to deselect the other files. */ + } + + WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, NULL); + WM_main_add_notifier(NC_ASSET | NA_SELECTED, NULL); +} + /* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA * may also be remembered, but only conditionally. */ #define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index b175844a710..2c9c2688e88 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -173,6 +173,7 @@ static void file_free(SpaceLink *sl) MEM_SAFE_FREE(sfile->params); MEM_SAFE_FREE(sfile->asset_params); + MEM_SAFE_FREE(sfile->runtime); if (sfile->layout) { MEM_freeN(sfile->layout); @@ -188,6 +189,10 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area) if (sfile->layout) { sfile->layout->dirty = true; } + + if (sfile->runtime == NULL) { + sfile->runtime = MEM_callocN(sizeof(*sfile->runtime), __func__); + } } static void file_exit(wmWindowManager *wm, ScrArea *area) @@ -209,6 +214,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl) /* clear or remove stuff from old */ sfilen->op = NULL; /* file window doesn't own operators */ + sfilen->runtime = NULL; sfilen->previews_timer = NULL; sfilen->smoothscroll_timer = NULL; @@ -392,6 +398,26 @@ static void file_refresh(const bContext *C, ScrArea *area) ED_area_tag_redraw(area); } +void file_on_reload_callback_register(SpaceFile *sfile, + onReloadFn callback, + onReloadFnData custom_data) +{ + sfile->runtime->on_reload = callback; + sfile->runtime->on_reload_custom_data = custom_data; +} + +static void file_on_reload_callback_call(SpaceFile *sfile) +{ + if (sfile->runtime->on_reload == NULL) { + return; + } + + sfile->runtime->on_reload(sfile, sfile->runtime->on_reload_custom_data); + + sfile->runtime->on_reload = NULL; + sfile->runtime->on_reload_custom_data = NULL; +} + static void file_listener(const wmSpaceTypeListenerParams *params) { ScrArea *area = params->area; @@ -419,12 +445,26 @@ static void file_listener(const wmSpaceTypeListenerParams *params) } break; } + switch (wmn->action) { + case NA_JOB_FINISHED: + file_on_reload_callback_call(sfile); + 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); + switch (wmn->action) { + case NA_SELECTED: + case NA_ACTIVATED: + ED_area_tag_refresh(area); + break; + case NA_ADDED: + case NA_REMOVED: + 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; } break; } @@ -464,8 +504,7 @@ static void file_main_region_listener(const wmRegionListenerParams *params) } break; case NC_ID: - if (ELEM(wmn->action, NA_RENAME)) { - /* In case the filelist shows ID names. */ + if (ELEM(wmn->action, NA_SELECTED, NA_ACTIVATED, NA_RENAME)) { ED_region_tag_redraw(region); } break; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index dc1775b09c6..856fa569645 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -66,6 +66,9 @@ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; /* Defined in `node_intern.h`. */ typedef struct SpaceNode_Runtime SpaceNode_Runtime; +/* Defined in `file_intern.h`. */ +typedef struct SpaceFile_Runtime SpaceFile_Runtime; + /* -------------------------------------------------------------------- */ /** \name SpaceLink (Base) * \{ */ @@ -846,6 +849,8 @@ typedef struct SpaceFile { short recentnr, bookmarknr; short systemnr, system_bookmarknr; + + SpaceFile_Runtime *runtime; } SpaceFile; /* SpaceFile.browse_mode (File Space Browsing Mode) */ diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index bfcb0039ca8..95972dd444f 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -424,6 +424,7 @@ void RNA_api_window(struct StructRNA *srna); void RNA_api_wm(struct StructRNA *srna); void RNA_api_space_node(struct StructRNA *srna); void RNA_api_space_text(struct StructRNA *srna); +void RNA_api_space_filebrowser(struct StructRNA *srna); void RNA_api_region_view3d(struct StructRNA *srna); void RNA_api_texture(struct StructRNA *srna); void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 409a2f097ed..5312aea9295 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -6569,6 +6569,8 @@ static void rna_def_space_filebrowser(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update( prop, NC_SPACE | ND_SPACE_FILE_PARAMS, "rna_FileBrowser_FSMenu_active_update"); + + RNA_api_space_filebrowser(srna); } static void rna_def_space_info(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index e4c0ade1533..205a88edf84 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -27,6 +27,7 @@ # include "BKE_global.h" +# include "ED_fileselect.h" # include "ED_screen.h" # include "ED_text.h" @@ -115,4 +116,24 @@ void RNA_api_space_text(StructRNA *srna) RNA_def_function_output(func, parm); } +void RNA_api_space_filebrowser(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "activate_asset_by_id", "ED_fileselect_activate_by_id"); + RNA_def_function_ui_description(func, "Activate the asset entry that represents the given ID"); + + parm = RNA_def_property(func, "id_to_activate", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(parm, "ID"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + parm = RNA_def_boolean( + func, + "deferred", + 0, + "", + "Whether to activate the ID immediately (false) or after the file browser refreshes (true)"); +} + #endif diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index f12832faa45..084ca2d2df5 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -461,6 +461,7 @@ typedef struct wmNotifier { #define NA_SELECTED 6 #define NA_ACTIVATED 7 #define NA_PAINTING 8 +#define NA_JOB_FINISHED 9 /* ************** Gesture Manager data ************** */ -- cgit v1.2.3