- the camera auto-follow returns, as a setting: Camera Following Style on the Controls options page — Smart (the default), Always, Never — so after an orbit drag the camera swings back behind you while you run; far sight still forces the chase off - broken addons announce themselves: world entry prints "3 addon load failures — type /errors to see them", and the `/errors` window lists every script error this session with its traceback — 256 deduplicated rows, repeats collapsing onto a count — while the five load-failure classes that only ever hit the terminal (missing .toc, unparseable FrameXML, dependency cycles…) finally get a channel - B opens the backpack alone, SHIFT-B opens all bags, F8–F11 toggle the individual slots — the reference's six bag commands instead of one command wearing every chord; and the Skills page gets its CLOSE button, with the ALL fold in the row font - cmangos-classic logons work: `CMSG_AUTH_SESSION` now carries the real client's twelve secure-addon records (342 bytes, compressing to 130) — an empty addon block is a shape no client can send, and cmangos kicks for it where vmangos shrugs; Warden-enabled anticheat remains a separate wall Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
755 lines
54 KiB
XML
755 lines
54 KiB
XML
<Ui>
|
||
<!--
|
||
benilla's Skills tab (decision 0437 phase 4): the 1.12 `SkillFrame`, re-expressed from the
|
||
reference FrameXML `SkillFrame.{xml,lua}` (session scratchpad `ref-ui/`, decision 0246
|
||
discipline — never committed) onto our own engine/feeds. Geometry/art-paths below are QUOTED
|
||
from the ref (line citations inline, into that same `SkillFrame.xml`/`.lua`); the Lua is
|
||
the ref's logic turned onto benilla's Era API (`GetNumSkillLines`/`GetSkillLineInfo`/
|
||
`Expand`/`CollapseSkillHeader`/`SetSelectedSkill`/`GetSelectedSkill`, decision 0437's skills
|
||
seam, `crates/benilla-ui/src/script/skills.rs`, built alongside this file).
|
||
|
||
A CHILD PAGE of `CharacterFrame` (ref: `parent="CharacterFrame"`, `id="4"` — ours too, since
|
||
the Reputation page landed and took slot 3 back), shown/
|
||
hidden by `CharacterFrame_ShowSubFrame` exactly like `PaperDollFrame` — but NOT a
|
||
physically nested `<Frame>` the way PaperDollFrame is: PaperDollFrame is declared INSIDE
|
||
CharacterFrame.xml's own `<Frames>` tree (a real engine parent/child), while this page is a
|
||
SEPARATE file's top-level `<Frame>` (CharacterFrame.xml is shared-tree with another session
|
||
this pass, so only its tab machinery is touched here — not its frame tree). `parent=` is
|
||
transcribed for fidelity but is a NO-OP in this engine (grepped `benilla-ui/src/loader`: the
|
||
XML `parent` attribute is read nowhere — only physical `<Frames>` nesting creates a real
|
||
parent). Position instead rides `<Anchors relativeTo="CharacterFrame">` (a NAMED
|
||
lookup, works regardless of tree position, the same mechanism every sibling-anchor in this
|
||
codebase already uses) — loaded right after `CharacterFrame.xml` in the load list so it
|
||
paints ON TOP of it (later file = higher z, the established house convention every top-level
|
||
window already relies on implicitly). Because a true engine Hide-cascade doesn't reach a
|
||
non-child, `CharacterFrame.xml`'s own `CharacterFrame_OnHide` was extended (its own
|
||
header comment) to loop-hide every `BENILLA_CHARACTERFRAME_SUBFRAMES` entry — the fix this
|
||
page's non-nested shape requires, done once so later non-nested tabs (Pet/Reputation/Honor)
|
||
inherit it for free.
|
||
|
||
NO OWN PORTRAIT (matches the ref: `ref-ui/SkillFrame.xml` l.130-213 draws no portrait Texture
|
||
at all): the shared quadrant background art below (`UI-Character-General-TopLeft/TopRight`,
|
||
the SAME "General" variant the ref uses, l.136-159) carries the SAME baked-in portrait-ring
|
||
cutout every PaperDollInfoFrame quadrant variant shares, so `CharacterFrame`'s own
|
||
portrait/name/level (drawn at a lower z, underneath) shows through unchanged — exactly the
|
||
ref's own real-client compositing (SkillFrame is a nested child there too, relying on the
|
||
same cutout rather than redrawing the portrait itself).
|
||
|
||
FLAT layout (TrainerFrame.xml/TradeSkillFrame.xml's own house constraint): this window has no
|
||
DETAIL FontStrings needing a nested child Frame in the first place — the minimal detail pane
|
||
(below) is a single StatusBar instance whose own name/rank FontStrings live on ITS OWN Layers
|
||
(a StatusBar, like a Button, renders its own Layers fine — only a plain child `<Frame>` loses
|
||
them), the exact `BenillaTradeSkillRankFrame` shape TradeSkillFrame.xml already proved.
|
||
|
||
v1 DEVIATIONS (each re-cited at its own site below):
|
||
1. THE DETAIL PANE IS MINIMAL-PLUS-DESCRIPTION-PLUS-ABANDON: the selected skill's rank
|
||
StatusBar + name + the DESCRIPTION BODY (`SkillDetailDescriptionText` — ref
|
||
`SkillDetailDescriptionText`/`SKILL_DESCRIPTION`, real since `GetSkillLineInfo`'s 13th
|
||
return carries `SkillLine.dbc` col 12) + the ABANDON BUTTON
|
||
(`SkillDetailUnlearnButton` → the `UNLEARN_SKILL` confirm → `AbandonSkill` →
|
||
`CMSG_UNLEARN_SKILL`; the isAbandonable predicate is `SkillRaceClassInfo.flags & 0x20`
|
||
— the server's own gate, real 5875 data: primary professions only). STILL OMITTED:
|
||
the training-point spend row (the ref's `LeftArrow`/`RightArrow`/`LearnSkillButton`/
|
||
`SkillDetailCostText`, all driven by `stepCost`/`rankCost`, which `GetSkillLineInfo`
|
||
always reports nil/0 — 0437's own named out-of-scope: 1.12 training points are dead
|
||
data).
|
||
2. NO SORT CHECKBOX (ref l.215-241's own XML-commented-out "Replace once code is ready..."
|
||
`SkillSortButton`): the ref itself ships this dead/commented, so there is nothing to
|
||
transcribe (TradeSkillFrame.xml's own "ref's own dead code is dropped" precedent).
|
||
3. NO ACCEPT BUTTON (ref l.318-337's `SkillFrameAcceptButton`) — it is XML-commented dead
|
||
in the ref, and it backs the training-point economy this pane doesn't ship (deviation 1),
|
||
so there is nothing to transcribe. Its neighbour `SkillFrameCancelButton` (l.339-357) is
|
||
NOT dead and IS built: the ref's comment closes at l.337, one line above it, and the real
|
||
client draws a CLOSE button in the page's bottom-right seat. This list used to claim both
|
||
were commented out, and that misread is exactly why that seat rendered empty — decision
|
||
1496. Only its `CancelSkillUps()` call drops (deviation 1's dead economy again); the two
|
||
hides are transcribed.
|
||
4. THE RANK TEXT FORMAT IS THE REF'S BYTE-EXACT ONE, not the task brief's own paraphrase:
|
||
`ref-ui/SkillFrame.lua` l.178-186 builds `rank .. " (" .. color .. modifier .. close ..
|
||
")/" .. max` (e.g. "57 (|cff20ff20+3|r)/75") — transcribed verbatim (the
|
||
reference file is the authority on the tuple/format, the brief's prose is a summary).
|
||
5. NO FILLBAR (ref's `$parentFillBar`, driven by `numTempPoints`): [`GetSkillLineInfo`]
|
||
always reports `numTempPoints = 0` (skills.rs's own module doc — 1.12 training points are
|
||
dead data), so the fill bar could never show — dropped outright, `TradeSkillFrame.xml`'s
|
||
OWN `BenillaTradeSkillRankFrame` (the identical StatusBar shape) already sets this local
|
||
precedent for the same reason.
|
||
6. NO HOVER TOOLTIP on a row: the ref's own `SkillFrame.lua` calls `GameTooltip` NOWHERE
|
||
(grepped the full reference file) — a skill line is pure descriptor state, nothing to
|
||
preview. Unlike Trainer/TradeSkill, this window needs no `GameTooltip:Set*Item` channel.
|
||
7. `LockHighlight`/`UnlockHighlight` ENGINE GAP (TalentFrame.xml/TradeSkillFrame.xml's own
|
||
"no engine equivalent" posture, grepped `benilla-ui/src/script/button.rs` — ships
|
||
texture-pairs/SetText/Enable/Disable/RegisterForClicks/SetButtonState/Click only): the
|
||
persistent selection glow is `SkillHighlight`, the separate overlay Frame
|
||
Trainer/TradeSkillFrame already use, moved onto the selected row's StatusBar.
|
||
8. GlobalStrings this window itself needs: NONE beyond the tab label `SKILLS` (already
|
||
declared in CharacterFrame.xml, quoted there byte-exact with its GlobalStrings.lua line
|
||
cite) — the ref's own `SkillFrame.lua` reads no other GlobalString.
|
||
|
||
Rows repaint on `SKILL_LINES_CHANGED` (registered here; `crates/benilla/src/ui_char.rs`'s
|
||
`watch_skill_ups`/`feed_skills` already fire it) and on `OnShow` (ref `SkillFrame_OnShow`,
|
||
l.4-6). The list is the house faux-scroll kit (ScrollTemplates.xml, the TrainerFrame/
|
||
TradeSkillFrame precedent) over 12 fixed row slots (ref `SKILLS_TO_DISPLAY = 12`,
|
||
`SkillFrame.lua:1` — the ref's own row count, and this page shares the ref's own 384×512
|
||
coordinate space since it fills the identical CharacterFrame page area).
|
||
-->
|
||
<Script><![CDATA[
|
||
-- ── Constants (ref SkillFrame.lua:1-2) ──────────────────────────────────────────────────────
|
||
local SKILLFRAME_SKILLS_DISPLAYED = 12 -- SKILLS_TO_DISPLAY
|
||
local SKILLFRAME_SKILL_HEIGHT = 15 -- SKILLFRAME_SKILL_HEIGHT
|
||
|
||
-- GlobalStrings (ref GlobalStrings.lua:3478), chunk-local per the codebase idiom — safe
|
||
-- because only THIS chunk's functions read it; the nil-"All" trap (TradeSkillFrame.xml's
|
||
-- deviation notes) is the inline-XML-handler case, and no inline handler references it.
|
||
-- Its earlier ABSENCE here made format() throw in UpdateDetail on every row selection —
|
||
-- half of the 2026-07-17 "tabs are flaky" report (the silent-error half).
|
||
local SKILL_DESCRIPTION = "|cffffffff%s|r %s"
|
||
local UNLEARN_SKILL = "Do you want to unlearn %s?" -- GlobalStrings.lua:4446
|
||
local UNLEARN = "Unlearn" -- GlobalStrings.lua:4445
|
||
local UNLEARN_SKILL_TOOLTIP = "Unlearn this profession" -- GlobalStrings.lua:4447
|
||
|
||
-- Paint the rank StatusBar `bar` + its `SkillName`/`SkillRank` FontStrings for one skill-line
|
||
-- ENTRY row (never a header — callers guard that): the ref's own bar-fill + rank-text half of
|
||
-- `SkillFrame_SetStatusBar` (l.76-187) and the detail's twin `SkillDetailFrame_SetStatusBar`
|
||
-- (l.161-187, l.370-399) — the SAME formatting either pane uses, factored once here since our
|
||
-- minimal detail pane (deviation 1) needs nothing else from that function.
|
||
function BenillaSkillFrame_PaintBar(bar, skillName, skillRank, skillModifier, skillMaxRank)
|
||
local nameText = getglobal(bar:GetName() .. "SkillName")
|
||
local rankText = getglobal(bar:GetName() .. "SkillRank")
|
||
-- The trough behind the fill (ref `$parentBackground`), recoloured per branch alongside
|
||
-- the fill itself — ref SkillFrame.lua:158 (normal) and :167 (proficiency), and the
|
||
-- detail pane's identical pair at :356/:376. The ref sets the normal-skill pair BEFORE
|
||
-- its `skillMaxRank` gate and lets the proficiency arm overwrite it; setting each arm's
|
||
-- own pair here is the same result with no dead write. The ref's THIRD writer of this
|
||
-- texture — the `skillCostType == 1/2/3` green/yellow/red block at :96-111, and the
|
||
-- `stepCost` "Learn <skill>" gray at :126 — is unreachable for us and would be
|
||
-- overwritten here even if it weren't: `stepCost`/`rankCost` are always nil and
|
||
-- `numTempPoints` always 0 (skills.rs's module doc — dead 1.12 data, deviation 1/5), so
|
||
-- every entry row takes the ref's own `else -- Normal skill` arm.
|
||
local bgTexture = getglobal(bar:GetName() .. "Background")
|
||
nameText:SetText(skillName)
|
||
nameText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
|
||
rankText:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
if skillMaxRank == 1 then
|
||
-- ref SkillFrame.lua:161-167 verbatim: "If max rank in a skill is 1 assume that
|
||
-- its a proficiency" — a FULL gray bar and NO rank text. Two kinds of line land
|
||
-- here, and the ref can't tell them apart because it doesn't need to: the armor
|
||
-- proficiencies, which the server really does report as 1/1, and the single-rank
|
||
-- lines (class skills, Dual Wield, racials, the per-mount riding lines) whose
|
||
-- `skillMaxRank` the engine already overrode to 1 off
|
||
-- `SkillRaceClassInfo.flags & 0x400` (skills.rs's `SkillEntry::mono`) — which is
|
||
-- why a hunter's `Beast Mastery 300/300` draws gray and numberless here, exactly
|
||
-- as it does in the real client.
|
||
bar:SetMinMaxValues(0, 1)
|
||
bar:SetValue(1)
|
||
bar:SetStatusBarColor(0.5, 0.5, 0.5)
|
||
rankText:SetText("")
|
||
bgTexture:SetVertexColor(1.0, 1.0, 1.0, 0.5)
|
||
elseif skillMaxRank == 0 then
|
||
-- Not reachable off a live server (a line the player HAS always carries a max ≥ 1)
|
||
-- and the ref leaves this case to fall through its own if/elseif untouched —
|
||
-- which, on a recycled row, would leave the PREVIOUS skill's bar and rank text
|
||
-- sitting there. We blank instead: a stale-state hole is a quirk, not behaviour.
|
||
bar:SetMinMaxValues(0, 1)
|
||
bar:SetValue(0)
|
||
bar:SetStatusBarColor(0, 0, 0, 0)
|
||
rankText:SetText("")
|
||
-- back to the template's own declared base, so a recycled row shows a neutral empty
|
||
-- trough rather than the previous skill's blue or white. The base lives in the
|
||
-- TEXEL (the template's `<Color 1,1,1,0.2>`), so restoring it means an IDENTITY
|
||
-- vertex colour — writing 0.2 here would multiply it to 0.04 (decision 1101).
|
||
bgTexture:SetVertexColor(1.0, 1.0, 1.0, 1.0)
|
||
else
|
||
bar:SetStatusBarColor(0.0, 0.0, 1.0, 0.5)
|
||
bgTexture:SetVertexColor(0.0, 0.0, 0.75, 0.5)
|
||
bar:SetMinMaxValues(0, skillMaxRank)
|
||
bar:SetValue(skillRank)
|
||
-- the ref's rank-text law (SkillFrame.lua:178-186), re-expressed here (this file's
|
||
-- header comment, deviation 4).
|
||
if skillModifier == 0 then
|
||
rankText:SetText(skillRank .. "/" .. skillMaxRank)
|
||
else
|
||
local color = RED_FONT_COLOR_CODE
|
||
if skillModifier > 0 then
|
||
color = GREEN_FONT_COLOR_CODE .. "+"
|
||
end
|
||
rankText:SetText(skillRank .. " (" .. color .. skillModifier .. FONT_COLOR_CODE_CLOSE .. ")/" .. skillMaxRank)
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Fill the detail pane (deviation 1) for the current `GetSelectedSkill()`, or blank it
|
||
-- when nothing is selected / the selection isn't a visible entry. The description body is
|
||
-- the ref's own (ref SkillFrame.lua l.211-217 hide/show alongside the bar; l.262 the
|
||
-- SKILL_DESCRIPTION format): `skillType` stays "" in EVERY reachable 1.12 branch — the
|
||
-- ref's single assignment ("Tertiary Skill:") is commented out in the reference itself —
|
||
-- so the format's first slot renders empty, byte-faithful. The unlearn button rides the
|
||
-- same fill (ref l.220-226): shown only for an abandonable line, carrying the name the
|
||
-- confirm popup formats and the index its accept abandons.
|
||
function BenillaSkillFrame_UpdateDetail()
|
||
local bar = getglobal("SkillDetailBar")
|
||
local desc = getglobal("SkillDetailDescriptionText")
|
||
local unlearn = getglobal("SkillDetailUnlearnButton")
|
||
local index = GetSelectedSkill()
|
||
if index == 0 then
|
||
bar:Hide()
|
||
desc:Hide()
|
||
unlearn:Hide()
|
||
return
|
||
end
|
||
local skillName, isHeader, _, skillRank, _, skillModifier, skillMaxRank, isAbandonable = GetSkillLineInfo(index)
|
||
if not skillName or isHeader then
|
||
bar:Hide()
|
||
desc:Hide()
|
||
unlearn:Hide()
|
||
return
|
||
end
|
||
bar:Show()
|
||
BenillaSkillFrame_PaintBar(bar, skillName, skillRank, skillModifier, skillMaxRank)
|
||
if isAbandonable then
|
||
unlearn.skillName = skillName
|
||
unlearn.index = index
|
||
unlearn:Show()
|
||
else
|
||
unlearn:Hide()
|
||
end
|
||
local skillType = ""
|
||
local skillDescription = select(13, GetSkillLineInfo(index)) or ""
|
||
desc:SetText(format(SKILL_DESCRIPTION, skillType, skillDescription))
|
||
desc:Show()
|
||
end
|
||
|
||
-- ── The abandon confirm + the unlearn button's handlers ──────────────────────────────────
|
||
-- The dialog is ref StaticPopup.lua:1121-1133 verbatim (minus the vestigial TEXT()
|
||
-- wrapper); its OnAccept receives dialog.data — the visible index the button stashed.
|
||
-- CANCEL stays the bare GlobalStrings global (DeathFrame.xml's own convention — the app
|
||
-- loads the real GlobalStrings.lua before any window file). The handlers are chunk
|
||
-- functions, NOT inline bodies, so the chunk-local strings above are visible to them
|
||
-- (the nil-"All" chunk-boundary rule, TradeSkillFrame.xml's deviation notes).
|
||
StaticPopupDialogs["UNLEARN_SKILL"] = {
|
||
text = UNLEARN_SKILL,
|
||
button1 = UNLEARN,
|
||
button2 = CANCEL,
|
||
OnAccept = function(index)
|
||
AbandonSkill(index)
|
||
end,
|
||
timeout = 60,
|
||
exclusive = 1,
|
||
whileDead = 1,
|
||
showAlert = 1,
|
||
hideOnEscape = 1
|
||
}
|
||
|
||
function BenillaSkillUnlearnButton_OnClick(btn)
|
||
local dialog = StaticPopup_Show("UNLEARN_SKILL", btn.skillName)
|
||
if dialog then
|
||
dialog.data = btn.index
|
||
end
|
||
end
|
||
|
||
function BenillaSkillUnlearnButton_OnEnter(btn)
|
||
GameTooltip:SetOwner(btn, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(UNLEARN_SKILL_TOOLTIP)
|
||
end
|
||
|
||
-- Paint list slot `i` (1..12) from the visible row at `index` (ref SkillFrame_SetStatusBar,
|
||
-- l.24-188 — the header branch, l.55-69, and the entry branch, l.76-187, collapsed: the
|
||
-- skillCostType coloring + stepCost/rankCost training-up arrows never apply here, since
|
||
-- GetSkillLineInfo always reports them nil/0, this file's header comment deviation 1).
|
||
function BenillaSkillFrame_SetRow(i, index, numRows)
|
||
local bar = getglobal("SkillRankFrame" .. i)
|
||
local label = getglobal("SkillTypeLabel" .. i)
|
||
|
||
if index > numRows then
|
||
bar:Hide()
|
||
bar.skillIndex = nil
|
||
label:Hide()
|
||
label.skillIndex = nil
|
||
return
|
||
end
|
||
|
||
local skillName, isHeader, isExpanded, skillRank, _, skillModifier, skillMaxRank = GetSkillLineInfo(index)
|
||
|
||
if isHeader then
|
||
bar:Hide()
|
||
bar.skillIndex = nil
|
||
label:Show()
|
||
label.skillIndex = index
|
||
label:SetText(skillName)
|
||
if isExpanded then
|
||
label:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up")
|
||
else
|
||
label:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up")
|
||
end
|
||
return
|
||
end
|
||
|
||
label:Hide()
|
||
label.skillIndex = nil
|
||
bar:Show()
|
||
bar.skillIndex = index
|
||
BenillaSkillFrame_PaintBar(bar, skillName, skillRank, skillModifier, skillMaxRank)
|
||
end
|
||
|
||
-- The list page (ref SkillFrame_UpdateSkills, l.402-448 — the dead
|
||
-- `UnitCharacterPoints("player")`/`SkillFrame.UpdatedSkillPoints` read, l.437-440, whose
|
||
-- result nothing downstream ever consumes even in the ref itself, is dropped — the
|
||
-- TradeSkillFrame.xml "ref's own dead code is dropped" precedent).
|
||
function BenillaSkillFrame_Update()
|
||
local numRows = GetNumSkillLines()
|
||
local scrollFrame = getglobal("SkillListScrollFrame")
|
||
FauxScrollFrame_Update(scrollFrame, numRows, SKILLFRAME_SKILLS_DISPLAYED, SKILLFRAME_SKILL_HEIGHT)
|
||
local offset = FauxScrollFrame_GetOffset(scrollFrame)
|
||
|
||
local highlight = getglobal("SkillHighlight")
|
||
highlight:Hide()
|
||
local selected = GetSelectedSkill()
|
||
|
||
for i = 1, SKILLFRAME_SKILLS_DISPLAYED do
|
||
local index = i + offset
|
||
BenillaSkillFrame_SetRow(i, index, numRows)
|
||
if selected == index and index <= numRows then
|
||
highlight:SetPoint("TOPLEFT", getglobal("SkillRankFrame" .. i), "TOPLEFT", -5, 0)
|
||
highlight:Show()
|
||
end
|
||
end
|
||
|
||
-- The collapse-all tab's +/- icon (ref l.417-429's own numHeaders/notExpanded scan).
|
||
local allExpanded = true
|
||
for i = 1, numRows do
|
||
local _, isHeader, isExpanded = GetSkillLineInfo(i)
|
||
if isHeader and not isExpanded then
|
||
allExpanded = false
|
||
end
|
||
end
|
||
local collapseAll = getglobal("SkillCollapseAllButton")
|
||
if numRows == 0 then
|
||
collapseAll:Disable()
|
||
else
|
||
collapseAll:Enable()
|
||
end
|
||
if allExpanded then
|
||
collapseAll.collapsed = nil
|
||
collapseAll:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up")
|
||
else
|
||
collapseAll.collapsed = 1
|
||
collapseAll:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up")
|
||
end
|
||
|
||
BenillaSkillFrame_UpdateDetail()
|
||
BenillaSkillExpandButtonFrame_Fit()
|
||
end
|
||
|
||
-- A rank-bar click selects it (ref SkillBar_OnClick, l.450-455).
|
||
function BenillaSkillRankFrame_OnClick(bar)
|
||
local index = bar.skillIndex
|
||
if not index then
|
||
return
|
||
end
|
||
SetSelectedSkill(index)
|
||
BenillaSkillFrame_Update()
|
||
end
|
||
|
||
-- A header click folds/unfolds its group (ref SkillLabelTemplate's own OnClick, l.72-80).
|
||
function BenillaSkillTypeLabel_OnClick(label)
|
||
local index = label.skillIndex
|
||
if not index then
|
||
return
|
||
end
|
||
local _, _, isExpanded = GetSkillLineInfo(index)
|
||
if isExpanded then
|
||
CollapseSkillHeader(index)
|
||
-- A fold reshuffles visible indices — an UNLEARN_SKILL confirm armed for a row
|
||
-- that no longer holds the selection must not fire against the wrong line (ref
|
||
-- SkillLabelTemplate's own OnClick, ref SkillFrame.xml l.72-78).
|
||
local dialog = StaticPopup_FindVisible("UNLEARN_SKILL")
|
||
if dialog and dialog.data ~= GetSelectedSkill() then
|
||
StaticPopup_Hide("UNLEARN_SKILL")
|
||
end
|
||
else
|
||
ExpandSkillHeader(index)
|
||
end
|
||
BenillaSkillFrame_Update()
|
||
end
|
||
|
||
-- The collapse-all tab (ref SkillFrameCollapseAllButton's own isExpanded flag, l.303-309,
|
||
-- driven the TrainerFrame.xml BenillaTrainerCollapseAllButton way since this engine's
|
||
-- CollapseSkillHeader(0)/ExpandSkillHeader(0) already fold/unfold every group at once).
|
||
function BenillaSkillCollapseAllButton_OnClick()
|
||
local b = getglobal("SkillCollapseAllButton")
|
||
if b.collapsed then
|
||
ExpandSkillHeader(0)
|
||
else
|
||
CollapseSkillHeader(0)
|
||
FauxScrollFrame_SetOffset(getglobal("SkillListScrollFrame"), 0)
|
||
end
|
||
BenillaSkillFrame_Update()
|
||
end
|
||
|
||
-- The tab is as wide as its own label (ref SkillFrameExpandButtonFrame's OnLoad, l.312-316:
|
||
-- SetWidth(SkillFrameCollapseAllButton:GetTextWidth()+45)) — the 45 is the two 8px caps plus
|
||
-- the label's 25px seat plus the margin the ref leaves before the right cap, and the middle
|
||
-- slab stretches into whatever that leaves off its own two anchors.
|
||
--
|
||
-- Run from BOTH the ref's own OnLoad and every Update, because a measure here is not the
|
||
-- ref's synchronous one: benilla seats the VM's font engine at the frame boundary
|
||
-- (`ui_script::extract`, ahead of the tick), and XML load happens BEFORE any frame — so the
|
||
-- OnLoad call reads 0 and the tab would keep a 45px stump forever. The zero guard is what
|
||
-- makes the pair safe: an unmeasured call leaves the width alone rather than squashing the
|
||
-- tab, and the first Update after the atlas exists fits it. (The house's own preference is
|
||
-- two opposing anchors and no Lua width — UiPanels.xml's tab-highlight note — but a span
|
||
-- can only be resolved from two anchors when both edges are frames; a text width has to be
|
||
-- asked for.)
|
||
function BenillaSkillExpandButtonFrame_Fit()
|
||
local label = getglobal("SkillCollapseAllButton")
|
||
local w = label:GetTextWidth()
|
||
if w and w > 0 then
|
||
getglobal("SkillExpandButtonFrame"):SetWidth(w + 45)
|
||
end
|
||
end
|
||
|
||
-- The page's own CLOSE (ref SkillFrameCancelButton's OnClick, l.350-356). The ref's
|
||
-- CancelSkillUps() drops out with the training-point economy this pane doesn't ship (this
|
||
-- file's header comment deviation 1); the two hides are the ref's own, in its own order —
|
||
-- the page first, then the window (CharacterFrame_OnHide's subframe loop would reach this
|
||
-- page anyway, but the ref hides it explicitly and so do we).
|
||
function BenillaSkillFrameCancelButton_OnClick()
|
||
getglobal("SkillFrame"):Hide()
|
||
HideUIPanel(getglobal("CharacterFrame"))
|
||
end
|
||
|
||
-- The window's wheel handler (bubbled up the parent chain from a row) → one row via the faux
|
||
-- kit (TrainerFrame.xml's own note: the engine bubbles a spin up the parent chain).
|
||
function BenillaSkillFrame_OnMouseWheel(delta)
|
||
BenillaFauxScrollFrame_OnMouseWheel(getglobal("SkillListScrollFrame"), delta)
|
||
end
|
||
|
||
-- ── Lifecycle (ref SkillFrame_OnLoad/_OnShow/_OnEvent, l.4-22, collapsed to the events this
|
||
-- page's feed actually fires: CHARACTER_POINTS_CHANGED backs the training-point economy this
|
||
-- pane doesn't ship, this file's header comment deviation 1). ─────────────────────────────────
|
||
function SkillFrame_OnLoad()
|
||
local frame = this
|
||
frame:RegisterEvent("SKILL_LINES_CHANGED")
|
||
getglobal("SkillListScrollFrame").updateFunc = BenillaSkillFrame_Update
|
||
-- The description body hangs under the detail bar — anchored here, not in XML,
|
||
-- because the bar is a child frame declared after the page's layers and anchors
|
||
-- resolve at SetPoint time (an XML forward reference silently lands on the page;
|
||
-- the MailFrame error-text OnLoad precedent, ref MailFrame.xml l.1040). Cleared
|
||
-- first: the load-time implicit anchor (decision 1310) seated this justifyH="LEFT"
|
||
-- string at the page's LEFT, and SetPoint replaces only its own point -- without the
|
||
-- clear both anchors stand and the left/center edges resolve off the page, not the
|
||
-- bar. (The ref needs no clear on ITS file only because its XML anchors the string.)
|
||
SkillDetailDescriptionText:ClearAllPoints()
|
||
SkillDetailDescriptionText:SetPoint("TOPLEFT", "SkillDetailBar", "BOTTOMLEFT", -2, -10)
|
||
end
|
||
|
||
function SkillFrame_OnShow()
|
||
BenillaSkillFrame_Update()
|
||
end
|
||
|
||
function SkillFrame_OnEvent(event)
|
||
local frame = this
|
||
if event == "SKILL_LINES_CHANGED" and frame:IsVisible() then
|
||
BenillaSkillFrame_Update()
|
||
end
|
||
end
|
||
]]></Script>
|
||
|
||
<!--
|
||
The rank StatusBar row (ref SkillStatusBarTemplate, l.4-65 — the FillBar dropped, this file's
|
||
header comment deviation 5): 271×15, name+rank overlaid, the Border child Button for OnClick
|
||
+ hover highlight (TradeSkillFrame.xml's own BenillaTradeSkillRankFrame shape, verbatim).
|
||
-->
|
||
<StatusBar name="BenillaSkillRankTemplate" virtual="true" hidden="true" drawLayer="BACKGROUND" minValue="0" maxValue="1" defaultValue="0">
|
||
<Size><AbsDimension x="271" y="15"/></Size>
|
||
<Layers>
|
||
<Layer level="ARTWORK">
|
||
<FontString name="$parentSkillName" inherits="GameFontNormalSmall">
|
||
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="6" y="1"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<FontString name="$parentSkillRank" inherits="GameFontHighlightSmall" justifyH="LEFT">
|
||
<Size><AbsDimension x="128" y="0"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentSkillName" relativePoint="RIGHT"><Offset><AbsDimension x="13" y="0"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="$parentBackground"><Color r="1.0" g="1.0" b="1.0" a="0.2"/></Texture>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<Button name="$parentBorder">
|
||
<Size><AbsDimension x="281" y="32"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<NormalTexture file="Interface\PaperDollInfoFrame\UI-Character-Skills-BarBorder"/>
|
||
<HighlightTexture file="Interface\PaperDollInfoFrame\UI-Character-Skills-BarBorderHighlight"/>
|
||
<Scripts><OnClick>BenillaSkillRankFrame_OnClick(self:GetParent())</OnClick></Scripts>
|
||
</Button>
|
||
</Frames>
|
||
<BarTexture name="$parentBar" file="Interface\PaperDollInfoFrame\UI-Character-Skills-Bar"/>
|
||
<BarColor r="0.25" g="0.25" b="0.75"/>
|
||
</StatusBar>
|
||
|
||
<!--
|
||
The category header row (ref SkillLabelTemplate, l.66-129, minus the DisabledTexture — this
|
||
window never Disable()s a header): 285×14, the +/- fold icon + name text.
|
||
-->
|
||
<Button name="BenillaSkillHeaderTemplate" virtual="true" hidden="true">
|
||
<Size><AbsDimension x="285" y="14"/></Size>
|
||
<Scripts><OnClick>BenillaSkillTypeLabel_OnClick(self)</OnClick></Scripts>
|
||
<NormalTexture file="Interface\Buttons\UI-MinusButton-UP">
|
||
<Size><AbsDimension x="16" y="16"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</NormalTexture>
|
||
<HighlightTexture file="Interface\Buttons\UI-PlusButton-Hilight" alphaMode="ADD">
|
||
<Size><AbsDimension x="16" y="16"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</HighlightTexture>
|
||
<ButtonText>
|
||
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="25" y="0"/></Offset></Anchor></Anchors>
|
||
</ButtonText>
|
||
<NormalFont inherits="GameFontHighlight" justifyH="LEFT"/>
|
||
</Button>
|
||
|
||
<!-- id=4, the ref's own: a page's id is the slot it occupies in the WINDOW'S OWN tab row, and
|
||
ToggleCharacter selects the tab from it (ref CharacterFrame.lua:11). This was 3 while
|
||
Reputation (the ref's 3) was not built; ReputationFrame.xml landed and took that slot, so
|
||
Skills is back on the reference's number. `character_tests.rs` pins every page's id against
|
||
its slot in BENILLA_CHARACTERFRAME_SUBFRAMES, which is what made the renumber loud rather
|
||
than silent — exactly as this comment predicted. -->
|
||
<Frame name="SkillFrame" enableMouse="true" parent="CharacterFrame" hidden="true" id="4">
|
||
<!-- The real 384×512 page. No <Anchors relativeTo> substitute for true parenting exists
|
||
(this file's header comment) — pinned to CharacterFrame's own TOPLEFT by name. -->
|
||
<Size><AbsDimension x="384" y="512"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterFrame" relativePoint="TOPLEFT"/></Anchors>
|
||
<!-- Transcribed for fidelity (ref l.131-133); no loader wiring exists yet for the hit-rect
|
||
shrink (TradeSkillFrame.xml's own "transcribe the hook even if nothing drives it yet"
|
||
posture, TalentFrame.xml's precedent). -->
|
||
<HitRectInsets><AbsInset left="0" right="30" top="0" bottom="75"/></HitRectInsets>
|
||
<Layers>
|
||
<!-- The shared quadrant background (ref l.136-183): NO portrait redraw here (this file's
|
||
header comment) — "General" TopLeft/TopRight (the same variant every PaperDollInfoFrame
|
||
page shares, carrying the portrait-ring cutout) + SkillFrame's own BotLeft/BotRight. -->
|
||
<Layer level="BACKGROUND">
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-General-TopLeft">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="2" y="-1"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-General-TopRight">
|
||
<Size><AbsDimension x="128" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="2" y="-1"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\PaperDollInfoFrame\SkillFrame-BotLeft">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors><Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="2" y="-1"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\PaperDollInfoFrame\SkillFrame-BotRight">
|
||
<Size><AbsDimension x="128" y="256"/></Size>
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="2" y="-1"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
<!-- The divider bar below the list, above the detail pane (ref l.186-211's own
|
||
TOPLEFT(15,-290); nudged to -305 here to clear this file's own 12-row chain, whose
|
||
last row sits slightly lower than the ref's fixed-slot geometry — a pixel-fit
|
||
adjustment, not a structural deviation). -->
|
||
<Layer level="ARTWORK">
|
||
<Texture name="SkillHorizontalBarLeft" file="Interface\ClassTrainerFrame\UI-ClassTrainer-HorizontalBar">
|
||
<Size><AbsDimension x="256" y="16"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="15" y="-305"/></Offset></Anchor></Anchors>
|
||
<TexCoords left="0" right="1.0" top="0" bottom="0.25"/>
|
||
</Texture>
|
||
<Texture file="Interface\ClassTrainerFrame\UI-ClassTrainer-HorizontalBar">
|
||
<Size><AbsDimension x="75" y="16"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativeTo="SkillHorizontalBarLeft" relativePoint="RIGHT"/></Anchors>
|
||
<TexCoords left="0" right="0.29296875" top="0.25" bottom="0.5"/>
|
||
</Texture>
|
||
<!-- The detail pane's description body (ref SkillDetailDescriptionText, l.579-591:
|
||
GameFontHighlightSmall, 275 wide, justified LEFT/TOP). The ref hangs it inside
|
||
its SkillDetailScrollChildFrame; this page's flat layout (header comment) has
|
||
no such child, so it hangs under the detail bar instead — the same pane
|
||
position, minus the (never-needed for one sentence) scroll machinery. The
|
||
anchor is set in SkillFrame_OnLoad, NOT here: the bar is a child frame
|
||
declared below and an XML forward reference silently lands on the page. -->
|
||
<FontString name="SkillDetailDescriptionText" inherits="GameFontHighlightSmall" justifyH="LEFT" justifyV="TOP" hidden="true">
|
||
<Size><AbsDimension x="275" y="0"/></Size>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- The scroll-wheel catcher (TrainerFrame.xml's own note) — MUST be first so every real
|
||
row below out-ranks it in hit-testing, and sized to the LIST REGION ONLY (rows span
|
||
y -79..-295, x 22..309), NEVER the whole page: unlike the trainer's standalone
|
||
window, this page is CharacterFrame's LAST child, so a full-page catcher
|
||
out-ranks every EARLIER CharacterFrame child — it ate the tab row and the close X
|
||
whenever Skills was up (the 2026-07-17 "can't switch back to Character" report;
|
||
character_tests.rs's tab_round_trip_with_a_selected_skill_by_point is the repro). -->
|
||
<Button name="SkillWheelCatcher">
|
||
<Size><AbsDimension x="290" y="222"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="20" y="-76"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnMouseWheel>BenillaSkillFrame_OnMouseWheel(arg1)</OnMouseWheel></Scripts>
|
||
</Button>
|
||
|
||
<!-- The expand/collapse-all tab (ref SkillFrameExpandButtonFrame, l.242-317 — the SAME
|
||
QuestLogSortTab art TrainerFrame.xml's own BenillaTrainerExpandButtonFrame uses).
|
||
The tab is SIZED BY ITS LABEL, the ref's own OnLoad law (l.312-316:
|
||
SetWidth(GetTextWidth()+45)) — the middle slab stretches between the two 8px caps
|
||
off its OWN two anchors (ref l.279-287), so the 45 is exactly the two caps plus the
|
||
label's seat. Was a fixed 54 with a fixed 38 middle, copied off
|
||
TrainerFrame.xml rather than read off THIS ref; the label's own font fix below
|
||
(12px, not 10) would have run under the right cap at that width. -->
|
||
<Frame name="SkillExpandButtonFrame">
|
||
<Size><AbsDimension x="54" y="32"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="70" y="-49"/></Offset></Anchor></Anchors>
|
||
<Layers><Layer level="BACKGROUND">
|
||
<Texture name="SkillExpandTabLeft" file="Interface\QuestFrame\UI-QuestLogSortTab-Left"><Size><AbsDimension x="8" y="32"/></Size><Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="0" y="6"/></Offset></Anchor></Anchors></Texture>
|
||
<Texture name="SkillExpandTabRight" file="Interface\QuestFrame\UI-QuestLogSortTab-Right"><Size><AbsDimension x="8" y="32"/></Size><Anchors><Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="6"/></Offset></Anchor></Anchors></Texture>
|
||
<Texture name="SkillExpandTabMiddle" file="Interface\QuestFrame\UI-QuestLogSortTab-Middle"><Size><AbsDimension x="0" y="32"/></Size><Anchors><Anchor point="LEFT" relativeTo="SkillExpandTabLeft" relativePoint="RIGHT"/><Anchor point="RIGHT" relativeTo="SkillExpandTabRight" relativePoint="LEFT"/></Anchors></Texture>
|
||
</Layer></Layers>
|
||
<Frames>
|
||
<!-- The ALL fold (ref SkillFrameCollapseAllButton, l.292-310). Its face is the
|
||
ref's SkillLabelTemplate one — the SAME face every SkillTypeLabel row wears
|
||
(BenillaSkillHeaderTemplate above, l.83-128 of the ref): the +/- glyph at
|
||
LEFT+3, the label at LEFT+25, and GameFontHighlight — WHITE at 12px, not
|
||
GameFontNormalSmall's yellow 10. Spelled out here rather than inherited
|
||
because this button keeps its own OnClick (this engine's
|
||
CollapseSkillHeader(0)/ExpandSkillHeader(0) fold everything at once, so it
|
||
needs no skillIndex/isExpanded bookkeeping) and this loader CONCATENATES an
|
||
instance's children onto its template's rather than replacing them, so an
|
||
inherited <Scripts> would stand alongside ours. Its seat is the ref's own
|
||
(-3,-3) off the left cap: the tab art's visible lip sits BELOW the
|
||
texture's geometric middle, so the label rides 3px low, not 3px high — the
|
||
+3 copied from TrainerFrame.xml put the whole "- All" 6px above where the
|
||
reference seats it. -->
|
||
<Button name="SkillCollapseAllButton" text="ALL">
|
||
<Size><AbsDimension x="40" y="22"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativeTo="SkillExpandTabLeft" relativePoint="RIGHT"><Offset><AbsDimension x="-3" y="-3"/></Offset></Anchor></Anchors>
|
||
<NormalTexture file="Interface\Buttons\UI-MinusButton-Up"><Size><AbsDimension x="16" y="16"/></Size><Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors></NormalTexture>
|
||
<HighlightTexture file="Interface\Buttons\UI-PlusButton-Hilight" alphaMode="ADD"><Size><AbsDimension x="16" y="16"/></Size><Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors></HighlightTexture>
|
||
<ButtonText><Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="25" y="0"/></Offset></Anchor></Anchors></ButtonText>
|
||
<NormalFont inherits="GameFontHighlight" justifyH="LEFT"/>
|
||
<Scripts><OnClick>BenillaSkillCollapseAllButton_OnClick()</OnClick></Scripts>
|
||
</Button>
|
||
</Frames>
|
||
<Scripts><OnLoad>BenillaSkillExpandButtonFrame_Fit()</OnLoad></Scripts>
|
||
</Frame>
|
||
|
||
<!-- The page's own CLOSE button (ref SkillFrameCancelButton, l.339-357: 80x22,
|
||
UIPanelButtonTemplate, CENTER of TOPLEFT (305,-422), text CLOSE). LIVE in the
|
||
reference, not dead: the ref's XML comment that swallows SkillFrameAcceptButton
|
||
CLOSES at l.337, one line ABOVE this button — this file's own header comment
|
||
deviation 3 read that boundary wrong and dropped a button the real client draws,
|
||
which is why the page's bottom-right seat sat empty (decision 1496). The
|
||
UIPanelButtonTemplate face is reconstructed locally, the house convention every
|
||
window here follows (CraftFrame.xml's BenillaCraftPanelButtonTemplate note) — one
|
||
site, so inline rather than a virtual template (GroupLootFrame.xml's own precedent
|
||
for a single ref-template button). -->
|
||
<Button name="SkillFrameCancelButton" text="CLOSE">
|
||
<Size><AbsDimension x="80" y="22"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="TOPLEFT"><Offset><AbsDimension x="305" y="-422"/></Offset></Anchor></Anchors>
|
||
<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>
|
||
<DisabledTexture file="Interface\Buttons\UI-Panel-Button-Disabled"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></DisabledTexture>
|
||
<HighlightTexture file="Interface\Buttons\UI-Panel-Button-Highlight" alphaMode="ADD"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></HighlightTexture>
|
||
<Scripts><OnClick>BenillaSkillFrameCancelButton_OnClick()</OnClick></Scripts>
|
||
</Button>
|
||
|
||
<!-- The persistent selection highlight (Trainer/TradeSkillFrame's own precedent, this
|
||
file's header comment deviation 7): 281×15, ARTWORK-layer UI-Listbox-Highlight2.
|
||
Declared BEFORE the rows so the row text paints OVER the glow (same z-tiebreak). -->
|
||
<Frame name="SkillHighlightFrame" hidden="true">
|
||
<Size><AbsDimension x="281" y="15"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||
<Layers><Layer level="ARTWORK">
|
||
<Texture name="SkillHighlight" file="Interface\Buttons\UI-Listbox-Highlight2">
|
||
<Anchors><Anchor point="TOPLEFT"/><Anchor point="BOTTOMRIGHT"/></Anchors>
|
||
</Texture>
|
||
</Layer></Layers>
|
||
</Frame>
|
||
|
||
<!-- 12 header-row slots (ref SkillTypeLabel1..12, l.358-465): 285×14, row1 LEFT of
|
||
TOPLEFT(22,-86); rows 2-12 chain by (0,-18). -->
|
||
<Button name="SkillTypeLabel1" inherits="BenillaSkillHeaderTemplate">
|
||
<Anchors><Anchor point="LEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="22" y="-86"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="SkillTypeLabel2" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel1"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel3" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel2"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel4" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel3"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel5" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel4"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel6" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel5"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel7" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel6"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel8" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel7"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel9" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel8"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel10" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel9"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel11" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel10"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="SkillTypeLabel12" inherits="BenillaSkillHeaderTemplate"><Anchors><Anchor point="LEFT" relativeTo="SkillTypeLabel11"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors></Button>
|
||
|
||
<!-- 12 rank-bar slots (ref SkillRankFrame1..12, l.746-853): 271×15, row1 TOPLEFT(38,-79);
|
||
rows 2-12 chain BOTTOMLEFT→TOPLEFT by (0,-3) — the SAME 18px pitch as the label chain
|
||
(15 bar height + 3 gap). -->
|
||
<StatusBar name="SkillRankFrame1" inherits="BenillaSkillRankTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="38" y="-79"/></Offset></Anchor></Anchors>
|
||
</StatusBar>
|
||
<StatusBar name="SkillRankFrame2" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame3" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame2" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame4" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame5" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame4" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame6" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame7" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame6" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame8" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame7" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame9" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame8" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame10" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame9" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame11" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame10" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
<StatusBar name="SkillRankFrame12" inherits="BenillaSkillRankTemplate"><Anchors><Anchor point="TOPLEFT" relativeTo="SkillRankFrame11" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors></StatusBar>
|
||
|
||
<!-- The faux-scroll frame (FauxScrollFrameTemplate, ScrollTemplates.xml): invisible
|
||
container over the 12 rows; only its right-hand Slider scroll bar renders. Sized to the
|
||
12-row span (SKILLFRAME_SKILLS_DISPLAYED × 18px pitch), TrainerFrame.xml's own
|
||
same-TOPLEFT-as-row1 convention. updateFunc set in SkillFrame_OnLoad. -->
|
||
<Frame name="SkillListScrollFrame" inherits="FauxScrollFrameTemplate">
|
||
<Size><AbsDimension x="296" y="216"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="22" y="-79"/></Offset></Anchor></Anchors>
|
||
</Frame>
|
||
|
||
<!-- The minimal detail pane (this file's header comment, deviation 1): the selected
|
||
skill's own rank StatusBar + name — no description/abandon/spend row. Reuses the SAME
|
||
rank template the list rows use (its Border click is harmless here: no .skillIndex is
|
||
ever set on this instance, so BenillaSkillRankFrame_OnClick's guard no-ops it). -->
|
||
<StatusBar name="SkillDetailBar" inherits="BenillaSkillRankTemplate" hidden="true">
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="38" y="-325"/></Offset></Anchor></Anchors>
|
||
<Frames>
|
||
<!-- The unlearn (abandon) button (ref $parentUnlearnButton, ref SkillFrame.xml
|
||
l.705-737, verbatim art/geometry): the red circle-slash right of the bar's
|
||
Border, shown by UpdateDetail only for an abandonable line. HitRectInsets
|
||
transcribed-inert (no loader wiring — CharacterFrame.xml's engine-gap note).
|
||
Handlers are chunk functions (the chunk-boundary rule — OnEnter reads the
|
||
chunk-local UNLEARN_SKILL_TOOLTIP). -->
|
||
<Button name="SkillDetailUnlearnButton" hidden="true">
|
||
<Size><AbsDimension x="32" y="32"/></Size>
|
||
<Anchors>
|
||
<Anchor point="LEFT" relativeTo="SkillDetailBarBorder" relativePoint="RIGHT">
|
||
<Offset><AbsDimension x="-2" y="-1"/></Offset>
|
||
</Anchor>
|
||
</Anchors>
|
||
<HitRectInsets><AbsInset left="9" right="7" top="-7" bottom="10"/></HitRectInsets>
|
||
<Scripts>
|
||
<OnClick>BenillaSkillUnlearnButton_OnClick(self)</OnClick>
|
||
<OnEnter>BenillaSkillUnlearnButton_OnEnter(self)</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
<NormalTexture file="Interface\Buttons\CancelButton-Up"/>
|
||
<PushedTexture file="Interface\Buttons\CancelButton-Down"/>
|
||
<HighlightTexture file="Interface\Buttons\CancelButton-Highlight" alphaMode="ADD"/>
|
||
</Button>
|
||
</Frames>
|
||
</StatusBar>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad>SkillFrame_OnLoad()</OnLoad>
|
||
<OnShow>SkillFrame_OnShow()</OnShow>
|
||
<OnEvent>SkillFrame_OnEvent(event)</OnEvent>
|
||
<OnMouseWheel>BenillaSkillFrame_OnMouseWheel(arg1)</OnMouseWheel>
|
||
</Scripts>
|
||
</Frame>
|
||
</Ui>
|