comments cite the reference by address, not by private note (#30)
Comments that pointed into the maintainer's private reverse-engineering notes (a note by name, a path, a section or finding id, the analysis's own name for a client function, a process word) now carry the fact itself, cited by the reference client's address, by vmangos file and line, or as "the reference". Nobody outside could follow those pointers. Comment text only, plus the test-assert and log strings that carried the same pointers. No claim changes: a comment the notes have since corrected keeps its wording here, and correcting it is separate work. The two reference generators, `scripts/gen-reference-globals.py` and `scripts/gen-reference-verb-events.py`, named the private notes' layout to find their inputs. They now take the input files as arguments (`--capture`, `--framexml`, `--names`, `--extents`, `--disasm`). Run on the same inputs, both write the committed tables row for row; only the two header lines that named the old environment variable change. Checked per file: - the code is identical: each file with its comments stripped compares equal before and after; a changed string literal is compared under a mask that proves only literal text moved and every literal kept its line count; - no client address the old text cited was dropped; - a second reviewer checked every added address against its derivation; - a detector for the notes' names, paths, ids, function names and process words finds none left; - `scripts/gates.sh` is green. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
co-authored by
Claude Opus 5.5
parent
beb6cc854f
commit
7b66dac9db
@@ -2,9 +2,8 @@
|
||||
//!
|
||||
//! The two bindings are `CScriptRegion` methods registered **once**, at `.data 0x87ca38` and
|
||||
//! `0x87ca40` inside the 19-record table `[0x87c9b8, 0x87ca50)` whose registrar `0x7a2e70` supplies
|
||||
//! base and count — so Frame, Texture, FontString and Model all run the *same* function (wow-re
|
||||
//! `system/ui/ui.md` §(b2), `scratch/name-string-widget-resolution.md` §3-4, ledger rows
|
||||
//! `0x7a2540`/`0x7a2940`). This module is that single function's argument half; what each caller
|
||||
//! base and count — so Frame, Texture, FontString and Model all run the *same* function
|
||||
//! (`0x7a2540`/`0x7a2940`). This module is that single function's argument half; what each caller
|
||||
//! keeps for itself is only the thing the reference reads off the receiver — the layout parent's
|
||||
//! default id, and where the anchor is stored.
|
||||
//!
|
||||
|
||||
@@ -180,8 +180,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// (CustomNameplates:437, a four-argument later-client form). Accepted rather than skipped
|
||||
// because dropping it silently is the very class this fixes, and one real site is still a site.
|
||||
m.set(
|
||||
// **The three argument positions are NOT one rule, and the fourth is the odd one.** Verified
|
||||
// together in wow-re `ui/scratch/xml-template-name-lookup.md` §5.2:
|
||||
// **The three argument positions are NOT one rule, and the fourth is the odd one:**
|
||||
//
|
||||
// · `name` and `layer` go through `0x6f3510` (is-number-**or**-string) then `0x6f3690`, and
|
||||
// **the result is never tested** — so a table is simply absent (unnamed / the pre-staged
|
||||
@@ -211,8 +210,8 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
)?;
|
||||
// ── The title region: Frame:CreateTitleRegion() / GetTitleRegion() ──────────────────────────
|
||||
//
|
||||
// wow-re `system/ui/scratch/widget-api-batch-benilla.md` Q6 (`0x773910` / `0x773820`). Four
|
||||
// details, each one a coin-flip a reimplementation loses:
|
||||
// The byte read (`0x773910` / `0x773820`). Four details, each one a coin-flip a
|
||||
// reimplementation loses:
|
||||
//
|
||||
// · **It reads NO argument at all** — nothing in `0x773910`-`0x773a1f` touches Lua index 2. So
|
||||
// `CustomNameplates/options.lua:73`'s `CreateTitleRegion(optionsFrame)` is harmless and
|
||||
@@ -224,10 +223,10 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// · **A fresh one has NO anchors** and does nothing until `SetPoint`/`SetAllPoints`. Both
|
||||
// corpus consumers immediately call `SetAllPoints`, which is the whole-window drag idiom.
|
||||
// · **`GetTitleRegion` answers 1 value (nil)** when there is none — note the asymmetry with
|
||||
// `GetBackdrop`, which answers 0 values. Q6 flags it explicitly; both converged
|
||||
// independently there, so both are reproduced here.
|
||||
// **ONE NAMED DIVERGENCE, because it is a superset and 1189 is what a superset costs.** Q6 says
|
||||
// the object answers *exactly* the 19 Region methods — no Show/Hide, no scripts, no textures.
|
||||
// `GetBackdrop`, which answers 0 values; both are reproduced here.
|
||||
// **ONE NAMED DIVERGENCE, because it is a superset and 1189 is what a superset costs.** The
|
||||
// object answers *exactly* the 19 Region methods (`0x7a2ea0`, no own table) — no Show/Hide, no
|
||||
// scripts, no textures.
|
||||
// Ours answers the whole shared region table, because Texture/FontString/Title use one
|
||||
// metatable here, so `titleRegion:SetTexture(…)` is accepted where the reference would raise
|
||||
// `attempt to call method`. It is inert rather than wrong — a title region never draws (the
|
||||
@@ -299,7 +298,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// Ignoring it is 1203's class exactly: the addon asks for a font, we accept the call, and the
|
||||
// string comes out in whatever the default is with no failure anywhere.
|
||||
//
|
||||
// The resolution order is carved (`0x773c30`): the FONT-object registry FIRST (`0x773d39`,
|
||||
// The resolution order is fixed (`0x773c30`): the FONT-object registry FIRST (`0x773d39`,
|
||||
// create=0), and only on a font miss the template registry (`0x773d47`). This routes through
|
||||
// the `SetFontObject` binding rather than reaching into the model, which is the same call the
|
||||
// XML `<FontString inherits=>` path makes — one implementation of "apply a font object", not
|
||||
@@ -333,9 +332,8 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
/// the exact call. So the rule for this list is one line long: **a name is accepted only once
|
||||
/// something fires it.**
|
||||
///
|
||||
/// The 1.12 script set is fully carved (wow-re `system/ui/scratch/rf28-typed-widget-loadxml.md`
|
||||
/// l.10-18 for the base map `0x76a0d0`, the per-type sections for each widget's additions;
|
||||
/// `system/ui/ui.md` l.544-556 summarises it), so what is missing here is never a mystery — it is a
|
||||
/// The 1.12 script set is fully mapped (the base table `0x76a0d0`, plus each widget's own
|
||||
/// per-type additions), so what is missing here is never a mystery — it is a
|
||||
/// deliberate not-yet. What the corpus actually asks for, and why each answer is what it is:
|
||||
///
|
||||
/// * **`OnKeyDown` / `OnKeyUp` / `OnChar`** (14 + 1 + 4 corpus sites over 13 addons) — **accepted**
|
||||
@@ -345,7 +343,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
/// above let them in the moment something fired them.
|
||||
/// * **`OnCursorChanged`** (4 sites over 3 addons, plus two in the SHIPPED FrameXML — all of them
|
||||
/// the `ScrollingEdit_OnCursorChanged` auto-scroll idiom) — **accepted since decision 2141**,
|
||||
/// which built the edge this entry said was missing. The EditBox's own slot (RF-28 `+0x428`),
|
||||
/// which built the edge this entry said was missing. The EditBox's own slot (`+0x428`),
|
||||
/// fired by the caret flush `0x77da80` with four float caret-position args in UI units;
|
||||
/// `editbox::drain_cursor_changed` is our counterpart, on the tick, gated on the caret having
|
||||
/// actually moved. The stock `MailFrame.xml` and `HelpFrame.xml` declare it, so until 2141 the
|
||||
@@ -440,7 +438,7 @@ fn get_script(lua: &Lua, this: &Table, name: &str) -> mlua::Result<Value> {
|
||||
}
|
||||
}
|
||||
|
||||
/// `CreateTexture`/`CreateFontString`'s third argument — `inheritsFrom` — in the carved order.
|
||||
/// `CreateTexture`/`CreateFontString`'s third argument — `inheritsFrom` — in the fixed order.
|
||||
///
|
||||
/// **Font-object registry first, template registry second** (`0x773d39` then `0x773d47`). That
|
||||
/// order is not cosmetic: `inherits=` is one attribute over two namespaces, and every corpus caller
|
||||
@@ -524,9 +522,8 @@ fn create_region(
|
||||
// 0x773a20` and `CreateFontString 0x773c30` build a synthetic node carrying
|
||||
// `name=<the Lua string>` and read it back through the same `GetAttribute(node, "name")` →
|
||||
// `CScriptRegion::SetName 0x76c650` the XML path uses, and `0x76c691` is one of that
|
||||
// expander's two call sites (wow-re `name-string-widget-resolution.md` §5/§6, whose
|
||||
// `name=` reader census names `0x773ba1` and `0x773dc4` — the addresses *inside* these two
|
||||
// bindings). A region's `$parent` is its OWNER frame, so the walk starts there.
|
||||
// expander's two call sites — `0x773ba1` and `0x773dc4` are the addresses *inside* these
|
||||
// two bindings. A region's `$parent` is its OWNER frame, so the walk starts there.
|
||||
//
|
||||
// `pfQuest/browser.lua:723` is `pfBrowser.input:CreateTexture("$parentSearchIcon",
|
||||
// "OVERLAY")`, and every named widget FonzAppraiser builds is this idiom.
|
||||
|
||||
@@ -85,7 +85,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
// ── GetObjectType / IsObjectType, frame side (wow-re `widget-type-identity.md` §6) ──────────
|
||||
// ── GetObjectType / IsObjectType, frame side (`0x7a11d0`/`0x7a1290`) ─────────────────────────
|
||||
//
|
||||
// The region side landed first because a FontString found it; `_Nameplates` is why this half
|
||||
// exists too — `_Nameplates.lua:164` tests `Nameplate:GetObjectType() ~= "Button"` and `:191`
|
||||
@@ -125,7 +125,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
FrameKind::Model => &["Model", "Frame", "Region"],
|
||||
// 4 deep: `PlayerModel` derives from `Model`, and `DressUpModel` (1969) and
|
||||
// `TabardModel` (1977) derive from it in turn, for the roster's maximum depth of 5
|
||||
// (wow-re `ui/scratch/widget-type-identity.md` §6).
|
||||
// (the reference's full 23-class roster).
|
||||
FrameKind::PlayerModel => &["PlayerModel", "Model", "Frame", "Region"],
|
||||
FrameKind::DressUpModel => &["DressUpModel", "PlayerModel", "Model", "Frame", "Region"],
|
||||
FrameKind::TabardModel => &["TabardModel", "PlayerModel", "Model", "Frame", "Region"],
|
||||
@@ -191,9 +191,8 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// 1.12 registers the type-identity pair **twice, under two names**. The Region script
|
||||
// (`CScriptRegion`) publishes `GetObjectType`/`IsObjectType` — that is the pair above, and its
|
||||
// `IsObjectType` binding is `0x7a1290`. The *frame* script (`CSimpleFrameScript.cpp`,
|
||||
// `__FILE__` `0x879504`) publishes `GetFrameType 0x773640` and `IsFrameType 0x773700` as well,
|
||||
// and wow-5875-re carved both (`system/ui/scratch/item17-frameapi-batch1.md`, 76-entry
|
||||
// registrar table verified at the bytes). `GetObjectType`/`IsObjectType` are what LATER
|
||||
// `__FILE__` `0x879504`) publishes `GetFrameType 0x773640` and `IsFrameType 0x773700` as well.
|
||||
// `GetObjectType`/`IsObjectType` are what LATER
|
||||
// clients kept; `GetFrameType`/`IsFrameType` are 1.12's own, and we shipped only the first
|
||||
// pair. That is 1189's superset argument inverted — not an extra name we invented, a real one
|
||||
// we were missing — and it cost the world map:
|
||||
@@ -212,12 +211,12 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// `[eax+0x18]`, the same case-insensitive whole-string compare, and answers the NUMBER 1 or
|
||||
// nil.
|
||||
//
|
||||
// **One edge is INFERRED and named rather than guessed silently:** wow-re's note glosses
|
||||
// `IsFrameType`'s *absent-argument* branch as "pushes the frame's own typename (`call [eax+4]`
|
||||
// GetName)", which is self-contradictory — a typename and a name are different slots — so the
|
||||
// branch is not settled. We take the sibling's behaviour (the `Usage:` raise) pending a byte
|
||||
// read. No caller in the 219-addon corpus, the director's AddOns, or the shipped FrameXML ever
|
||||
// omits the argument: `JIM_toolbox/Config2/Pulse_Config.lua:118` is the corpus's only
|
||||
// **One edge is INFERRED and named rather than guessed silently:** the one description of
|
||||
// `IsFrameType`'s *absent-argument* branch reads "pushes the frame's own typename (`call
|
||||
// [eax+4]` GetName)", which is self-contradictory — a typename and a name are different slots —
|
||||
// so the branch is not settled. We take the sibling's behaviour (the `Usage:` raise) pending a
|
||||
// byte read. No caller in the 219-addon corpus, the director's AddOns, or the shipped FrameXML
|
||||
// ever omits the argument: `JIM_toolbox/Config2/Pulse_Config.lua:118` is the corpus's only
|
||||
// `IsFrameType` site and it passes `"Slider"`.
|
||||
m.set(
|
||||
"GetFrameType",
|
||||
@@ -272,8 +271,8 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// ── The four structure queries: GetChildren / GetNumChildren / GetRegions / GetNumRegions ──
|
||||
//
|
||||
// Registered bindings in 1.12 (`GetNumRegions 0x773e60`, `GetRegions 0x773f60`,
|
||||
// `GetNumChildren 0x774080`, `GetChildren 0x774180` — wow-re `ui/ledger.tsv`, classified
|
||||
// ORCHESTRATION: each marshals and delegates, with no fidelity math of its own).
|
||||
// `GetNumChildren 0x774080`, `GetChildren 0x774180`): each marshals and delegates, with no
|
||||
// fidelity math of its own).
|
||||
//
|
||||
// **Why these four are worth more than their size.** They are how an addon walks a frame it did
|
||||
// not build, which is the whole basis of the "reskin the default UI" genre — and that genre is
|
||||
@@ -295,23 +294,21 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// **A detached region is not in the list.** `Region:SetParent(nil)` sets `Region::detached`
|
||||
// rather than removing the entry, because the owner's `Vec` is what `WidgetArena::destroy`
|
||||
// frees from — but the client's re-link virtual `0x77fd10` with a null parent genuinely
|
||||
// **unlinks from the old parent's draw layer and region list** (wow-re
|
||||
// `widget-api-batch-benilla.md` Q7, VERIFIED), so a detached region must be invisible to both
|
||||
// region verbs. Our flag is a representation choice; the list these report is the client's.
|
||||
// **unlinks from the old parent's draw layer and region list**, so a detached region must be
|
||||
// invisible to both region verbs. Our flag is a representation choice; the list these
|
||||
// report is the client's.
|
||||
//
|
||||
// **The count and the list come from ONE function** ([`regions_of`] / [`children_of`]), never
|
||||
// two walks with the same filter written twice. `GetNumRegions` disagreeing with
|
||||
// `#{GetRegions()}` is a bug an addon would hit as an off-by-one deep inside a loop it did not
|
||||
// write, and the only way to make it impossible is to have one of them BE the other.
|
||||
//
|
||||
// **Settled by a wow-re §5 quartet** (`ui/scratch/widget-list-bindings.md`), which confirmed two
|
||||
// of these choices and corrected a third:
|
||||
// **The order and inclusion rules below — one of them a correction:**
|
||||
//
|
||||
// · **The order is link order, oldest first, and no reversal.** `CSimpleFrame` embeds a punned
|
||||
// `TSList` header whose ctor sets `tail = &header`, `head = (&header)|1`, and BOTH linkers
|
||||
// append at the TAIL (`0x76a750` for regions, `0x76aa20` for children — one caller each).
|
||||
// Our insertion-order `Vec` is the same order. (wow-re's own `draw-order-law.md` said
|
||||
// "tail→head"; that was a direction mislabel and was corrected in the same round.)
|
||||
// Our insertion-order `Vec` is the same order.
|
||||
// · **Hidden children and regions are returned and counted** — a VERIFIED negative: the
|
||||
// counting loops never load the visibility word at all.
|
||||
// · **The TITLE REGION IS NOT RETURNED**, and that one corrected us. Both creation paths
|
||||
@@ -327,7 +324,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// empty, never nil.
|
||||
//
|
||||
// The one thing still out of reach is not these bindings': Questie reads
|
||||
// `({Minimap:GetChildren()})[9]` for the player arrow, and the §5 found why that index works —
|
||||
// `({Minimap:GetChildren()})[9]` for the player arrow; here is why that index works —
|
||||
// `CMinimap`'s ctor `0x4edbc0` builds NINE engine-owned `Model` children before the XML
|
||||
// `<Frames>` descent, the ninth (`[Minimap+0x338]`) being the arrow `SetPlayerFacing 0x4eb8e0`
|
||||
// writes. We create none of them, so index 9 is nil here until the minimap grows its engine
|
||||
@@ -364,8 +361,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
"GetNumRegions",
|
||||
lua.create_function(|lua, this: Table| Ok(regions_of(lua, &this)?.len()))?,
|
||||
)?;
|
||||
// SetParent — the runtime reparent, per the byte-verified law (wow-re
|
||||
// `ui/scratch/setparent-runtime-strata-level.md`; decision 1323). The binding half
|
||||
// SetParent — the runtime reparent (decision 1323). The binding half
|
||||
// (`0x7a1550`): the parent argument is a frame table, a NAME string (`0x76c760`), or an
|
||||
// explicit nil — an ABSENT argument is NOT the nil path (`0x6f3400` returns −1) and raises
|
||||
// like an unresolvable name; the cycle guard is the binding's own inline ancestor walk and
|
||||
@@ -518,7 +514,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
let h = frame_handle_of(lua, &this)?;
|
||||
let lvl = level.clamp(0, i64::from(u16::MAX)) as u16;
|
||||
// **A script level change carries no children** — the binding `0x774560` calls
|
||||
// `set_frame_level 0x76a4f0` with `propagate=0` (wow-re `ui/ui.md`, default levels).
|
||||
// `set_frame_level 0x76a4f0` with `propagate=0`.
|
||||
// Only the toplevel raise shifts a subtree. Stock `BonusActionButtonTemplate` is written
|
||||
// for this: it raises the button +2 and then its cooldown +2 by hand, landing the sweep
|
||||
// one level over the button — carrying the children made it three, over the
|
||||
@@ -586,9 +582,10 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
Ok(model.arena.frame(h).map(|f| f.alpha).unwrap_or(1.0))
|
||||
})?,
|
||||
)?;
|
||||
// Backdrop (backdrop-mechanism.md): SetBackdrop(table|nil) installs (or, with nil, tears down)
|
||||
// the frame's tiled bg + 8-piece border plate. The two color setters tint the bg / all 8 border
|
||||
// pieces (never the reverse — spec §4). The Lua-table SetBackdrop defaults both colors to WHITE
|
||||
// Backdrop (`0x7776e0` → `0x76a5d0`): SetBackdrop(table|nil) installs (or, with nil, tears
|
||||
// down) the frame's tiled bg + 8-piece border plate. The two color setters tint the bg / all 8
|
||||
// border pieces (never the reverse — `0x77f410`/`0x77f440`). The Lua-table SetBackdrop defaults
|
||||
// both colors to WHITE
|
||||
// (the ctor), so a caller must SetBackdropColor after to tint (the tooltip's OnLoad does).
|
||||
m.set(
|
||||
"SetBackdrop",
|
||||
@@ -616,7 +613,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
// `GetBackdrop()` (`0x777370`; wow-re `ui/scratch/widget-api-batch-benilla.md` Q5) — five things
|
||||
// `GetBackdrop()` (`0x777370`) — five things
|
||||
// a plausible implementation gets wrong, so each is spelled out with its reason:
|
||||
//
|
||||
// 1. It is a **reconstruction from the struct**, never the caller's table. The reference stores
|
||||
@@ -770,8 +767,8 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
))
|
||||
})?,
|
||||
)?;
|
||||
// EnableKeyboard(flag) / IsKeyboardEnabled() — `0x776f90` / `0x776ff0`, real Frame entries in
|
||||
// wow-re's frame-API carve, beside the mouse pair above.
|
||||
// EnableKeyboard(flag) / IsKeyboardEnabled() — `0x776f90` / `0x776ff0`, real Frame entries,
|
||||
// beside the mouse pair above.
|
||||
//
|
||||
// 8 corpus addons call this and were RAISING on it (`ColorPickerPlus:258`,
|
||||
// `Dewdrop-2.0.lua:2021-2022` — which is in ~65 addons — `AckisRecipeList/ARLFrame.lua:1650`).
|
||||
@@ -782,9 +779,9 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// three times (1203/1205/1211): the majority of the corpus calls pass **false**, and for those
|
||||
// our behaviour is already the reference's — we deliver no keys to arbitrary frames either. The
|
||||
// `true` callers want delivery we do not do, but they did not get it before this landed; they
|
||||
// got a raise that killed the enclosing function. And per
|
||||
// `frame-key-script-delivery.md` §3.2 being enabled genuinely is separable from having a
|
||||
// handler, so the flag is a real piece of the model, not a placeholder for one.
|
||||
// got a raise that killed the enclosing function. And being enabled genuinely is separable
|
||||
// from having a handler (`0x76af00` never touches the handler slots), so the flag is a real
|
||||
// piece of the model, not a placeholder for one.
|
||||
m.set(
|
||||
"EnableKeyboard",
|
||||
lua.create_function(|lua, (this, enable): (Table, bool)| {
|
||||
@@ -874,7 +871,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
))
|
||||
})?,
|
||||
)?;
|
||||
// Clamp-to-screen (`0x776c00`/`0x776cb0`, geometry flags bit4 — layout.md): the layout resolve
|
||||
// Clamp-to-screen (`0x776c00`/`0x776cb0`, geometry flags bit4): the layout resolve
|
||||
// keeps the frame's assembled rect inside the window, size preserved. GameTooltip frames
|
||||
// default true by construction (widget::Frame::clamped_to_screen — decision 0352).
|
||||
m.set(
|
||||
@@ -929,7 +926,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parse a Lua `SetBackdrop` table into a [`Backdrop`] (backdrop-mechanism.md §1). The keys read —
|
||||
/// Parse a Lua `SetBackdrop` table into a [`Backdrop`] (`0x7776e0`'s key reads). The keys read —
|
||||
/// exactly the compiled reader's set — are `bgFile`/`edgeFile` (strings), `tile` (boolean, default
|
||||
/// false), `tileSize`/`edgeSize` (numbers; a missing number leaves the ctor default: tileSize 0,
|
||||
/// edgeSize 32), and `insets{left,right,top,bottom}` (numbers, each default 0). A non-string file or
|
||||
@@ -1015,8 +1012,7 @@ fn children_of(lua: &Lua, this: &Table) -> mlua::Result<Vec<u32>> {
|
||||
/// This frame's live regions as stable ids, in creation order — **the title region and detached
|
||||
/// ones excluded** — the one walk `GetRegions` and `GetNumRegions` share.
|
||||
///
|
||||
/// Both exclusions are the client's list, not tidiness, and both are VERIFIED (wow-re
|
||||
/// `ui/scratch/widget-list-bindings.md`, §5 quartet):
|
||||
/// Both exclusions are the client's list, not tidiness:
|
||||
///
|
||||
/// - **Detached.** `SetParent(nil)` reaches `0x77fd55` → the removal virtual `0x76a7f0`, which
|
||||
/// unlinks the node and frees it, and then skips every re-link. We keep the entry only so the
|
||||
@@ -1051,8 +1047,7 @@ fn regions_of(lua: &Lua, this: &Table) -> mlua::Result<Vec<u32>> {
|
||||
}
|
||||
|
||||
/// One backdrop colour channel, the reference's own conversion (`SetBackdropColor 0x777d30` /
|
||||
/// `SetBackdropBorderColor 0x7780d0` — instruction-identical bar the delegate; wow-re
|
||||
/// `scratch/numeric-arg-coercion-law.md` Q4, VERIFIED).
|
||||
/// `SetBackdropBorderColor 0x7780d0` — instruction-identical bar the delegate).
|
||||
///
|
||||
/// **r/g/b are UNGATED and alpha is not**, and that asymmetry is the whole of this function:
|
||||
///
|
||||
@@ -1066,7 +1061,8 @@ fn regions_of(lua: &Lua, this: &Table) -> mlua::Result<Vec<u32>> {
|
||||
///
|
||||
/// Then the reference clamps to `[0,1]` with **NaN landing on 1.0** (the compare's unordered arm
|
||||
/// takes the high clamp), and quantizes `×255 + 0.5` through `__ftol` — round-half-up, not the
|
||||
/// bare truncate `chat-window-record.md`'s colour path uses. The field is a packed `0xAARRGGBB`
|
||||
/// bare truncate `SetChatWindowColor 0x4a14f0`'s colour path uses. The field is a packed
|
||||
/// `0xAARRGGBB`
|
||||
/// byte quad, so nothing finer survives the store and we quantize on the way in rather than
|
||||
/// pretend to a precision `GetBackdropColor` could not read back.
|
||||
fn backdrop_channel(lua: &Lua, v: Option<Value>, gated: bool) -> f32 {
|
||||
|
||||
@@ -115,7 +115,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
.map_or(0, |i| i.anchors.len() as i64))
|
||||
})?;
|
||||
// SetAllPoints([relativeTo]) — pin TOPLEFT+BOTTOMRIGHT to the target (default: the parent),
|
||||
// the XML `setAllPoints="true"` behavior as a method (rf24 `0x767800`'s SetAllPoints path).
|
||||
// the XML `setAllPoints="true"` behavior as a method (`0x767800`'s SetAllPoints path).
|
||||
set_shared(
|
||||
lua,
|
||||
m,
|
||||
|
||||
@@ -14,20 +14,20 @@
|
||||
//! ```
|
||||
//!
|
||||
//! and that layering is the reference's own: `RegisterForDrag 0x776d60` + the threshold-gated
|
||||
//! `OnDragStart`/`OnDragStop` pair (wow-re `cursor-dragdrop-payload.md` §9, our decision 0216 §3 —
|
||||
//! `OnDragStart`/`OnDragStop` pair (`0x76bf70`/`0x76c040`, our decision 0216 §3 —
|
||||
//! [`crate::script::cursor`], dispatched from [`crate::script::pointer`]) are a **separate**
|
||||
//! system from the engine move below. The gesture decides *when* the handlers run; this module
|
||||
//! owns only what happens between `StartMoving` and `StopMovingOrSizing`.
|
||||
//!
|
||||
//! ## The mechanism (wow-re `system/ui`, VERIFIED unless said otherwise)
|
||||
//! ## The mechanism
|
||||
//!
|
||||
//! The three flags are bits of the frame's flag word `[frame+0xb4]`, all written by the one
|
||||
//! generic setter `0x76a3c0` (`if (v) flags |= mask; else flags &= ~mask;` — no calls, no side
|
||||
//! effects): **movable `0x100`** (`SetMovable 0x776420` / `IsMovable 0x7764d0`), **resizable
|
||||
//! `0x200`** (`SetResizable 0x776590` / `IsResizable 0x776640`), **userPlaced `0x1000`**
|
||||
//! (`SetUserPlaced 0x776a50` / `IsUserPlaced 0x776b40`). The XML attributes land on the same
|
||||
//! setter (`movable="true"` → `0x76a3c0(0x100)`, `resizable="true"` → `0x200` — wow-re
|
||||
//! `rf24-framexml-loader.md`), which is why the loader now *calls* these instead of warning.
|
||||
//! setter (`movable="true"` → `0x76a3c0(0x100)`, `resizable="true"` → `0x200`), which is why the
|
||||
//! loader now *calls* these instead of warning.
|
||||
//!
|
||||
//! `StartMoving 0x776700` tests the movable bit and raises when it is clear, then enters the drag
|
||||
//! at `0x7652b0`, which `Raise()`s the frame, **sets the userPlaced bit itself**, and records the
|
||||
@@ -40,10 +40,10 @@
|
||||
//! Movement is a **pump**, run from the mouse-move handler: `0x7655b0` (a diffed-bit-exact
|
||||
//! PRIMITIVE) takes `dx = x − root+0xd08`, `dy = y − root+0xd0c`, and — only if either is
|
||||
//! non-zero — applies them and re-centers the sample. The application (`0x76a660` → the 9-case
|
||||
//! `geo_768710`, also a diffed-bit-exact PRIMITIVE) selects on the 3×3 region the drag grabbed:
|
||||
//! `0x768710`, also a diffed-bit-exact PRIMITIVE) selects on the 3×3 region the drag grabbed:
|
||||
//! the eight edge/corner cases resize, and **case 4, the plain move, accumulates the scaled delta
|
||||
//! straight into the anchor's offsets in place** — `xOffset += dx/scale`, `yOffset += dy/scale`
|
||||
//! (`CAnchor+0x4`/`+0x8`, wow-re `frame-model.md`) — then invalidates the layout (`0x7680e0`).
|
||||
//! (`CAnchor+0x4`/`+0x8`) — then invalidates the layout (`0x7680e0`).
|
||||
//!
|
||||
//! Two consequences worth stating, because both are easy to get wrong:
|
||||
//!
|
||||
@@ -59,13 +59,13 @@
|
||||
//!
|
||||
//! ## What benilla does NOT take from that, and why
|
||||
//!
|
||||
//! - **All anchors translate, not just one.** wow-re's note reads the case-4 accumulate as hitting
|
||||
//! a single anchor record; it is their composition of verified pieces, not a recorded finding,
|
||||
//! and a one-anchor translation would *deform* a frame stretched between two anchors instead of
|
||||
//! moving it. Every movable frame in practice carries exactly one anchor, where the two readings
|
||||
//! are identical, so translating the whole set is the same behaviour everywhere it is observable
|
||||
//! and the sane behaviour where it is not.
|
||||
//! - **No clamp rebate.** `geo_768710` rebates the residual delta when the clamp pushes back
|
||||
//! - **All anchors translate, not just one.** The case-4 accumulate could be read as hitting a
|
||||
//! single anchor record; that reading is a composition of verified pieces, not a recorded
|
||||
//! finding, and a one-anchor translation would *deform* a frame stretched between two anchors
|
||||
//! instead of moving it. Every movable frame in practice carries exactly one anchor, where the
|
||||
//! two readings are identical, so translating the whole set is the same behaviour everywhere it
|
||||
//! is observable and the sane behaviour where it is not.
|
||||
//! - **No clamp rebate.** `0x768710` rebates the residual delta when the clamp pushes back
|
||||
//! (`SetClampedToScreen`); we do not, so dragging a clamped frame into the screen edge and back
|
||||
//! out can lag the cursor. Named, not hidden — the rebate is one of the two halves of that
|
||||
//! primitive we have not transcribed (the other is the eight resize cases).
|
||||
@@ -105,8 +105,8 @@ pub(crate) struct FrameMove {
|
||||
///
|
||||
/// **The reference's drag MODE, reduced to the one bit that is observable from Lua.** The
|
||||
/// mouse-up handler `0x766420` auto-cancels modes 1 (modifier-drag) and 2 (title region) and
|
||||
/// leaves mode 3 (`StartMoving`) running until `StopMovingOrSizing`
|
||||
/// (wow-re `widget-api-batch-benilla.md` Q6). So a title drag ends on release while a scripted
|
||||
/// leaves mode 3 (`StartMoving`) running until `StopMovingOrSizing`. So a title drag ends on
|
||||
/// release while a scripted
|
||||
/// one outlives the button — which is exactly the distinction this module's own doc already
|
||||
/// records for the drag/move split.
|
||||
pub(crate) auto_stop: bool,
|
||||
@@ -129,7 +129,7 @@ pub(crate) struct FrameSizing {
|
||||
pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// SetMovable(flag) / IsMovable() — flag word bit 0x100 (`0x776420`/`0x7764d0` through the
|
||||
// generic setter `0x76a3c0`). A pure flag write: it moves nothing, and clearing it mid-drag
|
||||
// stops nothing either (the setter has no side effects — wow-re ledger `0x76a3c0`); it is the
|
||||
// stops nothing either (the setter has no side effects — `0x76a3c0`); it is the
|
||||
// guard `StartMoving` tests, and the XML `movable="true"` attribute writes the same bit.
|
||||
// mlua's bool conversion is Lua truthiness, so the corpus's `SetMovable(1)` reads as true —
|
||||
// matching the reference binding's own `toboolean` marshal.
|
||||
@@ -158,9 +158,8 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// ── The resize-bounds quad — `Set/GetMinResize`, `Set/GetMaxResize` ────────────────────────
|
||||
//
|
||||
// Frame method table `0x878ec0`: `GetMinResize 0x775f20` · `SetMinResize 0x776020` ·
|
||||
// `GetMaxResize 0x7761a0` · `SetMaxResize 0x7762a0`. Byte-carved end to end by wow-re
|
||||
// (`system/ui/scratch/resize-bounds-and-button-fontstring.md` §2), and every clause below is
|
||||
// from that read rather than from the shape of the name:
|
||||
// `GetMaxResize 0x7761a0` · `SetMaxResize 0x7762a0`. Every clause below is from the bytes,
|
||||
// not from the shape of the name:
|
||||
//
|
||||
// · **The argument gate is `lua_isnumber`, not a strict number** (`0x6f34d0` on BOTH slots 2
|
||||
// and 3), so a numeric STRING passes and is coerced — while a missing argument, an explicit
|
||||
@@ -289,17 +288,17 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
start_moving(&mut model, h)
|
||||
})?,
|
||||
)?;
|
||||
// StartSizing(point) — begin a resize drag from a named grip (`0x776830`, verified in wow-re's
|
||||
// ledger; the reference's own caller is `FloatingChatFrame.lua:600`,
|
||||
// StartSizing(point) — begin a resize drag from a named grip (`0x776830`; the reference's own
|
||||
// caller is `FloatingChatFrame.lua:600`,
|
||||
// `this:GetParent():StartSizing(anchorPoint)`).
|
||||
//
|
||||
// **What is verified and what is read, kept apart on purpose.** Verified: the verb exists, it
|
||||
// takes the grip name, it returns nothing, and `StopMovingOrSizing` ends it (the same slot
|
||||
// clear as a move). NOT recorded anywhere in wow-re — the ledger has it as ORCHESTRATION with
|
||||
// no inline math — is WHICH EDGES a given grip moves. Taken here as the plain meaning of an
|
||||
// anchor point, which is how the reference's own caller uses it (its resize grips pass the
|
||||
// corner they sit in): the named edges follow the cursor and the opposite ones stay put. If an
|
||||
// RE pass ever contradicts that, this comment is where to correct it.
|
||||
// clear as a move). Not settled anywhere — the verb only orchestrates, with no inline math — is
|
||||
// WHICH EDGES a given grip moves. Taken here as the plain meaning of an anchor point, which is
|
||||
// how the reference's own caller uses it (its resize grips pass the corner they sit in): the
|
||||
// named edges follow the cursor and the opposite ones stay put. If the bytes ever contradict
|
||||
// that, this comment is where to correct it.
|
||||
//
|
||||
// Four corpus addons reach it through ONE line — `FuBar_Panel.lua:980`, replicated into
|
||||
// FuBar_CorkFu, FuBar_FuXPFu, FuBar_SpellStatusFu and oRA2 — which is 1207's rule and why the
|
||||
@@ -329,7 +328,7 @@ pub(super) fn install(lua: &Lua, m: &Table) -> mlua::Result<()> {
|
||||
// caller error. The pump's switch is on the anchor point-id, and case 4 (CENTER) is the
|
||||
// one arm that never touches width or height: it shifts the frame's anchor offsets and
|
||||
// returns before the clamp is ever reached, so a CENTER grip is unbounded by
|
||||
// construction (wow-re `resize-bounds-and-button-fontstring.md` §3.6). This file used
|
||||
// construction (`0x768bfb`). This file used
|
||||
// to say *"a grip naming no edge would resize nothing; the reference has no such call
|
||||
// and we refuse rather than invent one"* — the bytes have since answered that, and the
|
||||
// answer is the translate below, which is exactly what [`advance_move`] already does.
|
||||
@@ -421,8 +420,8 @@ fn get_flag(lua: &Lua, this: &Table, which: Flag) -> mlua::Result<Value> {
|
||||
/// The family's refusal, named frame and all — the reference's own shape (it formats the frame's
|
||||
/// `GetName()`, substituting a literal when the frame is anonymous).
|
||||
///
|
||||
/// **The text is OURS.** wow-re records the guards and the three `.rdata` addresses
|
||||
/// (`0x879810` StartMoving, `0x879828` StartSizing, `0x879844` SetUserPlaced) but not the strings
|
||||
/// **The text is OURS.** The three `.rdata` addresses are known (`0x879810` StartMoving,
|
||||
/// `0x879828` StartSizing, `0x879844` SetUserPlaced) but not the strings
|
||||
/// at them — only the truncated IDA symbol stubs `aFrameSIsNotMov` / `aFrameSIsNotRes` /
|
||||
/// `aFrameSIsNotM_0`, which is what this wording is shaped after. Nothing should match on it.
|
||||
fn not_flagged(model: &Model, h: FrameHandle, want: &str) -> mlua::Error {
|
||||
@@ -463,13 +462,13 @@ fn start_moving(model: &mut Model, h: FrameHandle) -> mlua::Result<()> {
|
||||
}
|
||||
|
||||
/// Begin a **title-region** move — mode 2, the drag a mouse-down inside `frame:GetTitleRegion()`
|
||||
/// starts (wow-re Q6, `0x7662c0` → `0x765320(frame, mode=2, …)` → `0x7652b0`).
|
||||
/// starts (`0x7662c0` → `0x765320(frame, mode=2, …)` → `0x7652b0`).
|
||||
///
|
||||
/// [`start_moving`]'s body **minus the movable gate**, and that omission is the carved part rather
|
||||
/// than a shortcut: the movable bit is `frame+0xb4 & 0x100`, tested by `StartMoving` (`0x77678b`,
|
||||
/// else `"Frame %s is not movable"`) and by the modifier-drag path — and **not read anywhere** on
|
||||
/// `0x7662c0`→`0x765320`→`0x7652b0`→`0x768430`. Q6 marks the no-gate reading VERIFIED and the
|
||||
/// observable claim INFERRED, because both FrameXML users happen to be `movable="true"`; a title
|
||||
/// [`start_moving`]'s body **minus the movable gate**, and that omission is the settled part
|
||||
/// rather than a shortcut: the movable bit is `frame+0xb4 & 0x100`, tested by `StartMoving`
|
||||
/// (`0x77678b`, else `"Frame %s is not movable"`) and by the modifier-drag path — and **not read
|
||||
/// anywhere** on `0x7662c0`→`0x765320`→`0x7652b0`→`0x768430`. The no-gate reading is settled; the
|
||||
/// observable claim is INFERRED, because both FrameXML users happen to be `movable="true"`; a title
|
||||
/// region on a non-movable frame is the case that would tell them apart, and it drags here.
|
||||
///
|
||||
/// Returns whether a move actually started — `false` when one was already in flight, which is
|
||||
@@ -515,10 +514,9 @@ fn mark_user_placed_change(model: &mut Model, h: FrameHandle) {
|
||||
|
||||
/// Apply a frame's `SetMinResize`/`SetMaxResize` bounds to a proposed size, per axis.
|
||||
///
|
||||
/// The reference's predicate, transcribed (decision 1505; wow-re
|
||||
/// `system/ui/scratch/resize-bounds-and-button-fontstring.md` §3.5 — decoded from `geo_768710`'s
|
||||
/// **emitted** `jcc`, not from the FPU status mask, and deliberately not from the dead `geo_768550`
|
||||
/// copy whose operand order differs):
|
||||
/// The reference's predicate, transcribed (decision 1505 — decoded from `0x768710`'s **emitted**
|
||||
/// `jcc`, not from the FPU status mask, and deliberately not from the dead `0x768550` copy whose
|
||||
/// operand order differs):
|
||||
///
|
||||
/// ```text
|
||||
/// if (min != 0.0) and (v < min): v = min
|
||||
@@ -594,8 +592,8 @@ pub(crate) fn advance_size(model: &mut Model, pos: (f32, f32)) {
|
||||
return;
|
||||
};
|
||||
// The frame's own `SetMinResize`/`SetMaxResize` bounds — read before the mutable borrow, and
|
||||
// the only path in the client that consults them at all (`clamp_resize`, and wow-re's §3.1
|
||||
// reachability census behind it).
|
||||
// the only path in the client that consults them at all (`clamp_resize`, reached only through
|
||||
// `0x76a660`).
|
||||
let (new_w, new_h) = clamp_resize(model, sz.frame, w0 + dw, h0 + dh);
|
||||
// **The rebate.** A saturated clamp is not a bare `max`/`min` in the reference: the residual
|
||||
// it swallowed is subtracted back out of the drag delta before the delta reaches the anchors
|
||||
@@ -609,7 +607,7 @@ pub(crate) fn advance_size(model: &mut Model, pos: (f32, f32)) {
|
||||
// rule. The sign follows the grip: a growing edge (`dw = +dx`) adds the residual, a shrinking
|
||||
// one (`dw = -dx`) subtracts it, so the delta always agrees with the size the clamp allowed.
|
||||
// An axis nobody gripped is left alone rather than rebated against a bound the frame was
|
||||
// already outside of — that frame stays put until a drag touches its axis, which is §3.8.
|
||||
// already outside of — that frame stays put until a drag touches its axis.
|
||||
let rebate = |d: f32, want: f32, got: f32, grew: bool, gripped: bool| {
|
||||
if !gripped {
|
||||
return d;
|
||||
@@ -632,11 +630,11 @@ pub(crate) fn advance_size(model: &mut Model, pos: (f32, f32)) {
|
||||
// The planted edge: a frame anchored by its LEFT that is gripped on the LEFT has to move too,
|
||||
// or the resize would push the right edge instead. Only the gripped axis shifts.
|
||||
//
|
||||
// **Which edges travel is OURS, and the byte carve does not settle it** — stated rather than
|
||||
// **Which edges travel is OURS, and the bytes do not settle it** — stated rather than
|
||||
// quietly aligned. The reference collapses the frame to a single planted TOPLEFT anchor at
|
||||
// `StartSizing` (`0x768430`), so *its* travelling edges are necessarily LEFT and TOP; we keep
|
||||
// the authored anchor set intact and shift every anchor's offsets, which is a different model
|
||||
// with a different answer. The rebate above is the part the carve does settle, and it applies
|
||||
// with a different answer. The rebate above is the part the bytes do settle, and it applies
|
||||
// either way.
|
||||
if !input.anchors.is_empty() && (sz.left || sz.bottom) {
|
||||
for a in &mut input.anchors {
|
||||
@@ -686,7 +684,7 @@ pub(crate) fn advance_move(model: &mut Model, pos: (f32, f32)) {
|
||||
}
|
||||
// Offsets are LOCAL units — the resolver multiplies them by the frame's own layoutScale
|
||||
// (`anchor_resolve_x`), so the cursor's screen delta divides by it on the way in, exactly the
|
||||
// `dx/scale` of `geo_768710`'s case 4.
|
||||
// `dx/scale` of `0x768710`'s case 4.
|
||||
let inv = 1.0 / eff_scale(model, mv.frame);
|
||||
let (dx, dy) = (dx * inv, dy * inv);
|
||||
if let Some(input) = model.layout_inputs.get_mut(&mv.frame) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//! frames. Until this module it was parsed and thrown away with a warn-once, so a benilla dialog
|
||||
//! opened behind another one stayed behind it.
|
||||
//!
|
||||
//! ## The law (wow-re `system/ui/scratch/toplevel-raise.md`, §5 fan-out 2026-07-21 — VERIFIED)
|
||||
//! ## The law
|
||||
//!
|
||||
//! The flag is **`[frame+0xb4]` bit `0x1`**, written by the same pure bit-setter `0x76a3c0` as
|
||||
//! `movable` (`0x100`) and `resizable` (`0x200`): `if (v) flags |= mask; else flags &= ~mask;`, no
|
||||
@@ -23,11 +23,11 @@
|
||||
//! *ancestor* of the one that was clicked or shown.
|
||||
//! 2. **`force != 0` ⇒ recompute the OVERLAPPED bit** (`0x76513e..0x765290`): resolve the frame's
|
||||
//! pending layout, then scan its stratum bucket from **its own level upward** for a frame that is
|
||||
//! not itself, is not one of its descendants (`is_descendant 0x767010`), and whose screen rect
|
||||
//! not itself, is not one of its descendants (`0x767010`), and whose screen rect
|
||||
//! intersects non-emptily. The answer is stored as `+0xb4` bit `0x10`.
|
||||
//! 3. **The raise, gated on that bit** (`0x7651ac..0x7651e7`): `level_compact 0x764eb0` squeezes the
|
||||
//! free levels out of the stratum — over **every live frame of it, hidden included**
|
||||
//! (`ui/scratch/level-compact-law.md`) — then `set_frame_level(bucket->count, propagate = 1)`.
|
||||
//! 3. **The raise, gated on that bit** (`0x7651ac..0x7651e7`): level compaction (`0x764eb0`)
|
||||
//! squeezes the free levels out of the stratum — over **every live frame of it, hidden
|
||||
//! included** — then `set_frame_level(bucket->count, propagate = 1)`.
|
||||
//!
|
||||
//! Three consequences the tests pin: a raise is **`level := top occupied level + 1`**, not a list
|
||||
//! reshuffle; it is **occlusion-gated** — `Raise()` on a frame that overlaps nothing changes nothing
|
||||
@@ -51,10 +51,10 @@
|
||||
//! term *above* the link stamp in our key, so a bump lifts the frame over every same-strata frame
|
||||
//! regardless of when each was last shown. The arithmetic is pinned in
|
||||
//! `tests/toplevel.rs::a_raise_is_top_occupied_level_plus_one_after_compaction`.
|
||||
//! - **`level_compact`** is [`crate::widget::WidgetArena::compact_levels`] — an order-preserving
|
||||
//! - **Level compaction** is [`crate::widget::WidgetArena::compact_levels`] — an order-preserving
|
||||
//! renumber of **every frame** in one stratum, hidden ones included: `0x764eb0` walks the client's
|
||||
//! master frame list filtering on strata and level alone, and never reads `+0xd4`
|
||||
//! (`ui/scratch/level-compact-law.md`, decision 2104). It changes no draw order by itself; it is
|
||||
//! (decision 2104). It changes no draw order by itself; it is
|
||||
//! what keeps `level := max + 1` from ratcheting upward for the length of a session. Renumbering
|
||||
//! only the *bucket* (the visible half) is the one shape it may not have: the raise's `propagate`
|
||||
//! delta is computed in the new numbering and applied to levels that are still in the old one, so
|
||||
@@ -84,12 +84,12 @@
|
||||
//!
|
||||
//! ## Triggers — the census, and which ones benilla wires
|
||||
//!
|
||||
//! wow-re's complete rel32 + absolute-dword census finds six call sites. Ours:
|
||||
//! A complete rel32 + absolute-dword census finds six call sites. Ours:
|
||||
//!
|
||||
//! | site | what it is | benilla |
|
||||
//! |---|---|---|
|
||||
//! | `0x775b0a` (Lua `Frame:Raise()`) | the explicit script call | [`install`] |
|
||||
//! | `0x76aeec` in `effective_visible_show 0x76ae10` | **the Show trigger** | [`raise_on_show`], run from [`crate::script::event::fire_visibility_changes`] |
|
||||
//! | `0x76aeec` in `0x76ae10` | **the Show trigger** | [`raise_on_show`], run from [`crate::script::event::fire_visibility_changes`] |
|
||||
//! | `0x7652d7` in begin-move `0x7652b0` | drag start | [`super::movable`]'s `start_moving` |
|
||||
//! | `0x766392` in the mouse-down handler `0x7662c0` | **the click trigger** | [`crate::script::UiScript::mouse_button`]'s down arm, first thing — capture-else-hover, unguarded, ahead of the title-region swallow |
|
||||
//! | `0x764a4c` (`force = 0`) | re-applies an already-computed bit `0x10` | no counterpart (see the OVERLAPPED note above) |
|
||||
@@ -185,7 +185,7 @@ pub(in crate::script) fn raise(model: &mut Model, frame: FrameHandle) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// The Show trigger — `effective_visible_show 0x76ae10` @`0x76aee0`: on a genuine `+0xd4`
|
||||
/// The Show trigger — `0x76ae10` @`0x76aee0`: on a genuine `+0xd4`
|
||||
/// false→true transition, **test the frame's own toplevel bit** and raise if it is set.
|
||||
///
|
||||
/// The own-bit test is load-bearing and is why this is not just [`raise`]: the worker would walk up
|
||||
@@ -228,7 +228,7 @@ fn nearest_toplevel(model: &Model, frame: FrameHandle) -> Option<FrameHandle> {
|
||||
/// Every clause matters, and each is a separate test:
|
||||
/// - **`level >= t.level` only.** A toplevel frame that overlaps solely something *below* it is
|
||||
/// already on top of it, so there is nothing to raise over.
|
||||
/// - **`is_descendant 0x767010` exclusion.** A window overlaps its own children by construction;
|
||||
/// - **Excludes descendants (`0x767010`).** A window overlaps its own children by construction;
|
||||
/// without this every toplevel frame with content would raise on every trigger.
|
||||
/// - **non-empty intersection.** Frames that merely share an edge do not overlap — the intersection
|
||||
/// has to have positive width *and* height, so a zero-area touch is not an occlusion.
|
||||
|
||||
Reference in New Issue
Block a user