WIP: Basic support for registering asset shelf as a type in BPY #104991

Closed
Julian Eisel wants to merge 73 commits from JulianEisel:temp-asset-shelf-type-bpy into asset-shelf

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
7 changed files with 258 additions and 3 deletions
Showing only changes of commit dcb1147eef - Show all commits

View File

@ -128,6 +128,9 @@ typedef struct SpaceType {
/* region type definitions */
ListBase regiontypes;
/* Asset shelf type definitions */
ListBase asset_shelf_types; /* AssetShelfType */
/* read and write... */
/** Default key-maps to add. */
@ -396,6 +399,22 @@ typedef struct Menu {
struct uiLayout *layout; /* runtime for drawing */
} Menu;
/* asset shelf types */
typedef struct AssetShelfType {
struct AssetShelfType *next, *prev;
char idname[BKE_ST_MAXNAME]; /* unique name */
int space_type;
/* Determine if the asset shelf should be visible or not. */
bool (*poll)(const struct bContext *C, struct AssetShelfType *shelf_type);
/* RNA integration */
ExtensionRNA rna_ext;
} AssetShelfType;
/* Space-types. */
struct SpaceType *BKE_spacetype_from_id(int spaceid);

View File

@ -23,6 +23,10 @@ struct wmWindowManager;
/** Only needed for #RGN_TYPE_ASSET_SHELF (not #RGN_TYPE_ASSET_SHELF_FOOTER). */
void ED_asset_shelf_region_listen(const struct wmRegionListenerParams *params);
void ED_asset_shelf_region_draw(const bContext *C, struct ARegion *region);
void ED_asset_shelf_region_register(ARegionType *region_type,
const char *idname,
const int space_type);
void ED_asset_shelf_footer_region_init(struct wmWindowManager *wm, struct ARegion *region);
void ED_asset_shelf_footer_region(const struct bContext *C, struct ARegion *region);

View File

@ -18,7 +18,7 @@ bool ED_asset_filter_matches_asset(const AssetFilterSettings *filter, const Asse
ID_Type asset_type = ED_asset_handle_get_id_type(asset);
uint64_t asset_id_filter = BKE_idtype_idcode_to_idfilter(asset_type);
if ((filter->id_types & asset_id_filter) == 0) {
if (filter->id_types && (filter->id_types & asset_id_filter) == 0) {
return false;
}
/* Not very efficient (O(n^2)), could be improved quite a bit. */

View File

@ -54,6 +54,12 @@ static void asset_shelf_region_listen(const wmRegionListenerParams *params)
ED_region_tag_redraw(region);
}
break;
case NC_SCENE:
/* Asset shelf polls typically check the mode. */
if (ELEM(wmn->data, ND_MODE)) {
ED_region_tag_redraw(region);
}
break;
}
}
@ -68,6 +74,51 @@ void ED_asset_shelf_region_listen(const wmRegionListenerParams *params)
}
}
/**
* Check if there is any asset shelf type returning true in it's poll. If not, no asset shelf
* region should be displayed.
*/
static bool asset_shelf_region_header_type_poll(const bContext *C, HeaderType * /*header_type*/)
{
const SpaceLink *space_link = CTX_wm_space_data(C);
const SpaceType *space_type = BKE_spacetype_from_id(space_link->spacetype);
/* Is there any asset shelf type registered that returns true for it's poll? */
LISTBASE_FOREACH (AssetShelfType *, shelf_type, &space_type->asset_shelf_types) {
if (shelf_type->poll && shelf_type->poll(C, shelf_type)) {
return true;
}
}
return false;
}
void ED_asset_shelf_region_draw(const bContext *C, ARegion *region)
{
ED_region_header(C, region);
}
static void asset_shelf_region_draw(const bContext *C, Header *header)
{
uiLayout *layout = header->layout;
AssetFilterSettings dummy_filter_settings{0};
uiTemplateAssetShelf(layout, C, &dummy_filter_settings);
}
void ED_asset_shelf_region_register(ARegionType *region_type,
const char *idname,
const int space_type)
{
HeaderType *ht = MEM_cnew<HeaderType>(__func__);
strcpy(ht->idname, idname);
ht->space_type = space_type;
ht->region_type = RGN_TYPE_ASSET_SHELF_FOOTER;
ht->draw = asset_shelf_region_draw;
ht->poll = asset_shelf_region_header_type_poll;
BLI_addtail(&region_type->headertypes, ht);
}
void ED_asset_shelf_footer_region_listen(const wmRegionListenerParams *params)
{
asset_shelf_region_listen(params);
@ -505,6 +556,7 @@ void ED_asset_shelf_footer_register(ARegionType *region_type,
ht->space_type = space_type;
ht->region_type = RGN_TYPE_ASSET_SHELF_FOOTER;
ht->draw = asset_shelf_footer_draw;
ht->poll = asset_shelf_region_header_type_poll;
BLI_addtail(&region_type->headertypes, ht);
}

View File

@ -2243,8 +2243,10 @@ void ED_spacetype_view3d()
art->listener = ED_asset_shelf_region_listen;
art->context = view3d_asset_shelf_context;
art->init = view3d_header_region_init;
art->draw = ED_region_header;
art->draw = ED_asset_shelf_region_draw;
BLI_addhead(&st->regiontypes, art);
ED_asset_shelf_region_register(art, "VIEW3D_HT_asset_shelf_main", SPACE_VIEW3D);
/* regions: asset shelf footer */
art = MEM_cnew<ARegionType>("spacetype view3d asset shelf footer region");
art->regionid = RGN_TYPE_ASSET_SHELF_FOOTER;
@ -2255,7 +2257,7 @@ void ED_spacetype_view3d()
art->listener = ED_asset_shelf_footer_region_listen;
art->context = view3d_asset_shelf_context;
BLI_addhead(&st->regiontypes, art);
ED_asset_shelf_footer_register(art, "VIEW3D_HT_asset_shelf", SPACE_VIEW3D);
ED_asset_shelf_footer_register(art, "VIEW3D_HT_asset_shelf_footer", SPACE_VIEW3D);
/* regions: hud */
art = ED_area_type_hud(st->spaceid);

View File

@ -312,6 +312,13 @@ typedef struct uiList { /* some list UI data need to be saved in file */
uiListDyn *dyn_data;
} uiList;
typedef struct AssetShelf {
struct AssetShelf *next, *prev;
/** Runtime. */
struct AssetShelfType *type;
} AssetShelf;
typedef struct TransformOrientation {
struct TransformOrientation *next, *prev;
/** MAX_NAME. */

View File

@ -1020,6 +1020,132 @@ static StructRNA *rna_Menu_refine(PointerRNA *mtr)
return (menu->type && menu->type->rna_ext.srna) ? menu->type->rna_ext.srna : &RNA_Menu;
}
/* Asset Shelf */
static bool asset_shelf_poll(const bContext *C, AssetShelfType *shelf_type)
{
extern FunctionRNA rna_AssetShelf_poll_func;
PointerRNA ptr;
RNA_pointer_create(NULL, shelf_type->rna_ext.srna, NULL, &ptr); /* dummy */
FunctionRNA *func = &rna_AssetShelf_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
ParameterList list;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
shelf_type->rna_ext.call((bContext *)C, &ptr, func, &list);
void *ret;
RNA_parameter_get_lookup(&list, "visible", &ret);
/* Get the value before freeing. */
const bool is_visible = *(bool *)ret;
RNA_parameter_list_free(&list);
return is_visible;
}
static void rna_AssetShelf_unregister(Main *UNUSED(bmain), StructRNA *type)
{
AssetShelfType *shelf_type = RNA_struct_blender_type_get(type);
if (!shelf_type) {
return;
}
SpaceType *space_type = BKE_spacetype_from_id(shelf_type->space_type);
if (!space_type) {
return;
}
RNA_struct_free_extension(type, &shelf_type->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
BLI_freelinkN(&space_type->asset_shelf_types, shelf_type);
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
}
static StructRNA *rna_AssetShelf_register(Main *bmain,
ReportList *reports,
void *data,
const char *identifier,
StructValidateFunc validate,
StructCallbackFunc call,
StructFreeFunc free)
{
AssetShelfType dummy_shelf_type = {NULL};
AssetShelf dummy_shelf = {NULL};
PointerRNA dummy_shelf_type_ptr;
/* setup dummy shelf & shelf type to store static properties in */
dummy_shelf.type = &dummy_shelf_type;
RNA_pointer_create(NULL, &RNA_AssetShelf, &dummy_shelf, &dummy_shelf_type_ptr);
int have_function[1];
/* validate the python class */
if (validate(&dummy_shelf_type_ptr, data, have_function) != 0) {
return NULL;
}
if (strlen(identifier) >= sizeof(dummy_shelf_type.idname)) {
BKE_reportf(reports,
RPT_ERROR,
"Registering asset shelf class: '%s' is too long, maximum length is %d",
identifier,
(int)sizeof(dummy_shelf_type.idname));
return NULL;
}
SpaceType *space_type = BKE_spacetype_from_id(dummy_shelf_type.space_type);
if (!space_type) {
return NULL;
}
/* Check if we have registered this asset shelf type before, and remove it. */
LISTBASE_FOREACH (AssetShelfType *, iter_shelf_type, &space_type->asset_shelf_types) {
if (STREQ(iter_shelf_type->idname, dummy_shelf_type.idname)) {
if (iter_shelf_type->rna_ext.srna) {
rna_AssetShelf_unregister(bmain, iter_shelf_type->rna_ext.srna);
}
break;
}
}
if (!RNA_struct_available_or_report(reports, dummy_shelf_type.idname)) {
return NULL;
}
if (!RNA_struct_bl_idname_ok_or_report(reports, dummy_shelf_type.idname, "_AST_")) {
return NULL;
}
/* Create the new shelf type. */
AssetShelfType *shelf_type = MEM_mallocN(sizeof(*shelf_type), __func__);
memcpy(shelf_type, &dummy_shelf_type, sizeof(*shelf_type));
shelf_type->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, shelf_type->idname, &RNA_AssetShelf);
shelf_type->rna_ext.data = data;
shelf_type->rna_ext.call = call;
shelf_type->rna_ext.free = free;
RNA_struct_blender_type_set(shelf_type->rna_ext.srna, shelf_type);
shelf_type->poll = have_function[0] ? asset_shelf_poll : NULL;
BLI_addtail(&space_type->asset_shelf_types, shelf_type);
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
return shelf_type->rna_ext.srna;
}
static StructRNA *rna_AssetShelf_refine(PointerRNA *shelf_ptr)
{
AssetShelf *shelf = (AssetShelf *)shelf_ptr->data;
return (shelf->type && shelf->type->rna_ext.srna) ? shelf->type->rna_ext.srna : &RNA_AssetShelf;
}
static void rna_Panel_bl_description_set(PointerRNA *ptr, const char *value)
{
Panel *data = (Panel *)(ptr->data);
@ -1832,6 +1958,50 @@ static void rna_def_menu(BlenderRNA *brna)
RNA_define_verify_sdna(1);
}
static void rna_def_asset_shelf(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "AssetShelf", NULL);
RNA_def_struct_ui_text(srna, "Asset Shelf", "Regions for quick access to assets");
RNA_def_struct_refine_func(srna, "rna_AssetShelf_refine");
RNA_def_struct_register_funcs(
srna, "rna_AssetShelf_register", "rna_AssetShelf_unregister", NULL);
RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE_INHERIT);
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "type->idname");
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop,
"ID Name",
"If this is set, the asset gets a custom ID, otherwise it takes the "
"name of the class used to define the menu (for example, if the "
"class name is \"OBJECT_AST_hello\", and bl_idname is not set by the "
"script, then bl_idname = \"OBJECT_AST_hello\")");
prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->space_type");
RNA_def_property_enum_items(prop, rna_enum_space_type_items);
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(
prop, "Space Type", "The space where the asset shelf is going to be used in");
PropertyRNA *parm;
FunctionRNA *func;
func = RNA_def_function(srna, "poll", NULL);
RNA_def_function_ui_description(
func, "If this method returns a non-null output, then the asset shelf will be visible");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", ""));
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_asset_shelf_settings(BlenderRNA *brna)
{
StructRNA *srna = RNA_def_struct(brna, "AssetShelfSettings", NULL);
@ -1845,6 +2015,7 @@ void RNA_def_ui(BlenderRNA *brna)
rna_def_uilist(brna);
rna_def_header(brna);
rna_def_menu(brna);
rna_def_asset_shelf(brna);
rna_def_asset_shelf_settings(brna);
}