Skin the CoA Wardrobe tab (AppearanceWardrobeFrame)
Outer panel, close button, and the top-left portrait medallion get the same first-pass treatment as Vanity/Talent, plus the item collection panel: native background/border art stripped from Collection and its InsetOverlay/ShadowOverlay decoration, the 3D model preview's vanilla border removed, and the action buttons, search box, Filter/Order By dropdowns, page arrows, and category tabs skinned to match. Left native for a later pass: the icon grid contents, item slot buttons, and character model itself.
This commit is contained in:
@@ -16,3 +16,4 @@ Modules\DispelHighlight.lua
|
|||||||
Modules\ClassResources.lua
|
Modules\ClassResources.lua
|
||||||
Modules\TalentFrame.lua
|
Modules\TalentFrame.lua
|
||||||
Modules\VanityFrame.lua
|
Modules\VanityFrame.lua
|
||||||
|
Modules\WardrobeFrame.lua
|
||||||
|
|||||||
@@ -0,0 +1,300 @@
|
|||||||
|
local E, L, V, P, G = unpack(ElvUI)
|
||||||
|
local S = E:GetModule("Skins")
|
||||||
|
local CoA = E:GetModule("CoA")
|
||||||
|
|
||||||
|
local FRAME_NAME = "AppearanceWardrobeFrame"
|
||||||
|
|
||||||
|
local function SkinCloseButton(frame)
|
||||||
|
local close = _G[FRAME_NAME.."CloseButton"]
|
||||||
|
if not close then return end
|
||||||
|
|
||||||
|
-- Strictly once: HandleCloseButton strips the button every call, which
|
||||||
|
-- blanks the X texture it added on the first pass.
|
||||||
|
if not close.CoASkinned then
|
||||||
|
close.CoASkinned = true
|
||||||
|
|
||||||
|
S:HandleCloseButton(close)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Standard UIPanelButtonTemplate art, same as Vanity's action buttons --
|
||||||
|
-- S:HandleButton's own texture clearing handles these directly.
|
||||||
|
local function SkinActionButtons()
|
||||||
|
S:HandleButton(_G[FRAME_NAME.."PlayerModelSaveOutfitButton"])
|
||||||
|
S:HandleButton(_G[FRAME_NAME.."DisableTransmogButton"])
|
||||||
|
S:HandleButton(_G[FRAME_NAME.."DisableSpellVisualsButton"])
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SkinSearchBox()
|
||||||
|
S:HandleEditBox(_G[FRAME_NAME.."CollectionSearchBox"])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Filter and Order By share Vanity's exact dropdown art -- same nine
|
||||||
|
-- anonymous "Silver-Button" slices, confirmed by probe, that S:HandleButton
|
||||||
|
-- can't reach on its own, plus the same native mouse-down re-art problem on
|
||||||
|
-- click (SetTexture noop'd per region after clearing, same trick).
|
||||||
|
local DROPDOWN_ART_PATTERNS = {"Silver%-Button"}
|
||||||
|
|
||||||
|
local function StripDropdownArt(dropdown)
|
||||||
|
for i = 1, dropdown:GetNumRegions() do
|
||||||
|
local region = select(i, dropdown:GetRegions())
|
||||||
|
local texture = region.GetTexture and region:GetTexture()
|
||||||
|
|
||||||
|
if texture then
|
||||||
|
for _, pattern in ipairs(DROPDOWN_ART_PATTERNS) do
|
||||||
|
if tostring(texture):find(pattern) then
|
||||||
|
region:SetTexture(nil)
|
||||||
|
region.SetTexture = E.noop
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- suffix is "Filter" or "Sorting" -- both are CollectionX buttons with a
|
||||||
|
-- matching CollectionXMenu popout (confirmed by probe), same shape as
|
||||||
|
-- Vanity's single dropdown.
|
||||||
|
local function SkinCollectionDropdown(suffix)
|
||||||
|
local dropdown = _G[FRAME_NAME.."Collection"..suffix]
|
||||||
|
if not dropdown or dropdown.CoASkinned then return end
|
||||||
|
dropdown.CoASkinned = true
|
||||||
|
|
||||||
|
StripDropdownArt(dropdown)
|
||||||
|
|
||||||
|
S:HandleButton(dropdown)
|
||||||
|
|
||||||
|
-- The caret is a plain OVERLAY texture on the dropdown itself, not a
|
||||||
|
-- separate button, so it can't go through HandleNextPrevButton -- it's
|
||||||
|
-- retextured directly instead.
|
||||||
|
for i = 1, dropdown:GetNumRegions() do
|
||||||
|
local region = select(i, dropdown:GetRegions())
|
||||||
|
local texture = region.GetTexture and region:GetTexture()
|
||||||
|
|
||||||
|
if texture and tostring(texture):find("ChatFrameExpandArrow") then
|
||||||
|
-- No ArrowDown asset exists -- every other direction in ElvUI is
|
||||||
|
-- ArrowUp rotated, so this matches that convention.
|
||||||
|
region:SetTexture(E.Media.Textures.ArrowUp)
|
||||||
|
region:SetVertexColor(1, 1, 1)
|
||||||
|
region:SetTexCoord(0, 1, 0, 1)
|
||||||
|
region:SetRotation(S.ArrowRotation.down)
|
||||||
|
region:SetSize(14, 14)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local menu = _G[FRAME_NAME.."Collection"..suffix.."Menu"]
|
||||||
|
if menu and not menu.CoASkinned then
|
||||||
|
menu.CoASkinned = true
|
||||||
|
|
||||||
|
-- Panel only, matching how Vanity's own popup menu is treated -- the
|
||||||
|
-- option rows inside are a later pass.
|
||||||
|
menu:StripTextures()
|
||||||
|
menu:SetTemplate("Transparent")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SkinPagerArrows()
|
||||||
|
local prevButton = _G[FRAME_NAME.."CollectionPageLeftButton"]
|
||||||
|
local nextButton = _G[FRAME_NAME.."CollectionPageRightButton"]
|
||||||
|
|
||||||
|
if prevButton then S:HandleNextPrevButton(prevButton, "left") end
|
||||||
|
if nextButton then S:HandleNextPrevButton(nextButton, "right") end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Same Left/Center/Right art naming as the talent frame's tabs (confirmed by
|
||||||
|
-- probe), but these are proper descendants of Collection rather than
|
||||||
|
-- separately-placed siblings, so the frame-level bump Talent needs to clear
|
||||||
|
-- its own frame's regions doesn't apply here -- normal parent/child z-order
|
||||||
|
-- already puts them on top.
|
||||||
|
local TAB_TEXTURES = {"Left", "Center", "Right"}
|
||||||
|
|
||||||
|
local function StripTab(tab)
|
||||||
|
local name = tab:GetName()
|
||||||
|
if name then
|
||||||
|
for _, suffix in ipairs(TAB_TEXTURES) do
|
||||||
|
local tex = _G[name..suffix]
|
||||||
|
if tex then tex:SetTexture(nil) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local highlight = tab.GetHighlightTexture and tab:GetHighlightTexture()
|
||||||
|
if highlight then highlight:SetTexture(nil) end
|
||||||
|
|
||||||
|
local checked = tab.GetCheckedTexture and tab:GetCheckedTexture()
|
||||||
|
if checked then checked:SetTexture(nil) end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Only the tab being switched to gets any kind of hook fired -- the ones
|
||||||
|
-- switched away from never fire OnClick/OnShow/SetChecked again, but their
|
||||||
|
-- native art still comes back, so there's no event to catch it from. Same
|
||||||
|
-- fix as the talent frame's tabs: a cheap OnUpdate texture check, only pays
|
||||||
|
-- for the full strip when the native art has actually reappeared.
|
||||||
|
local function UpdateTabArt(tab)
|
||||||
|
local name = tab:GetName()
|
||||||
|
local tex = name and _G[name.."Left"]
|
||||||
|
|
||||||
|
if tex and tex:GetTexture() then
|
||||||
|
StripTab(tab)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SkinTab(tab)
|
||||||
|
if not tab.CoASkinned then
|
||||||
|
tab.CoASkinned = true
|
||||||
|
|
||||||
|
tab:CreateBackdrop("Default")
|
||||||
|
tab.backdrop:Point("TOPLEFT", 2, -2)
|
||||||
|
tab.backdrop:Point("BOTTOMRIGHT", -2, 2)
|
||||||
|
|
||||||
|
tab:HookScript("OnUpdate", UpdateTabArt)
|
||||||
|
end
|
||||||
|
|
||||||
|
StripTab(tab)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Named PoolFrameAppearanceTypeTabTemplate1 through 8 (confirmed by probe),
|
||||||
|
-- not pooled/created dynamically like the talent frame's spec choices, so a
|
||||||
|
-- plain indexed loop is enough -- no OnShow hook needed to catch late pool
|
||||||
|
-- fills.
|
||||||
|
local TAB_COUNT = 8
|
||||||
|
|
||||||
|
local function SkinCategoryTabs()
|
||||||
|
for i = 1, TAB_COUNT do
|
||||||
|
local tab = _G[FRAME_NAME.."CollectionPoolFrameAppearanceTypeTabTemplate"..i]
|
||||||
|
if tab then SkinTab(tab) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SkinFrame(frame)
|
||||||
|
if not frame.CoASkinned then
|
||||||
|
frame.CoASkinned = true
|
||||||
|
|
||||||
|
-- The native NineSlice panel draws its own ornate border/background on
|
||||||
|
-- top of the Transparent template's border, doubling up. Same fix as
|
||||||
|
-- the talent frame: strip and hide it.
|
||||||
|
local nineSlice = _G[FRAME_NAME.."NineSlice"]
|
||||||
|
if nineSlice then
|
||||||
|
nineSlice:StripTextures()
|
||||||
|
nineSlice:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The round medallion overhangs the top-left corner (confirmed by
|
||||||
|
-- probe: 61x61, TOPLEFT -6,8 -- matches the frame's own corner, not a
|
||||||
|
-- counter badge elsewhere, unlike Vanity's same-named "Portrait2"
|
||||||
|
-- texture). No flat equivalent, so it goes rather than getting
|
||||||
|
-- reskinned, same treatment as the talent frame's portrait.
|
||||||
|
local portrait = _G[FRAME_NAME.."PortraitFrame"]
|
||||||
|
if portrait then
|
||||||
|
portrait:StripTextures()
|
||||||
|
portrait:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The frame's own regions (confirmed by probe: 4 total, all BACKGROUND/
|
||||||
|
-- BORDER/OVERLAY textures, none of them functional -- unlike Vanity's
|
||||||
|
-- frame, nothing here doubles as a counter badge) are the wood-panel
|
||||||
|
-- background art. Strip it first, THEN apply the template -- SetTemplate
|
||||||
|
-- adds its own backdrop as real texture regions on this same frame, so
|
||||||
|
-- stripping afterward wiped the backdrop right back off (outer panel
|
||||||
|
-- came out fully invisible).
|
||||||
|
frame:StripTextures()
|
||||||
|
frame:SetTemplate("Transparent")
|
||||||
|
|
||||||
|
-- InsetOverlay's NineSlice and the ShadowOverlay are separate decorative
|
||||||
|
-- art layered over the item grid area (8-piece atlas borders/shadow
|
||||||
|
-- edges, confirmed via probe), stripped outright -- no functional
|
||||||
|
-- content lives on either.
|
||||||
|
local insetOverlayNineSlice = _G[FRAME_NAME.."CollectionInsetOverlayNineSlice"]
|
||||||
|
if insetOverlayNineSlice then
|
||||||
|
insetOverlayNineSlice:StripTextures()
|
||||||
|
insetOverlayNineSlice:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The actual panel behind the grid: Collection itself (confirmed via
|
||||||
|
-- /fstack -- InsetOverlay was the wrong target, its own rect doesn't
|
||||||
|
-- match the visible panel). Collection is the grid's real parent, so
|
||||||
|
-- no frame-level/strata juggling needed -- children always draw above
|
||||||
|
-- their own parent.
|
||||||
|
--
|
||||||
|
-- 16 of its own regions turned out to hold real art -- a background
|
||||||
|
-- tile plus ~14 atlas border/corner pieces (the ornate corners
|
||||||
|
-- /fstack couldn't ever pick out, since loose regions aren't frames
|
||||||
|
-- and don't show up there) -- none of it functional (the "Collected
|
||||||
|
-- 50/2744" counter is a separate FontString region, untouched by
|
||||||
|
-- StripTextures). Painting an opaque/red template over it earlier
|
||||||
|
-- just masked it; it was still there underneath, which is why
|
||||||
|
-- Transparent let it bleed back through. Strip first, then template,
|
||||||
|
-- same order as the outer frame -- SetTemplate's own WHITE8X8 backdrop
|
||||||
|
-- pieces land as regions on this same frame too, so stripping after
|
||||||
|
-- would wipe them right back off.
|
||||||
|
local collection = _G[FRAME_NAME.."Collection"]
|
||||||
|
if collection then
|
||||||
|
collection:StripTextures()
|
||||||
|
collection:SetTemplate("Transparent")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The 3D model preview's vanilla border is an anonymous child (first
|
||||||
|
-- of PlayerModel's own, confirmed by probe: 8-piece "UIFrame" atlas
|
||||||
|
-- border, sized to match the model panel). No name to key off of, same
|
||||||
|
-- as Vanity's pager arrows -- picked out positionally instead. The
|
||||||
|
-- race-specific scenic backdrop texture is PlayerModel's own region,
|
||||||
|
-- not this child's, so it's untouched.
|
||||||
|
local playerModel = _G[FRAME_NAME.."PlayerModel"]
|
||||||
|
local modelBorder = playerModel and select(1, playerModel:GetChildren())
|
||||||
|
if modelBorder and modelBorder:GetObjectType() == "Frame" then
|
||||||
|
modelBorder:StripTextures()
|
||||||
|
modelBorder:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
local shadowOverlay = _G[FRAME_NAME.."CollectionShadowOverlay"]
|
||||||
|
if shadowOverlay then
|
||||||
|
shadowOverlay:StripTextures()
|
||||||
|
shadowOverlay:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
frame:HookScript("OnShow", function(self)
|
||||||
|
SkinCloseButton(self)
|
||||||
|
SkinActionButtons()
|
||||||
|
SkinSearchBox()
|
||||||
|
SkinCollectionDropdown("Filter")
|
||||||
|
SkinCollectionDropdown("Sorting")
|
||||||
|
SkinPagerArrows()
|
||||||
|
SkinCategoryTabs()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
SkinCloseButton(frame)
|
||||||
|
SkinActionButtons()
|
||||||
|
SkinSearchBox()
|
||||||
|
SkinCollectionDropdown("Filter")
|
||||||
|
SkinCollectionDropdown("Sorting")
|
||||||
|
SkinPagerArrows()
|
||||||
|
SkinCategoryTabs()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function TryHook()
|
||||||
|
local frame = _G[FRAME_NAME]
|
||||||
|
if not frame then return false end
|
||||||
|
|
||||||
|
SkinFrame(frame)
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function CoA:InitializeWardrobeFrame()
|
||||||
|
if not E.private.skins.blizzard.enable then return end
|
||||||
|
if TryHook() then return end
|
||||||
|
|
||||||
|
-- Frame is created on-demand by its owning addon, the instant the player
|
||||||
|
-- first opens it -- a poll can't catch that before native art gets a
|
||||||
|
-- paint. ADDON_LOADED fires (synchronously, before control returns to
|
||||||
|
-- whatever code calls :Show()) the moment that addon finishes loading, so
|
||||||
|
-- skinning here lands before the first-ever :Show(). Confirmed in-game on
|
||||||
|
-- the talent frame's identical pattern; see TalentFrame.lua.
|
||||||
|
local loader = CreateFrame("Frame")
|
||||||
|
loader:RegisterEvent("ADDON_LOADED")
|
||||||
|
loader:SetScript("OnEvent", function(self)
|
||||||
|
if TryHook() then
|
||||||
|
self:UnregisterEvent("ADDON_LOADED")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -386,6 +386,10 @@ function CoA:Initialize()
|
|||||||
if self.InitializeVanityFrame then
|
if self.InitializeVanityFrame then
|
||||||
self:InitializeVanityFrame()
|
self:InitializeVanityFrame()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.InitializeWardrobeFrame then
|
||||||
|
self:InitializeWardrobeFrame()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function InitializeCallback()
|
local function InitializeCallback()
|
||||||
|
|||||||
Reference in New Issue
Block a user