WIP: Basic support for registering asset shelf as a type in BPY #104991
|
@ -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]) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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. */
|
||||
|
|
|
@ -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 ¬ifier) const;
|
||||
static bool listen(const wmNotifier ¬ifier);
|
||||
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 ¬ifier) const
|
||||
bool AssetList::listen(const wmNotifier ¬ifier)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -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(®ion_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(®ion_type->headertypes, ht);
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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. */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
set(INC
|
||||
../include
|
||||
../../asset_system
|
||||
../../blenfont
|
||||
../../blenkernel
|
||||
../../blenlib
|
||||
|
|
|
@ -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(®ion->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(®ion->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(®ion->v2d, V2D_COMMONVIEW_HEADER, region->winx, region->winy);
|
||||
}
|
||||
|
||||
int ED_area_headersize(void)
|
||||
{
|
||||
/* Accommodate widget and padding. */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
set(INC
|
||||
../include
|
||||
../asset
|
||||
../../blenfont
|
||||
../../blenkernel
|
||||
../../blenlib
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, \
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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", ""},
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue