Hover walk: no arg1, held during a move, no fling, published mouseover (#941)

Four pointer defects: OnEnter and OnLeave set `arg1 = true`; a frame being moved or sized still ran the hover walk; the pointer leaving the window fed `f32::MIN` to a move in flight, flinging the frame off-screen; and the mouseover token read the world pick, not the published mouseover.

In 1.12.1 both scripts run through `0x702690`, which sets no arg global. While `[root+0xcfc]` holds a move or size target, the walk pumps it (`0x7655b0`) and returns before any probe (`0x766164`–`0x7661a0`); a hide clears that slot (`0x76492e`). The pump only sees real cursor events. The token resolver reads the published pair `[0xb4e2c8]` (`0x515970`).

OnEnter and OnLeave fire with no arguments, `mouse_move` pumps a move or size and returns, a hide ends it, the pointer leave has its own call, and the aura feed reads the published mouseover.

Tests bite on the parent for each.

Fixes #932
Fixes #933
Fixes #936
Fixes #938

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Sam Sung
2026-10-12 04:08:29 +07:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 0fc40d3f87
commit 73623e31fa
13 changed files with 432 additions and 37 deletions
+21 -10
View File
@@ -178,11 +178,26 @@ impl UiScript {
model.arena.frame(fh)?.name.clone()
}
/// Move the cursor to `(x, y)`. When the hovered frame changes, fires `OnLeave(self, true)` on
/// the old one if still live and `OnEnter(self, true)` on the new; a disabled Button takes the
/// hover but fires neither ([`button::hover_notify_runs`]). Drags and frame moves advance
/// first. Returns the hovered frame id.
/// Move the cursor to `(x, y)`. When the hovered frame changes, fires `OnLeave` on the old one
/// if still live and `OnEnter` on the new, both with the arg globals untouched; a disabled
/// Button takes the hover but fires neither ([`button::hover_notify_runs`]). A frame move or
/// size in flight takes the move instead, and nothing else runs. Returns the hovered frame id.
pub fn mouse_move(&mut self, x: f32, y: f32) -> Option<u32> {
{
let mut model = self.model_mut();
// The walk saves the event before its move/size check (`0x76615f`), so the re-pick's
// position follows the cursor through a drag.
model.cursor_pos = (x, y);
// A move or size in flight is pumped and the walk returns (`0x766164`–`0x7661a0`)
// before any probe (`vtbl+0x3c`): no hit test, no drag start (`0x76b320`), no
// EditBox, slider or colour thumb drag (`0x77a860`, `0x789ba0`, `0x78bd80`), no
// Minimap probe (`0x4eb0c0`), and the hover holds until the drop.
if super::object::pump_move_or_size(&mut model, (x, y)) {
return model
.mouseover
.and_then(|h| model.frame_to_id.get(&h).copied());
}
}
// A drag-active EditBox extends its selection on every move (`0x77a860`).
editbox::drag_update(&self.lua, x, y);
let (new_handle, minimap_missed) = self.hover_walk(x, y);
@@ -200,14 +215,11 @@ impl UiScript {
Option<(u32, f64, f64, f64)>,
) = {
let mut model = self.model_mut();
model.cursor_pos = (x, y);
// Drags advance on every move, before the hover test: a drag within one frame crosses
// no hover boundary.
let slider_change = super::slider::drag_move(&mut model, x, y);
// The colour picker fires on every move, not only on a change: it has no change gate.
let color_change = super::colorselect::drag_move(&mut model, x, y);
super::object::advance_move(&mut model, (x, y));
super::object::advance_size(&mut model, (x, y));
let drag_start = cursor::maybe_start_drag(&mut model, (x, y));
let new_handle = new_id.and(new_handle);
if new_handle == model.mouseover {
@@ -262,9 +274,8 @@ impl UiScript {
super::mouseover::leave(&self.lua, h, script);
}
if let Some(nid) = enter_id {
if let Err(e) =
event::fire_widget_handler(&self.lua, nid, "OnEnter", vec![Value::Boolean(true)])
{
// The base enter's plain runner (`0x76b6e5` → `0x702690`) sets no arg global.
if let Err(e) = event::fire_widget_handler(&self.lua, nid, "OnEnter", Vec::new()) {
self.push_error(e);
}
}