Files
benilla-octo/crates/benilla-app/assets/ui/StanceBar.xml
T
SamandClaude Fable 5 d52a5670f6 case-folded slots, a chat-type table, and a seated spellbook
- GetInventorySlotInfo folds case the way the client does, and gains the twelve bag-slot rows the shipped data really carries
- ChatTypeGroup exists for addons that register their own chat types at file scope — one missing table was taking five addons down
- GetChannelList answers in join order, shaped by the addons that consume it, and the harness's `--why` can now open any demand count
- the survey seats a spellbook, and the shapeshift bar's shelf art exists hidden, both exposing paths an empty fixture could never reach

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 18:56:25 +07:00

259 lines
16 KiB
XML

<Ui>
<!--
The stance/shapeshift bar (vanilla ShapeshiftBarFrame, ref-BonusActionBarFrame.xml/.lua —
extracted from patch.MPQ). Warrior stances, druid forms, rogue Stealth: one CheckButton per
known form, checked = the ACTIVE form (the descriptor's UNIT_FIELD_BYTES_1 byte-2 form,
wow-re bonusbar-shapeshift.md), grey icon when not castable, cooldown swipe, click casts
the form (`crate::ui_shapeshift` drains CastShapeshiftForm onto the wire).
Geometry QUOTED from the ref, permanently in its RAISED mode (ShapeshiftBar_UpdatePosition's
MultiBarBottomLeft.isShowing branch — our bottom multibars are ALWAYS ON, MultiBars.xml):
frame BOTTOMLEFT at MainMenuBar TOPLEFT +(30,45); the ShapeshiftBarEnds/Middle shelf art
HIDDEN (raised mode hides it, so it is not modeled at all); buttons 30x30, button1 at frame
BOTTOMLEFT +(11,3), chained +7; NormalTexture UI-Quickslot2 at the raised mode's 50x50
(ref l.236-237), CENTER (0,-1) like the action template. Max 10 slots (NUM_SHAPESHIFT_SLOTS).
Ref divergences (deliberate):
- ONE refresh event: the app diffs the whole pushed form list (identity, active, castable,
cooldown) and fires UPDATE_SHAPESHIFT_FORMS on any change — so the ref's separate
Update/UpdateState split over six events (SPELL_UPDATE_COOLDOWN/_USABLE,
PLAYER_AURAS_CHANGED, UPDATE_INVENTORY_ALERTS "Wha??", ACTIONBAR_PAGE_CHANGED) collapses
into Update on UPDATE_SHAPESHIFT_FORMS + PLAYER_ENTERING_WORLD.
- No lastSelected bookkeeping (ref ShapeshiftBar_ChangeForm) — checked state is always
re-derived from the pushed `isActive`, never locally latched: the server's form byte is
the truth and the app re-pushes on its every change. (Verified dead in the ref itself:
`lastSelected` is written twice and read nowhere in the shipped FrameXML.)
-->
<Script><![CDATA[
NUM_SHAPESHIFT_SLOTS = 10
-- RIGHT-CLICK IS DEAD HERE, and deliberately (decision 1030 reverting 1027). The ref's
-- ShapeshiftButtonTemplate registers NOTHING: it inherits ActionButtonTemplate and then
-- overrides <OnLoad> with a body that only scales the cooldown, so the
-- `RegisterForClicks("LeftButtonUp","RightButtonUp")` that ActionButton_OnLoad gives every
-- other action-style button (ref ActionButton.lua:109) is lost and the default
-- {LeftButtonUp} stands. A right-press therefore neither flashes the pushed art
-- (0x77924b gates that on the same mask) nor casts. It reads like a Blizzard oversight
-- and it is the only bar that behaves this way — reproduced anyway, because the director
-- checked it against the reference and called faithful.
function BenillaShapeshiftButton_OnLoad(button, index)
button.index = index
button.icon = getglobal(button:GetName() .. "Icon")
button.cooldown = getglobal(button:GetName() .. "Cooldown")
end
-- The CheckButton widget toggles itself BEFORE OnClick fires (the widget contract); the
-- ref immediately reverts that toggle (ShapeshiftButtonTemplate OnClick, ref-
-- BonusActionBarFrame.xml l.31-38), so the checked ring never follows the click — only
-- the isActive repaint. That is what keeps a warrior's ACTIVE stance lit through the
-- click's silent wire no-op (stances never cancel — the 0x4b4963 guard), and a druid
-- form/Stealth lit until the server actually confirms the shift-out. The revert is
-- unconditional, which is why no click here can leave a lit form dark — unlike the pet
-- bar's flat SetChecked(0), which needs a repaint to be correct.
function BenillaShapeshiftButton_OnClick(button)
if button:GetChecked() then
button:SetChecked(nil)
else
button:SetChecked(1)
end
CastShapeshiftForm(button.index)
end
-- Hover: the form's spell tooltip through the engine channel (ref ShapeshiftBar's
-- GameTooltip:SetShapeshift; decision 0274 P2). Anchor: the ref's ShapeshiftButton
-- OnEnter (BonusActionBarFrame.xml l.40-45) takes the default corner when UberTooltips
-- is "1" — its byte-verified stock default (ActionBar.xml has the read) — so the branch
-- collapses to the default corner here too.
function BenillaShapeshiftButton_OnEnter(button)
if not GameTooltip then return end -- engine tests load file subsets
GameTooltip_SetDefaultAnchor(GameTooltip, button)
GameTooltip:SetShapeshift(button.index)
end
function BenillaShapeshiftButton_OnLeave(button)
GameTooltip:Hide()
end
-- Ref ShapeshiftBar_Update + ShapeshiftBar_UpdateState fused (SCOPE note above): size the
-- bar to the form count (hide the whole frame at 0 — a formless class never shows it),
-- then paint each button — icon, checked (active), the 1.0/0.4 castable tint (ref l.210-214),
-- cooldown swipe (CooldownFrame_SetTimer, Cooldown.xml's shared transcription).
function ShapeshiftBar_Update()
local numForms = GetNumShapeshiftForms()
if numForms > 0 then
ShapeshiftBarFrame:Show()
else
ShapeshiftBarFrame:Hide()
end
for i = 1, NUM_SHAPESHIFT_SLOTS do
local button = getglobal("ShapeshiftButton" .. i)
if i <= numForms then
local texture, name, isActive, isCastable = GetShapeshiftFormInfo(i)
button.icon:SetTexture(texture or BENILLA_FALLBACK_ICON)
local start, duration, enable = GetShapeshiftFormCooldown(i)
CooldownFrame_SetTimer(button.cooldown, start, duration, enable)
if isActive then
button:SetChecked(1)
else
button:SetChecked(0)
end
if isCastable then
button.icon:SetVertexColor(1.0, 1.0, 1.0)
else
button.icon:SetVertexColor(0.4, 0.4, 0.4)
end
button:Show()
else
button:Hide()
end
end
end
function ShapeshiftBar_OnLoad()
local frame = this
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("UPDATE_SHAPESHIFT_FORMS")
ShapeshiftBar_Update()
end
function ShapeshiftBar_OnEvent()
local frame = this
ShapeshiftBar_Update()
end
]]></Script>
<!--
One stance button (ref ShapeshiftButtonTemplate: 30x30, inherits ActionButtonTemplate's
art set): icon fills (BACKGROUND); Cooldown child (the ref SetScale(.83)s the 36px
template's — ours is sized 30x30 directly); the raised-mode 50x50 UI-Quickslot2 ring
CENTER (0,-1); the action template's pushed/highlight/checked trio.
-->
<CheckButton name="BenillaShapeshiftButtonTemplate" virtual="true">
<Size><AbsDimension x="30" y="30"/></Size>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentIcon"/>
</Layer>
</Layers>
<Frames>
<Cooldown name="$parentCooldown" hidden="true">
<Size><AbsDimension x="30" y="30"/></Size>
<Anchors>
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor>
</Anchors>
</Cooldown>
</Frames>
<NormalTexture name="$parentNormalTexture" file="Interface\Buttons\UI-Quickslot2">
<Size><AbsDimension x="50" y="50"/></Size>
<Anchors>
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor>
</Anchors>
</NormalTexture>
<PushedTexture file="Interface\Buttons\UI-Quickslot-Depress"/>
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
<Scripts>
<OnClick>BenillaShapeshiftButton_OnClick(self)</OnClick>
<OnEnter>BenillaShapeshiftButton_OnEnter(self)</OnEnter>
<OnLeave>BenillaShapeshiftButton_OnLeave(self)</OnLeave>
</Scripts>
</CheckButton>
<Frame name="ShapeshiftBarFrame" hidden="true">
<Size><AbsDimension x="29" y="32"/></Size>
<Anchors>
<Anchor point="BOTTOMLEFT" relativeTo="MainMenuBar" relativePoint="TOPLEFT"><Offset><AbsDimension x="30" y="45"/></Offset></Anchor>
</Anchors>
<!-- The shelf art (ref BonusActionBarFrame.xml l.220-249), declared HIDDEN.
The header above says this art "is not modeled at all" because raised mode hides it and
we are permanently raised. That reasoning was right about the PIXELS and wrong about
the NAMES: 1219/1223 settled that the reference does not choose between shown and
absent, and "we don't show it" is not a reason for it not to exist. Four frames landed
on that principle; these are the first REGIONS to, which is why the sweep that closed
the class missed them — it ran over the frames/tables ranking, and a Texture is
neither.
Two corpus addons index them, and both do pure LAYOUT — they do not use the art, they
move it, exactly the shape 1223 found for BonusActionBarFrame:
zBarEx/zMainBar.lua:288-290 SetParent(MainMenuBar) on all three
CT_BottomBar.lua:681-692 ClearAllPoints + SetPoint off-screen
Absent, `ShapeshiftBarLeft:ClearAllPoints()` is `attempt to index global` and takes the
addon's whole handler with it.
Geometry and TexCoords quoted: Left and Right are two crops of ONE `ShapeshiftBarEnds`
file (0..0.453125 and 0.453125..0.875), Middle its own. hidden="true" is the state
raised mode leaves them in, so this still draws nothing. -->
<Layers>
<Layer level="OVERLAY">
<Texture name="ShapeshiftBarLeft" file="Interface\ShapeshiftBar\ShapeshiftBarEnds" hidden="true">
<Size><AbsDimension x="45" y="50"/></Size>
<Anchors><Anchor point="BOTTOMLEFT"/></Anchors>
<TexCoords left="0" right="0.453125" top="0" bottom="1"/>
</Texture>
<Texture name="ShapeshiftBarMiddle" file="Interface\ShapeshiftBar\ShapeshiftBarMiddle" hidden="true">
<Size><AbsDimension x="38" y="50"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftBarLeft" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0" right="1" top="0" bottom="1"/>
</Texture>
<Texture name="ShapeshiftBarRight" file="Interface\ShapeshiftBar\ShapeshiftBarEnds" hidden="true">
<Size><AbsDimension x="42" y="50"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftBarMiddle" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0.453125" right="0.875" top="0" bottom="1"/>
</Texture>
</Layer>
</Layers>
<Frames>
<CheckButton name="ShapeshiftButton1" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="11" y="3"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 1)</OnLoad></Scripts>
</CheckButton>
<CheckButton name="ShapeshiftButton2" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftButton1" relativePoint="RIGHT"><Offset><AbsDimension x="7" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 2)</OnLoad></Scripts>
</CheckButton>
<CheckButton name="ShapeshiftButton3" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftButton2" relativePoint="RIGHT"><Offset><AbsDimension x="7" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 3)</OnLoad></Scripts>
</CheckButton>
<CheckButton name="ShapeshiftButton4" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftButton3" relativePoint="RIGHT"><Offset><AbsDimension x="7" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 4)</OnLoad></Scripts>
</CheckButton>
<CheckButton name="ShapeshiftButton5" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftButton4" relativePoint="RIGHT"><Offset><AbsDimension x="7" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 5)</OnLoad></Scripts>
</CheckButton>
<CheckButton name="ShapeshiftButton6" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftButton5" relativePoint="RIGHT"><Offset><AbsDimension x="7" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 6)</OnLoad></Scripts>
</CheckButton>
<CheckButton name="ShapeshiftButton7" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftButton6" relativePoint="RIGHT"><Offset><AbsDimension x="7" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 7)</OnLoad></Scripts>
</CheckButton>
<CheckButton name="ShapeshiftButton8" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftButton7" relativePoint="RIGHT"><Offset><AbsDimension x="7" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 8)</OnLoad></Scripts>
</CheckButton>
<CheckButton name="ShapeshiftButton9" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftButton8" relativePoint="RIGHT"><Offset><AbsDimension x="7" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 9)</OnLoad></Scripts>
</CheckButton>
<CheckButton name="ShapeshiftButton10" inherits="BenillaShapeshiftButtonTemplate">
<Anchors><Anchor point="LEFT" relativeTo="ShapeshiftButton9" relativePoint="RIGHT"><Offset><AbsDimension x="7" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>BenillaShapeshiftButton_OnLoad(self, 10)</OnLoad></Scripts>
</CheckButton>
</Frames>
<Scripts>
<OnLoad>ShapeshiftBar_OnLoad()</OnLoad>
<OnEvent>ShapeshiftBar_OnEvent()</OnEvent>
<!-- The stance bar is the pet/stance term of the managed bottom-stack positions
(UIParent.xml, decision 0272): its show/hide re-fires the pass, exactly the
ref's BonusActionBarFrame.xml:350-355. -->
<OnShow>UIParent_ManageFramePositions()</OnShow>
<OnHide>UIParent_ManageFramePositions()</OnHide>
</Scripts>
</Frame>
</Ui>