Mouse should now stick to borders when resize is clamped.

This commit is contained in:
Scott Duensing 2026-03-18 00:20:04 -05:00
parent 83860ac13d
commit fddd97ad91

View file

@ -1900,10 +1900,9 @@ int32_t wmReallocContentBuf(WindowT *win, const DisplayT *d) {
// //
// Initiates a window resize. Unlike drag (which stores mouse-to-origin // Initiates a window resize. Unlike drag (which stores mouse-to-origin
// offset), resize stores the absolute mouse position. wmResizeMove computes // offset), resize stores the absolute mouse position. wmResizeMove computes
// delta from this position each frame, then resets it — this incremental // delta from this position each frame, then conditionally resets it only
// approach avoids accumulating floating-point-like drift and handles the // on axes where the resize was applied. When clamped, the delta accumulates
// case where the resize is clamped (min/max size) without the window // so the border sticks to the mouse when the user reverses direction.
// "catching up" when the mouse returns to range.
void wmResizeBegin(WindowStackT *stack, int32_t idx, int32_t edge, int32_t mouseX, int32_t mouseY) { void wmResizeBegin(WindowStackT *stack, int32_t idx, int32_t edge, int32_t mouseX, int32_t mouseY) {
stack->resizeWindow = idx; stack->resizeWindow = idx;
@ -1975,9 +1974,11 @@ void wmResizeEnd(WindowStackT *stack) {
// //
// After resizing, the content buffer is reallocated and the app is notified // After resizing, the content buffer is reallocated and the app is notified
// via onResize + onPaint. dragOffX/Y are reset to the current mouse position // via onResize + onPaint. dragOffX/Y are reset to the current mouse position
// so the next frame's delta is incremental. This incremental approach means // only on axes where the resize was actually applied. If clamped (window at
// that if the resize is clamped (window at minimum size, user still dragging), // min/max size), dragOff is NOT updated on that axis, so the accumulated
// the window stays put and doesn't snap when the mouse re-enters range. // delta tracks how far the mouse moved past the border. When the user
// reverses direction, the border immediately follows — it "sticks" to
// the mouse pointer instead of creating a dead zone.
// //
// If the user resizes while maximized, the maximized flag is cleared. // If the user resizes while maximized, the maximized flag is cleared.
// This prevents wmRestore from snapping back to the pre-maximize geometry, // This prevents wmRestore from snapping back to the pre-maximize geometry,
@ -2005,6 +2006,13 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
// Mark old position dirty // Mark old position dirty
dirtyListAdd(dl, win->x, win->y, win->w, win->h); dirtyListAdd(dl, win->x, win->y, win->w, win->h);
// Track whether each axis actually changed, so we only update
// dragOff on axes where the resize was applied. If clamped, leaving
// dragOff unchanged makes the border "stick" to the mouse when the
// user reverses direction, instead of creating a dead zone.
bool appliedX = false;
bool appliedY = false;
if (stack->resizeEdge & RESIZE_LEFT) { if (stack->resizeEdge & RESIZE_LEFT) {
int32_t newX = win->x + dx; int32_t newX = win->x + dx;
int32_t newW = win->w - dx; int32_t newW = win->w - dx;
@ -2015,8 +2023,9 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
} }
if (newW >= minW) { if (newW >= minW) {
win->x = newX; win->x = newX;
win->w = newW; win->w = newW;
appliedX = true;
} }
} }
@ -2028,7 +2037,8 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
} }
if (newW >= minW) { if (newW >= minW) {
win->w = newW; win->w = newW;
appliedX = true;
} }
} }
@ -2042,8 +2052,9 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
} }
if (newH >= minH) { if (newH >= minH) {
win->y = newY; win->y = newY;
win->h = newH; win->h = newH;
appliedY = true;
} }
} }
@ -2055,7 +2066,8 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
} }
if (newH >= minH) { if (newH >= minH) {
win->h = newH; win->h = newH;
appliedY = true;
} }
} }
@ -2078,8 +2090,13 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
win->contentDirty = true; win->contentDirty = true;
} }
stack->dragOffX = mouseX; if (appliedX) {
stack->dragOffY = mouseY; stack->dragOffX = mouseX;
}
if (appliedY) {
stack->dragOffY = mouseY;
}
// Mark new position dirty // Mark new position dirty
dirtyListAdd(dl, win->x, win->y, win->w, win->h); dirtyListAdd(dl, win->x, win->y, win->w, win->h);