WIP: Brush assets project #106303
|
@ -235,9 +235,18 @@ class _draw_tool_settings_context_mode:
|
|||
return False
|
||||
|
||||
paint = context.tool_settings.sculpt
|
||||
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
|
||||
|
||||
brush = paint.brush
|
||||
|
||||
brush_name = brush.name if brush else None
|
||||
preview_icon_id = brush.preview.icon_id if brush and brush.preview else 0
|
||||
fallback_icon = 'BRUSH_DATA' if not preview_icon_id else 'NONE'
|
||||
layout.template_asset_shelf_popover(
|
||||
BrushAssetShelf.get_shelf_name_from_mode(context.object.mode),
|
||||
name=brush_name,
|
||||
icon=fallback_icon,
|
||||
icon_value=preview_icon_id,
|
||||
)
|
||||
|
||||
if brush is None:
|
||||
return False
|
||||
|
||||
|
@ -9023,6 +9032,23 @@ class BrushAssetShelf:
|
|||
# also activates the item.
|
||||
layout.menu_contents("VIEW3D_MT_brush_context_menu")
|
||||
|
||||
# Not nice, but needed unfortunately.
|
||||
@staticmethod
|
||||
def get_shelf_name_from_mode(obmode):
|
||||
mode_map = {
|
||||
'SCULPT': "VIEW3D_AST_brush_sculpt",
|
||||
'SCULPT_CURVES': "VIEW3D_AST_brush_sculpt_curves",
|
||||
'VERTEX_PAINT': "VIEW3D_AST_brush_vertex_paint",
|
||||
'WEIGHT_PAINT': "VIEW3D_AST_brush_weight_paint",
|
||||
'TEXTURE_PAINT': "VIEW3D_AST_brush_texture_paint",
|
||||
'PAINT_GPENCIL': "VIEW3D_AST_brush_gpencil_paint",
|
||||
'PAINT_GREASE_PENCIL': "VIEW3D_AST_brush_grease_pencil_paint",
|
||||
'SCULPT_GPENCIL': "VIEW3D_AST_brush_gpencil_sculpt",
|
||||
'VERTEX_GPENCIL': "VIEW3D_AST_brush_gpencil_vertex",
|
||||
'WEIGHT_GPENCIL': "VIEW3D_AST_brush_gpencil_weight",
|
||||
}
|
||||
return mode_map[obmode]
|
||||
|
||||
|
||||
class View3DAssetShelf(BrushAssetShelf):
|
||||
bl_space_type = "VIEW_3D"
|
||||
|
|
|
@ -34,6 +34,7 @@ set(SRC
|
|||
intern/asset_shelf.cc
|
||||
intern/asset_shelf_asset_view.cc
|
||||
intern/asset_shelf_catalog_selector.cc
|
||||
intern/asset_shelf_popup.cc
|
||||
intern/asset_shelf_regiondata.cc
|
||||
intern/asset_shelf_settings.cc
|
||||
intern/asset_temp_id_consumer.cc
|
||||
|
|
|
@ -17,9 +17,16 @@ struct bContextDataResult;
|
|||
struct BlendDataReader;
|
||||
struct BlendWriter;
|
||||
struct Main;
|
||||
struct SpaceType;
|
||||
struct uiBlock;
|
||||
struct RegionPollParams;
|
||||
struct wmWindowManager;
|
||||
|
||||
namespace blender {
|
||||
class StringRef;
|
||||
class StringRefNull;
|
||||
} // namespace blender
|
||||
|
||||
namespace blender::ed::asset::shelf {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -58,6 +65,22 @@ void header_regiontype_register(ARegionType *region_type, const int space_type);
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Asset shelf type */
|
||||
|
||||
bool type_poll(const bContext &C, const SpaceType &space_type, const AssetShelfType *shelf_type);
|
||||
AssetShelfType *type_find_from_idname(const SpaceType &space_type, StringRefNull idname);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Asset shelf popup */
|
||||
|
||||
uiBlock *popup_block_create(const bContext *C, ARegion *region, AssetShelfType *shelf_type);
|
||||
void type_popup_unlink(const AssetShelfType &shelf_type);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
void type_unlink(const Main &bmain, const AssetShelfType &shelf_type);
|
||||
|
|
|
@ -52,9 +52,7 @@ void send_redraw_notifier(const bContext &C)
|
|||
/** \name Shelf Type
|
||||
* \{ */
|
||||
|
||||
static bool asset_shelf_type_poll(const bContext &C,
|
||||
const SpaceType &space_type,
|
||||
const AssetShelfType *shelf_type)
|
||||
bool type_poll(const bContext &C, const SpaceType &space_type, const AssetShelfType *shelf_type)
|
||||
{
|
||||
if (!shelf_type) {
|
||||
return false;
|
||||
|
@ -71,7 +69,17 @@ static bool asset_shelf_type_poll(const bContext &C,
|
|||
return !shelf_type->poll || shelf_type->poll(&C, shelf_type);
|
||||
}
|
||||
|
||||
static AssetShelfType *asset_shelf_type_ensure(const SpaceType &space_type, AssetShelf &shelf)
|
||||
AssetShelfType *type_find_from_idname(const SpaceType &space_type, StringRefNull idname)
|
||||
{
|
||||
for (const std::unique_ptr<AssetShelfType> &shelf_type : space_type.asset_shelf_types) {
|
||||
if (idname == shelf_type->idname) {
|
||||
return shelf_type.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AssetShelfType *type_ensure(const SpaceType &space_type, AssetShelf &shelf)
|
||||
{
|
||||
if (shelf.type) {
|
||||
return shelf.type;
|
||||
|
@ -87,7 +95,7 @@ static AssetShelfType *asset_shelf_type_ensure(const SpaceType &space_type, Asse
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static AssetShelf *create_shelf_from_type(AssetShelfType &type)
|
||||
AssetShelf *create_shelf_from_type(AssetShelfType &type)
|
||||
{
|
||||
AssetShelf *shelf = MEM_new<AssetShelf>(__func__);
|
||||
*shelf = dna::shallow_zero_initialize();
|
||||
|
@ -149,8 +157,7 @@ static AssetShelf *update_active_shelf(const bContext &C,
|
|||
|
||||
/* Case 1: */
|
||||
if (shelf_regiondata.active_shelf &&
|
||||
asset_shelf_type_poll(
|
||||
C, space_type, asset_shelf_type_ensure(space_type, *shelf_regiondata.active_shelf)))
|
||||
type_poll(C, space_type, type_ensure(space_type, *shelf_regiondata.active_shelf)))
|
||||
{
|
||||
/* Not a strong precondition, but if this is wrong something weird might be going on. */
|
||||
BLI_assert(shelf_regiondata.active_shelf == shelf_regiondata.shelves.first);
|
||||
|
@ -164,7 +171,7 @@ static AssetShelf *update_active_shelf(const bContext &C,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (asset_shelf_type_poll(C, space_type, asset_shelf_type_ensure(space_type, *shelf))) {
|
||||
if (type_poll(C, space_type, type_ensure(space_type, *shelf))) {
|
||||
/* Found a valid previously activated shelf, reactivate it. */
|
||||
activate_shelf(shelf_regiondata, *shelf);
|
||||
return shelf;
|
||||
|
@ -173,7 +180,7 @@ static AssetShelf *update_active_shelf(const bContext &C,
|
|||
|
||||
/* Case 3: */
|
||||
for (const std::unique_ptr<AssetShelfType> &shelf_type : space_type.asset_shelf_types) {
|
||||
if (asset_shelf_type_poll(C, space_type, shelf_type.get())) {
|
||||
if (type_poll(C, space_type, shelf_type.get())) {
|
||||
AssetShelf *new_shelf = create_shelf_from_type(*shelf_type);
|
||||
BLI_addhead(&shelf_regiondata.shelves, new_shelf);
|
||||
/* Moves ownership to the regiondata. */
|
||||
|
@ -224,7 +231,7 @@ static bool asset_shelf_space_poll(const bContext *C, const SpaceLink *space_lin
|
|||
|
||||
/* Is there any asset shelf type registered that returns true for it's poll? */
|
||||
for (const std::unique_ptr<AssetShelfType> &shelf_type : space_type->asset_shelf_types) {
|
||||
if (asset_shelf_type_poll(*C, *space_type, shelf_type.get())) {
|
||||
if (type_poll(*C, *space_type, shelf_type.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -483,19 +490,13 @@ void region_draw(const bContext *C, ARegion *region)
|
|||
|
||||
void region_on_poll_success(const bContext *C, ARegion *region)
|
||||
{
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
|
||||
BLI_assert(region->regiontype == RGN_TYPE_ASSET_SHELF);
|
||||
if (!region->regiondata) {
|
||||
region->regiondata = MEM_cnew<RegionAssetShelf>("RegionAssetShelf");
|
||||
}
|
||||
|
||||
RegionAssetShelf *shelf_regiondata = RegionAssetShelf::get_from_asset_shelf_region(*region);
|
||||
RegionAssetShelf *shelf_regiondata = RegionAssetShelf::ensure_from_asset_shelf_region(*region);
|
||||
if (!shelf_regiondata) {
|
||||
BLI_assert_unreachable();
|
||||
return;
|
||||
}
|
||||
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
update_active_shelf(
|
||||
*C, *area->type, *shelf_regiondata, /*on_create=*/[&](AssetShelf &new_shelf) {
|
||||
/* Update region visibility (`'DEFAULT_VISIBLE'` option). */
|
||||
|
@ -812,6 +813,8 @@ void type_unlink(const Main &bmain, const AssetShelfType &shelf_type)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_popup_unlink(shelf_type);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -9,14 +9,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
struct ARegion;
|
||||
struct ARegionType;
|
||||
struct AssetLibraryReference;
|
||||
struct AssetShelf;
|
||||
struct AssetShelfType;
|
||||
struct AssetShelfSettings;
|
||||
struct bContext;
|
||||
struct BlendDataReader;
|
||||
struct BlendWriter;
|
||||
struct RegionAssetShelf;
|
||||
struct SpaceType;
|
||||
struct uiLayout;
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
@ -39,6 +44,11 @@ AssetShelf *active_shelf_from_context(const bContext *C);
|
|||
|
||||
void send_redraw_notifier(const bContext &C);
|
||||
|
||||
AssetShelfType *type_ensure(const SpaceType &space_type, AssetShelf &shelf);
|
||||
AssetShelf *create_shelf_from_type(AssetShelfType &type);
|
||||
|
||||
void library_selector_draw(const bContext *C, uiLayout *layout, AssetShelf &shelf);
|
||||
|
||||
/**
|
||||
* Deep-copies \a shelf_regiondata into newly allocated memory. Must be freed using
|
||||
* #regiondata_free().
|
||||
|
|
|
@ -45,12 +45,13 @@ class AssetView : public ui::AbstractGridView {
|
|||
* end of the string, for `fnmatch()` to work. */
|
||||
char search_string[sizeof(AssetShelfSettings::search_string) + 2] = "";
|
||||
std::optional<asset_system::AssetCatalogFilter> catalog_filter_ = std::nullopt;
|
||||
bool is_popup_ = false;
|
||||
|
||||
friend class AssetViewItem;
|
||||
friend class AssetDragController;
|
||||
|
||||
public:
|
||||
AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf);
|
||||
AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf, bool is_popup);
|
||||
~AssetView();
|
||||
|
||||
void build_items() override;
|
||||
|
@ -72,6 +73,7 @@ class AssetViewItem : public ui::PreviewGridItem {
|
|||
void disable_asset_drag();
|
||||
void build_grid_tile(uiLayout &layout) const override;
|
||||
void build_context_menu(bContext &C, uiLayout &column) const override;
|
||||
void on_activate(bContext &C) override;
|
||||
std::optional<bool> should_be_active() const override;
|
||||
bool is_filtered_visible() const override;
|
||||
|
||||
|
@ -88,8 +90,10 @@ class AssetDragController : public ui::AbstractViewItemDragController {
|
|||
void *create_drag_data() const override;
|
||||
};
|
||||
|
||||
AssetView::AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf)
|
||||
: library_ref_(library_ref), shelf_(shelf)
|
||||
AssetView::AssetView(const AssetLibraryReference &library_ref,
|
||||
const AssetShelf &shelf,
|
||||
const bool is_popup)
|
||||
: library_ref_(library_ref), shelf_(shelf), is_popup_(is_popup)
|
||||
{
|
||||
if (shelf.settings.search_string[0]) {
|
||||
BLI_strncpy_ensure_pad(
|
||||
|
@ -230,6 +234,14 @@ void AssetViewItem::build_context_menu(bContext &C, uiLayout &column) const
|
|||
}
|
||||
}
|
||||
|
||||
void AssetViewItem::on_activate(bContext & /*C*/)
|
||||
{
|
||||
const AssetView &asset_view = dynamic_cast<const AssetView &>(get_view());
|
||||
if (asset_view.is_popup_) {
|
||||
UI_popup_menu_close_from_but(reinterpret_cast<uiBut *>(view_item_button()));
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<bool> AssetViewItem::should_be_active() const
|
||||
{
|
||||
const AssetView &asset_view = dynamic_cast<const AssetView &>(get_view());
|
||||
|
@ -284,7 +296,8 @@ void build_asset_view(uiLayout &layout,
|
|||
BLI_assert(tile_width != 0);
|
||||
BLI_assert(tile_height != 0);
|
||||
|
||||
std::unique_ptr asset_view = std::make_unique<AssetView>(library_ref, shelf);
|
||||
const bool is_popup = region.regiontype == RGN_TYPE_TEMPORARY;
|
||||
std::unique_ptr asset_view = std::make_unique<AssetView>(library_ref, shelf, is_popup);
|
||||
asset_view->set_catalog_filter(catalog_filter_from_shelf_settings(shelf.settings, *library));
|
||||
asset_view->set_tile_size(tile_width, tile_height);
|
||||
|
||||
|
|
|
@ -174,32 +174,37 @@ void AssetCatalogSelectorTree::update_shelf_settings_from_enabled_catalogs()
|
|||
});
|
||||
}
|
||||
|
||||
void library_selector_draw(const bContext *C, uiLayout *layout, AssetShelf &shelf)
|
||||
{
|
||||
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
|
||||
|
||||
PointerRNA shelf_ptr = RNA_pointer_create(&CTX_wm_screen(C)->id, &RNA_AssetShelf, &shelf);
|
||||
|
||||
uiLayout *row = uiLayoutRow(layout, true);
|
||||
uiItemR(row, &shelf_ptr, "asset_library_reference", UI_ITEM_NONE, "", ICON_NONE);
|
||||
if (shelf.settings.asset_library_reference.type != ASSET_LIBRARY_LOCAL) {
|
||||
uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh");
|
||||
}
|
||||
}
|
||||
|
||||
static void catalog_selector_panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
const AssetLibraryReference *library_ref = CTX_wm_asset_library_ref(C);
|
||||
AssetShelf *shelf = active_shelf_from_context(C);
|
||||
if (!shelf) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiLayout *layout = panel->layout;
|
||||
uiBlock *block = uiLayoutGetBlock(layout);
|
||||
|
||||
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
|
||||
library_selector_draw(C, layout, *shelf);
|
||||
|
||||
PointerRNA shelf_ptr = RNA_pointer_create(&CTX_wm_screen(C)->id, &RNA_AssetShelf, shelf);
|
||||
|
||||
uiLayout *row = uiLayoutRow(layout, true);
|
||||
uiItemR(row, &shelf_ptr, "asset_library_reference", UI_ITEM_NONE, "", ICON_NONE);
|
||||
if (library_ref->type != ASSET_LIBRARY_LOCAL) {
|
||||
uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh");
|
||||
}
|
||||
|
||||
asset_system::AssetLibrary *library = list::library_get_once_available(*library_ref);
|
||||
asset_system::AssetLibrary *library = list::library_get_once_available(
|
||||
shelf->settings.asset_library_reference);
|
||||
if (!library) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiBlock *block = uiLayoutGetBlock(layout);
|
||||
ui::AbstractTreeView *tree_view = UI_block_add_view(
|
||||
*block,
|
||||
"asset catalog tree view",
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edasset
|
||||
*/
|
||||
|
||||
#include "asset_shelf.hh"
|
||||
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "UI_interface_c.hh"
|
||||
#include "UI_tree_view.hh"
|
||||
|
||||
#include "ED_asset_filter.hh"
|
||||
#include "ED_asset_list.hh"
|
||||
#include "ED_asset_shelf.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
namespace blender::ed::asset::shelf {
|
||||
|
||||
class StaticPopupShelves {
|
||||
public:
|
||||
Vector<AssetShelf *> popup_shelves;
|
||||
|
||||
~StaticPopupShelves()
|
||||
{
|
||||
for (AssetShelf *shelf : popup_shelves) {
|
||||
MEM_delete(shelf);
|
||||
}
|
||||
}
|
||||
|
||||
static Vector<AssetShelf *> &shelves()
|
||||
{
|
||||
static StaticPopupShelves storage;
|
||||
return storage.popup_shelves;
|
||||
}
|
||||
};
|
||||
|
||||
void type_popup_unlink(const AssetShelfType &shelf_type)
|
||||
{
|
||||
for (AssetShelf *shelf : StaticPopupShelves::shelves()) {
|
||||
if (shelf->type == &shelf_type) {
|
||||
shelf->type = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static AssetShelf *get_shelf_for_popup(const bContext *C, AssetShelfType &shelf_type)
|
||||
{
|
||||
const SpaceType *space_type = BKE_spacetype_from_id(shelf_type.space_type);
|
||||
|
||||
Vector<AssetShelf *> &popup_shelves = StaticPopupShelves::shelves();
|
||||
|
||||
for (AssetShelf *shelf : popup_shelves) {
|
||||
if (STREQ(shelf->idname, shelf_type.idname)) {
|
||||
if (type_poll(*C, *space_type, type_ensure(*space_type, *shelf))) {
|
||||
return shelf;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type_poll(*C, *space_type, &shelf_type)) {
|
||||
AssetShelf *new_shelf = create_shelf_from_type(shelf_type);
|
||||
popup_shelves.append(new_shelf);
|
||||
return new_shelf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class AssetCatalogTreeView : public ui::AbstractTreeView {
|
||||
AssetShelf &shelf_;
|
||||
asset_system::AssetCatalogTree catalog_tree_;
|
||||
|
||||
public:
|
||||
AssetCatalogTreeView(const asset_system::AssetLibrary &library, AssetShelf &shelf)
|
||||
: shelf_(shelf)
|
||||
{
|
||||
catalog_tree_ = build_filtered_catalog_tree(
|
||||
library,
|
||||
shelf_.settings.asset_library_reference,
|
||||
[this](const asset_system::AssetRepresentation &asset) {
|
||||
return (!shelf_.type->asset_poll || shelf_.type->asset_poll(shelf_.type, &asset));
|
||||
});
|
||||
}
|
||||
|
||||
void build_tree() override
|
||||
{
|
||||
if (catalog_tree_.is_empty()) {
|
||||
auto &item = this->add_tree_item<ui::BasicTreeViewItem>(RPT_("No applicable assets found"),
|
||||
ICON_INFO);
|
||||
item.disable_interaction();
|
||||
return;
|
||||
}
|
||||
|
||||
auto &all_item = this->add_tree_item<ui::BasicTreeViewItem>(IFACE_("All"));
|
||||
all_item.set_on_activate_fn([this](bContext &C, ui::BasicTreeViewItem &) {
|
||||
settings_set_all_catalog_active(shelf_.settings);
|
||||
send_redraw_notifier(C);
|
||||
});
|
||||
all_item.set_is_active_fn(
|
||||
[this]() { return settings_is_all_catalog_active(shelf_.settings); });
|
||||
all_item.uncollapse_by_default();
|
||||
|
||||
catalog_tree_.foreach_root_item([&, this](
|
||||
const asset_system::AssetCatalogTreeItem &catalog_item) {
|
||||
ui::BasicTreeViewItem &item = this->build_catalog_items_recursive(all_item, catalog_item);
|
||||
item.uncollapse_by_default();
|
||||
});
|
||||
}
|
||||
|
||||
ui::BasicTreeViewItem &build_catalog_items_recursive(
|
||||
ui::TreeViewOrItem &parent_view_item,
|
||||
const asset_system::AssetCatalogTreeItem &catalog_item) const
|
||||
{
|
||||
ui::BasicTreeViewItem &view_item = parent_view_item.add_tree_item<ui::BasicTreeViewItem>(
|
||||
catalog_item.get_name());
|
||||
|
||||
std::string catalog_path = catalog_item.catalog_path().str();
|
||||
view_item.set_on_activate_fn([this, catalog_path](bContext &C, ui::BasicTreeViewItem &) {
|
||||
settings_set_active_catalog(shelf_.settings, catalog_path);
|
||||
send_redraw_notifier(C);
|
||||
});
|
||||
view_item.set_is_active_fn([this, catalog_path]() {
|
||||
return settings_is_active_catalog(shelf_.settings, catalog_path);
|
||||
});
|
||||
|
||||
catalog_item.foreach_child(
|
||||
[&view_item, this](const asset_system::AssetCatalogTreeItem &child) {
|
||||
build_catalog_items_recursive(view_item, child);
|
||||
});
|
||||
|
||||
return view_item;
|
||||
}
|
||||
};
|
||||
|
||||
static void catalog_tree_draw(uiLayout &layout, AssetShelf &shelf)
|
||||
{
|
||||
const asset_system::AssetLibrary *library = list::library_get_once_available(
|
||||
shelf.settings.asset_library_reference);
|
||||
if (!library) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiBlock *block = uiLayoutGetBlock(&layout);
|
||||
ui::AbstractTreeView *tree_view = UI_block_add_view(
|
||||
*block,
|
||||
"asset shelf catalog tree view",
|
||||
std::make_unique<AssetCatalogTreeView>(*library, shelf));
|
||||
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, layout);
|
||||
}
|
||||
|
||||
uiBlock *popup_block_create(const bContext *C, ARegion *region, AssetShelfType *shelf_type)
|
||||
{
|
||||
uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
|
||||
UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER);
|
||||
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
|
||||
|
||||
AssetShelf *shelf = get_shelf_for_popup(C, *shelf_type);
|
||||
if (!shelf) {
|
||||
BLI_assert_unreachable();
|
||||
return block;
|
||||
}
|
||||
|
||||
const uiStyle *style = UI_style_get_dpi();
|
||||
|
||||
const float pad = 0.2f * UI_UNIT_Y; /* UI_MENU_PADDING */
|
||||
uiLayout *layout = UI_block_layout(
|
||||
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, pad, 0, UI_UNIT_X * 40, 0, pad / 2, style);
|
||||
|
||||
PointerRNA library_ref_ptr = RNA_pointer_create(
|
||||
&CTX_wm_screen(C)->id, &RNA_AssetLibraryReference, &shelf->settings.asset_library_reference);
|
||||
uiLayoutSetContextPointer(layout, "asset_library_reference", &library_ref_ptr);
|
||||
|
||||
uiLayout *row = uiLayoutRow(layout, false);
|
||||
uiLayout *sub = uiLayoutRow(row, false);
|
||||
uiLayoutSetUnitsX(sub, 10);
|
||||
uiLayoutSetFixedSize(sub, true);
|
||||
uiLayout *catalogs_col = uiLayoutColumn(sub, false);
|
||||
library_selector_draw(C, catalogs_col, *shelf);
|
||||
catalog_tree_draw(*catalogs_col, *shelf);
|
||||
|
||||
uiLayout *asset_view_col = uiLayoutColumn(row, false);
|
||||
build_asset_view(*asset_view_col, shelf->settings.asset_library_reference, *shelf, *C, *region);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::asset::shelf
|
|
@ -25,6 +25,19 @@ RegionAssetShelf *RegionAssetShelf::get_from_asset_shelf_region(const ARegion &r
|
|||
return static_cast<RegionAssetShelf *>(region.regiondata);
|
||||
}
|
||||
|
||||
RegionAssetShelf *RegionAssetShelf::ensure_from_asset_shelf_region(ARegion ®ion)
|
||||
{
|
||||
if (region.regiontype != RGN_TYPE_ASSET_SHELF) {
|
||||
/* Should only be called on main asset shelf region. */
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
if (!region.regiondata) {
|
||||
region.regiondata = MEM_cnew<RegionAssetShelf>("RegionAssetShelf");
|
||||
}
|
||||
return static_cast<RegionAssetShelf *>(region.regiondata);
|
||||
}
|
||||
|
||||
namespace blender::ed::asset::shelf {
|
||||
|
||||
RegionAssetShelf *regiondata_duplicate(const RegionAssetShelf *shelf_regiondata)
|
||||
|
|
|
@ -707,6 +707,18 @@ uiLayout *UI_popup_menu_layout(uiPopupMenu *pup);
|
|||
void UI_popup_menu_reports(bContext *C, ReportList *reports) ATTR_NONNULL();
|
||||
int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) ATTR_NONNULL(1, 2);
|
||||
|
||||
/**
|
||||
* If \a block is displayed in a popup menu, tag it for closing.
|
||||
* \param is_cancel: If set to true, the popup will be closed as being cancelled (e.g. when
|
||||
* pressing escape) as opposed to being handled successfully.
|
||||
*/
|
||||
void UI_popup_menu_close(const uiBlock *block, bool is_cancel = false);
|
||||
/**
|
||||
* Version of #UI_popup_menu_close() that can be called on a button contained in a popup menu
|
||||
* block. Convenience since the block may not be available.
|
||||
*/
|
||||
void UI_popup_menu_close_from_but(const uiBut *but, bool is_cancel = false);
|
||||
|
||||
/**
|
||||
* Allow setting menu return value from externals.
|
||||
* E.g. WM might need to do this for exiting files correctly.
|
||||
|
@ -1488,6 +1500,10 @@ uiBut *uiDefIconMenuBut(uiBlock *block,
|
|||
short height,
|
||||
const char *tip);
|
||||
|
||||
/**
|
||||
* Note that \a fun can set the #UI_BLOCK_KEEP_OPEN flag to the block it creates, to allow
|
||||
* refreshing the popup. That is, redrawing the layout, potentially affecting the popup size.
|
||||
*/
|
||||
uiBut *uiDefBlockBut(uiBlock *block,
|
||||
uiBlockCreateFunc func,
|
||||
void *arg,
|
||||
|
@ -2703,6 +2719,9 @@ void uiTemplateAssetView(uiLayout *layout,
|
|||
const char *drag_opname,
|
||||
PointerRNA *r_drag_op_properties);
|
||||
|
||||
void uiTemplateAssetShelfPopover(
|
||||
uiLayout *layout, bContext *C, const char *asset_shelf_id, const char *name, const int icon);
|
||||
|
||||
void uiTemplateLightLinkingCollection(uiLayout *layout,
|
||||
uiLayout *context_layout,
|
||||
PointerRNA *ptr,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
set(INC
|
||||
.
|
||||
../include
|
||||
../asset
|
||||
../../asset_system
|
||||
../../blenkernel
|
||||
../../blenloader
|
||||
|
@ -64,6 +65,7 @@ set(SRC
|
|||
regions/interface_regions.cc
|
||||
interface_string_search.cc
|
||||
interface_style.cc
|
||||
templates/interface_template_asset_shelf_popover.cc
|
||||
templates/interface_template_asset_view.cc
|
||||
templates/interface_template_attribute_search.cc
|
||||
templates/interface_template_bone_collection_tree.cc
|
||||
|
|
|
@ -11503,6 +11503,8 @@ static int ui_handle_menus_recursive(bContext *C,
|
|||
if (!menu->retvalue) {
|
||||
ui_handle_viewlist_items_hover(event, menu->region);
|
||||
}
|
||||
/* Handle mouse clicks on overlapping view item button. */
|
||||
ui_handle_view_item_event(C, event, but, menu->region);
|
||||
|
||||
if (do_towards_reinit) {
|
||||
ui_mouse_motion_towards_reinit(menu, event->xy);
|
||||
|
|
|
@ -977,6 +977,10 @@ uiBlock *ui_popup_block_refresh(bContext *C,
|
|||
ARegion *butregion,
|
||||
uiBut *but);
|
||||
|
||||
/**
|
||||
* Note that callbacks can set the #UI_BLOCK_KEEP_OPEN flag to the block it creates, to allow
|
||||
* refreshing the popup. That is, redrawing the layout, potentially affecting the popup size.
|
||||
*/
|
||||
uiPopupBlockHandle *ui_popup_block_create(bContext *C,
|
||||
ARegion *butregion,
|
||||
uiBut *but,
|
||||
|
|
|
@ -762,4 +762,14 @@ bool UI_popup_block_name_exists(const bScreen *screen, const blender::StringRef
|
|||
return false;
|
||||
}
|
||||
|
||||
void UI_popup_menu_close(const uiBlock *block, const bool is_cancel)
|
||||
{
|
||||
UI_popup_menu_retval_set(block, is_cancel ? UI_RETURN_CANCEL : UI_RETURN_OK, true);
|
||||
}
|
||||
|
||||
void UI_popup_menu_close_from_but(const uiBut *but, const bool is_cancel)
|
||||
{
|
||||
UI_popup_menu_close(but->block, is_cancel);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -885,6 +885,10 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
|
|||
uiBlock *block = ui_popup_block_refresh(C, handle, butregion, but);
|
||||
handle = block->handle;
|
||||
|
||||
if (block->flag & UI_BLOCK_KEEP_OPEN) {
|
||||
handle->can_refresh = true;
|
||||
}
|
||||
|
||||
/* keep centered on window resizing */
|
||||
if (block->bounds_type == UI_BLOCK_BOUNDS_POPUP_CENTER) {
|
||||
type.listener = ui_block_region_popup_window_listener;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edinterface
|
||||
*/
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
|
||||
#include "UI_interface_c.hh"
|
||||
#include "UI_resources.hh"
|
||||
#include "interface_intern.hh"
|
||||
|
||||
#include "ED_asset_shelf.hh"
|
||||
|
||||
using namespace blender;
|
||||
|
||||
static uiBlock *asset_shelf_block_fn(bContext *C, ARegion *region, void *arg_shelf_type)
|
||||
{
|
||||
AssetShelfType *shelf_type = reinterpret_cast<AssetShelfType *>(arg_shelf_type);
|
||||
return ed::asset::shelf::popup_block_create(C, region, shelf_type);
|
||||
}
|
||||
|
||||
void uiTemplateAssetShelfPopover(uiLayout *layout,
|
||||
bContext *C,
|
||||
const char *asset_shelf_id,
|
||||
const char *name,
|
||||
const BIFIconID icon)
|
||||
{
|
||||
const ScrArea *area = CTX_wm_area(C);
|
||||
AssetShelfType *shelf_type = ed::asset::shelf::type_find_from_idname(*area->type,
|
||||
asset_shelf_id);
|
||||
if (!shelf_type) {
|
||||
RNA_warning("Asset shelf type not found: %s", asset_shelf_id);
|
||||
return;
|
||||
}
|
||||
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
const bool use_big_size = !RGN_TYPE_IS_HEADER_ANY(region->regiontype);
|
||||
const short width = [&]() -> short {
|
||||
if (use_big_size) {
|
||||
return UI_UNIT_X * 6;
|
||||
}
|
||||
return UI_UNIT_X * (name ? 7 : 1.6f);
|
||||
}();
|
||||
const short height = UI_UNIT_Y * (use_big_size ? 6 : 1);
|
||||
|
||||
uiBlock *block = uiLayoutGetBlock(layout);
|
||||
uiBut *but = uiDefBlockBut(
|
||||
block, asset_shelf_block_fn, shelf_type, name, 0, 0, width, height, "Select an asset");
|
||||
ui_def_but_icon(but, icon, UI_HAS_ICON);
|
||||
UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
|
||||
|
||||
if (ed::asset::shelf::type_poll(*C, *area->type, shelf_type) == false) {
|
||||
UI_but_flag_enable(but, UI_BUT_DISABLED);
|
||||
}
|
||||
}
|
|
@ -204,7 +204,6 @@ GridViewItemDropTarget::GridViewItemDropTarget(AbstractGridView &view) : view_(v
|
|||
* side(s) as well.
|
||||
*/
|
||||
class BuildOnlyVisibleButtonsHelper {
|
||||
const View2D &v2d_;
|
||||
const AbstractGridView &grid_view_;
|
||||
const GridViewStyle &style_;
|
||||
const int cols_per_row_ = 0;
|
||||
|
@ -221,30 +220,34 @@ class BuildOnlyVisibleButtonsHelper {
|
|||
void fill_layout_after_visible(uiBlock &block) const;
|
||||
|
||||
private:
|
||||
IndexRange get_visible_range() const;
|
||||
IndexRange get_visible_range(const View2D &v2d) const;
|
||||
void add_spacer_button(uiBlock &block, int row_count) const;
|
||||
};
|
||||
|
||||
BuildOnlyVisibleButtonsHelper::BuildOnlyVisibleButtonsHelper(const View2D &v2d,
|
||||
const AbstractGridView &grid_view,
|
||||
const int cols_per_row)
|
||||
: v2d_(v2d), grid_view_(grid_view), style_(grid_view.get_style()), cols_per_row_(cols_per_row)
|
||||
: grid_view_(grid_view), style_(grid_view.get_style()), cols_per_row_(cols_per_row)
|
||||
{
|
||||
visible_items_range_ = this->get_visible_range();
|
||||
visible_items_range_ = this->get_visible_range(v2d);
|
||||
}
|
||||
|
||||
IndexRange BuildOnlyVisibleButtonsHelper::get_visible_range() const
|
||||
IndexRange BuildOnlyVisibleButtonsHelper::get_visible_range(const View2D &v2d) const
|
||||
{
|
||||
if ((v2d.flag & V2D_IS_INIT) == 0) {
|
||||
return IndexRange(0, grid_view_.get_item_count_filtered());
|
||||
}
|
||||
|
||||
int first_idx_in_view = 0;
|
||||
|
||||
const float scroll_ofs_y = std::abs(v2d_.cur.ymax - v2d_.tot.ymax);
|
||||
const float scroll_ofs_y = std::abs(v2d.cur.ymax - v2d.tot.ymax);
|
||||
if (!IS_EQF(scroll_ofs_y, 0)) {
|
||||
const int scrolled_away_rows = int(scroll_ofs_y) / style_.tile_height;
|
||||
|
||||
first_idx_in_view = scrolled_away_rows * cols_per_row_;
|
||||
}
|
||||
|
||||
const int view_height = BLI_rcti_size_y(&v2d_.mask);
|
||||
const int view_height = BLI_rcti_size_y(&v2d.mask);
|
||||
const int count_rows_in_view = std::max(view_height / style_.tile_height, 1);
|
||||
const int max_items_in_view = (count_rows_in_view + 1) * cols_per_row_;
|
||||
|
||||
|
|
|
@ -833,6 +833,7 @@ typedef struct AssetShelf {
|
|||
|
||||
AssetShelfSettings settings;
|
||||
|
||||
/** Only for the permanent asset shelf regions, not asset shelves in temporary popups. */
|
||||
short preferred_row_count;
|
||||
char _pad[6];
|
||||
} AssetShelf;
|
||||
|
@ -855,6 +856,8 @@ typedef struct RegionAssetShelf {
|
|||
AssetShelf *active_shelf; /* Non-owning. */
|
||||
#ifdef __cplusplus
|
||||
static RegionAssetShelf *get_from_asset_shelf_region(const ARegion ®ion);
|
||||
/** Creates the asset shelf region data if necessary, and returns it. */
|
||||
static RegionAssetShelf *ensure_from_asset_shelf_region(ARegion ®ion);
|
||||
#endif
|
||||
} RegionAssetShelf;
|
||||
|
||||
|
|
|
@ -963,6 +963,20 @@ static int rna_ui_get_enum_icon(bContext *C,
|
|||
return icon;
|
||||
}
|
||||
|
||||
void rna_uiTemplateAssetShelfPopover(uiLayout *layout,
|
||||
bContext *C,
|
||||
const char *asset_shelf_id,
|
||||
const char *name,
|
||||
BIFIconID icon,
|
||||
int icon_value)
|
||||
{
|
||||
if (icon_value && !icon) {
|
||||
icon = icon_value;
|
||||
}
|
||||
|
||||
uiTemplateAssetShelfPopover(layout, C, asset_shelf_id, name, icon);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void api_ui_item_common_heading(FunctionRNA *func)
|
||||
|
@ -2287,6 +2301,25 @@ void RNA_api_ui_layout(StructRNA *srna)
|
|||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
parm = RNA_def_pointer(func, "node", "Node", "Node", "Display inputs of this node");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
|
||||
func = RNA_def_function(srna, "template_asset_shelf_popover", "rna_uiTemplateAssetShelfPopover");
|
||||
RNA_def_function_ui_description(func, "Create a button to open an asset shelf in a popover");
|
||||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
parm = RNA_def_string(func,
|
||||
"asset_shelf",
|
||||
nullptr,
|
||||
0,
|
||||
"",
|
||||
"Identifier of the asset shelf to display (`bl_idname`)");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
parm = RNA_def_string(
|
||||
func, "name", nullptr, 0, "", "Optional name to indicate the active asset");
|
||||
RNA_def_property_clear_flag(parm, PROP_NEVER_NULL);
|
||||
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(parm, rna_enum_icon_items);
|
||||
RNA_def_property_ui_text(parm, "Icon", "Override automatic icon of the item");
|
||||
parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue