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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ************** */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user