From 20f38e1f7e371847039c5ddffeca2a1ff7a913c4 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 31 Aug 2026 20:15:38 +0700 Subject: [PATCH] deleting a good item asks in the reference's words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - deleting a rare-or-better item forks to the reference's typed confirm — "Type \"DELETE\" into the field to confirm": Yes starts disabled, the box takes focus, the button enables only while the field spells DELETE, and a reflexive Enter over a half-typed word is inert; the missing engine piece was one hook, the edit box's on-text-changed; beside it, the loot bind-on-pickup confirm — bind-on-pickup AND uncommon-or-better, two conjuncts and no others, so a white BoP drop is taken with no dialog and a bind-on-equip blue never asks here — with the reference's one-pending-slot latch, and the take split into two verbs the way 1.12 actually has it: the row click stays C-side, and LootSlot is only the confirmation's continuation - the message frames get their justify quartet, read out of the binary's method tables (with the Button table re-derived as the control that lacks it); Frame:EnableDrawLayer/DisableDrawLayer and Region:GetDrawLayer land — the disabled layers are a five-bit mask on the frame, so re-enabling a layer restores exactly what was showing underneath; and the Skills tab's children take the reference's names, with SKILLS_TO_DISPLAY published — pfUI loops over it and got "'for' limit must be a number" - the README's roadmap line now names what is genuinely big — battlegrounds and meeting stones, both verified still missing — plus the long tail, because the old line named four features that have since landed and small features go stale on a roadmap within a week Co-Authored-By: Claude Fable 5 --- README.md | 4 +- crates/benilla-app/assets/ui/LootFrame.xml | 71 ++- crates/benilla-app/assets/ui/SkillFrame.xml | 53 +- crates/benilla-app/assets/ui/UiPanels.xml | 146 +++++- crates/benilla-app/src/ui_loot.rs | 452 +++++++++++++++++- .../src/ui_script/character_tests.rs | 2 +- .../src/ui_script/delete_item_tests.rs | 226 ++++++++- .../benilla-app/src/ui_script/loot_tests.rs | 119 +++++ .../src/ui_script/skills_frame_tests.rs | 20 +- crates/benilla-ui/src/script/extract.rs | 9 + crates/benilla-ui/src/script/loot.rs | 75 ++- .../benilla-ui/src/script/messageframe/mod.rs | 121 ++++- .../src/script/messageframe/plain.rs | 4 + .../src/script/messageframe/scrolling.rs | 4 + crates/benilla-ui/src/script/mod.rs | 7 +- crates/benilla-ui/src/script/model.rs | 16 +- crates/benilla-ui/src/script/object.rs | 12 + .../src/script/object/frame_state.rs | 34 +- crates/benilla-ui/src/script/region/paint.rs | 26 +- .../src/widget/kinds/messageframe.rs | 46 ++ crates/benilla-ui/src/widget/mod.rs | 14 + 21 files changed, 1369 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index fe99a8b0..6fd67597 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ benilla is done when a 1.12.1 player can do everything here that they could in t client, it looks and feels the same, and it runs from a download on Windows, Linux and macOS. No dates; the order is what is likely, not a promise. -- The rest of the basics: battlegrounds, guild charters, the stable master, meeting stones, - GM tickets, master loot, cinematics and whatever else turns up. +- Battlegrounds and meeting stones, then the long tail of small features that separates a + working client from a finished one. - Addons, options and performance, ongoing. - The no-brainer fixes from VanillaFixes, SuperWoW and the like. - Playable downloads for Windows, Linux and macOS. Linux first. diff --git a/crates/benilla-app/assets/ui/LootFrame.xml b/crates/benilla-app/assets/ui/LootFrame.xml index 6a593a1d..0af1492c 100644 --- a/crates/benilla-app/assets/ui/LootFrame.xml +++ b/crates/benilla-app/assets/ui/LootFrame.xml @@ -34,9 +34,12 @@ The Era loot API this drives (all app-fed via the loot seam, benilla-ui `script/loot.rs`): GetNumLootItems(), GetLootSlotInfo(slot) -> texture,item,quantity,quality, LootSlotIsItem/ LootSlotIsCoin(slot), GetLootSlotLink(slot) (the row's item link, read by the click's - ctrl/shift arms — decision 1059), LootSlot(slot) (the row click's action), CloseLoot() (from - OnHide). The synthesized coin pile is row 1 when the loot carries gold; a row click sends the - money or the item's wire slot (the app maps it). + ctrl/shift arms — decision 1059), BenillaTakeLootSlot(slot) (the row click's action, which + in 1.12 is the C LootButton's and no Lua binding at all — decision 1744), LootSlot(slot) (the + LOOT_BIND confirmation continuation, its only 1.12 meaning), CloseLoot() (from OnHide). The + synthesized coin pile is row 1 when the loot carries gold; a row click sends the money or the + item's wire slot (the app maps it) — unless the row binds on pickup, where it raises the + soulbind confirm instead and the send waits for the OK. Paging (LootFrame.lua l.27-31,70-73,105-118): 4 rows/page; > 4 items spends one slot on the pager, showing 3 rows + Up/Down. We keep the current page across content-change repaints @@ -139,13 +142,13 @@ -- · The button code is never read (`0x4c1820` doesn't look at it), so a RIGHT-click loots -- exactly like a left one — which is why this handler takes no `mouseButton`. -- - -- benilla folds that C action into this Lua handler (`LootSlot(button.slot)`, this file's - -- model since 0084), so the gate has to be an early return here. Named divergence, not a - -- transcription slip: 1.12 exposes no plain "take slot N" binding at all — the real - -- `LootSlot 0x4c2e70` is the LOOT_BIND *confirmation continuation* (flag 1, gated on the - -- stashed slot at `[0x847cec]`; its only FrameXML caller is `StaticPopup.lua:606`). Moving - -- the take host-side onto the widget, and shrinking `LootSlot()` to that continuation, is - -- 1067's named follow-up. + -- benilla folds that C action into this Lua handler, so the gate has to be an early return + -- here. The verb it calls is `BenillaTakeLootSlot`, not `LootSlot`, and that is 1067's + -- named follow-up landed (decision 1744): 1.12 exposes no plain "take slot N" binding at + -- all — the real `LootSlot 0x4c2e70` is the LOOT_BIND *confirmation continuation* (flag 1, + -- gated on the stashed slot at `[0x847cec]`; its only FrameXML caller is + -- `StaticPopup.lua:606`, the entry below). Ours keeps exactly that meaning, so an addon + -- calling `LootSlot(n)` on an ordinary row does what it does on the real client: nothing. -- -- The reference's tail (StaticPopup_Hide("CONFIRM_LOOT_DISTRIBUTION") and the four -- LootFrame.selected* fields, l.155-161) is the MASTER-LOOT dropdown's bookkeeping — @@ -198,7 +201,7 @@ LootFrame.selectedItemName = button.name:GetText() if modified then return end - LootSlot(button.slot) + BenillaTakeLootSlot(button.slot) end -- Hover: the plain engine item tooltip, ITEM rows only — the ref's own gate (its @@ -302,12 +305,53 @@ LootFrame_Update() end + -- ── The soulbind confirm ────────────────────────────────────────────────────────────── + -- ref GlobalStrings.lua l.2612 / l.2818 / l.465, fallback form (the player's own localized + -- file runs off the patch chain first). + LOOT_NO_DROP = LOOT_NO_DROP or "Looting this item will bind it to you." + OKAY = OKAY or "Okay" + CANCEL = CANCEL or "Cancel" + + -- ref StaticPopup.lua l.601-611, verbatim. `OnAccept`'s argument is `dialog.data`, which + -- the driver below sets to the event's row — and `LootSlot` is the continuation verb, so + -- this line is the ONLY thing in the client that ever completes a bind-deferred take. + -- + -- Nothing else is needed: no OnCancel (declining just leaves the row in the window, and the + -- app drops the pending stash when the window turns over) and no OnUpdate poll, because the + -- window's own LOOT_CLOSED hides it (below, ref LootFrame.lua l.53-54). + StaticPopupDialogs["LOOT_BIND"] = { + text = LOOT_NO_DROP, + button1 = OKAY, + button2 = CANCEL, + OnAccept = function(slot) + LootSlot(slot) + end, + timeout = 0, + exclusive = 1, + hideOnEscape = 1, + } + + -- ref UIParent.lua l.317-323. The row rides on `dialog.data` rather than as a text arg — + -- LOOT_NO_DROP has no format specifier, so the dialog shows the same sentence whatever + -- binds; the number is only there to be handed back to LootSlot. + -- + -- The reference registers this on UIParent, which owns every bind confirm; benilla hangs it + -- on LootFrame, whose LOOT_CLOSED already has to hide the dialog. Same two moments, one + -- listener, and the arc stays in one file. + function BenillaLootBindConfirm(slot) + local dialog = StaticPopup_Show("LOOT_BIND") + if dialog then + dialog.data = slot + end + end + function LootFrame_OnLoad() local frame = this frame.page = 1 frame:RegisterEvent("LOOT_OPENED") frame:RegisterEvent("LOOT_UPDATE") frame:RegisterEvent("LOOT_CLOSED") + frame:RegisterEvent("LOOT_BIND_CONFIRM") -- Master loot (ref l.9-10). Neither event carries an argument: the candidate list is -- read back through GetMasterLootCandidate at menu-build time, not pushed. frame:RegisterEvent("OPEN_MASTER_LOOT_LIST") @@ -338,7 +382,12 @@ LootFrame_PageDown() end elseif event == "LOOT_CLOSED" then + -- ref l.53-54: the confirm dies with the window it addressed. Its row number would + -- name a slot in the NEXT corpse otherwise. + StaticPopup_Hide("LOOT_BIND") HideUIPanel(frame) + elseif event == "LOOT_BIND_CONFIRM" then + BenillaLootBindConfirm(arg1) elseif event == "OPEN_MASTER_LOOT_LIST" then -- Ref l.58-61. Anchored to the ROW that was clicked, not to the frame — the name -- the click stashed a moment ago. diff --git a/crates/benilla-app/assets/ui/SkillFrame.xml b/crates/benilla-app/assets/ui/SkillFrame.xml index 151f9392..701c9270 100644 --- a/crates/benilla-app/assets/ui/SkillFrame.xml +++ b/crates/benilla-app/assets/ui/SkillFrame.xml @@ -96,7 +96,14 @@ -->