UX: Prevent click-through panels and used header area

Does two main changes:
* Handle regions in the order as visible on screen. Practically this
  just means handling overlapping regions before non-overlapping ones.
* Don't handle any other regions after having found one containing the
  mouse pointer.

Fixes: T94016, T91538, T91579, T71899 (and a whole bunch of duplicates)
Addresses: T92364

Differential Revision: https://developer.blender.org/D13539

Reviewed by: Campbell Barton
This commit is contained in:
Julian Eisel 2022-01-27 18:35:43 +01:00
parent 4710f3346a
commit 87c13ac68c
Notes: blender-bot 2023-02-14 00:07:57 +01:00
Referenced by commit fb87578698, Fix T96255: Node socket fails to drag
Referenced by issue #94016, Pose Library: Clicking through the interface
Referenced by issue #92364, UX: Prevent click-through panels and used header area
Referenced by issue #91579, Click and drag on the right panel tabs will call active tool (Tweak, Box Select etc)
Referenced by issue #91538, Pose library panel doesn't play well with left click keymap for viewport rotation
Referenced by issue #86022, 3D View: mouse clicks pass through interface
Referenced by issue #71899, Sculpt move tool is applied when clicking within negative space of UI, regardless of active sculpt tool
1 changed files with 54 additions and 37 deletions

View File

@ -3298,14 +3298,6 @@ static bool wm_event_inside_rect(const wmEvent *event, const rcti *rect)
return false;
}
static bool wm_event_inside_region(const wmEvent *event, const ARegion *region)
{
if (wm_event_always_pass(event)) {
return true;
}
return ED_region_contains_xy(region, event->xy);
}
static ScrArea *area_event_inside(bContext *C, const int xy[2])
{
wmWindow *win = CTX_wm_window(C);
@ -3519,6 +3511,55 @@ static void wm_event_handle_xrevent(bContext *C,
}
#endif /* WITH_XR_OPENXR */
static int wm_event_do_region_handlers(bContext *C, wmEvent *event, ARegion *region)
{
CTX_wm_region_set(C, region);
/* Call even on non mouse events, since the */
wm_region_mouse_co(C, event);
const wmWindowManager *wm = CTX_wm_manager(C);
if (!BLI_listbase_is_empty(&wm->drags)) {
/* Does polls for drop regions and checks #uiButs. */
/* Need to be here to make sure region context is true. */
if (ELEM(event->type, MOUSEMOVE, EVT_DROP) || ISKEYMODIFIER(event->type)) {
wm_drags_check_ops(C, event);
}
}
return wm_handlers_do(C, event, &region->handlers);
}
/**
* Send event to region handlers in \a area.
*
* Two cases:
* 1) Always pass events (#wm_event_always_pass()) are sent to all regions.
* 2) Event is passed to the region visually under the cursor (#ED_area_find_region_xy_visual()).
*/
static int wm_event_do_handlers_area_regions(bContext *C, wmEvent *event, ScrArea *area)
{
/* Case 1. */
if (wm_event_always_pass(event)) {
int action = WM_HANDLER_CONTINUE;
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
action |= wm_event_do_region_handlers(C, event, region);
}
wm_event_handler_return_value_check(event, action);
return action;
}
/* Case 2. */
ARegion *region_hovered = ED_area_find_region_xy_visual(area, RGN_TYPE_ANY, event->xy);
if (!region_hovered) {
return WM_HANDLER_CONTINUE;
}
return wm_event_do_region_handlers(C, event, region_hovered);
}
void wm_event_do_handlers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@ -3701,36 +3742,12 @@ void wm_event_do_handlers(bContext *C)
if (wm_event_inside_rect(event, &area->totrct)) {
CTX_wm_area_set(C, area);
if ((action & WM_HANDLER_BREAK) == 0) {
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (wm_event_inside_region(event, region)) {
action |= wm_event_do_handlers_area_regions(C, event, area);
CTX_wm_region_set(C, region);
/* Call even on non mouse events, since the */
wm_region_mouse_co(C, event);
if (!BLI_listbase_is_empty(&wm->drags)) {
/* Does polls for drop regions and checks #uiButs. */
/* Need to be here to make sure region context is true. */
if (ELEM(event->type, MOUSEMOVE, EVT_DROP) || ISKEYMODIFIER(event->type)) {
wm_drags_check_ops(C, event);
}
}
action |= wm_handlers_do(C, event, &region->handlers);
/* Fileread case (python), T29489. */
if (CTX_wm_window(C) == NULL) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
if (action & WM_HANDLER_BREAK) {
break;
}
}
}
/* Fileread case (python), T29489. */
if (CTX_wm_window(C) == NULL) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
CTX_wm_region_set(C, NULL);