- the social window's third tab is live — the roster in both its views, the member card with its promote/demote/remove verbs, the rank editor's thirteen permissions, the guild information board, and the invite, leave, kick and note dialogs behind them - setting your hearthstone at an innkeeper now asks before it takes and says so afterwards, and the innkeeper's gossip lines get their own icons back - unavailable talents grey out, and every greyed icon in the client now goes through the same luminance fold the original used - the buff tooltip's remaining-time line reads gold with the client's own hour/minute ladder, the macro editor takes a shift-click to paste a spell, trainer rows repaint after a purchase, and a long book page stops flickering its ellipsis Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
527 lines
40 KiB
XML
527 lines
40 KiB
XML
<Ui>
|
||
<!--
|
||
benilla's gossip dialog (decision 0081 phase 3), RE-SKINNED to the real 1.12 gossip/quest
|
||
greeting window (dressing arc, decision 0084): the geometry and art below are QUOTED from the
|
||
real `GossipFrame.xml` (scratchpad `ref-GossipFrame.xml`; line citations inline), turned onto
|
||
our own feeds/intents. The name `GossipFrame`, its panel registration
|
||
(UiPanels.xml's UIPanelWindows["GossipFrame"], area="left", pushable=0), the Era gossip
|
||
feeds (GetGossipText/GetGossipOptions/IsGossipOptionCoded/SelectGossipOption/CloseGossip/
|
||
GetNumGossipQuests/GetGossipQuestInfo/SelectGossipQuest), and the intent functions are
|
||
UNCHANGED — only the window's dressing is real now.
|
||
|
||
A hidden window that shows on GOSSIP_SHOW and hides on GOSSIP_CLOSED. It wears the real
|
||
QuestFrame parchment: four quadrant slabs (UI-QuestGreeting-{TopLeft,TopRight,BotLeft,BotRight},
|
||
ref l.13-44) at the real 384×512 (ref l.128); the greeting body and the row list quoted from
|
||
the real GossipGreetingText / GossipTitleButtonTemplate (ref l.86-125, 223-264).
|
||
|
||
QUEST ROWS (decision 0088 §3, filled in): the real `GossipFrameUpdate` (ref l.24-29) fills ONE
|
||
shared `GossipTitleButton` pool through three sequential passes over a single `buttonIndex`
|
||
counter — `GossipFrameAvailableQuestsUpdate` (ref l.63-85) first, `GossipFrameActiveQuestsUpdate`
|
||
(ref l.87-109) second, `GossipFrameOptionsUpdate` (ref l.111-128) third — so quest rows always
|
||
land ABOVE the option rows, and the two blocks share the very same row buttons/anchors (a
|
||
`titleButton.type` field picked at fill time routes the click: `SelectGossipAvailableQuest` /
|
||
`SelectGossipActiveQuest` / `SelectGossipOption`, ref l.53-61). We mirror that shape exactly but
|
||
over our OWN flatter seam (`benilla-ui` `script/gossip.rs`): the app already resolves the wire's
|
||
available/active split and delivers ONE ordered `GetNumGossipQuests()`/`GetGossipQuestInfo(i)`
|
||
list (quest rows first, in wire order), so `BenillaGossipFrame_Update` below runs a single loop
|
||
over the shared `GossipRow1..8` pool — quest rows fill from i=1, option rows fill after
|
||
them — instead of the ref's three separate counters; a row's `.kind` ("quest"/"option") plus its
|
||
`.itemIndex` (the row's 1-based position within ITS OWN list) is all `BenillaGossipRow_OnClick`
|
||
needs to call the right one of `SelectGossipQuest`/`SelectGossipOption` (ref's three intents
|
||
collapse to two on our seam — see gossip.rs's doc comment). Per-row icon: active → the real
|
||
`Interface\GossipFrame\ActiveQuestIcon` (ref l.99), available → `Interface\GossipFrame\
|
||
AvailableQuestIcon` (ref l.75) — both verified present in the MPQ list. We DO run the ref's
|
||
per-row `GossipResize` auto-height (ref l.130-132, `SetHeight(GetTextHeight()+2)`) — see
|
||
`BenillaGossipRow_Resize` below — but skip its "too many quests" message()
|
||
(ref l.67-69/91-93/115-117): the shared 8-row cap below silently drops the overflow exactly
|
||
like the option rows always did.
|
||
|
||
ENGINE-SLICE CAVEAT (this branch predates the dressing arc's engine slice — named `<Font>`
|
||
objects are not implemented here yet, loader.rs "named Font objects are not implemented in v1").
|
||
The real window's `inherits="QuestFont"` FontStrings are transcribed faithfully below (they are
|
||
part of the quoted geometry), but until the font-object slice + our Fonts.xml land on this line
|
||
the loader warns "unknown template 'QuestFont'" and the strings render in the default font —
|
||
no worse than before (nothing here inherited a font). They light up automatically when the
|
||
slice merges. No <TexCoords> is used: every quadrant samples its whole texture (the real gossip
|
||
window uses TexCoords only on the material/patch art we omit), so this window needs none of it.
|
||
|
||
The NPC name rides in the title banner (ref GossipFrameNpcNameText, l.157-178): a GameFontHighlight
|
||
FontString centred at the window TOP -23, mirroring the merchant's pattern — the app resolves the
|
||
gossip NPC's guid through the NameCache and delivers the name as arg1 of GOSSIP_SHOW; empty until
|
||
it lands. The GOODBYE button rides bottom-right (ref GossipFrameGreetingGoodbyeButton, l.206-222),
|
||
wired to the same close path as the close button.
|
||
|
||
The scroll frame IS here now (ref l.223-436): the greeting + the 32-row pool ride a real
|
||
`<ScrollFrame>`, so a menu taller than the parchment scrolls instead of spilling out of the
|
||
window. See the ScrollFrame's own comment below. Nothing of the real window is knowingly
|
||
omitted any more except the BotLeftPatch material art.
|
||
|
||
UIPanel slot system (decision 0084 §2): carries NO hardcoded <Anchors> — ShowUIPanel/SetLeftFrame
|
||
SetPoints it to the left slot (TOPLEFT UIParent, 0, -104) on open; every show goes through
|
||
ShowUIPanel, every hide through HideUIPanel, never Show()/Hide() directly.
|
||
-->
|
||
<Script><![CDATA[
|
||
-- The shared row pool's cap (decision 0088 §3): quest rows fill from slot 1, option rows fill
|
||
-- after them, both drawing from the SAME GossipRow1..32 buttons (ref's single
|
||
-- GossipTitleButton pool, l.24-29/63-128). This IS the reference's number
|
||
-- (`NUMGOSSIPBUTTONS = 32`, ref-GossipFrame.lua l.1); benilla ran a cap of 8 only because an
|
||
-- overflowing menu had nowhere to go — with the scroll frame below, it does.
|
||
BENILLA_GOSSIP_MAX = 32
|
||
|
||
-- Every widget that can be the LOWEST visible thing in the scroll child, for the content
|
||
-- measure (BenillaScroll_ResizeChild, ScrollTemplates.xml). Built once at load, like the
|
||
-- quest window's per-panel lists.
|
||
BENILLA_GOSSIP_SCROLL_WIDGETS = (function()
|
||
local t = { "GossipGreetingText" }
|
||
for i = 1, BENILLA_GOSSIP_MAX do table.insert(t, "GossipRow" .. i) end
|
||
return t
|
||
end)()
|
||
|
||
-- The Era icon-type string → the real Blizzard gossip-icon texture (resolves from the MPQ at
|
||
-- render). Unmapped types fall back to the chat bubble (the app already defaults unknowns to
|
||
-- "gossip", so this is belt-and-braces).
|
||
--
|
||
-- These are ALL TEN the 1.12 install ships under `Interface\GossipFrame\*GossipIcon.blp`.
|
||
-- The reference builds the path by pasting the type string straight in (ref
|
||
-- GossipFrame.lua:123), so the shipped art is the whole vocabulary a row can draw. The app
|
||
-- indexes the wire icon byte into the client's own name table (`ui_gossip::
|
||
-- GOSSIP_ICON_TYPES`, VERIFIED at 0x84b7ac — decisions 1331/1335); four of these
|
||
-- (healer/banker/petition/tabard) were unreachable before 1331, which is why the
|
||
-- innkeeper's bind line drew a speech bubble (B249).
|
||
--
|
||
-- The client's table has an ELEVENTH name, `auctioneer` at index 10, and 5875 ships no
|
||
-- texture for it — the reference draws nothing there. No key for it here on purpose: our
|
||
-- lookup then falls back to the chat bubble, which is the better wrong answer than a
|
||
-- missing texture, and `ui_gossip`'s test pins the absence so nobody invents a path.
|
||
BENILLA_GOSSIP_ICONS = {
|
||
gossip = "Interface\\GossipFrame\\GossipGossipIcon",
|
||
vendor = "Interface\\GossipFrame\\VendorGossipIcon",
|
||
taxi = "Interface\\GossipFrame\\TaxiGossipIcon",
|
||
trainer = "Interface\\GossipFrame\\TrainerGossipIcon",
|
||
healer = "Interface\\GossipFrame\\HealerGossipIcon",
|
||
binder = "Interface\\GossipFrame\\BinderGossipIcon",
|
||
banker = "Interface\\GossipFrame\\BankerGossipIcon",
|
||
petition = "Interface\\GossipFrame\\PetitionGossipIcon",
|
||
tabard = "Interface\\GossipFrame\\TabardGossipIcon",
|
||
battlemaster = "Interface\\GossipFrame\\BattleMasterGossipIcon",
|
||
}
|
||
|
||
-- The real per-row quest icons (ref l.75/99) — active (in-progress/turn-in) vs available
|
||
-- (not yet accepted), the same split `GossipQuestRow.active` already carries off the wire.
|
||
BENILLA_GOSSIP_QUEST_ICON_ACTIVE = "Interface\\GossipFrame\\ActiveQuestIcon"
|
||
BENILLA_GOSSIP_QUEST_ICON_AVAILABLE = "Interface\\GossipFrame\\AvailableQuestIcon"
|
||
|
||
function BenillaGossipRow_OnLoad(button)
|
||
button.icon = getglobal(button:GetName() .. "Icon")
|
||
button.label = getglobal(button:GetName() .. "Label")
|
||
end
|
||
|
||
-- The ref's GossipResize (ref l.130-132: `SetHeight(GetTextHeight() + 2)`) — a row is as
|
||
-- tall as its OWN wrapped label. Load-bearing, not cosmetic: the rows hang off each other
|
||
-- in one static chain (each on the previous row's BOTTOMLEFT), so a row left at the
|
||
-- template's 16px while its label draws three wrapped lines puts the next row's text
|
||
-- straight through this one's — every long option overprinting its neighbour (the
|
||
-- director's judgement-menu screenshot). The reference's own LEFT-anchored label is only
|
||
-- correct BECAUSE of this resize: centring the text on a row sized to the text is the same
|
||
-- as top-aligning it.
|
||
--
|
||
-- Deviation from the ref, the same one the tab-fit carries (UiPanels.xml
|
||
-- `BenillaTabButton_OnUpdate`): the client's GetTextHeight is a synchronous font-engine
|
||
-- call, ours is the measure round-trip's answer and lands a frame late — 0 until the host
|
||
-- has measured THIS text. A zero keeps the current height (never collapses the row) and
|
||
-- the frame's OnUpdate below re-runs the fit until it settles.
|
||
function BenillaGossipRow_Resize(button)
|
||
local h = button.label:GetHeight()
|
||
if h <= 0 or button.benillaFitHeight == h then return end
|
||
button.benillaFitHeight = h
|
||
button:SetHeight(h + 2)
|
||
end
|
||
|
||
-- Size the scroll child to the rows actually on it, so the bar ranges over the real content
|
||
-- (the ref grows its child with the 15px GossipSpacerFrame under the last row instead —
|
||
-- ref-GossipFrame.lua l.39-44; the shared kit's BENILLA_SCROLL_PAD is that breathing room).
|
||
function BenillaGossipFrame_SizeScrollChild()
|
||
BenillaScroll_ResizeChild("GossipGreetingScroll", BENILLA_GOSSIP_SCROLL_WIDGETS)
|
||
end
|
||
|
||
-- The convergence driver (the tab-fit / quest-panel idiom): while the menu is up, re-fit
|
||
-- every visible row until its measure lands, after which the guard above makes this a
|
||
-- no-op compare per row per frame. OnUpdate only fires on effectively-visible frames, so
|
||
-- a closed gossip window costs nothing. The rows fit FIRST and the child is measured after,
|
||
-- so the scroll range sees their settled heights in the same pass.
|
||
function BenillaGossipFrame_OnUpdate()
|
||
for i = 1, BENILLA_GOSSIP_MAX do
|
||
local button = getglobal("GossipRow" .. i)
|
||
if button:IsShown() then
|
||
BenillaGossipRow_Resize(button)
|
||
end
|
||
end
|
||
BenillaGossipFrame_SizeScrollChild()
|
||
end
|
||
|
||
-- One shared row serves either a quest or an option depending on what
|
||
-- BenillaGossipFrame_Update assigned it this repaint (button.kind, set there) — mirrors the
|
||
-- ref's titleButton.type dispatch (ref l.53-61), collapsed onto our seam's two intents
|
||
-- (SelectGossipQuest covers both the ref's Available/Active clicks, gossip.rs's doc comment).
|
||
function BenillaGossipRow_OnClick(button)
|
||
if button.kind == "quest" then
|
||
SelectGossipQuest(button.itemIndex)
|
||
else
|
||
SelectGossipOption(button.itemIndex)
|
||
end
|
||
end
|
||
|
||
function BenillaGossipFrame_Update()
|
||
getglobal("GossipGreetingText"):SetText(GetGossipText() or "")
|
||
local numQuests = GetNumGossipQuests()
|
||
-- GetGossipOptions() returns a flat vararg of (label, type) pairs (the Era shape).
|
||
local opts = { GetGossipOptions() }
|
||
local numOptions = #opts / 2
|
||
for i = 1, BENILLA_GOSSIP_MAX do
|
||
local button = getglobal("GossipRow" .. i)
|
||
if i <= numQuests then
|
||
-- Quest rows fill first (ref l.27-28: available then active, already ordered by
|
||
-- the app before it reaches GetGossipQuestInfo) — the row's OWN 1-based position
|
||
-- IS its quest-list index, so no separate local counter is needed.
|
||
local title, active = GetGossipQuestInfo(i)
|
||
button.kind = "quest"
|
||
button.itemIndex = i
|
||
button.label:SetText(title)
|
||
BenillaGossipRow_Resize(button)
|
||
button.icon:SetTexture(active and BENILLA_GOSSIP_QUEST_ICON_ACTIVE or BENILLA_GOSSIP_QUEST_ICON_AVAILABLE)
|
||
button:Enable()
|
||
button:Show()
|
||
elseif i <= numQuests + numOptions then
|
||
-- Option rows fill after every quest row (ref l.29 runs last) — itemIndex is the
|
||
-- row's position WITHIN the options list, not the shared pool slot.
|
||
local optIndex = i - numQuests
|
||
local label = opts[(optIndex - 1) * 2 + 1]
|
||
local otype = opts[(optIndex - 1) * 2 + 2]
|
||
button.kind = "option"
|
||
button.itemIndex = optIndex
|
||
button.label:SetText(label)
|
||
-- A label whose measure is already cached (a revisit to this NPC) fits on this
|
||
-- very repaint; a fresh string fits on the next OnUpdate tick.
|
||
BenillaGossipRow_Resize(button)
|
||
button.icon:SetTexture(BENILLA_GOSSIP_ICONS[otype] or BENILLA_GOSSIP_ICONS.gossip)
|
||
-- Coded (password) options are greyed and unselectable in v1 (decision 0081).
|
||
if IsGossipOptionCoded(optIndex) then
|
||
button:Disable()
|
||
else
|
||
button:Enable()
|
||
end
|
||
button:Show()
|
||
else
|
||
button:Hide()
|
||
end
|
||
end
|
||
-- The ref's GossipFrameUpdate tail (ref-GossipFrame.lua l.46-48): a repaint always lands
|
||
-- back at the TOP of the menu, then re-ranges the bar off the new content.
|
||
getglobal("GossipGreetingScroll"):SetVerticalScroll(0)
|
||
BenillaGossipFrame_SizeScrollChild()
|
||
end
|
||
|
||
function GossipFrame_OnLoad()
|
||
local frame = this
|
||
-- The NPC portrait: the "npc" unit token → the interaction NPC's live model bake
|
||
-- (crates/benilla/src/portrait, InteractNpc). Bound once; the app re-resolves it every
|
||
-- frame, so a revisit to a different gossip NPC shows that face.
|
||
SetPortraitTexture(getglobal(frame:GetName() .. "Portrait"), "npc")
|
||
frame:RegisterEvent("GOSSIP_SHOW")
|
||
frame:RegisterEvent("GOSSIP_CLOSED")
|
||
end
|
||
|
||
-- The gossip NPC's name arrives as arg1 of GOSSIP_SHOW (the app resolves the NPC guid through
|
||
-- the NameCache); nil/empty until it lands → a blank banner (mirrors the merchant title).
|
||
function BenillaGossipFrame_SetTitle(name)
|
||
getglobal("GossipNpcNameText"):SetText(name or "")
|
||
end
|
||
|
||
function GossipFrame_OnEvent()
|
||
local frame = this
|
||
if event == "GOSSIP_SHOW" then
|
||
BenillaGossipFrame_SetTitle(arg1)
|
||
BenillaGossipFrame_Update()
|
||
ShowUIPanel(frame)
|
||
elseif event == "GOSSIP_CLOSED" then
|
||
HideUIPanel(frame)
|
||
end
|
||
end
|
||
|
||
function BenillaGossipCloseButton_OnClick()
|
||
-- vanilla's client-side close sends no packet; the app clears the menu on this intent
|
||
-- (which fires GOSSIP_CLOSED), and we hide immediately so there's no one-frame lag.
|
||
CloseGossip()
|
||
HideUIPanel(getglobal("GossipFrame"))
|
||
end
|
||
]]></Script>
|
||
|
||
<!--
|
||
One shared gossip row (ref GossipTitleButtonTemplate, l.86-125): the real 300×16 template, used
|
||
by the REAL client for quest rows AND option rows alike (a single pool, ref l.24-29/63-128) — we
|
||
do the same rather than carrying two near-identical templates. The type icon sits at the row's
|
||
TOPLEFT (16×16; ref $parentGossipIcon, l.92-102) — the real XML defaults it to
|
||
UI-Quest-BulletPoint, but the real client (like us) overrides it per row kind at Update time, so
|
||
we carry no default file and let BenillaGossipFrame_Update set it (quest → Active/AvailableQuestIcon,
|
||
ref l.75/99; option → the per-type GossipIcon). The label is QuestFont, LEFT, at LEFT +20 (ref
|
||
ButtonText, l.112-124). The highlight is the real UI-QuestTitleHighlight ADD glow (ref l.111).
|
||
-->
|
||
<Button name="BenillaGossipRowTemplate" virtual="true">
|
||
<Size><AbsDimension x="300" y="16"/></Size>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="$parentIcon">
|
||
<Size><AbsDimension x="16" y="16"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
<Layer level="ARTWORK">
|
||
<FontString name="$parentLabel" inherits="QuestFont" justifyH="LEFT">
|
||
<Size><AbsDimension x="275" y="0"/></Size>
|
||
<Anchors>
|
||
<Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="20" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<HighlightTexture file="Interface\QuestFrame\UI-QuestTitleHighlight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnClick>BenillaGossipRow_OnClick(self)</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
|
||
<Frame name="GossipFrame" hidden="true">
|
||
<!-- The real 384×512 window (ref l.128). No <Anchors> — ShowUIPanel/SetLeftFrame SetPoints this
|
||
to the left slot on open. -->
|
||
<Size><AbsDimension x="384" y="512"/></Size>
|
||
<Layers>
|
||
<!-- The four QuestGreeting quadrant slabs that ARE the parchment art (ref l.13-44): 256-wide
|
||
left halves, 128-wide right halves, each 256 tall, pinned to their corner. No <TexCoords>
|
||
— each samples its whole texture. The solid-colour fill is gone (the parchment is
|
||
opaque). -->
|
||
<Layer level="BACKGROUND">
|
||
<!-- NPC portrait 60×60 TOPLEFT (7,-6) (ref GossipFramePortrait), declared BEFORE the
|
||
parchment so it draws UNDER it and the parchment's ring frames the portrait (the empty
|
||
ring showed the scene through the hole before). Bound in OnLoad, circle-masked. -->
|
||
<Texture name="$parentPortrait">
|
||
<Size><AbsDimension x="60" y="60"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="7" y="-6"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestGreeting-TopLeft">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestGreeting-TopRight">
|
||
<Size><AbsDimension x="128" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"/></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestGreeting-BotLeft">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors><Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestGreeting-BotRight">
|
||
<Size><AbsDimension x="128" y="256"/></Size>
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"/></Anchors>
|
||
</Texture>
|
||
<!-- Ref GossipFrame.xml:191-202: gossip has no bottom-LEFT button, but the shared
|
||
UI-QuestGreeting-BotLeft art bakes the button recess in — the ref covers it
|
||
with this patch (the director's "bottom left hole"). -->
|
||
<Texture file="Interface\QuestFrame\UI-Quest-BotLeftPatch">
|
||
<Size><AbsDimension x="128" y="64"/></Size>
|
||
<Anchors><Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="22" y="68"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
<Layer level="ARTWORK">
|
||
<!-- NPC name banner (ref GossipFrameNpcNameText l.157-178): GameFontHighlight, centred
|
||
on the window at TOP -23. The app delivers the name as arg1 of GOSSIP_SHOW; blank
|
||
until it lands. CENTER + the single-point (~zero-width) rect keeps the name centred
|
||
regardless of length, exactly like the merchant's title. -->
|
||
<FontString name="GossipNpcNameText" inherits="GameFontHighlight" justifyH="CENTER">
|
||
<Anchors>
|
||
<Anchor point="TOP" relativePoint="TOP"><Offset><AbsDimension x="0" y="-23"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!--
|
||
The greeting + row list live inside a REAL ScrollFrame — the reference's own structure
|
||
(ref-GossipFrame.xml l.223-436, extracted via mpqx this session), which benilla omitted
|
||
on the grounds that "our short greeting needs no scrolling". A gossip menu of wrapped
|
||
roleplay options is exactly the case that breaks: once each row grew to its text
|
||
(BenillaGossipRow_Resize), four long options ran off the parchment and out of the
|
||
window (the director's second screenshot). The ref's answer is this scroll frame, and
|
||
it is now ours: 300x334 at the window's TOPLEFT +(23,-81) (ref l.223-233) over a child
|
||
the same size (ref l.235-239), the greeting at the child's +(10,-10) (ref l.241-252),
|
||
and the row chain hanging off the greeting exactly as before (ref l.256-269).
|
||
|
||
Content taller than the frame is CLIPPED to it and panned (engine mechanism, decision
|
||
0112) instead of overflowing; BenillaGossipFrame_SizeScrollChild sizes the child to the
|
||
measured content each repaint, which re-ranges the bar through OnScrollRangeChanged.
|
||
The ref grows its child with a 15px GossipSpacerFrame under the last row (ref l.421-432,
|
||
re-anchored per update by GossipFrame.lua l.39-44); ours is the shared kit's
|
||
BENILLA_SCROLL_PAD, the same breathing room by a plainer mechanism.
|
||
-->
|
||
<ScrollFrame name="GossipGreetingScroll">
|
||
<Size><AbsDimension x="300" y="334"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="23" y="-81"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:SetScrollChild(getglobal(self:GetName() .. "Child"))</OnLoad>
|
||
<OnMouseWheel>BenillaScroll_OnMouseWheel(this, arg1)</OnMouseWheel>
|
||
<OnVerticalScroll>BenillaScroll_SyncBar(this)</OnVerticalScroll>
|
||
<OnScrollRangeChanged>BenillaScroll_SyncBar(this)</OnScrollRangeChanged>
|
||
</Scripts>
|
||
<Frames>
|
||
<!-- The scrollbar rides the ScrollFrame as a child, the ref's UIPanelScrollFrameTemplate
|
||
shape (ref-UIPanelTemplates.xml l.166-181: $parentScrollBar, TOPLEFT->TOPRIGHT
|
||
+(6,-16) / BOTTOMLEFT->BOTTOMRIGHT +(6,16)) — so the bar's PARENT is the frame it
|
||
scrolls, with no name derivation. It wears the shared Slider bar (drag + arrows,
|
||
decision 0250); only OnValueChanged is overridden, off the faux kit's row-offset
|
||
handler onto the real-scroll one. Hidden until the content overflows (SyncBar). -->
|
||
<Slider name="$parentBar" inherits="BenillaScrollBarTemplate" hidden="true">
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="6" y="-16"/></Offset></Anchor>
|
||
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="6" y="16"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Scripts><OnValueChanged>BenillaScrollBar_OnValueChanged(self, arg1)</OnValueChanged></Scripts>
|
||
</Slider>
|
||
<Frame name="$parentChild">
|
||
<Size><AbsDimension x="300" y="334"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||
<Layers>
|
||
<Layer level="ARTWORK">
|
||
<!-- Greeting body: the real GossipGreetingText (ref l.241-252) — QuestFont,
|
||
LEFT, 270 wide so the engine wraps it, at the child's +(10,-10). -->
|
||
<FontString name="GossipGreetingText" inherits="QuestFont" justifyH="LEFT">
|
||
<Size><AbsDimension x="270" y="0"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="10" y="-10"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- The shared row pool, now the reference's full NUMGOSSIPBUTTONS = 32
|
||
(ref-GossipFrame.lua l.1; ours capped at 8 only because an overflowing
|
||
menu had nowhere to go). Quest rows fill it first, option rows after
|
||
(decision 0088 sec.3). Row 1 hangs off the GREETING's BOTTOMLEFT +(-10,-20),
|
||
the rest off the previous row's BOTTOMLEFT (ref l.256-269) — one static
|
||
chain, so rows re-flow off each other's measured heights with no runtime
|
||
repositioning. -->
|
||
<Button name="GossipRow1" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipGreetingText" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-10" y="-20"/></Offset></Anchor></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow2" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow1" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow3" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow2" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow4" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow3" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow5" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow4" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow6" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow5" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow7" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow6" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow8" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow7" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow9" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow8" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow10" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow9" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow11" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow10" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow12" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow11" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow13" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow12" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow14" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow13" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow15" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow14" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow16" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow15" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow17" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow16" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow18" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow17" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow19" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow18" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow20" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow19" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow21" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow20" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow22" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow21" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow23" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow22" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow24" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow23" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow25" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow24" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow26" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow25" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow27" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow26" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow28" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow27" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow29" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow28" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow30" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow29" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow31" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow30" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
<Button name="GossipRow32" inherits="BenillaGossipRowTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="GossipRow31" relativePoint="BOTTOMLEFT"/></Anchors><Scripts><OnLoad>BenillaGossipRow_OnLoad(self)</OnLoad></Scripts></Button>
|
||
</Frames>
|
||
</Frame>
|
||
</Frames>
|
||
</ScrollFrame>
|
||
<!-- Close: the real GossipFrameCloseButton position (CENTER on the window's TOPRIGHT,
|
||
-42,-31; ref l.179-187), on the minimize-button art our close already used (the real
|
||
UIPanelCloseButton art rides the tooltip/dialog arc). -->
|
||
<Button name="GossipCloseButton">
|
||
<Size><AbsDimension x="32" y="32"/></Size>
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-42" y="-31"/></Offset></Anchor>
|
||
</Anchors>
|
||
<NormalTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Up"/>
|
||
<PushedTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Down"/>
|
||
<HighlightTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Highlight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnClick>BenillaGossipCloseButton_OnClick()</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
<!-- GOODBYE button (ref GossipFrameGreetingGoodbyeButton l.206-222): the real red
|
||
UIPanelButtonTemplate, 78×22, BOTTOMRIGHT of the window -39,73. Our engine ships no
|
||
UIPanelButtonTemplate, so the button face is built directly from the very textures that
|
||
template resolves to — UI-Panel-Button-{Up,Down,Highlight} (all verified in the MPQ),
|
||
stretched over the button as its Normal/Pushed/Highlight art. The "Goodbye" label
|
||
(GlobalStrings GOODBYE = "Goodbye") is an OVERLAY FontString centred on the button (the
|
||
real ButtonText draws in the OVERLAY layer). Wired to the same close path as the close
|
||
button (CloseGossip → HideUIPanel), mirroring the ref's OnClick HideUIPanel(GossipFrame). -->
|
||
<Button name="GossipGoodbyeButton">
|
||
<Size><AbsDimension x="78" y="22"/></Size>
|
||
<Anchors>
|
||
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="-39" y="73"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<FontString name="$parentText" inherits="GameFontNormal" justifyH="CENTER" text="Goodbye">
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"/>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<!-- The button face occupies only the top-left 0.625×0.6875 of each file — the real
|
||
UIPanelButton*Texture templates slice it with exactly these TexCoords
|
||
(ref-UIPanelTemplates.xml l.3-17). Drawing the whole file (transparent padding
|
||
included) squashed the face into the scuffed blob the director's A/B caught. -->
|
||
<NormalFont inherits="GameFontNormal"/>
|
||
<HighlightFont inherits="GameFontHighlight"/>
|
||
<DisabledFont inherits="GameFontDisable"/>
|
||
<NormalTexture file="Interface\Buttons\UI-Panel-Button-Up">
|
||
<TexCoords left="0" right="0.625" top="0" bottom="0.6875"/>
|
||
</NormalTexture>
|
||
<PushedTexture file="Interface\Buttons\UI-Panel-Button-Down">
|
||
<TexCoords left="0" right="0.625" top="0" bottom="0.6875"/>
|
||
</PushedTexture>
|
||
<HighlightTexture file="Interface\Buttons\UI-Panel-Button-Highlight" alphaMode="ADD">
|
||
<TexCoords left="0" right="0.625" top="0" bottom="0.6875"/>
|
||
</HighlightTexture>
|
||
<Scripts>
|
||
<OnClick>BenillaGossipCloseButton_OnClick()</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad>GossipFrame_OnLoad()</OnLoad>
|
||
<OnEvent>GossipFrame_OnEvent()</OnEvent>
|
||
<!-- The row auto-height's settle pass (see BenillaGossipRow_Resize): our text measure
|
||
is a frame late, so the fit re-runs here until every visible row's label measure
|
||
lands. Fires only while the window is effectively visible. -->
|
||
<OnUpdate>BenillaGossipFrame_OnUpdate()</OnUpdate>
|
||
<!-- OnShow/OnHide, quoted from the real GossipFrame.xml frame Scripts (l.445/454): the
|
||
kits igQuestListOpen/Close, and — load-bearing — CloseGossip() on hide (the real
|
||
GossipFrame_OnHide). CloseGossip ends the gossip session whenever the frame hides,
|
||
INCLUDING when another NPC window displaces it at the UIPanel slot (SetLeftFrame →
|
||
oldFrame:Hide() → OnHide); without it the GossipState resource stayed set after a
|
||
vendor/quest window replaced the menu, and gossip would not reopen until the
|
||
range-guard reset it (decision 0095). No-packet client-side clear; idempotent with the
|
||
close button, which also calls it. Never fires at load (hidden="true"). -->
|
||
<OnShow>PlaySound("igQuestListOpen")</OnShow>
|
||
<OnHide>CloseGossip(); PlaySound("igQuestListClose")</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
</Ui>
|