Mouse becoming "unstuck" when resizing windows fixed.
This commit is contained in:
parent
f599ea8c0d
commit
a3e7292591
8 changed files with 107 additions and 32 deletions
10
dvx/dvxApp.c
10
dvx/dvxApp.c
|
|
@ -794,7 +794,15 @@ static void dispatchEvents(AppContextT *ctx) {
|
||||||
// Handle active resize
|
// Handle active resize
|
||||||
if (ctx->stack.resizeWindow >= 0) {
|
if (ctx->stack.resizeWindow >= 0) {
|
||||||
if (buttons & MOUSE_LEFT) {
|
if (buttons & MOUSE_LEFT) {
|
||||||
wmResizeMove(&ctx->stack, &ctx->dirty, &ctx->display, mx, my);
|
int32_t clampX = mx;
|
||||||
|
int32_t clampY = my;
|
||||||
|
wmResizeMove(&ctx->stack, &ctx->dirty, &ctx->display, &clampX, &clampY);
|
||||||
|
|
||||||
|
if (clampX != mx || clampY != my) {
|
||||||
|
platformMouseWarp(clampX, clampY);
|
||||||
|
ctx->mouseX = clampX;
|
||||||
|
ctx->mouseY = clampY;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
wmResizeEnd(&ctx->stack);
|
wmResizeEnd(&ctx->stack);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -899,6 +899,10 @@ void wgtSetEnabled(WidgetT *w, bool enabled);
|
||||||
// Set read-only mode (allows scrolling/selection but blocks editing)
|
// Set read-only mode (allows scrolling/selection but blocks editing)
|
||||||
void wgtSetReadOnly(WidgetT *w, bool readOnly);
|
void wgtSetReadOnly(WidgetT *w, bool readOnly);
|
||||||
|
|
||||||
|
// Set/get keyboard focus
|
||||||
|
void wgtSetFocused(WidgetT *w);
|
||||||
|
WidgetT *wgtGetFocused(void);
|
||||||
|
|
||||||
// Show/hide a widget
|
// Show/hide a widget
|
||||||
void wgtSetVisible(WidgetT *w, bool visible);
|
void wgtSetVisible(WidgetT *w, bool visible);
|
||||||
|
|
||||||
|
|
|
||||||
62
dvx/dvxWm.c
62
dvx/dvxWm.c
|
|
@ -2011,14 +2011,16 @@ void wmResizeEnd(WindowStackT *stack) {
|
||||||
// which would be confusing — the user's manual resize represents their
|
// which would be confusing — the user's manual resize represents their
|
||||||
// new intent.
|
// new intent.
|
||||||
|
|
||||||
void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_t mouseX, int32_t mouseY) {
|
void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_t *mouseX, int32_t *mouseY) {
|
||||||
if (stack->resizeWindow < 0 || stack->resizeWindow >= stack->count) {
|
if (stack->resizeWindow < 0 || stack->resizeWindow >= stack->count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowT *win = stack->windows[stack->resizeWindow];
|
WindowT *win = stack->windows[stack->resizeWindow];
|
||||||
int32_t dx = mouseX - stack->dragOffX;
|
int32_t mx = *mouseX;
|
||||||
int32_t dy = mouseY - stack->dragOffY;
|
int32_t my = *mouseY;
|
||||||
|
int32_t dx = mx - stack->dragOffX;
|
||||||
|
int32_t dy = my - stack->dragOffY;
|
||||||
|
|
||||||
// Compute dynamic minimum size for this window
|
// Compute dynamic minimum size for this window
|
||||||
int32_t minW;
|
int32_t minW;
|
||||||
|
|
@ -2032,13 +2034,6 @@ 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;
|
||||||
|
|
@ -2053,11 +2048,14 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
|
||||||
newX = 0;
|
newX = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newW >= minW) {
|
if (newW < minW) {
|
||||||
|
newW = minW;
|
||||||
|
newX = win->x + win->w - minW;
|
||||||
|
}
|
||||||
|
|
||||||
win->x = newX;
|
win->x = newX;
|
||||||
win->w = newW;
|
win->w = newW;
|
||||||
appliedX = true;
|
mx = newX;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack->resizeEdge & RESIZE_RIGHT) {
|
if (stack->resizeEdge & RESIZE_RIGHT) {
|
||||||
|
|
@ -2071,10 +2069,12 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
|
||||||
newW = d->width - win->x;
|
newW = d->width - win->x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newW >= minW) {
|
if (newW < minW) {
|
||||||
win->w = newW;
|
newW = minW;
|
||||||
appliedX = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
win->w = newW;
|
||||||
|
mx = win->x + newW;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack->resizeEdge & RESIZE_TOP) {
|
if (stack->resizeEdge & RESIZE_TOP) {
|
||||||
|
|
@ -2091,11 +2091,14 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
|
||||||
newY = 0;
|
newY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newH >= minH) {
|
if (newH < minH) {
|
||||||
|
newH = minH;
|
||||||
|
newY = win->y + win->h - minH;
|
||||||
|
}
|
||||||
|
|
||||||
win->y = newY;
|
win->y = newY;
|
||||||
win->h = newH;
|
win->h = newH;
|
||||||
appliedY = true;
|
my = newY;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack->resizeEdge & RESIZE_BOTTOM) {
|
if (stack->resizeEdge & RESIZE_BOTTOM) {
|
||||||
|
|
@ -2109,10 +2112,12 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
|
||||||
newH = d->height - win->y;
|
newH = d->height - win->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newH >= minH) {
|
if (newH < minH) {
|
||||||
win->h = newH;
|
newH = minH;
|
||||||
appliedY = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
win->h = newH;
|
||||||
|
my = win->y + newH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If resized while maximized, consider it no longer maximized
|
// If resized while maximized, consider it no longer maximized
|
||||||
|
|
@ -2134,13 +2139,14 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
|
||||||
win->contentDirty = true;
|
win->contentDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appliedX) {
|
// Always update dragOff to the clamped position so the next delta
|
||||||
stack->dragOffX = mouseX;
|
// is computed from the edge, not from where the mouse wandered.
|
||||||
}
|
stack->dragOffX = mx;
|
||||||
|
stack->dragOffY = my;
|
||||||
|
|
||||||
if (appliedY) {
|
// Report clamped position back so the caller can warp the cursor
|
||||||
stack->dragOffY = mouseY;
|
*mouseX = mx;
|
||||||
}
|
*mouseY = my;
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,9 @@ void wmDragMove(WindowStackT *stack, DirtyListT *dl, int32_t mouseX, int32_t mou
|
||||||
// Update window dimensions during an active resize. Enforces MIN_WINDOW_W/H
|
// Update window dimensions during an active resize. Enforces MIN_WINDOW_W/H
|
||||||
// and optional maxW/maxH constraints. Reallocates the content buffer if the
|
// and optional maxW/maxH constraints. Reallocates the content buffer if the
|
||||||
// content area size changed, then calls onResize to notify the application.
|
// content area size changed, then calls onResize to notify the application.
|
||||||
void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_t mouseX, int32_t mouseY);
|
// mouseX/mouseY are in/out: on return they hold the clamped position so the
|
||||||
|
// caller can warp the hardware cursor to keep it stuck to the window edge.
|
||||||
|
void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_t *mouseX, int32_t *mouseY);
|
||||||
|
|
||||||
// Begin a window drag operation. Records the mouse offset from the window
|
// Begin a window drag operation. Records the mouse offset from the window
|
||||||
// origin so the window doesn't jump to the cursor position.
|
// origin so the window doesn't jump to the cursor position.
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,11 @@ bool platformMouseWheelInit(void);
|
||||||
// driver between polls).
|
// driver between polls).
|
||||||
int32_t platformMouseWheelPoll(void);
|
int32_t platformMouseWheelPoll(void);
|
||||||
|
|
||||||
|
// Move the mouse cursor to an absolute screen position. Uses INT 33h
|
||||||
|
// function 04h on DOS, SDL_WarpMouseInWindow on Linux. Used to clamp
|
||||||
|
// the cursor to window edges during resize operations.
|
||||||
|
void platformMouseWarp(int32_t x, int32_t y);
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Input — Keyboard
|
// Input — Keyboard
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -1199,6 +1199,25 @@ int32_t platformMouseWheelPoll(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// platformMouseWarp
|
||||||
|
// ============================================================
|
||||||
|
//
|
||||||
|
// Moves the mouse cursor to an absolute screen position via INT 33h
|
||||||
|
// function 04h. Used to clamp the cursor to window edges during resize
|
||||||
|
// so the pointer visually sticks to the border.
|
||||||
|
|
||||||
|
void platformMouseWarp(int32_t x, int32_t y) {
|
||||||
|
__dpmi_regs r;
|
||||||
|
|
||||||
|
memset(&r, 0, sizeof(r));
|
||||||
|
r.x.ax = 0x0004;
|
||||||
|
r.x.cx = x;
|
||||||
|
r.x.dx = y;
|
||||||
|
__dpmi_int(0x33, &r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// platformSpanCopy8
|
// platformSpanCopy8
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -454,6 +454,15 @@ void wgtSetDebugLayout(AppContextT *ctx, bool enabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// wgtGetFocused
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
WidgetT *wgtGetFocused(void) {
|
||||||
|
return sFocusedWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// wgtSetEnabled
|
// wgtSetEnabled
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
@ -466,6 +475,26 @@ void wgtSetEnabled(WidgetT *w, bool enabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// wgtSetFocused
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
void wgtSetFocused(WidgetT *w) {
|
||||||
|
if (!w || !w->enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sFocusedWidget && sFocusedWidget != w) {
|
||||||
|
sFocusedWidget->focused = false;
|
||||||
|
wgtInvalidatePaint(sFocusedWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
w->focused = true;
|
||||||
|
sFocusedWidget = w;
|
||||||
|
wgtInvalidatePaint(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// wgtSetReadOnly
|
// wgtSetReadOnly
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,9 @@ DXE_EXPORT_TABLE(shellExportTable)
|
||||||
DXE_EXPORT(wgtSetText)
|
DXE_EXPORT(wgtSetText)
|
||||||
DXE_EXPORT(wgtSetTooltip)
|
DXE_EXPORT(wgtSetTooltip)
|
||||||
DXE_EXPORT(wgtGetText)
|
DXE_EXPORT(wgtGetText)
|
||||||
|
DXE_EXPORT(wgtGetFocused)
|
||||||
DXE_EXPORT(wgtSetEnabled)
|
DXE_EXPORT(wgtSetEnabled)
|
||||||
|
DXE_EXPORT(wgtSetFocused)
|
||||||
DXE_EXPORT(wgtSetReadOnly)
|
DXE_EXPORT(wgtSetReadOnly)
|
||||||
DXE_EXPORT(wgtSetVisible)
|
DXE_EXPORT(wgtSetVisible)
|
||||||
DXE_EXPORT(wgtGetContext)
|
DXE_EXPORT(wgtGetContext)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue