UI: Turn asset shelf popup into a popover, add operator to call from shortcut
Turns the asset shelf into a popover which reduces some of the special handling. An operator `WM_OT_call_asset_shelf_popover()` (similar to `WM_OT_call_panel()`) is added to be able to call the popover from shortcuts. Exactly this was an important aspect for the brush assets project, to allow quick searching for brushes from the popup. A custom shortcut can be added to asset shelf popovers using "Assign Shortcut" in the context menu of buttons invoking it. The popover is spawned with the mouse hovering the first asset and the search button active using "semi modal" handling. That means while the popover is open, any text input is captured by the search button, while the rest of the popover stays interactive. So for example navigating through asset catalogs is possible, a single click activates an asset and closes the popover. Reviewed as part of the asset shelf project, see: - https://projects.blender.org/blender/blender/issues/116337 - https://projects.blender.org/blender/blender/pulls/106303
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "RNA_types.hh"
|
||||
@@ -295,6 +296,9 @@ struct PanelType {
|
||||
short region_type;
|
||||
/* For popovers, 0 for default. */
|
||||
int ui_units_x;
|
||||
/** For popovers, position the popover at the given offset (multiplied by #UI_UNIT_X/#UI_UNIT_Y)
|
||||
* relative to the top left corner, if it's not attached to a button. */
|
||||
blender::float2 offset_units_xy;
|
||||
int order;
|
||||
|
||||
int flag;
|
||||
|
||||
@@ -34,7 +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_popover.cc
|
||||
intern/asset_shelf_regiondata.cc
|
||||
intern/asset_shelf_settings.cc
|
||||
intern/asset_temp_id_consumer.cc
|
||||
|
||||
@@ -65,7 +65,7 @@ void header_region_init(wmWindowManager *wm, ARegion *region);
|
||||
void header_region(const bContext *C, ARegion *region);
|
||||
void header_region_listen(const wmRegionListenerParams *params);
|
||||
int header_region_size();
|
||||
void header_regiontype_register(ARegionType *region_type, const int space_type);
|
||||
void types_register(ARegionType *region_type, const int space_type);
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -90,7 +90,6 @@ AssetShelfType *type_find_from_idname(const StringRef 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);
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "AS_asset_catalog_path.hh"
|
||||
#include "AS_asset_library.hh"
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
@@ -831,7 +832,7 @@ static void asset_shelf_header_draw(const bContext *C, Header *header)
|
||||
uiItemR(sub, &shelf_ptr, "search_filter", UI_ITEM_NONE, "", ICON_VIEWZOOM);
|
||||
}
|
||||
|
||||
void header_regiontype_register(ARegionType *region_type, const int space_type)
|
||||
static void header_regiontype_register(ARegionType *region_type, const int space_type)
|
||||
{
|
||||
HeaderType *ht = MEM_cnew<HeaderType>(__func__);
|
||||
STRNCPY(ht->idname, "ASSETSHELF_HT_settings");
|
||||
@@ -843,8 +844,13 @@ void header_regiontype_register(ARegionType *region_type, const int space_type)
|
||||
};
|
||||
|
||||
BLI_addtail(®ion_type->headertypes, ht);
|
||||
}
|
||||
|
||||
void types_register(ARegionType *region_type, const int space_type)
|
||||
{
|
||||
header_regiontype_register(region_type, space_type);
|
||||
catalog_selector_panel_register(region_type);
|
||||
popover_panel_register(region_type);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -38,6 +38,7 @@ void build_asset_view(uiLayout &layout,
|
||||
const ARegion ®ion);
|
||||
|
||||
void catalog_selector_panel_register(ARegionType *region_type);
|
||||
void popover_panel_register(ARegionType *region_type);
|
||||
|
||||
AssetShelf *active_shelf_from_context(const bContext *C);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "AS_asset_library.hh"
|
||||
#include "AS_asset_representation.hh"
|
||||
|
||||
#include "BKE_asset.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "BLI_fnmatch.h"
|
||||
@@ -41,13 +42,12 @@ class AssetView : public ui::AbstractGridView {
|
||||
const AssetShelf &shelf_;
|
||||
std::optional<AssetWeakReference> active_asset_;
|
||||
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, bool is_popup);
|
||||
AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf);
|
||||
|
||||
void build_items() override;
|
||||
bool begin_filtering(const bContext &C) const override;
|
||||
@@ -84,10 +84,8 @@ class AssetDragController : public ui::AbstractViewItemDragController {
|
||||
void *create_drag_data() const override;
|
||||
};
|
||||
|
||||
AssetView::AssetView(const AssetLibraryReference &library_ref,
|
||||
const AssetShelf &shelf,
|
||||
const bool is_popup)
|
||||
: library_ref_(library_ref), shelf_(shelf), is_popup_(is_popup)
|
||||
AssetView::AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf)
|
||||
: library_ref_(library_ref), shelf_(shelf)
|
||||
{
|
||||
if (shelf.type->get_active_asset) {
|
||||
if (const AssetWeakReference *weak_ref = shelf.type->get_active_asset(shelf.type)) {
|
||||
@@ -294,8 +292,7 @@ void build_asset_view(uiLayout &layout,
|
||||
BLI_assert(tile_width != 0);
|
||||
BLI_assert(tile_height != 0);
|
||||
|
||||
const bool is_popup = region.regiontype == RGN_TYPE_TEMPORARY;
|
||||
std::unique_ptr asset_view = std::make_unique<AssetView>(library_ref, shelf, is_popup);
|
||||
std::unique_ptr asset_view = std::make_unique<AssetView>(library_ref, shelf);
|
||||
asset_view->set_catalog_filter(catalog_filter_from_shelf_settings(shelf.settings, *library));
|
||||
asset_view->set_tile_size(tile_width, tile_height);
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "UI_interface_c.hh"
|
||||
@@ -22,6 +24,8 @@
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
namespace blender::ed::asset::shelf {
|
||||
|
||||
class StaticPopupShelves {
|
||||
@@ -51,20 +55,20 @@ void type_popup_unlink(const AssetShelfType &shelf_type)
|
||||
}
|
||||
}
|
||||
|
||||
static AssetShelf *get_shelf_for_popup(const bContext *C, AssetShelfType &shelf_type)
|
||||
static AssetShelf *get_shelf_for_popup(const bContext &C, AssetShelfType &shelf_type)
|
||||
{
|
||||
Vector<AssetShelf *> &popup_shelves = StaticPopupShelves::shelves();
|
||||
|
||||
for (AssetShelf *shelf : popup_shelves) {
|
||||
if (STREQ(shelf->idname, shelf_type.idname)) {
|
||||
if (type_poll_for_popup(*C, ensure_shelf_has_type(*shelf))) {
|
||||
if (type_poll_for_popup(C, ensure_shelf_has_type(*shelf))) {
|
||||
return shelf;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type_poll_for_popup(*C, &shelf_type)) {
|
||||
if (type_poll_for_popup(C, &shelf_type)) {
|
||||
AssetShelf *new_shelf = create_shelf_from_type(shelf_type);
|
||||
new_shelf->settings.display_flag |= ASSETSHELF_SHOW_NAMES;
|
||||
popup_shelves.append(new_shelf);
|
||||
@@ -134,10 +138,16 @@ class AssetCatalogTreeView : public ui::AbstractTreeView {
|
||||
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);
|
||||
});
|
||||
const int parent_count = view_item.count_parents() + 1;
|
||||
|
||||
catalog_item.foreach_child([&, this](const asset_system::AssetCatalogTreeItem &child) {
|
||||
ui::BasicTreeViewItem &child_item = build_catalog_items_recursive(view_item, child);
|
||||
|
||||
/* Uncollapse to some level (gives quick acces, but don't let the tree get too big). */
|
||||
if (parent_count < 3) {
|
||||
child_item.uncollapse_by_default();
|
||||
}
|
||||
});
|
||||
|
||||
return view_item;
|
||||
}
|
||||
@@ -160,36 +170,43 @@ static void catalog_tree_draw(uiLayout &layout, AssetShelf &shelf)
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, layout);
|
||||
}
|
||||
|
||||
uiBlock *popup_block_create(const bContext *C, ARegion *region, AssetShelfType *shelf_type)
|
||||
static AssetShelfType *lookup_type_from_idname_in_context(const bContext *C)
|
||||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
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);
|
||||
UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
|
||||
UI_block_direction_set(block, UI_DIR_DOWN);
|
||||
const std::optional<StringRefNull> idname = CTX_data_string_get(C, "asset_shelf_idname");
|
||||
if (!idname) {
|
||||
return nullptr;
|
||||
}
|
||||
return type_find_from_idname(*idname);
|
||||
}
|
||||
|
||||
AssetShelf *shelf = get_shelf_for_popup(C, *shelf_type);
|
||||
constexpr int LEFT_COL_WIDTH_UNITS = 10;
|
||||
constexpr int RIGHT_COL_WIDTH_UNITS = 30;
|
||||
constexpr int LAYOUT_WIDTH_UNITS = LEFT_COL_WIDTH_UNITS + RIGHT_COL_WIDTH_UNITS;
|
||||
|
||||
static void popover_panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
AssetShelfType *shelf_type = lookup_type_from_idname_in_context(C);
|
||||
BLI_assert_msg(shelf_type != nullptr, "couldn't find asset shelf type from context");
|
||||
|
||||
const ARegion *region = CTX_wm_region_popup(C) ? CTX_wm_region_popup(C) : CTX_wm_region(C);
|
||||
|
||||
uiLayout *layout = panel->layout;
|
||||
uiLayoutSetUnitsX(layout, LAYOUT_WIDTH_UNITS);
|
||||
|
||||
AssetShelf *shelf = get_shelf_for_popup(*C, *shelf_type);
|
||||
if (!shelf) {
|
||||
BLI_assert_unreachable();
|
||||
return block;
|
||||
return;
|
||||
}
|
||||
|
||||
const uiStyle *style = UI_style_get_dpi();
|
||||
|
||||
const int layout_width = UI_UNIT_X * 40;
|
||||
const int left_col_width = 10 * UI_UNIT_X;
|
||||
const int right_col_width = layout_width - left_col_width;
|
||||
uiLayout *layout = UI_block_layout(
|
||||
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, layout_width, 0, 0, style);
|
||||
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
PointerRNA library_ref_ptr = RNA_pointer_create(
|
||||
&screen->id, &RNA_AssetLibraryReference, &shelf->settings.asset_library_reference);
|
||||
uiLayoutSetContextPointer(layout, "asset_library_reference", &library_ref_ptr);
|
||||
|
||||
uiLayout *row = uiLayoutRow(layout, false);
|
||||
uiLayout *catalogs_col = uiLayoutColumn(row, false);
|
||||
uiLayoutSetUnitsX(catalogs_col, left_col_width / UI_UNIT_X);
|
||||
uiLayoutSetUnitsX(catalogs_col, LEFT_COL_WIDTH_UNITS);
|
||||
uiLayoutSetFixedSize(catalogs_col, true);
|
||||
library_selector_draw(C, catalogs_col, *shelf);
|
||||
catalog_tree_draw(*catalogs_col, *shelf);
|
||||
@@ -198,14 +215,53 @@ uiBlock *popup_block_create(const bContext *C, ARegion *region, AssetShelfType *
|
||||
uiLayout *sub = uiLayoutRow(right_col, false);
|
||||
/* Same as file/asset browser header. */
|
||||
PointerRNA shelf_ptr = RNA_pointer_create(&screen->id, &RNA_AssetShelf, shelf);
|
||||
uiItemR(sub, &shelf_ptr, "search_filter", UI_ITEM_R_IMMEDIATE, "", ICON_VIEWZOOM);
|
||||
uiItemR(sub,
|
||||
&shelf_ptr,
|
||||
"search_filter",
|
||||
/* Force the button to be active in a semi-modal state. */
|
||||
UI_ITEM_R_TEXT_BUT_FORCE_SEMI_MODAL_ACTIVE,
|
||||
"",
|
||||
ICON_VIEWZOOM);
|
||||
|
||||
uiLayout *asset_view_col = uiLayoutColumn(right_col, false);
|
||||
uiLayoutSetUnitsX(asset_view_col, right_col_width / UI_UNIT_X);
|
||||
uiLayoutSetUnitsX(asset_view_col, RIGHT_COL_WIDTH_UNITS);
|
||||
uiLayoutSetFixedSize(asset_view_col, true);
|
||||
build_asset_view(*asset_view_col, shelf->settings.asset_library_reference, *shelf, *C, *region);
|
||||
|
||||
return block;
|
||||
build_asset_view(*asset_view_col, shelf->settings.asset_library_reference, *shelf, *C, *region);
|
||||
}
|
||||
|
||||
static bool popover_panel_poll(const bContext *C, PanelType * /*panel_type*/)
|
||||
{
|
||||
const AssetShelfType *shelf_type = lookup_type_from_idname_in_context(C);
|
||||
if (!shelf_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return type_poll_for_popup(*C, shelf_type);
|
||||
}
|
||||
|
||||
void popover_panel_register(ARegionType *region_type)
|
||||
{
|
||||
/* Uses global paneltype registry to allow usage as popover. So only register this once (may be
|
||||
* called from multiple spaces). */
|
||||
if (WM_paneltype_find("ASSETSHELF_PT_popover_panel", true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PanelType *pt = MEM_cnew<PanelType>(__func__);
|
||||
STRNCPY(pt->idname, "ASSETSHELF_PT_popover_panel");
|
||||
STRNCPY(pt->label, N_("Asset Shelf Panel"));
|
||||
STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
|
||||
pt->description = N_("Display an asset shelf in a popover panel");
|
||||
pt->draw = popover_panel_draw;
|
||||
pt->poll = popover_panel_poll;
|
||||
pt->listener = asset::list::asset_reading_region_listen_fn;
|
||||
/* Move to have first asset item under cursor. */
|
||||
pt->offset_units_xy.x = -(LEFT_COL_WIDTH_UNITS + 1.5f);
|
||||
/* Offset so mouse is below search button, over the first row of assets. */
|
||||
pt->offset_units_xy.y = 2.5f;
|
||||
BLI_addtail(®ion_type->paneltypes, pt);
|
||||
WM_paneltype_add(pt);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::asset::shelf
|
||||
@@ -91,6 +91,9 @@ void attribute_search_add_items(StringRefNull str,
|
||||
uiSearchItems *items,
|
||||
bool is_first);
|
||||
|
||||
bool asset_shelf_popover_invoke(bContext &C,
|
||||
blender::StringRef asset_shelf_idname,
|
||||
ReportList &reports);
|
||||
/**
|
||||
* Some drop targets simply allow dropping onto/into them, others support dragging in-between them.
|
||||
* Classes implementing the drop-target interface can use this type to control the behavior by
|
||||
|
||||
@@ -2269,6 +2269,10 @@ MenuType *UI_but_menutype_get(const uiBut *but);
|
||||
* This is a bit of a hack but best keep it in one place at least.
|
||||
*/
|
||||
PanelType *UI_but_paneltype_get(const uiBut *but);
|
||||
/**
|
||||
* This is a bit of a hack but best keep it in one place at least.
|
||||
*/
|
||||
std::optional<blender::StringRefNull> UI_but_asset_shelf_type_idname_get(const uiBut *but);
|
||||
void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout);
|
||||
/**
|
||||
* Used for popup panels only.
|
||||
@@ -2789,8 +2793,11 @@ void uiTemplateAssetView(uiLayout *layout,
|
||||
|
||||
namespace blender::ui {
|
||||
|
||||
void template_asset_shelf_popover(
|
||||
uiLayout &layout, const bContext &C, StringRefNull asset_shelf_id, StringRef name, int icon);
|
||||
void template_asset_shelf_popover(uiLayout &layout,
|
||||
const bContext &C,
|
||||
StringRefNull asset_shelf_id,
|
||||
StringRefNull name,
|
||||
int icon);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,13 @@ static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDPro
|
||||
return "WM_OT_call_menu";
|
||||
}
|
||||
|
||||
if (std::optional asset_shelf_idname = UI_but_asset_shelf_type_idname_get(but)) {
|
||||
IDProperty *prop = blender::bke::idprop::create_group(__func__).release();
|
||||
IDP_AddToGroup(prop, bke::idprop::create("name", *asset_shelf_idname).release());
|
||||
*r_prop = prop;
|
||||
return "WM_OT_call_asset_shelf_popover";
|
||||
}
|
||||
|
||||
if (PanelType *pt = UI_but_paneltype_get(but)) {
|
||||
IDProperty *prop = blender::bke::idprop::create_group(__func__).release();
|
||||
IDP_AddToGroup(prop, bke::idprop::create("name", pt->idname).release());
|
||||
|
||||
@@ -1014,10 +1014,12 @@ uiPopupBlockHandle *ui_popup_menu_create(
|
||||
|
||||
/* `interface_region_popover.cc` */
|
||||
|
||||
using uiPopoverCreateFunc = std::function<void(bContext *, uiLayout *, PanelType *)>;
|
||||
|
||||
uiPopupBlockHandle *ui_popover_panel_create(bContext *C,
|
||||
ARegion *butregion,
|
||||
uiBut *but,
|
||||
uiMenuCreateFunc menu_func,
|
||||
uiPopoverCreateFunc popover_func,
|
||||
const PanelType *panel_type);
|
||||
|
||||
/* `interface_region_menu_pie.cc` */
|
||||
@@ -1552,6 +1554,9 @@ void UI_OT_eyedropper_driver(wmOperatorType *ot);
|
||||
|
||||
void UI_OT_eyedropper_gpencil_color(wmOperatorType *ot);
|
||||
|
||||
/* interface_template_asset_shelf_popover.cc */
|
||||
std::optional<blender::StringRefNull> UI_asset_shelf_idname_from_button_context(const uiBut *but);
|
||||
|
||||
/* interface_template_asset_view.cc */
|
||||
|
||||
uiListType *UI_UL_asset_view();
|
||||
|
||||
@@ -3195,6 +3195,10 @@ void uiItemPopoverPanel_ptr(
|
||||
icon = ICON_BLANK1;
|
||||
}
|
||||
|
||||
const bContextStore *previous_ctx = CTX_store_get(C);
|
||||
/* Set context for polling (and panel header drawing). */
|
||||
CTX_store_set(const_cast<bContext *>(C), layout->context);
|
||||
|
||||
const bool ok = (pt->poll == nullptr) || pt->poll(C, pt);
|
||||
if (ok && (pt->draw_header != nullptr)) {
|
||||
layout = uiLayoutRow(layout, true);
|
||||
@@ -3206,6 +3210,9 @@ void uiItemPopoverPanel_ptr(
|
||||
panel.flag = PNL_POPOVER;
|
||||
pt->draw_header(C, &panel);
|
||||
}
|
||||
|
||||
CTX_store_set(const_cast<bContext *>(C), previous_ctx);
|
||||
|
||||
uiBut *but = ui_item_menu(
|
||||
layout, name, icon, ui_item_paneltype_func, pt, nullptr, TIP_(pt->description), true);
|
||||
but->type = UI_BTYPE_POPOVER;
|
||||
@@ -6109,6 +6116,11 @@ PanelType *UI_but_paneltype_get(const uiBut *but)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<blender::StringRefNull> UI_but_asset_shelf_type_idname_get(const uiBut *but)
|
||||
{
|
||||
return UI_asset_shelf_idname_from_button_context(but);
|
||||
}
|
||||
|
||||
void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
|
||||
{
|
||||
Menu menu{};
|
||||
|
||||
@@ -61,8 +61,8 @@ struct uiPopover {
|
||||
wmKeyMap *keymap;
|
||||
wmEventHandler_Keymap *keymap_handler;
|
||||
|
||||
uiMenuCreateFunc menu_func;
|
||||
const PanelType *menu_arg;
|
||||
uiPopoverCreateFunc popover_func;
|
||||
const PanelType *panel_type;
|
||||
|
||||
/* Size in pixels (ui scale applied). */
|
||||
int ui_size_x;
|
||||
@@ -114,9 +114,9 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
|
||||
if (!pup->layout) {
|
||||
ui_popover_create_block(C, handle->region, pup, WM_OP_INVOKE_REGION_WIN);
|
||||
|
||||
if (pup->menu_func) {
|
||||
if (pup->popover_func) {
|
||||
pup->block->handle = handle;
|
||||
pup->menu_func(C, pup->layout, const_cast<PanelType *>(pup->menu_arg));
|
||||
pup->popover_func(C, pup->layout, const_cast<PanelType *>(pup->panel_type));
|
||||
pup->block->handle = nullptr;
|
||||
}
|
||||
|
||||
@@ -185,6 +185,20 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
|
||||
* areas near the bottom of the window on refreshes. */
|
||||
handle->max_size_y = UI_UNIT_Y * 16.0f;
|
||||
}
|
||||
else if (pup->panel_type &&
|
||||
(pup->panel_type->offset_units_xy.x || pup->panel_type->offset_units_xy.y))
|
||||
{
|
||||
UI_block_flag_enable(block, UI_BLOCK_LOOP);
|
||||
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
|
||||
UI_block_direction_set(block, block->direction);
|
||||
block->minbounds = UI_MENU_WIDTH_MIN;
|
||||
|
||||
const int bounds_offset[2] = {
|
||||
int(pup->panel_type->offset_units_xy.x * UI_UNIT_X),
|
||||
int(pup->panel_type->offset_units_xy.y * UI_UNIT_Y),
|
||||
};
|
||||
UI_block_bounds_set_popup(block, block_margin, bounds_offset);
|
||||
}
|
||||
else {
|
||||
/* Not attached to a button. */
|
||||
int bounds_offset[2] = {0, 0};
|
||||
@@ -233,20 +247,20 @@ static void ui_block_free_func_POPOVER(void *arg_pup)
|
||||
wmWindow *window = pup->window;
|
||||
WM_event_remove_keymap_handler(&window->modalhandlers, pup->keymap);
|
||||
}
|
||||
MEM_freeN(pup);
|
||||
MEM_delete(pup);
|
||||
}
|
||||
|
||||
uiPopupBlockHandle *ui_popover_panel_create(bContext *C,
|
||||
ARegion *butregion,
|
||||
uiBut *but,
|
||||
uiMenuCreateFunc menu_func,
|
||||
uiPopoverCreateFunc popover_func,
|
||||
const PanelType *panel_type)
|
||||
{
|
||||
wmWindow *window = CTX_wm_window(C);
|
||||
const uiStyle *style = UI_style_get_dpi();
|
||||
|
||||
/* Create popover, buttons are created from callback. */
|
||||
uiPopover *pup = MEM_cnew<uiPopover>(__func__);
|
||||
uiPopover *pup = MEM_new<uiPopover>(__func__);
|
||||
pup->but = but;
|
||||
|
||||
/* FIXME: maybe one day we want non panel popovers? */
|
||||
@@ -259,8 +273,8 @@ uiPopupBlockHandle *ui_popover_panel_create(bContext *C,
|
||||
(text_points_max / float(UI_DEFAULT_TEXT_POINTS));
|
||||
}
|
||||
|
||||
pup->menu_func = menu_func;
|
||||
pup->menu_arg = panel_type;
|
||||
pup->popover_func = popover_func;
|
||||
pup->panel_type = panel_type;
|
||||
|
||||
#ifdef USE_UI_POPOVER_ONCE
|
||||
{
|
||||
@@ -335,7 +349,7 @@ int UI_popover_panel_invoke(bContext *C, const char *idname, bool keep_open, Rep
|
||||
|
||||
uiPopover *UI_popover_begin(bContext *C, int ui_menu_width, bool from_active_button)
|
||||
{
|
||||
uiPopover *pup = MEM_cnew<uiPopover>(__func__);
|
||||
uiPopover *pup = MEM_new<uiPopover>(__func__);
|
||||
if (ui_menu_width == 0) {
|
||||
ui_menu_width = U.widget_unit * UI_POPOVER_WIDTH_UNITS;
|
||||
}
|
||||
|
||||
@@ -7,28 +7,28 @@
|
||||
*/
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_report.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_interface_c.hh"
|
||||
#include "UI_resources.hh"
|
||||
#include "interface_intern.hh"
|
||||
|
||||
#include "ED_asset_shelf.hh"
|
||||
|
||||
namespace blender::ui {
|
||||
#include "WM_api.hh"
|
||||
|
||||
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);
|
||||
}
|
||||
namespace blender::ui {
|
||||
|
||||
void template_asset_shelf_popover(uiLayout &layout,
|
||||
const bContext &C,
|
||||
const StringRefNull asset_shelf_id,
|
||||
const StringRef name,
|
||||
const StringRefNull name,
|
||||
const BIFIconID icon)
|
||||
{
|
||||
AssetShelfType *shelf_type = ed::asset::shelf::type_find_from_idname(asset_shelf_id);
|
||||
@@ -38,30 +38,64 @@ void template_asset_shelf_popover(uiLayout &layout,
|
||||
}
|
||||
|
||||
const ARegion *region = CTX_wm_region(&C);
|
||||
uiBlock *block = uiLayoutGetBlock(&layout);
|
||||
|
||||
uiLayout *row = uiLayoutRow(&layout, true);
|
||||
const bool use_big_size = !RGN_TYPE_IS_HEADER_ANY(region->regiontype);
|
||||
const bool use_preview_icon = use_big_size;
|
||||
const short width = [&]() -> short {
|
||||
if (use_big_size) {
|
||||
return UI_UNIT_X * 6;
|
||||
}
|
||||
return UI_UNIT_X * (name.is_empty() ? 1.6f : 7);
|
||||
}();
|
||||
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");
|
||||
uiLayoutSetContextString(row, "asset_shelf_idname", asset_shelf_id);
|
||||
if (use_big_size) {
|
||||
uiLayoutSetScaleX(row, 6);
|
||||
uiLayoutSetScaleY(row, 6);
|
||||
}
|
||||
else {
|
||||
uiLayoutSetUnitsX(row, name.is_empty() ? 1.6f : 7);
|
||||
}
|
||||
|
||||
uiItemPopoverPanel(row, &C, "ASSETSHELF_PT_popover_panel", name.c_str(), icon);
|
||||
uiBut *but = static_cast<uiBut *>(block->buttons.last);
|
||||
if (use_preview_icon) {
|
||||
ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
|
||||
}
|
||||
else {
|
||||
ui_def_but_icon(but, icon, UI_HAS_ICON);
|
||||
UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
|
||||
}
|
||||
|
||||
bool asset_shelf_popover_invoke(bContext &C, StringRef asset_shelf_idname, ReportList &reports)
|
||||
{
|
||||
AssetShelfType *shelf_type = ed::asset::shelf::type_find_from_idname(asset_shelf_idname);
|
||||
if (ed::asset::shelf::type_poll_for_popup(C, shelf_type) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ed::asset::shelf::type_poll_for_popup(C, shelf_type) == false) {
|
||||
UI_but_flag_enable(but, UI_BUT_DISABLED);
|
||||
PanelType *pt = WM_paneltype_find("ASSETSHELF_PT_popover_panel", true);
|
||||
if (pt == nullptr) {
|
||||
BKE_reportf(&reports, RPT_ERROR, "Asset shelf popover panel type not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Skip panel poll check here. Should usually be done, but requires passing the asset shelf type
|
||||
* name via some context-store, but there's nothing to provide that here. Asset shelf type is
|
||||
* polled above, so it's okay. */
|
||||
|
||||
std::string asset_shelf_id_str = asset_shelf_idname;
|
||||
ui_popover_panel_create(
|
||||
&C,
|
||||
nullptr,
|
||||
nullptr,
|
||||
[asset_shelf_id_str](bContext *C, uiLayout *layout, void *arg_pt) {
|
||||
uiLayoutSetContextString(layout, "asset_shelf_idname", asset_shelf_id_str);
|
||||
ui_item_paneltype_func(C, layout, arg_pt);
|
||||
},
|
||||
pt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace blender::ui
|
||||
|
||||
using namespace blender;
|
||||
|
||||
std::optional<StringRefNull> UI_asset_shelf_idname_from_button_context(const uiBut *but)
|
||||
{
|
||||
return UI_but_context_string_get(but, "asset_shelf_idname");
|
||||
}
|
||||
|
||||
@@ -1224,7 +1224,7 @@ void ED_spacetype_image()
|
||||
art->listener = asset::shelf::header_region_listen;
|
||||
art->context = asset::shelf::context;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
asset::shelf::header_regiontype_register(art, SPACE_IMAGE);
|
||||
asset::shelf::types_register(art, SPACE_IMAGE);
|
||||
|
||||
/* regions: hud */
|
||||
art = ED_area_type_hud(st->spaceid);
|
||||
|
||||
@@ -2199,7 +2199,7 @@ void ED_spacetype_view3d()
|
||||
art->listener = asset::shelf::header_region_listen;
|
||||
art->context = asset::shelf::context;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
asset::shelf::header_regiontype_register(art, SPACE_VIEW3D);
|
||||
asset::shelf::types_register(art, SPACE_VIEW3D);
|
||||
|
||||
/* regions: hud */
|
||||
art = ED_area_type_hud(st->spaceid);
|
||||
|
||||
@@ -973,7 +973,7 @@ void rna_uiTemplateAssetShelfPopover(uiLayout *layout,
|
||||
icon = icon_value;
|
||||
}
|
||||
|
||||
blender::ui::template_asset_shelf_popover(*layout, *C, asset_shelf_id, name, icon);
|
||||
blender::ui::template_asset_shelf_popover(*layout, *C, asset_shelf_id, name ? name : "", icon);
|
||||
}
|
||||
|
||||
PointerRNA rna_uiTemplatePopupConfirm(uiLayout *layout,
|
||||
|
||||
@@ -2254,6 +2254,39 @@ static void WM_OT_call_panel(wmOperatorType *ot)
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
static int asset_shelf_popover_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
char *asset_shelf_id = RNA_string_get_alloc(op->ptr, "name", nullptr, 0, nullptr);
|
||||
BLI_SCOPED_DEFER([&]() { MEM_freeN(asset_shelf_id); });
|
||||
|
||||
if (!blender::ui::asset_shelf_popover_invoke(*C, asset_shelf_id, *op->reports)) {
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
return OPERATOR_INTERFACE;
|
||||
}
|
||||
|
||||
/* Needs to be defined at WM level to be globally accessible. */
|
||||
static void WM_OT_call_asset_shelf_popover(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Call Asset Shelf Popover";
|
||||
ot->idname = "WM_OT_call_asset_shelf_popover";
|
||||
ot->description = "Open a predefined asset shelf in a popup";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = asset_shelf_popover_invoke;
|
||||
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
|
||||
RNA_def_string(ot->srna,
|
||||
"name",
|
||||
nullptr,
|
||||
0,
|
||||
"Asset Shelf Name",
|
||||
"Identifier of the asset shelf to display");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -4140,6 +4173,7 @@ void wm_operatortypes_register()
|
||||
WM_operatortype_append(WM_OT_call_menu);
|
||||
WM_operatortype_append(WM_OT_call_menu_pie);
|
||||
WM_operatortype_append(WM_OT_call_panel);
|
||||
WM_operatortype_append(WM_OT_call_asset_shelf_popover);
|
||||
WM_operatortype_append(WM_OT_radial_control);
|
||||
WM_operatortype_append(WM_OT_stereo3d_set);
|
||||
#if defined(WIN32)
|
||||
|
||||
Reference in New Issue
Block a user