the numerals kit goes stock, and a chat link is its own mouse target
- the status-bar numerals kit (`TextStatusBar.xml` + `.lua`) is the reference's own, and the attempt found a class of silent failure: `TextStatusBar_Initialize()` takes no argument in 1.12 and acts on `this`; ours took an optional bar, our unit frames passed one, and the reference's version ignores it — so the numerals would simply never appear, no error, nothing missing; seventeen of our signatures differ from the reference's that way (Lua drops a surplus argument in silence), written down before their files migrate, and the three "ours narrower" ones — `StaticPopup_Hide(which, data)`, `StaticPopup_FindVisible`, `WorldMapButton_OnClick(button, frame)` — closed now, because that direction bites when a STOCK file arrives and calls our version
- a chat link needs no mouse on its frame: wow-re read the client's ctors as mouse-enabling Button, CheckButton, Slider, ColorSelect and EditBox and NOT the scroll frames; the objection ("something makes a 1.12 chat link clickable") resolved as the engine synthesising one mouse-enabled `CSimpleHyperlinkButton` per link span (`0x7a3240`) — so a link span is a hit-test candidate on its own, the chat window is inert everywhere else, and the wheel is its own predicate rather than a borrowed mouse bit; seven `*ScrollFrame` known divergences retire
- the relic fit rule: `IsValidForSlot`'s slot-17 leg is an EQUALITY — `(InventoryType == RELIC) == hasRelicSlot` — so a relic lights the ranged slot for a druid and a bow does not, on the bag bar and the paper doll alike; closing it half-right would have lit the highlight for a druid dragging a bow
- a chain `.xml` whose `.lua` never loaded: `MoneyInputFrame.xml` had been on the chain without its `.lua`, so the template loaded and all ten `MoneyInputFrame_*` verbs read nil, silently — a gate now fails any chain `.xml` whose `.lua` sibling is neither sourced nor listed; the gap report's LOAD column carries the probe's collision caveat, its fx column stops crying wolf (it follows `<Script file=>`, stops reading `.Field(` as a global, subtracts a file's own locals), and a window is its xml PLUS the lua it sources
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -50,7 +50,7 @@ use crate::order;
|
||||
use crate::widget::FrameHandle;
|
||||
|
||||
use super::clip::{effective_clip, scroll_clip_sources};
|
||||
use super::{button, cursor, editbox, event, UiScript};
|
||||
use super::{button, cursor, editbox, event, Model, UiScript};
|
||||
|
||||
/// The double-click interval — **300 ms, VERIFIED off the bytes**, a hardcoded instruction
|
||||
/// immediate: `0x77937b 81 f9 2c 01 00 00 cmp ecx, 0x12c`, comparing `now − [this+0x334]` inside
|
||||
@@ -127,6 +127,15 @@ pub(super) fn install(lua: &mlua::Lua) -> mlua::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Whether `(x, y)` falls inside one of this frame's hyperlink spans — the engine half of the
|
||||
/// reference's per-span `CSimpleHyperlinkButton` children.
|
||||
fn link_span_hit(model: &Model, fh: FrameHandle, x: f32, y: f32) -> bool {
|
||||
model
|
||||
.link_spans
|
||||
.get(&fh)
|
||||
.is_some_and(|spans| spans.iter().any(|(r, _, _)| point_in_rect(*r, x, y)))
|
||||
}
|
||||
|
||||
impl UiScript {
|
||||
/// Hit-test the cursor at `(x, y)` and return the **handle** of the captured frame (the
|
||||
/// topmost-drawn mouse-enabled, effective-visible frame whose rect contains the point **and**
|
||||
@@ -146,7 +155,22 @@ impl UiScript {
|
||||
let sorted = order::traversal(&model.arena);
|
||||
let scroll_sources = scroll_clip_sources(&model);
|
||||
order::hit_test(&sorted, |fh| {
|
||||
model.arena.is_mouse_enabled(fh)
|
||||
// Mouse-enabled, **or inside one of this frame's hyperlink spans**.
|
||||
//
|
||||
// That second half is how the reference makes a chat link clickable on a frame that
|
||||
// takes no mouse at all. `CSimpleMessageScrollFrame`'s ctor leaves `[+0xcc] = 0`, so
|
||||
// `ChatFrame1` is never in the hit-test index — instead the engine synthesises one
|
||||
// mouse-enabled `CSimpleHyperlinkButton` child PER SPAN (`0x7a3240`, born through the
|
||||
// `CSimpleButton` ctor) and routes the three hyperlink scripts back to the parent
|
||||
// (wow-re `mouse-enable-law.md` + the follow-up round `68987021`).
|
||||
//
|
||||
// We hold the spans as rects on the parent rather than as child frames, so the same
|
||||
// law expresses as a disjunct here. What it buys is everything the reference gets from
|
||||
// the split: the chat window is a hit candidate only over a LINK, so `GetMouseFocus()`
|
||||
// answers what is behind it elsewhere, its `movable="true"` +
|
||||
// `<TitleRegion setAllPoints="true"/>` stay inert so it drags by its tab and not its
|
||||
// body, and a hover over plain text reassigns to whatever is underneath.
|
||||
(model.arena.is_mouse_enabled(fh) || link_span_hit(&model, fh, x, y))
|
||||
&& model.resolved.get(&fh).is_some_and(|r| {
|
||||
point_in_rect(inset_rect(*r, model.arena.hit_rect_insets(fh)), x, y)
|
||||
})
|
||||
@@ -155,6 +179,26 @@ impl UiScript {
|
||||
})
|
||||
}
|
||||
|
||||
/// [`Self::hit_test`] over the frames that take the WHEEL — either bit, since a mouse-enabled
|
||||
/// frame with an `<OnMouseWheel>` is a candidate for both. Same rect and clip rules; only the
|
||||
/// enable predicate differs.
|
||||
fn hit_test_wheel(&self, x: f32, y: f32) -> Option<u32> {
|
||||
let model = self.model_ref();
|
||||
let sorted = order::traversal(&model.arena);
|
||||
let scroll_sources = scroll_clip_sources(&model);
|
||||
let fh = order::hit_test(&sorted, |fh| {
|
||||
(model.arena.is_mouse_wheel_enabled(fh)
|
||||
|| model.arena.is_mouse_enabled(fh)
|
||||
|| link_span_hit(&model, fh, x, y))
|
||||
&& model.resolved.get(&fh).is_some_and(|r| {
|
||||
point_in_rect(inset_rect(*r, model.arena.hit_rect_insets(fh)), x, y)
|
||||
})
|
||||
&& effective_clip(&model, &scroll_sources, fh)
|
||||
.is_none_or(|c| point_in_rect(c, x, y))
|
||||
})?;
|
||||
model.frame_to_id.get(&fh).copied()
|
||||
}
|
||||
|
||||
/// Hit-test the cursor at `(x, y)` and return the **id** of the captured frame, or `None` —
|
||||
/// [`Self::hit_test_frame`] with the id lookup every caller in the input path wants. The id is
|
||||
/// the same one used across this host (e.g. the layout [`crate::layout::Handle`]); the app can
|
||||
@@ -749,7 +793,13 @@ impl UiScript {
|
||||
/// [`UiScript::errors`].
|
||||
pub fn mouse_wheel(&mut self, x: f32, y: f32, delta: f32) {
|
||||
let target: Option<u32> = {
|
||||
let hit = self.hit_test(x, y);
|
||||
// **Wheel-enabled OR mouse-enabled**, not mouse-enabled alone. The reference's wheel
|
||||
// dispatcher `0x7664f0` walks its OWN index and calls the hit probe directly, ignoring
|
||||
// hover, capture and the mouse bit — `EnableMouse` is not a prerequisite
|
||||
// (wow-re `mouse-enable-law.md` §6). Ours went through the mouse hit test, which
|
||||
// coupled the two: correcting the ctor list to the reference's (ScrollFrame is inert
|
||||
// on the mouse bit) silently stopped every scroll pane from taking the wheel.
|
||||
let hit = self.hit_test_wheel(x, y);
|
||||
let model = self.model_ref();
|
||||
hit.and_then(|id| {
|
||||
let mut h = *model.id_to_frame.get(&id)?;
|
||||
|
||||
Reference in New Issue
Block a user