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.
37 changed files with 1344 additions and 81 deletions

View File

@ -221,6 +221,10 @@ std::string AssetLibraryService::root_path_from_library_ref(
return essentials_directory_path();
}
if (ELEM(library_reference.type, ASSET_LIBRARY_ESSENTIALS)) {
return essentials_directory_path();
}
bUserAssetLibrary *custom_library = find_custom_asset_library_from_library_ref(
library_reference);
if (!custom_library || !custom_library->path[0]) {

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,26 @@ 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, const struct AssetShelfType *shelf_type);
/* Determine if an individual asset should be visible or not. May be a temporary design,
* visibility should be first and foremost controlled by asset traits. */
bool (*asset_poll)(const struct AssetShelfType *shelf_type, const struct AssetHandle *asset);
/* RNA integration */
ExtensionRNA rna_ext;
} AssetShelfType;
/* Space-types. */
struct SpaceType *BKE_spacetype_from_id(int spaceid);

View File

@ -4190,5 +4190,44 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
*/
{
/* Keep this block, even when empty. */
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
&sl->regionbase;
{
ARegion *new_asset_shelf_footer = do_versions_add_region_if_not_found(
regionbase,
RGN_TYPE_ASSET_SHELF_FOOTER,
"asset shelf footer for view3d (versioning)",
RGN_TYPE_UI);
if (new_asset_shelf_footer != nullptr) {
new_asset_shelf_footer->alignment = RGN_ALIGN_BOTTOM;
new_asset_shelf_footer->flag |= RGN_FLAG_HIDDEN;
}
}
{
ARegion *new_asset_shelf = do_versions_add_region_if_not_found(
regionbase,
RGN_TYPE_ASSET_SHELF,
"asset shelf for view3d (versioning)",
RGN_TYPE_ASSET_SHELF_FOOTER);
if (new_asset_shelf != nullptr) {
new_asset_shelf->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
new_asset_shelf->flag |= RGN_FLAG_DYNAMIC_SIZE;
}
}
}
}
}
}
/* Should we really use the "All" library by default? Consider loading time and memory usage.
*/
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
workspace->asset_library_ref.type = ASSET_LIBRARY_ALL;
workspace->asset_library_ref.custom_library_index = -1;
}
}
}

View File

@ -260,6 +260,9 @@ void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_templat
BKE_workspace_tool_remove(workspace, static_cast<bToolRef *>(workspace->tools.first));
}
workspace->asset_library_ref.type = ASSET_LIBRARY_ALL;
workspace->asset_library_ref.custom_library_index = -1;
/* For 2D animation template. */
if (STREQ(workspace->id.name + 2, "Drawing")) {
workspace->object_mode = OB_MODE_PAINT_GPENCIL;

View File

@ -13,6 +13,8 @@ set(INC
../../windowmanager
../../../../intern/clog
../../../../intern/guardedalloc
# dna_type_offsets.h
${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
)
@ -31,6 +33,7 @@ set(SRC
intern/asset_list.cc
intern/asset_mark_clear.cc
intern/asset_ops.cc
intern/asset_shelf.cc
intern/asset_temp_id_consumer.cc
intern/asset_type.cc
@ -44,6 +47,7 @@ set(SRC
ED_asset_list.h
ED_asset_list.hh
ED_asset_mark_clear.h
ED_asset_shelf.h
ED_asset_temp_id_consumer.h
ED_asset_type.h
intern/asset_library_reference.hh

View File

@ -58,8 +58,7 @@ struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
/**
* \return True if the region needs a UI redraw.
*/
bool ED_assetlist_listen(const struct AssetLibraryReference *library_reference,
const struct wmNotifier *notifier);
bool ED_assetlist_listen(const struct wmNotifier *notifier);
/**
* \return The number of assets stored in the asset list for \a library_reference, or -1 if there
* is no list fetched for it.

View File

@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edasset
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
struct ARegionType;
struct AssetShelfSettings;
struct bContext;
struct bContextDataResult;
struct BlendDataReader;
struct BlendWriter;
struct wmWindowManager;
/* -------------------------------------------------------------------- */
/* Asset Shelf Regions */
/** 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);
void ED_asset_shelf_footer_region_listen(const struct wmRegionListenerParams *params);
void ED_asset_shelf_footer_register(struct ARegionType *region_type,
const char *idname,
const int space_type);
/* -------------------------------------------------------------------- */
/* Asset Shelf Settings */
/**
* Deep-copies \a shelf_settings into newly allocated memory. Must be freed using #MEM_freeN() or
* #MEM_delete().
*/
AssetShelfSettings *ED_asset_shelf_settings_duplicate(const AssetShelfSettings *shelf_settings);
/**
* Frees the contained data, not \a shelf_settings itself.
*/
void ED_asset_shelf_settings_free(AssetShelfSettings *shelf_settings);
void ED_asset_shelf_settings_blend_write(struct BlendWriter *writer,
const struct AssetShelfSettings *storage);
void ED_asset_shelf_settings_blend_read_data(struct BlendDataReader *reader,
struct AssetShelfSettings **storage);
/* -------------------------------------------------------------------- */
/**
* Creates an `"asset_shelf_settings"` context member, pointing to \a shelf_settings.
*/
int ED_asset_shelf_context(const struct bContext *C,
const char *member,
struct bContextDataResult *result,
struct AssetShelfSettings *shelf_settings);
#ifdef __cplusplus
}
#endif

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

@ -118,7 +118,7 @@ class AssetList : NonCopyable {
bool isLoaded() const;
asset_system::AssetLibrary *asset_library() const;
void iterate(AssetListIterFn fn) const;
bool listen(const wmNotifier &notifier) const;
static bool listen(const wmNotifier &notifier);
int size() const;
void tagMainDataDirty() const;
void remapID(ID *id_old, ID *id_new) const;
@ -256,7 +256,7 @@ AssetHandle AssetList::asset_get_by_index(int index) const
/**
* \return True if the asset-list needs a UI redraw.
*/
bool AssetList::listen(const wmNotifier &notifier) const
bool AssetList::listen(const wmNotifier &notifier)
{
switch (notifier.category) {
case NC_ID: {
@ -496,14 +496,9 @@ ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
return filelist_geticon_image_ex(asset_handle->file_data);
}
bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
const wmNotifier *notifier)
bool ED_assetlist_listen(const wmNotifier *notifier)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
if (list) {
return list->listen(*notifier);
}
return false;
return AssetList::listen(*notifier);
}
int ED_assetlist_size(const AssetLibraryReference *library_reference)

View File

@ -0,0 +1,563 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edasset
*/
#include "AS_asset_catalog.hh"
#include "AS_asset_catalog_tree.hh"
#include "AS_asset_library.hh"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BLO_read_write.h"
#include "BLT_translation.h"
#include "DNA_screen_types.h"
#include "ED_asset_list.h"
#include "ED_asset_list.hh"
#include "ED_screen.h"
#include "RNA_prototypes.h"
#include "UI_interface.h"
#include "UI_interface.hh"
#include "UI_resources.h"
#include "UI_tree_view.hh"
#include "WM_api.h"
#include "ED_asset_shelf.h"
using namespace blender;
static void asset_shelf_send_redraw_notifier(bContext &C)
{
WM_event_add_notifier(&C, NC_SPACE | ND_SPACE_ASSET_SHELF, nullptr);
}
/* -------------------------------------------------------------------- */
/** \name Asset Shelf Regions
* \{ */
static void asset_shelf_region_listen(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
const wmNotifier *wmn = params->notifier;
switch (wmn->category) {
case NC_SPACE:
if (wmn->data == ND_SPACE_ASSET_SHELF) {
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;
}
}
void ED_asset_shelf_region_listen(const wmRegionListenerParams *params)
{
if (ED_assetlist_listen(params->notifier)) {
ED_region_tag_redraw_no_rebuild(params->region);
}
/* If the asset list didn't catch the notifier, let the region itself listen. */
else {
asset_shelf_region_listen(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);
}
void ED_asset_shelf_footer_region_init(wmWindowManager * /*wm*/, ARegion *region)
{
ED_region_header_init(region);
}
void ED_asset_shelf_footer_region(const bContext *C, ARegion *region)
{
ED_region_header(C, region);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Asset Shelf Settings
* \{ */
AssetShelfSettings *ED_asset_shelf_settings_duplicate(const AssetShelfSettings *shelf_settings)
{
if (!shelf_settings) {
return nullptr;
}
static_assert(
std::is_trivial_v<AssetShelfSettings>,
"AssetShelfSettings needs to be trivial to allow freeing with MEM_freeN() (API promise)");
AssetShelfSettings *new_settings = MEM_new<AssetShelfSettings>(__func__, *shelf_settings);
LISTBASE_FOREACH (LinkData *, catalog_path_item, &shelf_settings->enabled_catalog_paths) {
LinkData *new_path_item = static_cast<LinkData *>(MEM_dupallocN(catalog_path_item));
new_path_item->data = BLI_strdup((char *)catalog_path_item->data);
BLI_addtail(&new_settings->enabled_catalog_paths, new_path_item);
}
return new_settings;
}
static void asset_shelf_settings_clear_enabled_catalogs(AssetShelfSettings &shelf_settings)
{
LISTBASE_FOREACH_MUTABLE (LinkData *, catalog_path_item, &shelf_settings.enabled_catalog_paths) {
MEM_freeN(catalog_path_item->data);
BLI_freelinkN(&shelf_settings.enabled_catalog_paths, catalog_path_item);
}
BLI_assert(BLI_listbase_is_empty(&shelf_settings.enabled_catalog_paths));
}
static void asset_shelf_settings_set_active_catalog(AssetShelfSettings &shelf_settings,
const asset_system::AssetCatalogPath &path)
{
MEM_delete(shelf_settings.active_catalog_path);
shelf_settings.active_catalog_path = BLI_strdupn(path.c_str(), path.length());
}
static bool asset_shelf_settings_is_active_catalog(const AssetShelfSettings &shelf_settings,
const asset_system::AssetCatalogPath &path)
{
return shelf_settings.active_catalog_path && shelf_settings.active_catalog_path == path.str();
}
void ED_asset_shelf_settings_free(AssetShelfSettings *shelf_settings)
{
asset_shelf_settings_clear_enabled_catalogs(*shelf_settings);
MEM_delete(shelf_settings->active_catalog_path);
}
void ED_asset_shelf_settings_blend_write(BlendWriter *writer,
const AssetShelfSettings *shelf_settings)
{
if (!shelf_settings) {
return;
}
BLO_write_struct(writer, AssetShelfSettings, shelf_settings);
LISTBASE_FOREACH (LinkData *, catalog_path_item, &shelf_settings->enabled_catalog_paths) {
BLO_write_struct(writer, LinkData, catalog_path_item);
BLO_write_string(writer, (const char *)catalog_path_item->data);
}
}
void ED_asset_shelf_settings_blend_read_data(BlendDataReader *reader,
AssetShelfSettings **shelf_settings)
{
if (!*shelf_settings) {
return;
}
BLO_read_data_address(reader, shelf_settings);
BLO_read_list(reader, &(*shelf_settings)->enabled_catalog_paths);
LISTBASE_FOREACH (LinkData *, catalog_path_item, &(*shelf_settings)->enabled_catalog_paths) {
BLO_read_data_address(reader, &catalog_path_item->data);
}
}
static bool asset_shelf_settings_is_catalog_path_enabled(
const AssetShelfSettings &shelf_settings, const asset_system::AssetCatalogPath &path)
{
LISTBASE_FOREACH (LinkData *, catalog_path_item, &shelf_settings.enabled_catalog_paths) {
if (StringRef((const char *)catalog_path_item->data) == path.str()) {
return true;
}
}
return false;
}
static void asset_shelf_settings_set_catalog_path_enabled(
AssetShelfSettings &shelf_settings, const asset_system::AssetCatalogPath &path)
{
char *path_copy = BLI_strdupn(path.c_str(), path.length());
BLI_addtail(&shelf_settings.enabled_catalog_paths, BLI_genericNodeN(path_copy));
}
static void asset_shelf_settings_foreach_enabled_catalog_path(
const AssetShelfSettings &shelf_settings,
FunctionRef<void(const asset_system::AssetCatalogPath &catalog_path)> fn)
{
LISTBASE_FOREACH (LinkData *, catalog_path_item, &shelf_settings.enabled_catalog_paths) {
fn(asset_system::AssetCatalogPath((char *)catalog_path_item->data));
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Asset Shelf Context
* \{ */
int ED_asset_shelf_context(const bContext *C,
const char *member,
bContextDataResult *result,
AssetShelfSettings *shelf_settings)
{
static const char *context_dir[] = {
"asset_shelf_settings",
"active_file", /* XXX yuk... */
nullptr,
};
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, context_dir);
return CTX_RESULT_OK;
}
bScreen *screen = CTX_wm_screen(C);
if (CTX_data_equals(member, "asset_shelf_settings")) {
CTX_data_pointer_set(result, &screen->id, &RNA_AssetShelfSettings, shelf_settings);
return CTX_RESULT_OK;
}
/* XXX hack. Get the asset from the hovered button, but needs to be the file... */
if (CTX_data_equals(member, "active_file")) {
const uiBut *but = UI_context_active_but_get(C);
if (!but) {
return CTX_RESULT_NO_DATA;
}
const bContextStore *but_context = UI_but_context_get(but);
if (!but_context) {
return CTX_RESULT_NO_DATA;
}
const PointerRNA *file_ptr = CTX_store_ptr_lookup(
but_context, "active_file", &RNA_FileSelectEntry);
if (!file_ptr) {
return CTX_RESULT_NO_DATA;
}
CTX_data_pointer_set_ptr(result, file_ptr);
return CTX_RESULT_OK;
}
return CTX_RESULT_MEMBER_NOT_FOUND;
}
static AssetShelfSettings *get_asset_shelf_settings_from_context(const bContext *C)
{
PointerRNA shelf_settings_ptr = CTX_data_pointer_get_type(
C, "asset_shelf_settings", &RNA_AssetShelfSettings);
return static_cast<AssetShelfSettings *>(shelf_settings_ptr.data);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Asset Catalog Selector UI
*
* Popup containing a tree-view to select which catalogs to display in the asset shelf footer.
* \{ */
class AssetCatalogSelectorTree : public ui::AbstractTreeView {
asset_system::AssetLibrary &library_;
asset_system::AssetCatalogTree *catalog_tree_;
AssetShelfSettings &shelf_settings_;
public:
class Item;
AssetCatalogSelectorTree(asset_system::AssetLibrary &library, AssetShelfSettings &shelf_settings)
: library_(library), shelf_settings_(shelf_settings)
{
asset_system::AssetCatalogService *catalog_service = library_.catalog_service.get();
catalog_tree_ = catalog_service->get_catalog_tree();
}
void build_tree() override
{
if (!catalog_tree_) {
return;
}
catalog_tree_->foreach_root_item([this](asset_system::AssetCatalogTreeItem &catalog_item) {
build_catalog_items_recursive(*this, catalog_item);
});
}
Item &build_catalog_items_recursive(ui::TreeViewOrItem &parent_view_item,
asset_system::AssetCatalogTreeItem &catalog_item) const
{
Item &view_item = parent_view_item.add_tree_item<Item>(catalog_item, shelf_settings_);
catalog_item.foreach_child([&view_item, this](asset_system::AssetCatalogTreeItem &child) {
build_catalog_items_recursive(view_item, child);
});
return view_item;
}
void update_shelf_settings_from_enabled_catalogs();
class Item : public ui::BasicTreeViewItem {
asset_system::AssetCatalogTreeItem catalog_item_;
/* Is the catalog path enabled in this redraw? Set on construction, updated by the UI (which
* gets a pointer to it). The UI needs it as char. */
char catalog_path_enabled_ = false;
public:
Item(asset_system::AssetCatalogTreeItem &catalog_item, AssetShelfSettings &shelf_settings)
: ui::BasicTreeViewItem(catalog_item.get_name()),
catalog_item_(catalog_item),
catalog_path_enabled_(asset_shelf_settings_is_catalog_path_enabled(
shelf_settings, catalog_item.catalog_path()))
{
}
bool is_catalog_path_enabled() const
{
return catalog_path_enabled_ != 0;
}
asset_system::AssetCatalogPath catalog_path() const
{
return catalog_item_.catalog_path();
}
void build_row(uiLayout &row) override
{
AssetCatalogSelectorTree &tree = dynamic_cast<AssetCatalogSelectorTree &>(get_tree_view());
uiBlock *block = uiLayoutGetBlock(&row);
uiLayoutSetEmboss(&row, UI_EMBOSS);
if (!is_collapsible()) {
uiItemL(&row, nullptr, ICON_BLANK1);
}
uiBut *but = uiDefButC(block,
UI_BTYPE_CHECKBOX,
0,
catalog_item_.get_name().c_str(),
0,
0,
UI_UNIT_X * 10,
UI_UNIT_Y,
(char *)&catalog_path_enabled_,
0,
0,
0,
0,
TIP_("Toggle catalog visibility in the asset shelf"));
UI_but_func_set(but, [&tree](bContext &C) {
tree.update_shelf_settings_from_enabled_catalogs();
asset_shelf_send_redraw_notifier(C);
});
UI_but_flag_disable(but, UI_BUT_UNDO);
}
};
};
void AssetCatalogSelectorTree::update_shelf_settings_from_enabled_catalogs()
{
asset_shelf_settings_clear_enabled_catalogs(shelf_settings_);
foreach_item([this](ui::AbstractTreeViewItem &view_item) {
const auto &selector_tree_item = dynamic_cast<AssetCatalogSelectorTree::Item &>(view_item);
if (selector_tree_item.is_catalog_path_enabled()) {
asset_shelf_settings_set_catalog_path_enabled(shelf_settings_,
selector_tree_item.catalog_path());
}
});
}
static uiBlock *asset_shelf_catalog_selector_block_draw(bContext *C,
ARegion *region,
void * /*arg1*/)
{
const AssetLibraryReference *library_ref = CTX_wm_asset_library_ref(C);
asset_system::AssetLibrary *library = ED_assetlist_library_get_once_available(*library_ref);
AssetShelfSettings *shelf_settings = get_asset_shelf_settings_from_context(C);
uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
UI_block_flag_enable(block,
UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPUP_CAN_REFRESH);
uiLayout *layout = UI_block_layout(block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
0,
0,
UI_UNIT_X * 12,
UI_UNIT_Y,
0,
UI_style_get());
uiItemL(layout, "Enable Catalogs", ICON_NONE);
uiItemS(layout);
uiLayoutSetEmboss(layout, UI_EMBOSS_NONE);
if (library && shelf_settings) {
ui::AbstractTreeView *tree_view = UI_block_add_view(
*block,
"asset catalog tree view",
std::make_unique<AssetCatalogSelectorTree>(*library, *shelf_settings));
ui::TreeViewBuilder builder(*block);
builder.build_tree_view(*tree_view);
}
UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
UI_block_direction_set(block, UI_DIR_UP);
return block;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Catalog toggle buttons
* \{ */
static void add_catalog_toggle_buttons(AssetShelfSettings &shelf_settings, uiLayout &layout)
{
uiBlock *block = uiLayoutGetBlock(&layout);
const uiStyle *style = UI_style_get_dpi();
asset_shelf_settings_foreach_enabled_catalog_path(
shelf_settings, [&shelf_settings, block, style](const asset_system::AssetCatalogPath &path) {
const char *name = path.name().c_str();
const int string_width = UI_fontstyle_string_width(&style->widget, name);
const int pad_x = UI_UNIT_X * 0.3f;
const int but_width = std::min(string_width + 2 * pad_x, UI_UNIT_X * 8);
uiBut *but = uiDefBut(
block,
UI_BTYPE_TAB,
0,
name,
0,
0,
but_width,
UI_UNIT_Y,
nullptr,
0,
0,
0,
0,
"Enable catalog, making contained assets visible in the asset shelf");
UI_but_drawflag_enable(but, UI_BUT_ALIGN_TOP);
UI_but_func_set(but, [&shelf_settings, path](bContext &C) {
asset_shelf_settings_set_active_catalog(shelf_settings, path);
asset_shelf_send_redraw_notifier(C);
});
UI_but_func_pushed_state_set(but, [&shelf_settings, path](const uiBut &) -> bool {
return asset_shelf_settings_is_active_catalog(shelf_settings, path);
});
});
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Asset Shelf Footer
*
* Implemented as HeaderType for #RGN_TYPE_ASSET_SHELF_FOOTER.
* \{ */
static void asset_shelf_footer_draw(const bContext *C, Header *header)
{
uiLayout *layout = header->layout;
uiBlock *block = uiLayoutGetBlock(layout);
const AssetLibraryReference *library_ref = CTX_wm_asset_library_ref(C);
ED_assetlist_storage_fetch(library_ref, C);
uiDefIconBlockBut(block,
asset_shelf_catalog_selector_block_draw,
nullptr,
0,
ICON_RIGHTARROW,
0,
0,
UI_UNIT_X * 1.5f,
UI_UNIT_Y,
TIP_("Select catalogs to display"));
uiItemS(layout);
AssetShelfSettings *shelf_settings = get_asset_shelf_settings_from_context(C);
if (shelf_settings) {
add_catalog_toggle_buttons(*shelf_settings, *layout);
}
}
void ED_asset_shelf_footer_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_footer_draw;
ht->poll = asset_shelf_region_header_type_poll;
BLI_addtail(&region_type->headertypes, ht);
}
/** \} */

View File

@ -701,6 +701,7 @@ enum {
ED_KEYMAP_FOOTER = (1 << 9),
ED_KEYMAP_GPENCIL = (1 << 10),
ED_KEYMAP_NAVBAR = (1 << 11),
ED_KEYMAP_ASSET_SHELF = (1 << 12),
};
/** #SCREEN_OT_space_context_cycle direction. */

View File

@ -168,6 +168,7 @@ enum {
UI_BLOCK_SEARCH_ONLY = 1 << 25,
/** Hack for quick setup (splash screen) to draw text centered. */
UI_BLOCK_QUICK_SETUP = 1 << 26,
UI_BLOCK_POPUP_CAN_REFRESH = 1 << 27,
};
/** #uiPopupBlockHandle.menuretval */
@ -1755,8 +1756,6 @@ void UI_but_focus_on_enter_event(struct wmWindow *win, uiBut *but);
void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN);
void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, const void *arg);
struct PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
const char *opname,
wmOperatorCallContext opcontext,
@ -2179,6 +2178,7 @@ int uiLayoutGetAlignment(uiLayout *layout);
bool uiLayoutGetFixedSize(uiLayout *layout);
bool uiLayoutGetKeepAspect(uiLayout *layout);
int uiLayoutGetWidth(uiLayout *layout);
int uiLayoutGetRootHeight(uiLayout *layout);
float uiLayoutGetScaleX(uiLayout *layout);
float uiLayoutGetScaleY(uiLayout *layout);
float uiLayoutGetUnitsX(uiLayout *layout);
@ -2616,6 +2616,9 @@ void uiTemplateAssetView(struct uiLayout *layout,
struct PointerRNA *r_activate_op_properties,
const char *drag_opname,
struct PointerRNA *r_drag_op_properties);
void uiTemplateAssetShelf(uiLayout *layout,
const struct bContext *C,
const struct AssetFilterSettings *filter_settings);
/**
* \return: A RNA pointer for the operator properties.

View File

@ -18,10 +18,10 @@ namespace blender::nodes::geo_eval_log {
struct GeometryAttributeInfo;
}
struct PointerRNA;
struct bContext;
struct StructRNA;
struct uiBlock;
struct uiList;
struct uiBut;
struct uiSearchItems;
namespace blender::ui {
@ -110,6 +110,9 @@ void UI_list_filter_and_sort_items(uiList *ui_list,
const char *propname,
uiListItemGetNameFn get_name_fn = nullptr);
void UI_but_func_set(uiBut *but, std::function<void(bContext &)> func);
void UI_but_func_pushed_state_set(uiBut *but, std::function<bool(const uiBut &)> func);
/**
* Override this for all available view types.
*/

View File

@ -64,6 +64,7 @@ set(SRC
interface_region_tooltip.cc
interface_regions.cc
interface_style.cc
interface_template_asset_shelf.cc
interface_template_asset_view.cc
interface_template_attribute_search.cc
interface_template_list.cc

View File

@ -51,6 +51,7 @@
#include "BLT_translation.h"
#include "UI_interface.h"
#include "UI_interface.hh"
#include "UI_interface_icons.h"
#include "UI_view2d.h"
@ -749,6 +750,10 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
if (but->func != oldbut->func) {
return false;
}
if (but->apply_func.target<void(bContext &)>() !=
oldbut->apply_func.target<void(bContext &)>()) {
return false;
}
if (but->funcN != oldbut->funcN) {
return false;
}
@ -2181,7 +2186,7 @@ int ui_but_is_pushed_ex(uiBut *but, double *value)
{
int is_push = 0;
if (but->pushed_state_func) {
return but->pushed_state_func(but, but->pushed_state_arg);
return but->pushed_state_func(*but);
}
if (but->bit) {
@ -6028,6 +6033,11 @@ void UI_but_func_set(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2)
but->func_arg2 = arg2;
}
void UI_but_func_set(uiBut *but, std::function<void(bContext &)> func)
{
but->apply_func = func;
}
void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2)
{
if (but->func_argN) {
@ -6060,10 +6070,9 @@ void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFre
but->tip_arg_free = free_arg;
}
void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, const void *arg)
void UI_but_func_pushed_state_set(uiBut *but, std::function<bool(const uiBut &)> func)
{
but->pushed_state_func = func;
but->pushed_state_arg = arg;
ui_but_update(but);
}

View File

@ -459,45 +459,47 @@ struct uiHandleButtonData {
};
struct uiAfterFunc {
uiAfterFunc *next, *prev;
uiAfterFunc *next = nullptr, *prev = nullptr;
uiButHandleFunc func;
void *func_arg1;
void *func_arg2;
uiButHandleFunc func = nullptr;
void *func_arg1 = nullptr;
void *func_arg2 = nullptr;
/** C++ version of #func above, without need for void pointer arguments. */
std::function<void(bContext &)> apply_func;
uiButHandleNFunc funcN;
void *func_argN;
uiButHandleNFunc funcN = nullptr;
void *func_argN = nullptr;
uiButHandleRenameFunc rename_func;
void *rename_arg1;
void *rename_orig;
uiButHandleRenameFunc rename_func = nullptr;
void *rename_arg1 = nullptr;
void *rename_orig = nullptr;
uiBlockHandleFunc handle_func;
void *handle_func_arg;
int retval;
uiBlockHandleFunc handle_func = nullptr;
void *handle_func_arg = nullptr;
int retval = 0;
uiMenuHandleFunc butm_func;
void *butm_func_arg;
int a2;
uiMenuHandleFunc butm_func = nullptr;
void *butm_func_arg = nullptr;
int a2 = 0;
wmOperator *popup_op;
wmOperatorType *optype;
wmOperator *popup_op = nullptr;
wmOperatorType *optype = nullptr;
wmOperatorCallContext opcontext;
PointerRNA *opptr;
PointerRNA *opptr = nullptr;
PointerRNA rnapoin;
PropertyRNA *rnaprop;
PointerRNA rnapoin = {};
PropertyRNA *rnaprop = nullptr;
void *search_arg;
uiFreeArgFunc search_arg_free_fn;
void *search_arg = nullptr;
uiFreeArgFunc search_arg_free_fn = nullptr;
uiBlockInteraction_CallbackData custom_interaction_callbacks;
uiBlockInteraction_Handle *custom_interaction_handle;
uiBlockInteraction_CallbackData custom_interaction_callbacks = {};
uiBlockInteraction_Handle *custom_interaction_handle = nullptr;
bContextStore *context;
bContextStore *context = nullptr;
char undostr[BKE_UNDO_STR_MAX];
char drawstr[UI_MAX_DRAW_STR];
char undostr[BKE_UNDO_STR_MAX] = "";
char drawstr[UI_MAX_DRAW_STR] = "";
};
static void button_activate_init(bContext *C,
@ -745,7 +747,7 @@ static ListBase UIAfterFuncs = {nullptr, nullptr};
static uiAfterFunc *ui_afterfunc_new()
{
uiAfterFunc *after = MEM_cnew<uiAfterFunc>(__func__);
uiAfterFunc *after = MEM_new<uiAfterFunc>(__func__);
BLI_addtail(&UIAfterFuncs, after);
@ -802,8 +804,9 @@ static void popup_check(bContext *C, wmOperator *op)
*/
static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but)
{
return (but->func || but->funcN || but->rename_func || but->optype || but->rnaprop ||
block->handle_func || (but->type == UI_BTYPE_BUT_MENU && block->butm_func) ||
return (but->func || but->apply_func || but->funcN || but->rename_func || but->optype ||
but->rnaprop || block->handle_func ||
(but->type == UI_BTYPE_BUT_MENU && block->butm_func) ||
(block->handle && block->handle->popup_op));
}
@ -828,10 +831,11 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
else {
after->func = but->func;
}
after->func_arg1 = but->func_arg1;
after->func_arg2 = but->func_arg2;
after->apply_func = but->apply_func;
after->funcN = but->funcN;
after->func_argN = (but->func_argN) ? MEM_dupallocN(but->func_argN) : nullptr;
@ -1000,7 +1004,8 @@ static void ui_apply_but_funcs_after(bContext *C)
LISTBASE_FOREACH_MUTABLE (uiAfterFunc *, afterf, &funcs) {
uiAfterFunc after = *afterf; /* Copy to avoid memory leak on exit(). */
BLI_freelinkN(&funcs, afterf);
BLI_remlink(&funcs, afterf);
MEM_delete(afterf);
if (after.context) {
CTX_store_set(C, after.context);
@ -1042,6 +1047,9 @@ static void ui_apply_but_funcs_after(bContext *C)
if (after.func) {
after.func(C, after.func_arg1, after.func_arg2);
}
if (after.apply_func) {
after.apply_func(*C);
}
if (after.funcN) {
after.funcN(C, after.func_argN, after.func_arg2);
}
@ -2089,7 +2097,8 @@ static bool ui_but_drag_init(bContext *C,
RGN_TYPE_NAV_BAR,
RGN_TYPE_HEADER,
RGN_TYPE_TOOL_HEADER,
RGN_TYPE_FOOTER)) {
RGN_TYPE_FOOTER,
RGN_TYPE_ASSET_SHELF_FOOTER)) {
const int region_alignment = RGN_ALIGN_ENUM_FROM_MASK(data->region->alignment);
int lock_axis = -1;

View File

@ -7,6 +7,8 @@
#pragma once
#include <functional>
#include "BLI_compiler_attrs.h"
#include "BLI_rect.h"
#include "BLI_vector.hh"
@ -190,6 +192,9 @@ struct uiBut {
uiButHandleFunc func = nullptr;
void *func_arg1 = nullptr;
void *func_arg2 = nullptr;
/** C++ version of #func above. Allows storing arbitrary data in a type safe way, no void
* pointer arguments.*/
std::function<void(bContext &)> apply_func;
uiButHandleNFunc funcN = nullptr;
void *func_argN = nullptr;
@ -266,8 +271,7 @@ struct uiBut {
double *editval = nullptr;
float *editvec = nullptr;
uiButPushedStateFunc pushed_state_func = nullptr;
const void *pushed_state_arg = nullptr;
std::function<bool(const uiBut &)> pushed_state_func;
/** Little indicator (e.g., counter) displayed on top of some icons. */
IconTextOverlay icon_overlay_text = {};

View File

@ -4087,7 +4087,7 @@ static void ui_litem_layout_box(uiLayout *litem)
const uiStyle *style = litem->root->style;
int boxspace = style->boxspace;
if (litem->root->type == UI_LAYOUT_HEADER) {
if (litem->root->type == UI_LAYOUT_HEADER && false) {
boxspace = 0;
}
@ -5114,6 +5114,11 @@ int uiLayoutGetWidth(uiLayout *layout)
return layout->w;
}
int uiLayoutGetRootHeight(uiLayout *layout)
{
return layout->root->layout->h;
}
float uiLayoutGetScaleX(uiLayout *layout)
{
return layout->scale[0];

View File

@ -593,6 +593,11 @@ uiBlock *ui_popup_block_refresh(bContext *C,
block->flag |= UI_BLOCK_LOOP;
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
/* TODO does this flag need to be checked in more cases? */
if (block->flag & UI_BLOCK_POPUP_CAN_REFRESH) {
handle->can_refresh = true;
}
/* defer this until blocks are translated (below) */
block->oldblock = nullptr;

View File

@ -0,0 +1,188 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edinterface
*/
#include "AS_asset_library.hh"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "ED_asset.h"
#include "RNA_access.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "interface_intern.hh"
#include "RNA_prototypes.h"
using namespace blender;
/* TODO copy of #asset_view_item_but_drag_set(). */
static void asset_tile_but_drag_set(uiBut &but, AssetHandle &asset_handle)
{
ID *id = ED_asset_handle_get_local_id(&asset_handle);
if (id != nullptr) {
UI_but_drag_set_id(&but, id);
return;
}
char blend_path[FILE_MAX_LIBEXTRA];
/* Context can be null here, it's only needed for a File Browser specific hack that should go
* away before too long. */
ED_asset_handle_get_full_library_path(&asset_handle, blend_path);
if (blend_path[0]) {
ImBuf *imbuf = ED_assetlist_asset_image_get(&asset_handle);
UI_but_drag_set_asset(&but,
&asset_handle,
BLI_strdup(blend_path),
FILE_ASSET_IMPORT_APPEND,
ED_asset_handle_get_preview_icon_id(&asset_handle),
imbuf,
1.0f);
}
}
static void asset_tile_draw(uiLayout &layout,
AssetHandle &asset_handle,
const int width,
const int height,
const bool show_names)
{
PointerRNA file_ptr;
RNA_pointer_create(
nullptr,
&RNA_FileSelectEntry,
/* XXX passing file pointer here, should be asset handle or asset representation. */
const_cast<FileDirEntry *>(asset_handle.file_data),
&file_ptr);
uiLayoutSetContextPointer(&layout, "active_file", &file_ptr);
uiBlock *block = uiLayoutGetBlock(&layout);
const StringRefNull name = ED_asset_handle_get_name(&asset_handle);
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_PREVIEW_TILE,
0,
ED_asset_handle_get_preview_icon_id(&asset_handle),
show_names ? name.c_str() : "",
0,
0,
width,
height,
nullptr,
0,
0,
0,
0,
name.c_str());
ui_def_but_icon(but,
ED_asset_handle_get_preview_icon_id(&asset_handle),
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
asset_tile_but_drag_set(*but, asset_handle);
}
static std::optional<asset_system::AssetCatalogFilter> catalog_filter_from_shelf_settings(
const AssetShelfSettings *shelf_settings, const asset_system::AssetLibrary *library)
{
if (!shelf_settings || !shelf_settings->active_catalog_path) {
return {};
}
asset_system ::AssetCatalog *active_catalog = library->catalog_service->find_catalog_by_path(
shelf_settings->active_catalog_path);
if (!active_catalog) {
return {};
}
return library->catalog_service->create_catalog_filter(active_catalog->catalog_id);
}
/* TODO calling a (.py defined) callback for every asset isn't exactly great. Should be a temporary
* solution until there is proper filtering by asset traits. */
/**
* Returns true if the asset should be visible. That is, if any of the visible asset shelves has no
* poll function (all assets should be displayed), or its #AssetShelfType.asset_poll function
* returns true.
*/
static bool asset_shelf_asset_poll(const SpaceType &space_type,
const bContext &C,
const AssetHandle &asset)
{
LISTBASE_FOREACH (AssetShelfType *, shelf_type, &space_type.asset_shelf_types) {
if (!shelf_type->poll || !shelf_type->poll(&C, shelf_type)) {
continue;
}
if (!shelf_type->asset_poll || shelf_type->asset_poll(shelf_type, &asset)) {
return true;
}
}
return false;
}
void uiTemplateAssetShelf(uiLayout *layout,
const bContext *C,
const AssetFilterSettings *filter_settings)
{
const AssetLibraryReference *library_ref = CTX_wm_asset_library_ref(C);
const PointerRNA shelf_settings_ptr = CTX_data_pointer_get_type(
C, "asset_shelf_settings", &RNA_AssetShelfSettings);
const AssetShelfSettings *shelf_settings = static_cast<AssetShelfSettings *>(
shelf_settings_ptr.data);
Vector<decltype(AssetShelfType::asset_poll)> asset_polls;
ED_assetlist_storage_fetch(library_ref, C);
ED_assetlist_ensure_previews_job(library_ref, C);
const asset_system::AssetLibrary *library = ED_assetlist_library_get_once_available(
*library_ref);
if (!library) {
return;
}
std::optional<asset_system::AssetCatalogFilter> catalog_filter =
catalog_filter_from_shelf_settings(shelf_settings, library);
uiLayoutSetScaleX(layout, 1.0f);
uiLayoutSetScaleY(layout, 1.0f);
const bool show_names = true;
const int height = uiLayoutGetRootHeight(layout) - UI_style_get_dpi()->boxspace * 2;
/* Width is derived from the height. It's the height without the space for the name (if there is
* any). */
const int width = height - (show_names ? 0 : UI_UNIT_Y);
uiLayout *box = uiLayoutBox(layout);
uiLayout *row = uiLayoutRow(box, false);
const SpaceLink *space_link = CTX_wm_space_data(C);
const SpaceType *space_type = BKE_spacetype_from_id(space_link->spacetype);
ED_assetlist_iterate(*library_ref, [&](AssetHandle asset) {
if (!asset_shelf_asset_poll(*space_type, *C, asset)) {
return true;
}
if (!ED_asset_filter_matches_asset(filter_settings, &asset)) {
/* Don't do anything else, but return true to continue iterating. */
return true;
}
/* Filter by active catalog. */
const AssetMetaData *asset_data = ED_asset_handle_get_metadata(&asset);
if (catalog_filter && !catalog_filter->contains(asset_data->catalog_id)) {
return true;
}
asset_tile_draw(*row, asset, width, height, show_names);
return true;
});
}

View File

@ -146,7 +146,6 @@ static void asset_view_filter_items(uiList *ui_list,
static void asset_view_listener(uiList *ui_list, wmRegionListenerParams *params)
{
AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata;
const wmNotifier *notifier = params->notifier;
switch (notifier->category) {
@ -158,7 +157,7 @@ static void asset_view_listener(uiList *ui_list, wmRegionListenerParams *params)
}
}
if (ED_assetlist_listen(&list_data->asset_library_ref, params->notifier)) {
if (ED_assetlist_listen(params->notifier)) {
ED_region_tag_redraw(params->region);
}
}

View File

@ -153,7 +153,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
else if (g_theme_state.regionid == RGN_TYPE_CHANNELS) {
cp = ts->list;
}
else if (ELEM(g_theme_state.regionid, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
else if (ELEM(g_theme_state.regionid,
RGN_TYPE_HEADER,
RGN_TYPE_FOOTER,
RGN_TYPE_ASSET_SHELF_FOOTER)) {
cp = ts->header;
}
else if (g_theme_state.regionid == RGN_TYPE_NAV_BAR) {
@ -187,7 +190,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
else if (g_theme_state.regionid == RGN_TYPE_CHANNELS) {
cp = ts->list_text;
}
else if (ELEM(g_theme_state.regionid, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
else if (ELEM(g_theme_state.regionid,
RGN_TYPE_HEADER,
RGN_TYPE_FOOTER,
RGN_TYPE_ASSET_SHELF_FOOTER)) {
cp = ts->header_text;
}
else {
@ -201,7 +207,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
else if (g_theme_state.regionid == RGN_TYPE_CHANNELS) {
cp = ts->list_text_hi;
}
else if (ELEM(g_theme_state.regionid, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
else if (ELEM(g_theme_state.regionid,
RGN_TYPE_HEADER,
RGN_TYPE_FOOTER,
RGN_TYPE_ASSET_SHELF_FOOTER)) {
cp = ts->header_text_hi;
}
else {
@ -215,7 +224,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
else if (g_theme_state.regionid == RGN_TYPE_CHANNELS) {
cp = ts->list_title;
}
else if (ELEM(g_theme_state.regionid, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
else if (ELEM(g_theme_state.regionid,
RGN_TYPE_HEADER,
RGN_TYPE_FOOTER,
RGN_TYPE_ASSET_SHELF_FOOTER)) {
cp = ts->header_title;
}
else {

View File

@ -167,7 +167,7 @@ void AbstractTreeViewItem::collapse_chevron_click_fn(struct bContext *C,
* lookup the hovered item via context here. */
const wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C);
const ARegion *region = CTX_wm_menu(C) ? CTX_wm_menu(C) : CTX_wm_region(C);
uiViewItemHandle *hovered_item_handle = UI_region_views_find_item_at(region,
win->eventstate->xy);

View File

@ -2,6 +2,7 @@
set(INC
../include
../../asset_system
../../blenfont
../../blenkernel
../../blenlib

View File

@ -33,6 +33,7 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
#include "ED_asset.h"
#include "ED_buttons.h"
#include "ED_screen.h"
#include "ED_screen_types.h"
@ -931,9 +932,14 @@ static void fullscreen_azone_init(ScrArea *area, ARegion *region)
#define AZONEPAD_ICON (0.45f * U.widget_unit)
static void region_azone_edge(AZone *az, ARegion *region)
{
/* If region is overlapped (transparent background), move #AZone to content.
* Note this is an arbitrary amount that matches nicely with numbers elsewhere. */
int overlap_padding = (region->overlap) ? int(0.4f * U.widget_unit) : 0;
/* If there is no visible region background, users typically expect the #AZone to be closer to
* the content, so move it a bit. Headers-like regions are usually thin and there's not much
* padding around them, so don't touch the #AZone there (also avoids mouse hover conflicts with
* actual contents).
* Note that this is an arbitrary amount that matches nicely with numbers elsewhere. */
const int overlap_padding = (region->overlap && !RGN_TYPE_IS_HEADER_ANY(region->regiontype)) ?
int(0.4f * U.widget_unit) :
0;
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
@ -1243,7 +1249,9 @@ bool ED_region_is_overlap(int spacetype, int regiontype)
RGN_TYPE_UI,
RGN_TYPE_TOOL_PROPS,
RGN_TYPE_FOOTER,
RGN_TYPE_TOOL_HEADER)) {
RGN_TYPE_TOOL_HEADER,
RGN_TYPE_ASSET_SHELF,
RGN_TYPE_ASSET_SHELF_FOOTER)) {
return true;
}
}
@ -1318,6 +1326,9 @@ static void region_rect_recursive(
else if (region->regiontype == RGN_TYPE_FOOTER) {
prefsizey = ED_area_footersize();
}
else if (region->regiontype == RGN_TYPE_ASSET_SHELF_FOOTER) {
prefsizey = ED_area_footersize();
}
else if (ED_area_is_global(area)) {
prefsizey = ED_region_global_size_y();
}
@ -1728,6 +1739,11 @@ static void ed_default_handlers(
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Region Context Menu", 0, 0);
WM_event_add_keymap_handler(&region->handlers, keymap);
}
if (flag & ED_KEYMAP_ASSET_SHELF) {
/* standard keymap for asset shelf regions */
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Asset Shelf", 0, 0);
WM_event_add_keymap_handler(&region->handlers, keymap);
}
/* Keep last because of LMB/RMB handling, see: #57527. */
if (flag & ED_KEYMAP_GPENCIL) {
@ -3289,12 +3305,15 @@ void ED_region_header_layout(const bContext *C, ARegion *region)
bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE;
/* Height of buttons and scaling needed to achieve it. */
const int buttony = min_ii(UI_UNIT_Y, region->winy - 2 * UI_SCALE_FAC);
const bool is_fixed_header_height = region->type->prefsizey == HEADERY;
const int buttony = is_fixed_header_height ? UI_UNIT_Y :
region->winy - 2 * UI_SCALE_FAC - UI_HEADER_OFFSET;
const float buttony_scale = buttony / float(UI_UNIT_Y);
/* Vertically center buttons. */
int xco = UI_HEADER_OFFSET;
int yco = buttony + (region->winy - buttony) / 2;
int yco = is_fixed_header_height ? buttony + (region->winy - buttony) / 2 :
buttony + UI_HEADER_OFFSET / 2;
int maxco = xco;
/* XXX workaround for 1 px alignment issue. Not sure what causes it...
@ -3399,7 +3418,6 @@ void ED_region_header_init(ARegion *region)
{
UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_HEADER, region->winx, region->winy);
}
int ED_area_headersize(void)
{
/* Accommodate widget and padding. */

View File

@ -1435,7 +1435,9 @@ static bScreen *screen_state_to_nonnormal(bContext *C,
RGN_TYPE_FOOTER,
RGN_TYPE_TOOLS,
RGN_TYPE_NAV_BAR,
RGN_TYPE_EXECUTE)) {
RGN_TYPE_EXECUTE,
RGN_TYPE_ASSET_SHELF,
RGN_TYPE_ASSET_SHELF_FOOTER)) {
region->flag |= RGN_FLAG_HIDDEN;
}
}

View File

@ -2625,15 +2625,19 @@ static int area_max_regionsize(ScrArea *area, ARegion *scale_region, AZEdge edge
dist -= region->winx;
}
else if (scale_region->alignment == RGN_ALIGN_TOP &&
(region->alignment == RGN_ALIGN_BOTTOM ||
ELEM(
region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER))) {
(region->alignment == RGN_ALIGN_BOTTOM || ELEM(region->regiontype,
RGN_TYPE_HEADER,
RGN_TYPE_TOOL_HEADER,
RGN_TYPE_FOOTER,
RGN_TYPE_ASSET_SHELF_FOOTER))) {
dist -= region->winy;
}
else if (scale_region->alignment == RGN_ALIGN_BOTTOM &&
(region->alignment == RGN_ALIGN_TOP ||
ELEM(
region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER))) {
(region->alignment == RGN_ALIGN_TOP || ELEM(region->regiontype,
RGN_TYPE_HEADER,
RGN_TYPE_TOOL_HEADER,
RGN_TYPE_FOOTER,
RGN_TYPE_ASSET_SHELF_FOOTER))) {
dist -= region->winy;
}
}

View File

@ -864,6 +864,7 @@ static bool is_filtered_lib_type(FileListInternEntry *file,
if (file->typeflag & FILE_TYPE_BLENDERLIB) {
return is_filtered_id_file_type(file, file->blentype, file->name, filter);
}
return is_filtered_file_type(file, filter);
}

View File

@ -2,6 +2,7 @@
set(INC
../include
../asset
../../blenfont
../../blenkernel
../../blenlib

View File

@ -48,6 +48,7 @@
#include "BKE_viewer_path.h"
#include "BKE_workspace.h"
#include "ED_asset_shelf.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_render.h"
@ -290,6 +291,21 @@ static SpaceLink *view3d_create(const ScrArea * /*area*/, const Scene *scene)
region->alignment = RGN_ALIGN_RIGHT;
region->flag = RGN_FLAG_HIDDEN;
/* asset shelf footer */
region = MEM_cnew<ARegion>("asset shelf footer for view3d");
BLI_addtail(&v3d->regionbase, region);
region->regiontype = RGN_TYPE_ASSET_SHELF_FOOTER;
region->alignment = RGN_ALIGN_BOTTOM;
region->flag = RGN_FLAG_HIDDEN;
/* asset shelf */
region = MEM_cnew<ARegion>("asset shelf for view3d");
BLI_addtail(&v3d->regionbase, region);
region->regiontype = RGN_TYPE_ASSET_SHELF;
region->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
region->flag |= RGN_FLAG_DYNAMIC_SIZE;
/* main region */
region = MEM_cnew<ARegion>("main region for view3d");
@ -327,11 +343,21 @@ static void view3d_free(SpaceLink *sl)
}
BKE_viewer_path_clear(&vd->viewer_path);
if (vd->asset_shelf) {
ED_asset_shelf_settings_free(vd->asset_shelf);
MEM_SAFE_FREE(vd->asset_shelf);
}
}
/* spacetype; init callback */
static void view3d_init(wmWindowManager * /*wm*/, ScrArea * /*area*/)
static void view3d_init(wmWindowManager * /*wm*/, ScrArea *area)
{
BLI_assert(area->spacetype == SPACE_VIEW3D);
View3D *v3d = static_cast<View3D *>(area->spacedata.first);
if (!v3d->asset_shelf) {
v3d->asset_shelf = MEM_cnew<AssetShelfSettings>("AssetShelfSettings");
}
}
static void view3d_exit(wmWindowManager * /*wm*/, ScrArea *area)
@ -367,6 +393,8 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
BKE_viewer_path_copy(&v3dn->viewer_path, &v3do->viewer_path);
v3dn->asset_shelf = ED_asset_shelf_settings_duplicate(v3do->asset_shelf);
/* copy or clear inside new stuff */
return (SpaceLink *)v3dn;
@ -2003,6 +2031,14 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
return CTX_RESULT_MEMBER_NOT_FOUND;
}
static int view3d_asset_shelf_context(const bContext *C,
const char *member,
bContextDataResult *result)
{
View3D *v3d = CTX_wm_view3d(C);
return ED_asset_shelf_context(C, member, result, v3d->asset_shelf);
}
static void view3d_id_remap_v3d_ob_centers(View3D *v3d, const struct IDRemapper *mappings)
{
if (BKE_id_remapper_apply(mappings, (ID **)&v3d->ob_center, ID_REMAP_APPLY_DEFAULT) ==
@ -2078,6 +2114,8 @@ static void view3d_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
BKE_screen_view3d_do_versions_250(v3d, &sl->regionbase);
BKE_viewer_path_blend_read_data(reader, &v3d->viewer_path);
ED_asset_shelf_settings_blend_read_data(reader, &v3d->asset_shelf);
}
static void view3d_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
@ -2106,6 +2144,8 @@ static void view3d_blend_write(BlendWriter *writer, SpaceLink *sl)
BKE_screen_view3d_shading_blend_write(writer, &v3d->shading);
BKE_viewer_path_blend_write(writer, &v3d->viewer_path);
ED_asset_shelf_settings_blend_write(writer, v3d->asset_shelf);
}
void ED_spacetype_view3d()
@ -2197,6 +2237,31 @@ void ED_spacetype_view3d()
art->draw = view3d_header_region_draw;
BLI_addhead(&st->regiontypes, art);
/* regions: asset shelf */
art = MEM_cnew<ARegionType>("spacetype view3d asset shelf region");
art->regionid = RGN_TYPE_ASSET_SHELF;
art->prefsizey = HEADERY * 3.5f;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_ASSET_SHELF | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES |
ED_KEYMAP_HEADER;
art->listener = ED_asset_shelf_region_listen;
art->context = view3d_asset_shelf_context;
art->init = view3d_header_region_init;
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;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_ASSET_SHELF | ED_KEYMAP_VIEW2D | ED_KEYMAP_FOOTER;
art->init = ED_asset_shelf_footer_region_init;
art->draw = ED_asset_shelf_footer_region;
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_footer", SPACE_VIEW3D);
/* regions: hud */
art = ED_area_type_hud(st->spaceid);
BLI_addhead(&st->regiontypes, art);

View File

@ -20,7 +20,7 @@
#define _DNA_DEFAULT_AssetLibraryReference \
{ \
.type = ASSET_LIBRARY_LOCAL, \
.type = ASSET_LIBRARY_ALL, \
/* Not needed really (should be ignored for anything but #ASSET_LIBRARY_CUSTOM), but helps debugging. */ \
.custom_library_index = -1, \
}

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. */
@ -661,8 +668,10 @@ typedef enum eRegion_Type {
/* Region type used exclusively by internal code and add-ons to register draw callbacks to the XR
* context (surface, mirror view). Does not represent any real region. */
RGN_TYPE_XR = 13,
RGN_TYPE_ASSET_SHELF = 14,
RGN_TYPE_ASSET_SHELF_FOOTER = 15,
#define RGN_TYPE_NUM (RGN_TYPE_XR + 1)
#define RGN_TYPE_NUM (RGN_TYPE_ASSET_SHELF_FOOTER + 1)
} eRegion_Type;
/* use for function args */
@ -673,8 +682,8 @@ typedef enum eRegion_Type {
/* Check for any kind of header region. */
#define RGN_TYPE_IS_HEADER_ANY(regiontype) \
(((1 << (regiontype)) & \
((1 << RGN_TYPE_HEADER) | 1 << (RGN_TYPE_TOOL_HEADER) | (1 << RGN_TYPE_FOOTER))) != 0)
(((1 << (regiontype)) & ((1 << RGN_TYPE_HEADER) | 1 << (RGN_TYPE_TOOL_HEADER) | \
(1 << RGN_TYPE_FOOTER) | (1 << RGN_TYPE_ASSET_SHELF_FOOTER))) != 0)
/** #ARegion.alignment */
enum {
@ -748,6 +757,12 @@ enum {
RGN_DRAW_EDITOR_OVERLAYS = 32,
};
typedef struct AssetShelfSettings {
/* TODO make this per mode? (or use a custom identifier?) */
ListBase enabled_catalog_paths; /* #LinkData */
const char *active_catalog_path;
} AssetShelfSettings;
#ifdef __cplusplus
}
#endif

View File

@ -360,6 +360,8 @@ typedef struct View3D {
/** Path to the viewer node that is currently previewed. This is retrieved from the workspace. */
ViewerPath viewer_path;
struct AssetShelfSettings *asset_shelf;
/** Runtime evaluation data (keep last). */
View3D_Runtime runtime;
} View3D;

View File

@ -26,6 +26,8 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
{RGN_TYPE_UI, "UI", 0, "UI", ""},
{RGN_TYPE_TOOLS, "TOOLS", 0, "Tools", ""},
{RGN_TYPE_TOOL_PROPS, "TOOL_PROPS", 0, "Tool Properties", ""},
{RGN_TYPE_ASSET_SHELF, "ASSET_SHELF", 0, "Asset Shelf", ""},
{RGN_TYPE_ASSET_SHELF_FOOTER, "ASSET_SHELF_FOOTER", 0, "Asset Shelf Footer", ""},
{RGN_TYPE_PREVIEW, "PREVIEW", 0, "Preview", ""},
{RGN_TYPE_HUD, "HUD", 0, "Floating Region", ""},
{RGN_TYPE_NAV_BAR, "NAVIGATION_BAR", 0, "Navigation Bar", ""},

View File

@ -1068,6 +1068,156 @@ 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_asset_poll(const AssetShelfType *shelf_type, const AssetHandle *asset)
{
extern FunctionRNA rna_AssetShelf_asset_poll___func;
PointerRNA ptr;
RNA_pointer_create(NULL, shelf_type->rna_ext.srna, NULL, &ptr); /* dummy */
FunctionRNA *func = &rna_AssetShelf_asset_poll___func;
ParameterList list;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "asset_handle", &asset);
shelf_type->rna_ext.call(NULL, &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 bool asset_shelf_poll(const bContext *C, const 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[2];
/* 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;
shelf_type->asset_poll = have_function[1] ? asset_shelf_asset_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);
@ -1880,6 +2030,67 @@ 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);
func = RNA_def_function(srna, "asset_poll__", NULL);
RNA_def_function_ui_description(
func,
"TEMPORARY DESIGN; Expect compatibility breakage. Determine if an asset should be visible "
"in the asset shelf. 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, "asset_handle", "AssetHandle", "", "");
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);
RNA_def_struct_ui_text(srna, "Asset Shelf Settings", "");
}
void RNA_def_ui(BlenderRNA *brna)
{
rna_def_ui_layout(brna);
@ -1887,6 +2098,8 @@ 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);
}
#endif /* RNA_RUNTIME */

View File

@ -485,6 +485,7 @@ typedef struct wmNotifier {
#define ND_SPACE_CLIP (20 << 16)
#define ND_SPACE_FILE_PREVIEW (21 << 16)
#define ND_SPACE_SPREADSHEET (22 << 16)
#define ND_SPACE_ASSET_SHELF (23 << 16)
/* NC_ASSET */
/* Denotes that the AssetList is done reading some previews. NOT that the preview generation of

View File

@ -6116,6 +6116,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
RGN_TYPE_HEADER,
RGN_TYPE_TOOL_HEADER,
RGN_TYPE_FOOTER,
RGN_TYPE_ASSET_SHELF_FOOTER,
RGN_TYPE_TEMPORARY,
RGN_TYPE_HUD)) {
return;