UI: Remove asset view template specific UI list features

Reverts most of the additions from ae1dc8f5f9 and 68c6fc6d38 to allow
internally defined UI lists to set operators to execute on click and
drag events. This was added and used only for the asset view UI
template was removed for 5.0 in the previous commit, as part of #110461.

Pull Request: https://projects.blender.org/blender/blender/pulls/140149
This commit is contained in:
Julian Eisel 2025-06-12 11:50:41 +02:00 committed by Gitea
parent ae9ca35e3b
commit e9bb58e6df
8 changed files with 8 additions and 389 deletions

View File

@ -2647,19 +2647,6 @@ void template_tree(uiLayout *layout, bContext *C);
*/ */
bool UI_list_item_index_is_filtered_visible(const struct uiList *ui_list, int item_idx); bool UI_list_item_index_is_filtered_visible(const struct uiList *ui_list, int item_idx);
/**
* \return An RNA pointer for the operator properties.
*/
PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list,
blender::StringRefNull opname,
bool create_properties);
/**
* \return An RNA pointer for the operator properties.
*/
PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
blender::StringRefNull opname,
bool create_properties);
/* UI Operators */ /* UI Operators */
struct uiDragColorHandle { struct uiDragColorHandle {
float color[4]; float color[4];
@ -2902,18 +2889,6 @@ void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p);
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src); bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src);
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
/**
* A version of #WM_key_event_operator_string that's limited to UI elements.
*
* This supports showing shortcuts in context-menus (for example),
* for actions that can also be activated using shortcuts while the cursor is over the button.
* Without this those shortcuts aren't discoverable for users.
*/
std::optional<std::string> UI_key_event_operator_string(const bContext *C,
blender::StringRefNull opname,
IDProperty *properties,
bool is_strict);
/* ui_interface_region_tooltip.c */ /* ui_interface_region_tooltip.c */
/** /**

View File

@ -1261,42 +1261,6 @@ static void ui_apply_but_VIEW_ITEM(bContext *C,
ui_apply_but_ROW(C, block, but, data); ui_apply_but_ROW(C, block, but, data);
} }
/**
* \note Ownership of \a properties is moved here. The #uiAfterFunc owns it now.
*
* \param context_but: The button to use context from when calling or polling the operator.
*
* \returns true if the operator was executed, otherwise false.
*/
static bool ui_list_invoke_item_operator(bContext *C,
const uiBut *context_but,
wmOperatorType *ot,
PointerRNA **properties)
{
if (!ui_but_context_poll_operator(C, ot, context_but)) {
return false;
}
/* Allow the context to be set from the hovered button, so the list item draw callback can set
* context for the operators. */
ui_handle_afterfunc_add_operator_ex(ot, properties, WM_OP_INVOKE_DEFAULT, context_but);
return true;
}
static void ui_apply_but_LISTROW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
{
uiBut *listbox = ui_list_find_from_row(data->region, but);
if (listbox) {
uiList *list = static_cast<uiList *>(listbox->custom_data);
if (list && list->dyn_data->custom_activate_optype) {
ui_list_invoke_item_operator(
C, but, list->dyn_data->custom_activate_optype, &list->dyn_data->custom_activate_opptr);
}
}
ui_apply_but_ROW(C, block, but, data);
}
static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data) static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
{ {
if (!data->text_edit.edit_string) { if (!data->text_edit.edit_string) {
@ -2410,15 +2374,13 @@ static void ui_apply_but(
case UI_BTYPE_CHECKBOX_N: case UI_BTYPE_CHECKBOX_N:
ui_apply_but_TOG(C, but, data); ui_apply_but_TOG(C, but, data);
break; break;
case UI_BTYPE_LISTROW:
case UI_BTYPE_ROW: case UI_BTYPE_ROW:
ui_apply_but_ROW(C, block, but, data); ui_apply_but_ROW(C, block, but, data);
break; break;
case UI_BTYPE_VIEW_ITEM: case UI_BTYPE_VIEW_ITEM:
ui_apply_but_VIEW_ITEM(C, block, but, data); ui_apply_but_VIEW_ITEM(C, block, but, data);
break; break;
case UI_BTYPE_LISTROW:
ui_apply_but_LISTROW(C, block, but, data);
break;
case UI_BTYPE_TAB: case UI_BTYPE_TAB:
ui_apply_but_TAB(C, but, data); ui_apply_but_TAB(C, but, data);
break; break;
@ -5208,15 +5170,6 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
{ {
ret = WM_UI_HANDLER_CONTINUE; ret = WM_UI_HANDLER_CONTINUE;
} }
/* Same special case handling for UI lists. Return CONTINUE so that a tweak or CLICK event
* will be sent for the list to work with. */
const uiBut *listbox = ui_list_find_mouse_over(data->region, event);
if (listbox) {
const uiList *ui_list = static_cast<const uiList *>(listbox->custom_data);
if (ui_list && ui_list->dyn_data->custom_drag_optype) {
ret = WM_UI_HANDLER_CONTINUE;
}
}
const uiBut *view_but = ui_view_item_find_mouse_over(data->region, event->xy); const uiBut *view_but = ui_view_item_find_mouse_over(data->region, event->xy);
if (view_but) { if (view_but) {
ret = WM_UI_HANDLER_CONTINUE; ret = WM_UI_HANDLER_CONTINUE;
@ -9957,133 +9910,6 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
return retval; return retval;
} }
/**
* Activate the underlying list-row button, so the row is highlighted.
* Early exits if \a activate_dragging is true, but the custom drag operator fails to execute.
* Gives the wanted behavior where the item is activated on a click-drag event when the custom drag
* operator is executed.
*/
static int ui_list_activate_hovered_row(bContext *C,
ARegion *region,
const uiList *ui_list,
const wmEvent *event,
bool activate_dragging)
{
const bool do_drag = activate_dragging && ui_list->dyn_data->custom_drag_optype;
if (do_drag) {
const uiBut *hovered_but = ui_but_find_mouse_over(region, event);
if (!ui_list_invoke_item_operator(C,
hovered_but,
ui_list->dyn_data->custom_drag_optype,
&ui_list->dyn_data->custom_drag_opptr))
{
return WM_UI_HANDLER_CONTINUE;
}
}
int mouse_xy[2];
WM_event_drag_start_xy(event, mouse_xy);
uiBut *listrow = ui_list_row_find_mouse_over(region, mouse_xy);
if (listrow) {
wmOperatorType *custom_activate_optype = ui_list->dyn_data->custom_activate_optype;
/* Hacky: Ensure the custom activate operator is not called when the custom drag operator
* was. Only one should run! */
if (activate_dragging && do_drag) {
((uiList *)ui_list)->dyn_data->custom_activate_optype = nullptr;
}
/* Simulate click on listrow button itself (which may be overlapped by another button). Also
* calls the custom activate operator (#uiListDyn::custom_activate_optype). */
UI_but_execute(C, region, listrow);
((uiList *)ui_list)->dyn_data->custom_activate_optype = custom_activate_optype;
}
return WM_UI_HANDLER_BREAK;
}
static bool ui_list_is_hovering_draggable_but(bContext *C,
const uiList *list,
const ARegion *region,
const wmEvent *event)
{
/* On a tweak event, uses the coordinates from where tweaking was started. */
int mouse_xy[2];
WM_event_drag_start_xy(event, mouse_xy);
const uiBut *hovered_but = ui_but_find_mouse_over_ex(
region, mouse_xy, false, false, nullptr, nullptr);
if (list->dyn_data->custom_drag_optype) {
if (ui_but_context_poll_operator(C, list->dyn_data->custom_drag_optype, hovered_but)) {
return true;
}
}
return (hovered_but && ui_but_drag_is_draggable(hovered_but));
}
static int ui_list_handle_click_drag(bContext *C,
const uiList *ui_list,
ARegion *region,
const wmEvent *event)
{
if (event->type != LEFTMOUSE) {
return WM_UI_HANDLER_CONTINUE;
}
int retval = WM_UI_HANDLER_CONTINUE;
const bool is_draggable = ui_list_is_hovering_draggable_but(C, ui_list, region, event);
bool activate = false;
bool activate_dragging = false;
if (event->val == KM_CLICK_DRAG) {
if (is_draggable) {
activate_dragging = true;
activate = true;
}
}
/* #KM_CLICK is only sent after an uncaught release event, so the foreground button gets all
* regular events (including mouse presses to start dragging) and this part only kicks in if it
* hasn't handled the release event. Note that if there's no overlaid button, the row selects
* on the press event already via regular #UI_BTYPE_LISTROW handling. */
else if (event->val == KM_CLICK) {
activate = true;
}
if (activate) {
retval = ui_list_activate_hovered_row(C, region, ui_list, event, activate_dragging);
}
return retval;
}
static void ui_list_activate_row_from_index(
bContext *C, ARegion *region, uiBut *listbox, uiList *ui_list, int index)
{
uiBut *new_active_row = ui_list_row_find_index(region, index, listbox);
if (new_active_row) {
/* Preferred way to update the active item, also calls the custom activate operator
* (#uiListDyn::custom_activate_optype). */
UI_but_execute(C, region, new_active_row);
}
else {
/* A bit ugly, set the active index in RNA directly. That's because a button that's
* scrolled away in the list box isn't created at all.
* The custom activate operator (#uiListDyn::custom_activate_optype) is not called in this case
* (which may need the row button context). */
RNA_property_int_set(&listbox->rnapoin, listbox->rnaprop, index);
RNA_property_update(C, &listbox->rnapoin, listbox->rnaprop);
ui_apply_but_undo(listbox);
}
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
}
static int ui_list_get_increment(const uiList *ui_list, const int type, const int columns) static int ui_list_get_increment(const uiList *ui_list, const int type, const int columns)
{ {
int increment = 0; int increment = 0;
@ -10139,10 +9965,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi
} }
} }
if (event->type == LEFTMOUSE) { if (val == KM_PRESS) {
retval = ui_list_handle_click_drag(C, ui_list, region, event);
}
else if (val == KM_PRESS) {
if ((ELEM(type, EVT_UPARROWKEY, EVT_DOWNARROWKEY, EVT_LEFTARROWKEY, EVT_RIGHTARROWKEY) && if ((ELEM(type, EVT_UPARROWKEY, EVT_DOWNARROWKEY, EVT_LEFTARROWKEY, EVT_RIGHTARROWKEY) &&
(event->modifier == 0)) || (event->modifier == 0)) ||
(ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && (event->modifier == KM_CTRL))) (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && (event->modifier == KM_CTRL)))
@ -10196,7 +10019,12 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi
CLAMP(value, min, max); CLAMP(value, min, max);
if (value != value_orig) { if (value != value_orig) {
ui_list_activate_row_from_index(C, region, listbox, ui_list, value); RNA_property_int_set(&listbox->rnapoin, listbox->rnaprop, value);
RNA_property_update(C, &listbox->rnapoin, listbox->rnaprop);
ui_apply_but_undo(listbox);
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
redraw = true; redraw = true;
} }
retval = WM_UI_HANDLER_BREAK; retval = WM_UI_HANDLER_BREAK;

View File

@ -1504,7 +1504,6 @@ bool ui_but_contains_point_px(const uiBut *but, const ARegion *region, const int
uiBut *ui_list_find_mouse_over(const ARegion *region, uiBut *ui_list_find_mouse_over(const ARegion *region,
const wmEvent *event) ATTR_WARN_UNUSED_RESULT; const wmEvent *event) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_list_find_from_row(const ARegion *region, const uiBut *row_but) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_list_row_find_mouse_over(const ARegion *region, const int xy[2]) uiBut *ui_list_row_find_mouse_over(const ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT; ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_list_row_find_index(const ARegion *region, uiBut *ui_list_row_find_index(const ARegion *region,

View File

@ -459,17 +459,6 @@ static bool ui_list_contains_row(const uiBut *listbox_but, const uiBut *listrow_
return ui_but_rna_equals(listbox_but, listrow_but); return ui_but_rna_equals(listbox_but, listrow_but);
} }
static bool ui_but_is_listbox_with_row(const uiBut *but, const void *customdata)
{
const uiBut *row_but = static_cast<const uiBut *>(customdata);
return (but->type == UI_BTYPE_LISTBOX) && ui_list_contains_row(but, row_but);
}
uiBut *ui_list_find_from_row(const ARegion *region, const uiBut *row_but)
{
return ui_but_find(region, ui_but_is_listbox_with_row, row_but);
}
static bool ui_but_is_listrow(const uiBut *but, const void * /*customdata*/) static bool ui_but_is_listrow(const uiBut *but, const void * /*customdata*/)
{ {
return but->type == UI_BTYPE_LISTROW; return but->type == UI_BTYPE_LISTROW;

View File

@ -26,7 +26,6 @@
#include "BKE_context.hh" #include "BKE_context.hh"
#include "BKE_global.hh" #include "BKE_global.hh"
#include "BKE_idprop.hh"
#include "BKE_lib_id.hh" #include "BKE_lib_id.hh"
#include "BKE_screen.hh" #include "BKE_screen.hh"
@ -1032,115 +1031,3 @@ void UI_butstore_update(uiBlock *block)
} }
/** \} */ /** \} */
/* -------------------------------------------------------------------- */
/** \name Key Event from UI
* \{ */
/**
* Follow the logic from #wm_keymap_item_find_in_keymap.
*/
static bool ui_key_event_property_match(const StringRefNull opname,
IDProperty *properties,
const bool is_strict,
wmOperatorType *ui_optype,
PointerRNA *ui_opptr)
{
if (ui_optype->idname != opname) {
return false;
}
bool match = false;
if (properties) {
if (ui_opptr &&
IDP_EqualsProperties_ex(properties, static_cast<IDProperty *>(ui_opptr->data), is_strict))
{
match = true;
}
}
else {
match = true;
}
return match;
}
std::optional<std::string> UI_key_event_operator_string(const bContext *C,
const StringRefNull opname,
IDProperty *properties,
const bool is_strict)
{
/* NOTE: currently only actions on UI Lists are supported (for the asset manager).
* Other kinds of events can be supported as needed. */
ARegion *region = CTX_wm_region(C);
if (region == nullptr) {
return std::nullopt;
}
/* Early exit regions which don't have UI-Lists. */
if ((region->runtime->type->keymapflag & ED_KEYMAP_UI) == 0) {
return std::nullopt;
}
uiBut *but = UI_region_active_but_get(region);
if (but == nullptr) {
return std::nullopt;
}
if (but->type != UI_BTYPE_PREVIEW_TILE) {
return std::nullopt;
}
short event_val = KM_NOTHING;
short event_type = KM_NOTHING;
uiBut *listbox = nullptr;
for (int i = but->block->buttons.size() - 1; i >= 0; i--) {
uiBut *but_iter = but->block->buttons[i].get();
if ((but_iter->type == UI_BTYPE_LISTBOX) && ui_but_contains_rect(but_iter, &but->rect)) {
listbox = but_iter;
break;
}
}
if (listbox && listbox->custom_data) {
uiList *list = static_cast<uiList *>(listbox->custom_data);
uiListDyn *dyn_data = list->dyn_data;
if ((dyn_data->custom_activate_optype != nullptr) &&
ui_key_event_property_match(opname,
properties,
is_strict,
dyn_data->custom_activate_optype,
dyn_data->custom_activate_opptr))
{
event_val = KM_CLICK;
event_type = LEFTMOUSE;
}
else if ((dyn_data->custom_activate_optype != nullptr) &&
ui_key_event_property_match(opname,
properties,
is_strict,
dyn_data->custom_drag_optype,
dyn_data->custom_drag_opptr))
{
event_val = KM_CLICK_DRAG;
event_type = LEFTMOUSE;
}
}
if ((event_val != KM_NOTHING) && (event_type != KM_NOTHING)) {
return WM_keymap_item_raw_to_string(KM_NOTHING,
KM_NOTHING,
KM_NOTHING,
KM_NOTHING,
KM_NOTHING,
0,
event_val,
event_type,
false);
}
return std::nullopt;
}
/** \} */

View File

@ -346,15 +346,6 @@ static void uilist_free_dyn_data(uiList *ui_list)
return; return;
} }
if (dyn_data->custom_activate_opptr) {
WM_operator_properties_free(dyn_data->custom_activate_opptr);
MEM_delete(dyn_data->custom_activate_opptr);
}
if (dyn_data->custom_drag_opptr) {
WM_operator_properties_free(dyn_data->custom_drag_opptr);
MEM_delete(dyn_data->custom_drag_opptr);
}
MEM_SAFE_FREE(dyn_data->items_filter_flags); MEM_SAFE_FREE(dyn_data->items_filter_flags);
MEM_SAFE_FREE(dyn_data->items_filter_neworder); MEM_SAFE_FREE(dyn_data->items_filter_neworder);
MEM_SAFE_FREE(dyn_data->customdata); MEM_SAFE_FREE(dyn_data->customdata);
@ -1300,46 +1291,6 @@ void uiTemplateList(uiLayout *layout,
nullptr); nullptr);
} }
PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list,
const StringRefNull opname,
bool create_properties)
{
uiListDyn *dyn_data = ui_list->dyn_data;
dyn_data->custom_activate_optype = WM_operatortype_find(opname.c_str(), false);
if (!dyn_data->custom_activate_optype) {
return nullptr;
}
if (create_properties) {
PointerRNA *opptr = dyn_data->custom_activate_opptr;
WM_operator_properties_alloc(&dyn_data->custom_activate_opptr,
opptr ? (IDProperty **)&opptr->data : nullptr,
opname.c_str());
}
return dyn_data->custom_activate_opptr;
}
PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
const StringRefNull opname,
bool create_properties)
{
uiListDyn *dyn_data = ui_list->dyn_data;
dyn_data->custom_drag_optype = WM_operatortype_find(opname.c_str(), false);
if (!dyn_data->custom_drag_optype) {
return nullptr;
}
if (create_properties) {
PointerRNA *opptr = dyn_data->custom_drag_opptr;
WM_operator_properties_alloc(&dyn_data->custom_drag_opptr,
opptr ? (IDProperty **)&opptr->data : nullptr,
opname.c_str());
}
return dyn_data->custom_drag_opptr;
}
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/** \name List-types Registration /** \name List-types Registration

View File

@ -303,9 +303,6 @@ typedef struct uiListDyn {
int *items_filter_neworder; int *items_filter_neworder;
struct wmOperatorType *custom_drag_optype; struct wmOperatorType *custom_drag_optype;
struct PointerRNA *custom_drag_opptr;
struct wmOperatorType *custom_activate_optype;
struct PointerRNA *custom_activate_opptr;
} uiListDyn; } uiListDyn;
typedef struct uiList { /* some list UI data need to be saved in file */ typedef struct uiList { /* some list UI data need to be saved in file */

View File

@ -1645,13 +1645,6 @@ std::optional<std::string> WM_key_event_operator_string(const bContext *C,
return WM_keymap_item_to_string(kmi, false); return WM_keymap_item_to_string(kmi, false);
} }
/* Check UI state (non key-map actions for UI regions). */
if (std::optional<std::string> result = UI_key_event_operator_string(
C, opname, properties, is_strict))
{
return result;
}
return std::nullopt; return std::nullopt;
} }