Fix: UI: Improve scrollbar hotspot region

Mouse and action zone interaction for scrollbars depend on `v2d->vert`
and `v2d->hor`, which are updated through `view2d_masks`. However,
scrollbar drawing through `UI_view2d_scrollers_draw` calls
`view2d_scrollers_calc`, which pads these sizes further, meaning that
drawn scrollbars are slightly out of sync with their hotspots. This is
noticeable at track edges for shrinking scrollers or when tracks are
opaque. Fix by moving the extra (noticeable) padding code from
`view2d_scrollers_calc` to `view2d_masks`.

Pull Request: https://projects.blender.org/blender/blender/pulls/135021
This commit is contained in:
John Kiril Swenson
2025-03-11 01:10:48 +01:00
committed by Harley Acheson
parent d29f631b18
commit d8f3f8cc61
5 changed files with 29 additions and 26 deletions
@@ -2222,6 +2222,9 @@ ENUM_OPERATORS(eUI_Item_Flag, UI_ITEM_R_TEXT_BUT_FORCE_SEMI_MODAL_ACTIVE)
#define UI_HEADER_OFFSET ((void)0, 0.4f * UI_UNIT_X)
#define UI_AZONESPOTW UI_HEADER_OFFSET /* Width of corner action zone #AZone. */
#define UI_AZONESPOTH (0.6f * U.widget_unit) /* Height of corner action zone #AZone. */
/* uiLayoutOperatorButs flags */
enum {
UI_TEMPLATE_OP_PROPS_SHOW_TITLE = 1 << 0,
@@ -189,11 +189,20 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
v2d->hor.ymin = v2d->hor.ymax - scroll_height;
}
/* adjust vertical scroller if there's a horizontal scroller, to leave corner free */
/* Adjust horizontal scroller to avoid interfering with splitter areas. */
if (scroll & V2D_SCROLL_HORIZONTAL) {
v2d->hor.xmin += UI_AZONESPOTW;
v2d->hor.xmax -= UI_AZONESPOTW;
}
/* Adjust vertical scroller to avoid horizontal scrollers and splitter areas. */
if (scroll & V2D_SCROLL_VERTICAL) {
/* Note that top splitter areas are in the header,
* outside of `mask_scroll`, so we can ignore them. */
v2d->vert.ymin += UI_AZONESPOTH;
if (scroll & V2D_SCROLL_BOTTOM) {
/* on bottom edge of region */
v2d->vert.ymin = v2d->hor.ymax;
v2d->vert.ymin = max_ii(v2d->hor.ymax, v2d->vert.ymin);
}
else if (scroll & V2D_SCROLL_TOP) {
/* on upper edge of region */
@@ -1376,7 +1385,6 @@ void view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom, View2DScrollers
rcti vert, hor;
float fac1, fac2, totsize, scrollsize;
const int scroll = view2d_scroll_mapped(v2d->scroll);
int smaller;
/* Always update before drawing (for dynamically sized scrollers). */
view2d_masks(v2d, mask_custom);
@@ -1384,26 +1392,20 @@ void view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom, View2DScrollers
vert = v2d->vert;
hor = v2d->hor;
/* slider rects need to be smaller than region and not interfere with splitter areas */
hor.xmin += UI_HEADER_OFFSET;
hor.xmax -= UI_HEADER_OFFSET;
vert.ymin += UI_HEADER_OFFSET;
vert.ymax -= UI_HEADER_OFFSET;
/* width of sliders */
smaller = int(0.1f * U.widget_unit);
/* Pad scrollbar drawing away from region edges. */
const int edge_pad = int(0.1f * U.widget_unit);
if (scroll & V2D_SCROLL_BOTTOM) {
hor.ymin += smaller;
hor.ymin += edge_pad;
}
else {
hor.ymax -= smaller;
hor.ymax -= edge_pad;
}
if (scroll & V2D_SCROLL_LEFT) {
vert.xmin += smaller;
vert.xmin += edge_pad;
}
else {
vert.xmax -= smaller;
vert.xmax -= edge_pad;
}
CLAMP_MAX(vert.ymin, vert.ymax - V2D_SCROLL_HANDLE_SIZE_HOTSPOT);
+8 -8
View File
@@ -1002,21 +1002,21 @@ static void area_azone_init(const wmWindow *win, const bScreen *screen, ScrArea
/* Bottom-left. */
{area->totrct.xmin - U.pixelsize,
area->totrct.ymin - U.pixelsize,
area->totrct.xmin + AZONESPOTW,
area->totrct.ymin + AZONESPOTH},
area->totrct.xmin + UI_AZONESPOTW,
area->totrct.ymin + UI_AZONESPOTH},
/* Bottom-right. */
{area->totrct.xmax - AZONESPOTW,
{area->totrct.xmax - UI_AZONESPOTW,
area->totrct.ymin - U.pixelsize,
area->totrct.xmax + U.pixelsize,
area->totrct.ymin + AZONESPOTH},
area->totrct.ymin + UI_AZONESPOTH},
/* Top-left. */
{area->totrct.xmin - U.pixelsize,
area->totrct.ymax - AZONESPOTH,
area->totrct.xmin + AZONESPOTW,
area->totrct.ymax - UI_AZONESPOTH,
area->totrct.xmin + UI_AZONESPOTW,
area->totrct.ymax + U.pixelsize},
/* Top-right. */
{area->totrct.xmax - AZONESPOTW,
area->totrct.ymax - AZONESPOTH,
{area->totrct.xmax - UI_AZONESPOTW,
area->totrct.ymax - UI_AZONESPOTH,
area->totrct.xmax + U.pixelsize,
area->totrct.ymax + U.pixelsize},
};
@@ -59,8 +59,6 @@ enum class AreaDockTarget {
Center, /* Middle portion of area. */
};
#define AZONESPOTW UI_HEADER_OFFSET /* width of corner #AZone - max */
#define AZONESPOTH (0.6f * U.widget_unit) /* height of corner #AZone */
#define AZONEFADEIN (5.0f * U.widget_unit) /* when #AZone is totally visible */
#define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the #AZone */
+1 -1
View File
@@ -898,7 +898,7 @@ static AZone *area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const b
}
else {
const int mouse_sq = square_i(xy[0] - az->x2) + square_i(xy[1] - az->y2);
const int spot_sq = square_i(AZONESPOTW);
const int spot_sq = square_i(UI_AZONESPOTW);
const int fadein_sq = square_i(AZONEFADEIN);
const int fadeout_sq = square_i(AZONEFADEOUT);