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:
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; });
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user