mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-11 23:34:04 +09:00
various mouse nav fixes, font rom update
This commit is contained in:
@@ -3703,13 +3703,12 @@ function openRetunePopup() {
|
||||
if (sel < 0) sel = 0
|
||||
let scroll = centerScroll(sel, 0, listH, n)
|
||||
|
||||
// OK/Cancel button placement (bottom inside row)
|
||||
const btnRow = py + ph - 2
|
||||
const labelOK = `[ OK ]`.length
|
||||
const labelCan = `[ Cancel ]`.length
|
||||
const totalW = labelOK + 2 + labelCan
|
||||
const btnXOk = px + ((pw - totalW) >>> 1)
|
||||
const btnXCan = btnXOk + labelOK + 2
|
||||
let done = false
|
||||
let confirmed = false
|
||||
const buttons = makePopupButtonRow(py + ph - 2, px, pw, [
|
||||
{ label: 'OK', action: () => { confirmed = true; done = true }, default: true },
|
||||
{ label: 'Cancel', action: () => { done = true } },
|
||||
])
|
||||
|
||||
const repaint = () => {
|
||||
con.color_pair(230, colPopupBack)
|
||||
@@ -4089,8 +4088,18 @@ const MOUSE_POPUP_STACK = []
|
||||
|
||||
// Wrap push/pop so closing a popup also drops any onHoverLeave that would otherwise
|
||||
// be invoked against the popup's stale regions on the next mouse move.
|
||||
//
|
||||
// When the pop happens with a mouse button still held, the popup was almost certainly
|
||||
// closed by a click. We arm `swallowResidualClick` so the trailing mouse_up (and any
|
||||
// echo mouse_down from that same physical click) doesn't leak into the panel that the
|
||||
// popup was covering. A keyboard close leaves no button held, so this is a no-op.
|
||||
let swallowResidualClick = false
|
||||
function pushMousePopup(regions) { MOUSE_POPUP_STACK.push(regions); lastHoveredRegion = null }
|
||||
function popMousePopup() { MOUSE_POPUP_STACK.pop(); lastHoveredRegion = null }
|
||||
function popMousePopup() {
|
||||
MOUSE_POPUP_STACK.pop()
|
||||
lastHoveredRegion = null
|
||||
if ((sys.peek(-37) & 0x07) !== 0) swallowResidualClick = true
|
||||
}
|
||||
|
||||
function pixelToCell(px, py) {
|
||||
return [(py / CELL_PH | 0) + 1, (px / CELL_PW | 0) + 1] // [cy, cx], 1-indexed
|
||||
@@ -4108,6 +4117,16 @@ function dispatchMouseEvent(event) {
|
||||
const t = event[0]
|
||||
if (t !== 'mouse_down' && t !== 'mouse_wheel' && t !== 'mouse_up' && t !== 'mouse_move') return false
|
||||
|
||||
// Eat residual events from the click that just closed a popup. The flag is armed
|
||||
// by popMousePopup when a button was still held at pop time; it clears on the
|
||||
// matching mouse_up so the next fresh press goes through normally.
|
||||
if (swallowResidualClick && MOUSE_POPUP_STACK.length === 0) {
|
||||
if (t === 'mouse_up') { swallowResidualClick = false; return true }
|
||||
if (t === 'mouse_down') { return true }
|
||||
if (t === 'mouse_move') { return true }
|
||||
// mouse_wheel passes through — it's its own gesture, not part of the closing click
|
||||
}
|
||||
|
||||
const [cy, cx] = pixelToCell(event[1], event[2])
|
||||
const pool = (MOUSE_POPUP_STACK.length > 0)
|
||||
? MOUSE_POPUP_STACK[MOUSE_POPUP_STACK.length - 1]
|
||||
|
||||
@@ -737,6 +737,7 @@ function actActivate() {
|
||||
firstRunLatch = true
|
||||
con.curs_set(0); clearScr()
|
||||
refreshFilePanelCache(windowMode)
|
||||
pendingPostExecDrain = true
|
||||
redraw()
|
||||
}
|
||||
}
|
||||
@@ -927,6 +928,7 @@ function actMore() {
|
||||
firstRunLatch = true
|
||||
con.curs_set(0); clearScr()
|
||||
refreshFilePanelCache(windowMode)
|
||||
pendingPostExecDrain = true
|
||||
redraw()
|
||||
}
|
||||
}
|
||||
@@ -985,11 +987,17 @@ function setupPanelMouseRegions() {
|
||||
}
|
||||
},
|
||||
onClick: (cy, cx, btn) => {
|
||||
if (btn !== 1) return
|
||||
const target = scroll[windowMode] + rowIdx
|
||||
if (target >= dirFileList[windowMode].length) return
|
||||
cursor[windowMode] = target
|
||||
actActivate()
|
||||
if (btn === 1) {
|
||||
cursor[windowMode] = target
|
||||
actActivate()
|
||||
}
|
||||
else if (btn === 2) {
|
||||
cursor[windowMode] = target
|
||||
drawFilePanel()
|
||||
actMore()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1026,11 +1034,19 @@ _redraw()
|
||||
// like fsh.js can hand off with the mouse button still held; without this,
|
||||
// input.withEvent's first call edge-detects that as a fresh mouse_down at the
|
||||
// cursor and activates whichever file row happens to sit there.
|
||||
input.withEvent(() => {})
|
||||
//
|
||||
// The same problem reappears after every child app returns, but draining
|
||||
// inside the dispatcher callback is undone by TVDOS.SYS:1235 (input.withEvent
|
||||
// unconditionally writes inputwork.oldMouse = its-stale-local-snapshot at the
|
||||
// end of the outer call). So actActivate / actMore set pendingPostExecDrain
|
||||
// and the main loop calls drainInheritedInput() AFTER input.withEvent returns.
|
||||
function drainInheritedInput() { input.withEvent(() => {}) }
|
||||
drainInheritedInput()
|
||||
|
||||
let redrawRequested = false
|
||||
let exit = false
|
||||
let firstRunLatch = true
|
||||
let pendingPostExecDrain = false
|
||||
|
||||
while (!exit) {
|
||||
input.withEvent(event => {
|
||||
@@ -1066,6 +1082,16 @@ while (!exit) {
|
||||
_redraw()
|
||||
}
|
||||
})
|
||||
|
||||
// Re-baseline mouse state AFTER input.withEvent returns so its trailing
|
||||
// `inputwork.oldMouse = mouse` (TVDOS.SYS:1235) doesn't overwrite the
|
||||
// freshly-correct state with the stale snapshot taken at the start of the
|
||||
// outer call. Without this, a child app exited by a click leaves zfm with
|
||||
// oldBtns=0 while the user is still holding → spurious mouse_down next poll.
|
||||
if (pendingPostExecDrain) {
|
||||
pendingPostExecDrain = false
|
||||
drainInheritedInput()
|
||||
}
|
||||
}
|
||||
|
||||
con.curs_set(1)
|
||||
|
||||
Reference in New Issue
Block a user