Fix asset shelf context menu acting on active, not clicked asset

Make sure the view item the context menu is spawned from is always activated.
The brush assets context menu relies on that (it accesses the active brush from
paint settings, and the brush needs to be imported to apply operations like
"Edit Metadata").

Had to refactor how closing the popup on activation works. It's now a general
view feature and enabled by default. Can be disabled using
`ui::AbstractView::set_popup_keep_open()`.

Pull Request: https://projects.blender.org/blender/blender/pulls/124043

Part of the brush assets project, see:
- https://projects.blender.org/blender/blender/issues/116337
- https://projects.blender.org/blender/blender/pulls/106303
This commit is contained in:
Julian Eisel
2024-07-02 16:12:33 +02:00
parent fa6951755e
commit e108517bd6
7 changed files with 56 additions and 20 deletions

View File

@@ -68,7 +68,6 @@ 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 should_be_filtered_visible(StringRefNull filter_string) const override;
@@ -233,14 +232,6 @@ void AssetViewItem::build_context_menu(bContext &C, uiLayout &column) const
}
}
void AssetViewItem::on_activate(bContext & /*C*/)
{
const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());
if (asset_view.is_popup_) {
UI_popup_menu_close_from_but(reinterpret_cast<uiBut *>(this->view_item_button()));
}
}
std::optional<bool> AssetViewItem::should_be_active() const
{
const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());

View File

@@ -88,6 +88,9 @@ class AssetCatalogTreeView : public ui::AbstractTreeView {
[this](const asset_system::AssetRepresentation &asset) {
return (!shelf_.type->asset_poll || shelf_.type->asset_poll(shelf_.type, &asset));
});
/* Keep the popup open when clicking to activate a catalog. */
this->set_popup_keep_open();
}
void build_tree() override

View File

@@ -69,6 +69,8 @@ class AbstractView {
std::optional<rcti> bounds_;
std::string context_menu_title;
/** See #set_popup_keep_open(). */
bool popup_keep_open_ = false;
public:
virtual ~AbstractView() = default;
@@ -117,6 +119,10 @@ class AbstractView {
std::string get_context_menu_title() const;
void set_context_menu_title(const std::string &title);
bool get_popup_keep_open() const;
/** If this view is displayed in a popup, don't close it when clicking to activate items. */
void set_popup_keep_open();
void clear_search_highlight();
protected:

View File

@@ -3453,6 +3453,8 @@ bool UI_view_item_can_rename(const blender::ui::AbstractViewItem &item);
void UI_view_item_begin_rename(blender::ui::AbstractViewItem &item);
bool UI_view_item_supports_drag(const blender::ui::AbstractViewItem &item);
/** If this view is displayed in a popup, don't close it when clicking to activate items. */
bool UI_view_item_popup_keep_open(const blender::ui::AbstractViewItem &item);
/**
* Attempt to start dragging \a item_. This will not work if the view item doesn't
* support dragging, i.e. if it won't create a drag-controller upon request.

View File

@@ -4914,6 +4914,21 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
return WM_UI_HANDLER_CONTINUE;
}
static void force_activate_view_item_but(bContext *C, ARegion *region, uiButViewItem *but)
{
if (but->active) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else {
UI_but_execute(C, region, but);
}
/* By default, activating a view item closes the popup. */
if (!UI_view_item_popup_keep_open(*but->view_item)) {
UI_popup_menu_close_from_but(but);
}
}
static int ui_do_but_VIEW_ITEM(bContext *C,
uiBut *but,
uiHandleButtonData *data,
@@ -4937,7 +4952,7 @@ static int ui_do_but_VIEW_ITEM(bContext *C,
data->dragstarty = event->xy[1];
}
else {
button_activate_state(C, but, BUTTON_STATE_EXIT);
force_activate_view_item_but(C, data->region, view_item_but);
}
return WM_UI_HANDLER_CONTINUE;
@@ -8110,15 +8125,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
(event->modifier & (KM_SHIFT | KM_CTRL | KM_ALT | KM_OSKEY)) == 0 &&
(event->val == KM_PRESS))
{
/* For some button types that are typically representing entire sets of data, right-clicking
* to spawn the context menu should also activate the item. This makes it clear which item
* will be operated on.
* Apply the button immediately, so context menu polls get the right active item. */
/* For some button types that are typically representing entire sets of data,
* right-clicking to spawn the context menu should also activate the item. This makes it
* clear which item will be operated on. Apply the button immediately, so context menu
* polls get the right active item. */
uiBut *clicked_view_item_but = but->type == UI_BTYPE_VIEW_ITEM ?
but :
ui_view_item_find_mouse_over(data->region, event->xy);
if (clicked_view_item_but) {
UI_but_execute(C, data->region, clicked_view_item_but);
ui_apply_but_funcs_after(C);
}
/* RMB has two options now */
@@ -10036,20 +10052,23 @@ static int ui_handle_view_item_event(bContext *C,
if (event->val == KM_PRESS) {
/* Only bother finding the active view item button if the active button isn't already a
* view item. */
uiBut *view_but = (active_but && active_but->type == UI_BTYPE_VIEW_ITEM) ?
active_but :
ui_view_item_find_mouse_over(region, event->xy);
uiButViewItem *view_but = static_cast<uiButViewItem *>(
(active_but && active_but->type == UI_BTYPE_VIEW_ITEM) ?
active_but :
ui_view_item_find_mouse_over(region, event->xy));
/* Will free active button if there already is one. */
if (view_but) {
UI_but_execute(C, region, view_but);
force_activate_view_item_but(C, region, view_but);
}
}
break;
case EVT_RETKEY:
case EVT_PADENTER:
if (event->val == KM_PRESS) {
if (uiBut *search_highlight_but = ui_view_item_find_search_highlight(region)) {
UI_but_execute(C, region, search_highlight_but);
if (uiButViewItem *search_highlight_but = static_cast<uiButViewItem *>(
ui_view_item_find_search_highlight(region)))
{
force_activate_view_item_but(C, region, search_highlight_but);
return WM_UI_HANDLER_BREAK;
}
}

View File

@@ -210,6 +210,16 @@ void AbstractView::set_context_menu_title(const std::string &title)
context_menu_title = title;
}
bool AbstractView::get_popup_keep_open() const
{
return popup_keep_open_;
}
void AbstractView::set_popup_keep_open()
{
popup_keep_open_ = true;
}
void AbstractView::clear_search_highlight()
{
this->foreach_view_item([](AbstractViewItem &item) { item.is_highlighted_search_ = false; });

View File

@@ -386,6 +386,11 @@ bool UI_view_item_supports_drag(const AbstractViewItem &item)
return item.create_drag_controller() != nullptr;
}
bool UI_view_item_popup_keep_open(const AbstractViewItem &item)
{
return item.get_view().get_popup_keep_open();
}
bool UI_view_item_drag_start(bContext &C, const AbstractViewItem &item)
{
const std::unique_ptr<AbstractViewItemDragController> drag_controller =