diff --git a/AddOnSkins/Core/API.lua b/AddOnSkins/Core/API.lua
index 2b9a0dd5..6fc383ea 100644
--- a/AddOnSkins/Core/API.lua
+++ b/AddOnSkins/Core/API.lua
@@ -119,7 +119,7 @@ function AS:Desaturate(frame)
end
function AS:SkinTooltip(tooltip, scale)
- return AS:SkinTooltip(tooltip, scale)
+ return S:HandleTooltip(tooltip, scale)
end
function AS:AdjustForTheme(number, offset)
@@ -128,4 +128,4 @@ end
function AS:EnumObjects(enumFuncs, yieldFunc)
return S:EnumObjects(enumFuncs, yieldFunc)
-end
+end
\ No newline at end of file
diff --git a/AddOnSkins/Core/Core.lua b/AddOnSkins/Core/Core.lua
index 2ffc3be8..2f1acf0e 100644
--- a/AddOnSkins/Core/Core.lua
+++ b/AddOnSkins/Core/Core.lua
@@ -6,18 +6,25 @@ local AddOnName = ...
local ES = AS.EmbedSystem
local _G = _G
-local pairs, ipairs, type, pcall, tinsert = pairs, ipairs, type, pcall, tinsert
-local floor, print, format, strlower, strmatch, strlen = floor, print, format, strlower, strmatch, strlen
+local select, pairs, ipairs, type, pcall, tinsert = select, pairs, ipairs, type, pcall, tinsert
+local floor, print, format, strlower, strfind, strmatch, strlen = floor, print, format, strlower, strfind, strmatch, strlen
+local sort = sort
local geterrorhandler = geterrorhandler
-local IsAddOnLoaded, C_Timer = C_AddOns.IsAddOnLoaded, C_Timer
+local C_AddOns = C_AddOns
+local IsAddOnLoaded = (C_AddOns and C_AddOns.IsAddOnLoaded) or _G.IsAddOnLoaded
+if not IsAddOnLoaded then
+ IsAddOnLoaded = function() return false end
+end
+local C_Timer = C_Timer
AS.SkinErrors = {}
local Validator = CreateFrame('Frame')
function AS:CheckOption(optionName, ...)
- for _, addon in next, {...} do
+ for i = 1, select('#', ...) do
+ local addon = select(i, ...)
if not addon then break end
if not AS:CheckAddOn(addon) then return false end
end
@@ -63,7 +70,22 @@ function AS:Delay(delay, func)
end
function AS:CheckAddOn(addon)
- return AS.AddOns[strlower(addon)] or false
+ local key = strlower(addon or '')
+ -- Prefer runtime loaded state: enable-state APIs can be unreliable on Anniversary
+ -- (per-character enablement stored differently than on Retail).
+ local loaded = (C_AddOns and C_AddOns.IsAddOnLoaded and C_AddOns.IsAddOnLoaded(addon))
+ or (_G.IsAddOnLoaded and _G.IsAddOnLoaded(addon))
+ if loaded then return true end
+ -- ElvUI may not appear enabled in the addon list on Anniversary but its global is present.
+ if key == 'elvui' then return _G.ElvUI ~= nil end
+ if AS.AddOns[key] ~= nil then return AS.AddOns[key] end
+ local state
+ if C_AddOns and C_AddOns.GetAddOnEnableState then
+ state = C_AddOns.GetAddOnEnableState(addon, AS.MyName)
+ else
+ state = _G.GetAddOnEnableState and _G.GetAddOnEnableState(AS.MyName, addon)
+ end
+ return (state or 0) > 0
end
function AS:GetAddOnVersion(addon)
@@ -83,6 +105,24 @@ function AS:Round(num, idp)
return floor(num * mult + 0.5) / mult
end
+function AS:Scale(Number)
+ return AS.Mult * floor(Number / AS.Mult + .5)
+end
+
+function AS:OrderedPairs(t, f)
+ local a = {}
+ for n in pairs(t) do tinsert(a, n) end
+ sort(a, f)
+ local i = 0
+ local iter = function()
+ i = i + 1
+ if a[i] == nil then return nil
+ else return a[i], t[a[i]]
+ end
+ end
+ return iter
+end
+
function AS:RegisterForPetBattleHide(frame)
RegisterStateDriver(frame, 'visibility', '[petbattle] hide; show')
end
@@ -159,9 +199,12 @@ local function errorhandler(err)
end
function AS:CallSkin(addonName, func, event, ...)
- if AS.Debug then
+ if AS.Debug or AS:CheckOption('SkinDebug') then
local args = {...}
- xpcall(function() func(self, event, unpack(args)) end, errorhandler)
+ local ok, err = xpcall(function() func(self, event, unpack(args)) end, function(e) return e..'\n'..debugstack() end)
+ if not ok then
+ AS:Print('SkinDebug ['..addonName..']: '..tostring(err))
+ end
else
local pass = pcall(func, self, event, ...)
if not pass then
@@ -196,7 +239,7 @@ function AS:UnregisterSkinEvent(addonName, event)
end
function AS:UpdateMedia()
- AS.Blank = AS.Libs.LSM:Fetch('statusbar', 'Solid')
+ AS.Blank = AS.Libs.LSM:Fetch('background', 'Solid') or AS.Libs.LSM:Fetch('statusbar', 'Solid')
AS.Font = AS.Libs.LSM:Fetch('font', "Friz Quadrata TT")
AS.PixelFont = AS.Libs.LSM:Fetch('font', "Arial Narrow")
AS.NormTex = AS.Libs.LSM:Fetch('statusbar', "Blizzard")
@@ -218,7 +261,7 @@ function AS:StartUp(event, ...)
AS:SecureHook(_G.ElvUI[1], 'UpdateMedia')
end
- if not AS.Debug then
+ if not AS.Debug and not AS:CheckOption('SkinDebug') then
for Version, SkinTable in pairs(_G.AddOnSkinsDS) do
if Version == AS.Version or Version < AS.Version then
if Version < AS.Version then
@@ -233,7 +276,7 @@ function AS:StartUp(event, ...)
-- Check Blizzard for already loaded
for addonName, funcs in next, AS.skins do
- if strmatch(addonName, '^Blizzard_') and AS:CheckOption(addonName) then
+ if strfind(addonName, '^Blizzard_') and AS:CheckOption(addonName) then
for _, func in ipairs(funcs) do
if IsAddOnLoaded(addonName) then
AS:CallSkin(addonName, func, 'ADDON_LOADED', addonName)
@@ -254,30 +297,37 @@ function AS:StartUp(event, ...)
end
ES:Initialize()
+ ES:HookToggleButtonTooltip()
AS.RunOnce = true
end
function AS:Init(event, addon)
- if event == 'ADDON_LOADED' and (AS.Initialized or IsAddOnLoaded(AddOnName)) then
- if addon == AddOnName then
- AS.Initialized = true
- AS:BuildProfile()
- AS:UpdateMedia()
-
- for addonName, funcs in next, AS.preload do
- if AS.AlreadyLoaded[addonName] then
- AS:RunPreload(addonName)
- end
+ -- IsAddOnLoaded can be nil on Anniversary; use the addon argument as the reliable signal.
+ if event == 'ADDON_LOADED' and addon == AddOnName then
+ AS.Initialized = true
+ AS:BuildProfile()
+ AS:UpdateMedia()
+
+ for addonName in next, AS.preload do
+ if AS.AlreadyLoaded[addonName] then
+ AS:RunPreload(addonName)
end
end
+ end
+ if event == 'ADDON_LOADED' and AS.Initialized then
AS:RunPreload(addon)
end
if event == 'PLAYER_LOGIN' then
AS:BuildOptions()
+ -- Resolve EP lazily: ElvUI_Libraries may load after AddOnSkins Init.lua runs.
+ if not AS.Libs.EP then
+ AS.Libs.EP = LibStub('LibElvUIPlugin-1.0', true)
+ end
+
for addOnEvent in pairs(AS.events) do
AS:RegisterEvent(addOnEvent, 'SkinEvent')
end
diff --git a/AddOnSkins/Core/ElvUI.lua b/AddOnSkins/Core/ElvUI.lua
index a0ba5b96..98e1cd3e 100644
--- a/AddOnSkins/Core/ElvUI.lua
+++ b/AddOnSkins/Core/ElvUI.lua
@@ -12,6 +12,8 @@ local ES = AS.EmbedSystem
local E, L = unpack(ElvUI)
function AS:UpdateMedia()
+ if not E then E = unpack(ElvUI) end
+
S.Media.Blank = AS.Libs.LSM:Fetch('background', 'ElvUI Blank')
S.Media.StatusBar = AS.Libs.LSM:Fetch('statusbar', E.private.general.normTex)
@@ -20,6 +22,11 @@ function AS:UpdateMedia()
S.Media.borderColor = E.media.bordercolor
S.Media.valueColor = E.media.rgbvaluecolor
+ -- Also update the AS-level fields used by skins that reference AS.BackdropColor etc.
+ AS.BackdropColor = E.media.backdropcolor
+ AS.BorderColor = E.media.bordercolor
+ AS.Color = E.media.rgbvaluecolor or AS.ClassColor
+
S.Media.TexCoords = { 0, 1, 0, 1 }
local modifier = 0.04 * E.db.general.cropIcon
for i, v in ipairs(S.Media.TexCoords) do
@@ -44,7 +51,6 @@ function ES:Hooks()
hooksecurefunc(E:GetModule('Layout'), 'ToggleChatPanels', function() ES:Check() end)
if RightChatToggleButton then
- RightChatToggleButton:RegisterForClicks('AnyDown')
RightChatToggleButton:SetScript('OnClick', function(s, btn)
if btn == 'RightButton' then
if ES.Main:IsShown() then
@@ -70,26 +76,35 @@ function ES:Hooks()
end
end
end)
+ end
+end
- RightChatToggleButton:SetScript('OnEnter', function(s)
- if E.db[s.parent:GetName()..'Faded'] then
- s.parent:Show()
- UIFrameFadeIn(s.parent, 0.2, s.parent:GetAlpha(), 1)
- UIFrameFadeIn(s, 0.2, s:GetAlpha(), 1)
- if not AS:CheckOption('EmbedIsHidden') then
- ES.Main:Show()
- end
+-- Hook RightChatToggleButton tooltip unconditionally so the Right Click
+-- line appears even when the embed system is disabled.
+function ES:HookToggleButtonTooltip()
+ if not (E and RightChatToggleButton) then return end
+ if RightChatToggleButton._asTipHooked then return end
+ RightChatToggleButton._asTipHooked = true
+
+ RightChatToggleButton:RegisterForClicks('AnyDown')
+ RightChatToggleButton:HookScript('OnEnter', function(s)
+ if E.db[s.parent:GetName()..'Faded'] then
+ s.parent:Show()
+ UIFrameFadeIn(s.parent, 0.2, s.parent:GetAlpha(), 1)
+ UIFrameFadeIn(s, 0.2, s:GetAlpha(), 1)
+ if not AS:CheckOption('EmbedIsHidden') then
+ ES.Main:Show()
end
+ end
- if not s.parent.editboxforced then
- _G.GameTooltip:SetOwner(s, 'ANCHOR_TOPLEFT', 0, 4)
- _G.GameTooltip:ClearLines()
- _G.GameTooltip:AddDoubleLine(L["Left Click:"], L["Toggle Chat Frame"], 1, 1, 1)
- _G.GameTooltip:AddDoubleLine(L["Right Click:"], L["Toggle Embedded Addon"], 1, 1, 1)
- _G.GameTooltip:Show()
- end
- end)
- end
+ if not s.parent.editboxforced then
+ _G.GameTooltip:SetOwner(s, 'ANCHOR_TOPLEFT', 0, 4)
+ _G.GameTooltip:ClearLines()
+ _G.GameTooltip:AddDoubleLine(L["Left Click:"], L["Toggle Chat Frame"], 1, 1, 1)
+ _G.GameTooltip:AddDoubleLine(L["Right Click:"], L["Toggle Embedded Addon"], 1, 1, 1)
+ _G.GameTooltip:Show()
+ end
+ end)
end
function ES:Resize()
diff --git a/AddOnSkins/Core/EmbedSystem.lua b/AddOnSkins/Core/EmbedSystem.lua
index f6bd0fc1..924e6c39 100644
--- a/AddOnSkins/Core/EmbedSystem.lua
+++ b/AddOnSkins/Core/EmbedSystem.lua
@@ -127,18 +127,20 @@ function ES:Check(Message)
if not (AS:CheckOption('EmbedSystem') or AS:CheckOption('EmbedSystemDual')) then return end
ES:Resize()
- ES.Main:SetShown(not (AS:CheckOption('EmbedIsHidden') or AS:CheckOption('EmbedOoC')))
+ local shouldShow = not (AS:CheckOption('EmbedIsHidden') or AS:CheckOption('EmbedOoC'))
+ ES.Main:SetShown(shouldShow)
+ ES:ToggleChatFrame(shouldShow)
for _, Window in next, ES.Windows do
Window:SetFrameStrata(strsub(AS:CheckOption('EmbedFrameStrata'), 3))
Window:SetFrameLevel(AS:CheckOption('EmbedFrameLevel'))
end
- if AS:CheckEmbed('Details') then ES:Details() end
- if AS:CheckEmbed('Omen') then ES:Omen() end
- if AS:CheckEmbed('Skada') then ES:Skada() end
- if AS:CheckEmbed('TinyDPS') then ES:TinyDPS() end
- if AS:CheckEmbed('Recount') then ES:Recount() end
+ if AS:CheckEmbed('Details') and ES.Details then ES:Details() end
+ if AS:CheckEmbed('Omen') and ES.Omen then ES:Omen() end
+ if AS:CheckEmbed('Skada') and ES.Skada then ES:Skada() end
+ if AS:CheckEmbed('TinyDPS') and ES.TinyDPS then ES:TinyDPS() end
+ if AS:CheckEmbed('Recount') and ES.Recount then ES:Recount() end
if Message and AS:CheckOption('EmbedSystemMessage') then
if AS:CheckOption('EmbedMain') then AS:Print(format(L["Embed System: Main: '%s'"], AS:CheckOption('EmbedMain'))) end
diff --git a/AddOnSkins/Core/Options.lua b/AddOnSkins/Core/Options.lua
index c7c60859..bb8859ee 100644
--- a/AddOnSkins/Core/Options.lua
+++ b/AddOnSkins/Core/Options.lua
@@ -12,7 +12,8 @@ local strlower = strlower
local strtrim = strtrim
local unpack = unpack
-local GetAddOnMetadata = C_AddOns and C_AddOns.GetAddOnMetadata or GetAddOnMetadata
+local C_AddOns = C_AddOns
+local GetAddOnMetadata = (C_AddOns and C_AddOns.GetAddOnMetadata) or _G.GetAddOnMetadata
local GENERAL = GENERAL
local hooksecurefunc = hooksecurefunc
local tContains = tContains
@@ -109,6 +110,7 @@ AS.Options.args.general = ACH:Group(GENERAL, nil, 0, nil, function(info) return
AS.Options.args.general.args.general = ACH:Group(' ', nil, 1)
AS.Options.args.general.args.general.inline = true
AS.Options.args.general.args.general.args.LoginMsg = ACH:Toggle(L["Login Message"], nil, 1)
+AS.Options.args.general.args.general.args.SkinDebug = ACH:Toggle('Enable Skin Debugging', nil, 2)
AS.Options.args.general.args.Theme = ACH:Select(L["Themes"], nil, 2, { PixelPerfect = L["Thin Border"], TwoPixel = L["Two Pixel"], ThickBorder = L["Thick Border"] })
AS.Options.args.general.args.SkinTemplate = ACH:Select(L["Template"], nil, 3, function() local tbl = CopyTable(DefaultTemplates) if AS:CheckOption('ElvUIStyle', 'ElvUI') then tbl.Custom = nil end return tbl end)
@@ -223,6 +225,7 @@ function AS:BuildProfile()
HideChatFrame = 'NONE',
HighlightColor = { 1, .8, .1 },
LoginMsg = false,
+ SkinDebug = false,
Parchment = false,
SelectedColor = { 0, 0.44, .87 },
Shadows = true,
@@ -288,6 +291,9 @@ function AS:BuildOptions()
if AS.Libs.EP and AS:CheckAddOn('ElvUI') then
AS.Libs.EP:RegisterPlugin('AddOnSkins', AS.GetOptions)
+ -- On Anniversary, LibElvUIPlugin may not fire the callback if ElvUI_Options
+ -- is already loaded by this point. Force one call to ensure hooks are set up.
+ C_Timer.After(0, function() pcall(AS.GetOptions, AS) end)
else
AS.Libs.AC:RegisterOptionsTable('AddOnSkins', AS.Options)
AS.Libs.ACD:AddToBlizOptions('AddOnSkins', 'AddOnSkins')
diff --git a/AddOnSkins/Core/Skins.lua b/AddOnSkins/Core/Skins.lua
index 0616f4cc..b950901d 100644
--- a/AddOnSkins/Core/Skins.lua
+++ b/AddOnSkins/Core/Skins.lua
@@ -1488,14 +1488,19 @@ do
function S:HandleCloseButton(button, point, x, y)
S:StripTextures(button)
- if not button.Texture then
- button.Texture = button:CreateTexture(nil, 'OVERLAY')
+ -- button.Texture may exist as a parentKey from UIPanelCloseButton but still
+ -- hold a numeric fileID after StripTextures. Only skip if it's a string path
+ -- (i.e. was already set by a previous HandleCloseButton call).
+ if not button.Texture or type(button.Texture:GetTexture()) ~= 'string' then
+ if not button.Texture then
+ button.Texture = button:CreateTexture(nil, 'OVERLAY')
+ button:HookScript('OnEnter', closeOnEnter)
+ button:HookScript('OnLeave', closeOnLeave)
+ button:SetHitRectInsets(6, 6, 7, 7)
+ end
S:Point(button.Texture, 'CENTER')
button.Texture:SetTexture(Media.Close)
S:Size(button.Texture, 12, 12)
- button:HookScript('OnEnter', closeOnEnter)
- button:HookScript('OnLeave', closeOnLeave)
- button:SetHitRectInsets(6, 6, 7, 7)
end
if point then
@@ -1670,8 +1675,19 @@ function S:HandleTooltip(tooltip, scale, showHook)
S:HandleBlizzardRegions(tooltip)
S:SetTemplate(tooltip, nil, nil, nil, nil, nil, nil, nil, true)
+ -- HandleBlizzardRegions hides .Center (it's in BlizzardRegions list),
+ -- but SetTemplate needs it as the backdrop fill texture. Re-show it.
+ if tooltip.Center and not tooltip.Center:IsShown() then
+ tooltip.Center:Show()
+ end
+
if showHook then
- tooltip:HookScript('OnShow', function(tt) S:SetTemplate(tt) end)
+ tooltip:HookScript('OnShow', function(tt)
+ S:SetTemplate(tt)
+ if tt.Center and not tt.Center:IsShown() then
+ tt.Center:Show()
+ end
+ end)
end
if scale then
@@ -2295,4 +2311,4 @@ function S:PLAYER_LOGIN()
end
end
-S:RegisterEvent('PLAYER_LOGIN')
+S:RegisterEvent('PLAYER_LOGIN')
\ No newline at end of file
diff --git a/AddOnSkins/Init.lua b/AddOnSkins/Init.lua
index d6aca94e..1285333f 100644
--- a/AddOnSkins/Init.lua
+++ b/AddOnSkins/Init.lua
@@ -1,7 +1,27 @@
local _G = _G
-local format, strlower = format, strlower
+local format, strlower, select = format, strlower, select
+
+local C_AddOns = C_AddOns
+
+-- TBC Anniversary: C_AddOns namespace exists but legacy globals may be nil.
+-- Restore them so skin files and libraries that reference the globals directly work.
+if not _G.IsAddOnLoaded and C_AddOns and C_AddOns.IsAddOnLoaded then _G.IsAddOnLoaded = C_AddOns.IsAddOnLoaded end
+if not _G.GetAddOnMetadata and C_AddOns and C_AddOns.GetAddOnMetadata then _G.GetAddOnMetadata = C_AddOns.GetAddOnMetadata end
+if not _G.GetAddOnInfo and C_AddOns and C_AddOns.GetAddOnInfo then _G.GetAddOnInfo = C_AddOns.GetAddOnInfo end
+if not _G.GetNumAddOns and C_AddOns and C_AddOns.GetNumAddOns then _G.GetNumAddOns = C_AddOns.GetNumAddOns end
+-- Do NOT alias C_AddOns.GetAddOnEnableState into the legacy global: they have
+-- opposite argument orders. Callers that need the legacy (character, name)
+-- signature must use _G.GetAddOnEnableState directly; callers that use the
+-- C_AddOns namespace call it as (name, character).
+if not _G.GetAddOnEnableState and C_AddOns and C_AddOns.GetAddOnEnableState then
+ _G.GetAddOnEnableState = function(character, name) return C_AddOns.GetAddOnEnableState(name, character) end
+end
+
+local GetAddOnInfo = (C_AddOns and C_AddOns.GetAddOnInfo) or _G.GetAddOnInfo
+local GetAddOnMetadata = (C_AddOns and C_AddOns.GetAddOnMetadata) or _G.GetAddOnMetadata
+local GetNumAddOns = (C_AddOns and C_AddOns.GetNumAddOns) or _G.GetNumAddOns
+local IsAddOnLoaded = (C_AddOns and C_AddOns.IsAddOnLoaded) or _G.IsAddOnLoaded
-local GetAddOnEnableState, GetAddOnInfo, GetAddOnMetadata, GetNumAddOns, IsAddOnLoaded = C_AddOns.GetAddOnEnableState, C_AddOns.GetAddOnInfo, C_AddOns.GetAddOnMetadata, C_AddOns.GetNumAddOns, C_AddOns.IsAddOnLoaded
local UnitName, GetRealmName, UnitClass, UnitFactionGroup = UnitName, GetRealmName, UnitClass, UnitFactionGroup
local UIParent, CreateFrame = UIParent, CreateFrame
@@ -43,6 +63,15 @@ AS.Noop = function() end
AS.TexCoords = { .08, .92, .08, .92 }
AS.Faction = UnitFactionGroup('player')
+local screenW, screenH = GetPhysicalScreenSize and GetPhysicalScreenSize()
+AS.ScreenWidth = screenW or 1920
+AS.ScreenHeight = screenH or 1080
+AS.UIScale = UIParent:GetScale()
+AS.Mult = 1
+
+local classColor = _G.RAID_CLASS_COLORS[AS.MyClass]
+AS.ClassColor = { classColor.r, classColor.g, classColor.b }
+
AS.preload = {}
AS.skins = {}
AS.events = {}
@@ -55,8 +84,14 @@ AS.AlreadyLoaded = {}
for i = 1, GetNumAddOns() do
local Name, _, _, _, Reason = GetAddOnInfo(i)
local LoweredName = strlower(Name)
- AS.AddOns[LoweredName] = GetAddOnEnableState(Name, AS.MyName) == 2 and (not Reason or Reason ~= 'DEMAND_LOADED')
- AS.AlreadyLoaded[Name] = IsAddOnLoaded(Name)
+ local enableState
+ if C_AddOns and C_AddOns.GetAddOnEnableState then
+ enableState = C_AddOns.GetAddOnEnableState(Name, AS.MyName)
+ else
+ enableState = _G.GetAddOnEnableState and _G.GetAddOnEnableState(AS.MyName, Name)
+ end
+ AS.AddOns[LoweredName] = (enableState or 0) > 0 and (not Reason or Reason ~= 'DEMAND_LOADED')
+ AS.AlreadyLoaded[Name] = IsAddOnLoaded and IsAddOnLoaded(Name) or false
AS.AddOnVersion[LoweredName] = GetAddOnMetadata(Name, 'Version')
end
diff --git a/AddOnSkins/Skins/AddOns/Ace3.lua b/AddOnSkins/Skins/AddOns/Ace3.lua
index a20f3b80..be45b959 100644
--- a/AddOnSkins/Skins/AddOns/Ace3.lua
+++ b/AddOnSkins/Skins/AddOns/Ace3.lua
@@ -10,6 +10,115 @@ function AS:Ace3()
local oldRegisterAsWidget = AceGUI.RegisterAsWidget
local ColorBlind = GetCVarBool('colorblindmode')
+ local BLANK = (_G.ElvUI and _G.ElvUI[1] and _G.ElvUI[1].media.blankTex)
+ or [[Interface\Buttons\WHITE8X8]]
+
+ local function SkinAceCheckBox(widget)
+ local frame = widget.frame
+ if frame._asSkinned then return end
+ frame._asSkinned = true
+
+ -- Wipe button-state slots
+ frame:SetNormalTexture('')
+ frame:SetPushedTexture('')
+ frame:SetHighlightTexture('')
+ frame:SetCheckedTexture(BLANK)
+ local ct = frame:GetCheckedTexture()
+ if ct then ct:SetAlpha(0) end
+
+ -- Hide all texture regions (checkbg, check, highlight are Textures on frame)
+ for i = 1, frame:GetNumRegions() do
+ local r = select(i, frame:GetRegions())
+ if r and r.GetObjectType and r:GetObjectType() ~= 'FontString' then
+ r:SetTexture(nil)
+ r:SetAlpha(0)
+ r:Hide()
+ end
+ end
+ -- Prevent SetType() from restoring them
+ widget.checkbg.SetTexture = AS.noop
+ widget.check.SetTexture = AS.noop
+ widget.highlight.SetTexture = AS.noop
+
+ local border = frame:CreateTexture(nil, 'BACKGROUND')
+ border:SetPoint('TOPLEFT', frame, 'TOPLEFT', 2, -5)
+ border:SetSize(13, 13)
+ border:SetTexture(BLANK)
+ border:SetVertexColor(unpack(AS.BorderColor))
+ frame._aceBorder = border
+
+ local fill = frame:CreateTexture(nil, 'ARTWORK')
+ fill:SetPoint('TOPLEFT', border, 'TOPLEFT', 1, -1)
+ fill:SetSize(11, 11)
+ fill:SetTexture(BLANK)
+ fill:SetVertexColor(unpack(AS.Color))
+ fill:Hide()
+ frame._aceFill = fill
+
+ local function Update(f)
+ if f:GetChecked() then
+ f._aceBorder:SetVertexColor(unpack(AS.Color))
+ f._aceFill:Show()
+ else
+ f._aceBorder:SetVertexColor(unpack(AS.BorderColor))
+ f._aceFill:Hide()
+ end
+ end
+
+ frame:HookScript('OnClick', Update)
+ hooksecurefunc(frame, 'SetChecked', function(f)
+ C_Timer.After(0, function() Update(f) end)
+ end)
+ C_Timer.After(0, function() Update(frame) end)
+ end
+
+ local function SkinAceDropdown(widget)
+ local dd = widget.dropdown -- UIDropDownMenuTemplate frame
+ if dd._asSkinned then return end
+ dd._asSkinned = true
+
+ -- Strip the three UIDropDownMenu background textures
+ local name = dd:GetName()
+ for _, suffix in ipairs({'Left','Middle','Right'}) do
+ local tex = _G[name..suffix]
+ if tex then tex:SetTexture(nil) tex:Hide() end
+ end
+
+ -- Apply backdrop directly on the dropdown frame
+ AS:SetTemplate(dd)
+ dd:SetBackdropColor(unpack(AS.BackdropColor))
+
+ -- Arrow button
+ local btn = _G[name..'Button']
+ if btn then
+ for _, getter in ipairs({'GetNormalTexture','GetPushedTexture','GetHighlightTexture','GetDisabledTexture'}) do
+ local tex = btn[getter] and btn[getter](btn)
+ if tex then tex:SetTexture(nil) tex:Hide() end
+ end
+ local arrow = dd:CreateTexture(nil, 'OVERLAY')
+ arrow:SetTexture([[Interface\AddOns\AddOnSkins\Media\Textures\Arrow]])
+ arrow:SetRotation(3.14)
+ arrow:SetSize(12, 12)
+ arrow:SetPoint('RIGHT', dd, 'RIGHT', -4, 0)
+ arrow:SetVertexColor(1, 1, 1)
+ dd:HookScript('OnEnter', function()
+ arrow:SetVertexColor(unpack(AS.Color))
+ dd:SetBackdropBorderColor(unpack(AS.Color))
+ end)
+ dd:HookScript('OnLeave', function()
+ arrow:SetVertexColor(1, 1, 1)
+ dd:SetBackdropBorderColor(unpack(AS.BorderColor))
+ end)
+ end
+
+ -- Label color fix
+ if widget.label then
+ hooksecurefunc(widget.label, 'SetTextColor', function(self, r, g, b)
+ if r == 1 and g == 0.82 and b == 0 then self:SetTextColor(1,1,1,1) end
+ end)
+ end
+ end
+
AceGUI.RegisterAsWidget = function(self, widget)
local TYPE = widget.type
if TYPE == 'MultiLineEditBox' then
@@ -22,63 +131,9 @@ function AS:Ace3()
widget.scrollBG:SetPoint('BOTTOMLEFT', widget.button, 'TOPLEFT')
widget.scrollFrame:SetPoint('BOTTOMRIGHT', widget.scrollBG, 'BOTTOMRIGHT', -4, 8)
elseif TYPE == 'CheckBox' then
- S:CreateBackdrop(widget.checkbg)
- S:SetInside(widget.checkbg.backdrop, widget.checkbg, 4, 4)
- widget.checkbg.backdrop:SetFrameLevel(widget.checkbg.backdrop:GetFrameLevel() + 1)
-
- widget.checkbg:SetTexture('')
- widget.highlight:SetTexture('')
-
- if not ColorBlind then
- S:SetInside(widget.checkbg.backdrop, widget.checkbg, 5, 5)
-
- widget.check:SetTexture(AS.NormTex)
-
- hooksecurefunc(widget.check, "SetDesaturated", function(self, value)
- if value == true then
- self:SetVertexColor(.6, .6, .6, .8)
- else
- self:SetVertexColor(unpack(S.Media.valueColor))
- end
- end)
-
- widget.check.SetTexture = S.noop
- S:SetInside(widget.check, widget.checkbg.backdrop)
- else
- S:SetOutside(widget.check, widget.checkbg.backdrop, 3, 3)
- end
-
- widget.checkbg.SetTexture = S.noop
- widget.highlight.SetTexture = AS.noop
+ SkinAceCheckBox(widget)
elseif TYPE == 'Dropdown' then
- local frame = widget.dropdown
- local button = widget.button
- local text = widget.text
-
- S:HandleFrame(frame, true)
- frame.backdrop:SetPoint('TOPLEFT', 15, -2)
- frame.backdrop:SetPoint("BOTTOMRIGHT", -21, 0)
-
- S:HandleNextPrevButton(button)
-
- widget.label:ClearAllPoints()
- widget.label:SetPoint('BOTTOMLEFT', frame.backdrop, 'TOPLEFT', 2, 0)
- hooksecurefunc(widget.label, 'SetTextColor', function(self, r, g, b, a)
- if r == 1 and g == 0.82 and b == 0 then
- self:SetTextColor(1, 1, 1, 1)
- end
- end)
-
- button:SetSize(20, 20)
- button:ClearAllPoints()
- button:SetPoint('RIGHT', frame.backdrop, 'RIGHT', -2, 0)
-
- text:ClearAllPoints()
- text:SetJustifyH("RIGHT")
- text:SetPoint('RIGHT', button, 'LEFT', -3, 0)
-
- button:HookScript('PostClick', function(s) S:SetTemplate(s.obj.pullout.frame) end)
- widget.button_cover:HookScript('PostClick', function(s) S:SetTemplate(s.obj.pullout.frame) end)
+ SkinAceDropdown(widget)
elseif TYPE == 'LSM30_Font' or TYPE == 'LSM30_Sound' or TYPE == 'LSM30_Border' or TYPE == 'LSM30_Background' or TYPE == 'LSM30_Statusbar' then
local frame = widget.frame
local button = frame.dropButton
@@ -218,8 +273,14 @@ function AS:Ace3()
for i = 1, frame:GetNumChildren() do
local child = select(i, frame:GetChildren())
- if child:GetObjectType() == 'Button' and child:GetText() then
+ local childType = child:GetObjectType()
+ local childText = childType == 'Button' and child:GetText()
+ if childText and childText ~= '' then
S:HandleButton(child)
+ elseif childType == 'Button' then
+ -- statusbg: Button without label text, has its own backdrop
+ S:StripTextures(child)
+ S:SetTemplate(child)
else
S:StripTextures(child)
end
diff --git a/AddOnSkins/Skins/AddOns/Atlas.lua b/AddOnSkins/Skins/AddOns/Atlas.lua
index 96c0f6eb..f7000f53 100644
--- a/AddOnSkins/Skins/AddOns/Atlas.lua
+++ b/AddOnSkins/Skins/AddOns/Atlas.lua
@@ -1,49 +1,644 @@
-local AS, L, S, R = unpack(AddOnSkins)
-
-function R:Atlas(event, addon)
- S:HandleFrame(AtlasFrame)
- S:HandleFrame(AtlasFrameSmall)
-
- -- Skin Elements
- S:HandleCloseButton(AtlasFrameCloseButton)
- S:HandleCloseButton(AtlasFrameSmallCloseButton)
- S:HandleButton(AtlasFrameOptionsButton)
- S:HandleButton(AtlasFrameSmallOptionsButton)
- S:HandleButton(AtlasSearchButton)
- S:HandleButton(AtlasSearchClearButton)
- S:HandleButton(AtlasSwitchButton)
- S:HandleDropDownBox(AtlasFrameDropDown)
- S:HandleDropDownBox(AtlasFrameDropDownType)
- S:HandleDropDownBox(AtlasFrameSmallDropDown)
- S:HandleDropDownBox(AtlasFrameSmallDropDownType)
- S:HandleEditBox(AtlasSearchEditBox)
- S:HandleScrollBar(AtlasScrollBarScrollBar)
-
- --Reposition Elements
- AtlasFrameCloseButton:ClearAllPoints()
- AtlasFrameCloseButton:SetPoint('TOPRIGHT', AtlasFrame, 'TOPRIGHT', -5, -5)
- AtlasFrameSmallCloseButton:ClearAllPoints()
- AtlasFrameSmallCloseButton:SetPoint('TOPRIGHT', AtlasFrameSmall, 'TOPRIGHT', -5, -5)
- AtlasFrameCollapseButton:ClearAllPoints()
- AtlasFrameCollapseButton:SetPoint('BOTTOM', AtlasFrame, 'BOTTOM', 0, 12)
- AtlasFrameSmallExpandButton:ClearAllPoints()
- AtlasFrameSmallExpandButton:SetPoint('BOTTOMRIGHT', AtlasFrameSmall, 'BOTTOMRIGHT', -10, 10)
- AtlasFrameOptionsButton:ClearAllPoints()
- AtlasFrameOptionsButton:SetPoint('LEFT', AtlasFrameLockButton, 'RIGHT', 4, 0)
- AtlasFrameSmallOptionsButton:ClearAllPoints()
- AtlasFrameSmallOptionsButton:SetPoint('LEFT', AtlasFrameSmallLockButton, 'RIGHT', 4, 0)
- AtlasFrameLockButton:ClearAllPoints()
- AtlasFrameLockButton:SetPoint('TOPLEFT', AtlasFrame, 'TOPLEFT', 5, -5)
- AtlasFrameSmallLockButton:ClearAllPoints()
- AtlasFrameSmallLockButton:SetPoint('TOPLEFT', AtlasFrameSmall, 'TOPLEFT', 10, -10)
- AtlasSearchClearButton:ClearAllPoints()
- AtlasSearchClearButton:SetPoint('RIGHT', AtlasSwitchButton, 'LEFT', -3, 0)
- AtlasSearchButton:ClearAllPoints()
- AtlasSearchButton:SetPoint('RIGHT', AtlasSearchClearButton, 'LEFT', -3, 0)
- AtlasSearchEditBox:ClearAllPoints()
- AtlasSearchEditBox:SetPoint('BOTTOM', AtlasFrame, 'BOTTOM', 95, 7)
- AtlasSwitchButton:ClearAllPoints()
- AtlasSwitchButton:SetPoint('BOTTOMRIGHT', AtlasFrame, 'BOTTOMRIGHT', -10, 10)
+-- Atlas skin for AddOnSkins.
+-- Supports the Retail-engine Atlas fork used on TBC Anniversary servers.
+
+local AS = unpack(AddOnSkins)
+
+local ARROW_TEX = [[Interface\AddOns\AddOnSkins\Media\Textures\Arrow]]
+local ARROW_ROTATION_DOWN = 3.14
+
+local function Safe(func, name)
+ local f = type(name) == "string" and _G[name] or name
+ if f then func(AS, f) end
+end
+
+-- ----------------------------------------------------------------
+-- WowStyle1DropdownTemplate skin
+-- ----------------------------------------------------------------
+
+local function SkinWowStyleDropdown(name)
+ local f = _G[name]
+ if not f or f._atlasSkinned then return end
+ f._atlasSkinned = true
+
+ for _, child in ipairs({f:GetChildren()}) do
+ child:Hide()
+ end
+
+ for i = 1, f:GetNumRegions() do
+ local r = select(i, f:GetRegions())
+ if r and r ~= f.Arrow and r ~= f.Text and r ~= f.Label then
+ if r.SetTexture then r:SetTexture(nil) end
+ if r.SetAtlas then pcall(r.SetAtlas, r, '') end
+ r:SetAlpha(0)
+ end
+ end
+
+ AS:SetTemplate(f)
+
+ if f.Arrow then
+ if f.Arrow.SetAtlas then pcall(f.Arrow.SetAtlas, f.Arrow, nil) end
+ f.Arrow:SetTexture(ARROW_TEX, 'CLAMPTOBLACKADDITIVE', 'CLAMPTOBLACKADDITIVE')
+ f.Arrow:SetRotation(ARROW_ROTATION_DOWN)
+ f.Arrow:SetVertexColor(1, 1, 1)
+ f.Arrow:SetAlpha(1)
+
+ if f.Arrow.SetAtlas then
+ hooksecurefunc(f.Arrow, 'SetAtlas', function(self)
+ self:SetTexture(ARROW_TEX, 'CLAMPTOBLACKADDITIVE', 'CLAMPTOBLACKADDITIVE')
+ self:SetRotation(ARROW_ROTATION_DOWN)
+ self:SetVertexColor(1, 1, 1)
+ end)
+ end
+
+ f:HookScript('OnEnter', function()
+ f.Arrow:SetVertexColor(unpack(AS.Color))
+ if f.SetBackdropBorderColor then f:SetBackdropBorderColor(unpack(AS.Color)) end
+ end)
+ f:HookScript('OnLeave', function()
+ f.Arrow:SetVertexColor(1, 1, 1)
+ if f.SetBackdropBorderColor then f:SetBackdropBorderColor(unpack(AS.BorderColor)) end
+ end)
+ end
+end
+
+-- ----------------------------------------------------------------
+-- Header layout
+-- ----------------------------------------------------------------
+
+--[[
+ Header layout:
+
+ [Cat v] [Zone v] [Options] [AtlasQuest] [Lock][X]
+
+ Options and AtlasQuest are centred on the visible dropdown control
+ (not its label). WowStyle1DropdownTemplate has the Label anchored
+ 14px above the frame top, so the visible control centre sits at
+ frame.CENTRE - no extra Y offset needed when anchoring to CENTER.
+
+ Close and Lock sit flush in the top-right corner. The icon visible
+ to their left (AtlasLoot/LFG) is hidden by default and not part of
+ the normal header flow.
+--]]
+
+-- Apply ElvUI-style dark backdrop + accent border on hover to a button.
+-- Hides all existing button textures (UIPanelButtonTemplate gloss, highlight, etc.)
+-- without calling StripTextures which breaks Classic backdrop creation.
+-- keepIcon: if true, skips hiding regions (for Lock/LFG which have an icon texture).
+local function ApplyButtonSkin(btn, keepIcon)
+ if not btn then return end
+ -- Clear Blizzard template textures.
+ if not keepIcon and btn.SetNormalTexture then btn:SetNormalTexture('') end
+ if btn.SetHighlightTexture then btn:SetHighlightTexture('') end
+ if btn.SetPushedTexture then btn:SetPushedTexture('') end
+ if btn.SetDisabledTexture then btn:SetDisabledTexture('') end
+ -- Hide any remaining region textures (e.g. UIPanelButtonTemplate .Center, gloss).
+ if not keepIcon then
+ for i = 1, btn:GetNumRegions() do
+ local r = select(i, btn:GetRegions())
+ if r and r.IsObjectType and r:IsObjectType('Texture') then r:Hide() end
+ end
+ end
+ -- Apply dark backdrop + border. glossTex=false = no statusbar gloss layer.
+ if not btn.SetBackdrop and BackdropTemplateMixin then
+ Mixin(btn, BackdropTemplateMixin)
+ end
+ AS.Skins:SetTemplate(btn, nil, false)
+ -- Accent border on hover, plain border on leave.
+ if not btn._atlasHoverHooked then
+ btn._atlasHoverHooked = true
+ btn:HookScript('OnEnter', AS.Skins.SetModifiedBackdrop)
+ btn:HookScript('OnLeave', AS.Skins.SetOriginalBackdrop)
+ end
+end
+
+local function SkinNoGlowBtn(btn)
+ ApplyButtonSkin(btn, false)
+end
+AS.ApplyAtlasButtonSkin = ApplyButtonSkin -- exposed for dependent skins (AtlasQuest)
+
+local function SkinTransparentBtn(btn)
+ if not btn then return end
+ -- Kill glow/highlight: SetHighlightTexture('') may not work on XML-defined textures,
+ -- so also hide the texture object directly.
+ if btn.SetHighlightTexture then btn:SetHighlightTexture('') end
+ if btn.SetPushedTexture then btn:SetPushedTexture('') end
+ if btn.SetDisabledTexture then btn:SetDisabledTexture('') end
+ local ht = btn.GetHighlightTexture and btn:GetHighlightTexture()
+ if ht then ht:SetTexture(nil); ht:Hide() end
+ -- Apply backdrop for border-only hover (no fill, border hidden until hover).
+ if not btn.SetBackdrop and BackdropTemplateMixin then Mixin(btn, BackdropTemplateMixin) end
+ AS.Skins:SetTemplate(btn, nil, false)
+ btn:SetBackdropColor(0, 0, 0, 0)
+ btn:SetBackdropBorderColor(0, 0, 0, 0)
+ if btn.iborder then btn.iborder:Hide() end
+ if btn.oborder then btn.oborder:Hide() end
+ -- Border-only hover (no glow).
+ if not btn._transparentHoverHooked then
+ btn._transparentHoverHooked = true
+ btn._atlasHoverHooked = true
+ btn:HookScript('OnEnter', function(self)
+ self:SetBackdropBorderColor(unpack(AS.Color))
+ end)
+ btn:HookScript('OnLeave', function(self)
+ self:SetBackdropBorderColor(0, 0, 0, 0)
+ end)
+ end
+end
+
+local function LayoutHeader(atlas)
+ local pn = atlas:GetName()
+ local mf = _G[pn..'MapFrame']
+
+ -- Dropdowns: keep their original TOPLEFT anchor (set by Atlas Templates.lua).
+ -- We only override the X to flush left; Y stays as Atlas placed them.
+ local cat = _G[pn..'DropDownType']
+ local zone = _G[pn..'DropDown']
+ if cat then
+ cat:ClearAllPoints()
+ cat:SetPoint('TOPLEFT', atlas, 'TOPLEFT', 4, -44)
+ end
+ if cat and zone then
+ zone:ClearAllPoints()
+ zone:SetPoint('LEFT', cat, 'RIGHT', 8, 0)
+ end
+
+ local ref = zone or cat
+
+ -- Options and Close/Lock: all deferred so GetBottom() returns real values.
+ local optsBtn = _G[pn..'OptionsButton']
+ local closeBtn = _G[pn..'CloseButton']
+ local lockBtn = _G[pn..'LockButton']
+
+ if optsBtn then SkinNoGlowBtn(optsBtn); optsBtn:SetSize(80, 20) end
+ if closeBtn then closeBtn:SetSize(32, 32) end
+ if lockBtn then lockBtn:SetSize(20, 20); SkinTransparentBtn(lockBtn) end
+ local lfgBtn = _G[pn..'LFGButton']
+ if lfgBtn then lfgBtn:SetSize(20, 20); SkinTransparentBtn(lfgBtn) end
+ -- Add proper border-highlight hover to close, lock, lfg.
+
+
+ C_Timer.After(0, function()
+ if not ref then return end
+
+ -- Options/AQ: centre on dropdown control.
+ -- Dropdown h=24, button h=20 -> bottom of button must be 2px above dd bottom
+ -- so their centres align: dd_centre = dd_bot+12, btn_centre = btn_bot+10 -> offset=2.
+ local btnCentreOffset = (ref:GetHeight() - 20) / 2
+ if optsBtn then
+ optsBtn:ClearAllPoints()
+ optsBtn:SetPoint('LEFT', ref, 'RIGHT', 10, 0)
+ optsBtn:SetPoint('BOTTOM', ref, 'BOTTOM', 0, btnCentreOffset)
+ end
+
+ -- Close/Lock/LFG: centred on AtlasFrameTitleContainer (the dark title bar).
+ local titleBar = _G[pn..'TitleContainer'] or _G[pn..'TitleBg']
+ local function TopOffsetHeader(btn)
+ if titleBar then
+ local tCentre = titleBar:GetTop() - titleBar:GetHeight() / 2
+ return tCentre - atlas:GetTop() + btn:GetHeight() / 2
+ else
+ -- Fallback: use header strip centre
+ local hH = atlas:GetTop() - (mf and mf:GetTop() or (atlas:GetTop() - 74))
+ return -(hH / 2 - btn:GetHeight() / 2)
+ end
+ end
+ if closeBtn then
+ closeBtn:ClearAllPoints()
+ closeBtn:SetPoint('RIGHT', atlas, 'RIGHT', 0, 0)
+ closeBtn:SetPoint('TOP', atlas, 'TOP', 0, TopOffsetHeader(closeBtn))
+ end
+ if lockBtn and closeBtn then
+ lockBtn:ClearAllPoints()
+ lockBtn:SetPoint('RIGHT', closeBtn, 'LEFT', 4, 0)
+ lockBtn:SetPoint('TOP', atlas, 'TOP', 0, TopOffsetHeader(lockBtn))
+ end
+ local lfg = _G[pn..'LFGButton']
+ if lfg and lockBtn then
+ lfg:ClearAllPoints()
+ lfg:SetPoint('RIGHT', lockBtn, 'LEFT', -4, 0)
+ lfg:SetPoint('TOP', atlas, 'TOP', 0, TopOffsetHeader(lfg))
+ end
+ end)
+
+ -- AtlasQuest button is a child of AtlasQuestButtonFrame which resets its
+ -- XML anchor on every Show. Hook AtlasFrame:OnShow to reapply our layout.
+ local function PositionAQButton()
+ local aqBtn = _G['AQ_AtlasToggle']
+ if not aqBtn or not ref then return end
+ aqBtn:SetSize(90, 20)
+ local anchor = optsBtn or ref
+ local ddCY = ref:GetBottom() + ref:GetHeight() / 2
+ local topOff = ddCY - atlas:GetTop() + aqBtn:GetHeight() / 2
+ aqBtn:ClearAllPoints()
+ aqBtn:SetPoint('LEFT', anchor, 'RIGHT', 4, 0)
+ aqBtn:SetPoint('TOP', atlas, 'TOP', 0, topOff)
+
+ -- Clear Blizzard template textures every call (AQ restores them on Show).
+ if aqBtn.SetNormalTexture then aqBtn:SetNormalTexture('') end
+ if aqBtn.SetHighlightTexture then aqBtn:SetHighlightTexture('') end
+ if aqBtn.SetPushedTexture then aqBtn:SetPushedTexture('') end
+ for i = 1, aqBtn:GetNumRegions() do
+ local r = select(i, aqBtn:GetRegions())
+ if r and r.IsObjectType and r:IsObjectType('Texture') then r:Hide() end
+ end
+ -- Backdrop as a sibling frame so AtlasQuestInsideFrame can't cover it.
+ if not aqBtn._asBD then
+ -- Parent to aqBtn so it moves with it; frameLevel 0 within the button
+ -- ensures it draws behind the button's own FontString regions.
+ local bd = CreateFrame('Frame', nil, aqBtn, 'BackdropTemplate')
+ bd:SetAllPoints(aqBtn)
+ bd:SetFrameLevel(0)
+ AS.Skins:SetTemplate(bd, nil, false)
+ aqBtn._asBD = bd
+ aqBtn:HookScript('OnEnter', function()
+ bd:SetBackdropBorderColor(unpack(AS.Color))
+ end)
+ aqBtn:HookScript('OnLeave', function()
+ bd:SetBackdropBorderColor(unpack(AS.BorderColor))
+ end)
+ end
+
+
+ -- Block AtlasQuest from restoring textures — hook once per button object.
+ if not aqBtn._aqTexHooked then
+ aqBtn._aqTexHooked = true
+ hooksecurefunc(aqBtn, 'SetNormalTexture', function(self, tex)
+ if tex ~= '' and not self._aqSkipHook then
+ self._aqSkipHook = true
+ self:SetNormalTexture('')
+ self._aqSkipHook = false
+ end
+ end)
+ hooksecurefunc(aqBtn, 'SetHighlightTexture', function(self, tex)
+ if tex ~= '' and not self._aqSkipHook then
+ self._aqSkipHook = true
+ self:SetHighlightTexture('')
+ self._aqSkipHook = false
+ end
+ end)
+ end
+
+ -- Re-apply backdrop when AtlasQuestInsideFrame shows (actual parent of the button).
+ local aqInsideFrame = _G['AtlasQuestInsideFrame']
+ if aqInsideFrame and not aqInsideFrame._asSkinHooked then
+ aqInsideFrame._asSkinHooked = true
+ aqInsideFrame:HookScript('OnShow', function()
+ local btn = _G['AQ_AtlasToggle']
+ if btn then AS.Skins:SetTemplate(btn, nil, false) end
+ end)
+ end
+ end
+ -- AQ loads after Atlas; defer initial placement and reapply on every Show.
+ C_Timer.After(1, PositionAQButton)
+ atlas:HookScript('OnShow', function() C_Timer.After(0, PositionAQButton) end)
+end
+
+-- ----------------------------------------------------------------
+-- Main skin
+-- ----------------------------------------------------------------
+
+function AS:Atlas(event, addon)
+ local loaded = (C_AddOns and C_AddOns.IsAddOnLoaded and C_AddOns.IsAddOnLoaded('Atlas'))
+ or (_G.IsAddOnLoaded and _G.IsAddOnLoaded('Atlas'))
+ if not loaded then return end
+
+ local AtlasFrame = _G['AtlasFrame']
+ local AtlasFrameSmall = _G['AtlasFrameSmall']
+
+ -- NineSlice piece names created by PortraitFrameTemplate.
+ local NINE_SLICE = {
+ 'TopLeftCorner','TopRightCorner','BottomLeftCorner','BottomRightCorner',
+ 'TopEdge','BottomEdge','LeftEdge','RightEdge','Center',
+ 'TopBorder','BottomBorder','LeftBorder','RightBorder',
+ 'TopLeftBorder','TopRightBorder','BottomLeftBorder','BottomRightBorder',
+ }
+ local function HideNineSlice(f)
+ if not f then return end
+ for _, piece in ipairs(NINE_SLICE) do
+ local p = _G[f:GetName()..piece]
+ if p then p:Hide() end
+ end
+ end
+
+ local function SkinAtlasFrame(f, mapFrameName)
+ if not f then return end
+ AS:StripTextures(f)
+ HideNineSlice(f)
+ -- CreateBackdrop instead of SetTemplate: the backdrop frame sits at
+ -- frameLevel-1, below MapFrame children, so it won't tint the map.
+ -- SetTemplate creates a Center texture on AtlasFrame itself which
+ -- shares frameLevel with MapFrame and draws over the map image.
+ if f.SetBackdrop then f:SetBackdrop(nil) end
+ if f.Center then f.Center:Hide() end
+ AS:CreateBackdrop(f)
+ if f.oborder then f.oborder:Hide() end
+ AS:CreateShadow(f)
+ if f.Portrait then f.Portrait:Hide() end
+ if f.PortraitContainer then f.PortraitContainer:Hide() end
+ -- Hide named PortraitFrameTemplate textures StripTextures may miss.
+ local pn = f:GetName()
+ if pn then
+ for _, suffix in ipairs({
+ 'Bg', 'TitleBg', 'Portrait', 'PortraitFrame', 'TitleText',
+ 'TopTileStreaks', 'BotLeftCorner', 'BotRightCorner',
+ }) do
+ local tex = _G[pn..suffix]
+ if tex and tex.Hide then tex:Hide() end
+ end
+ end
+ local mf = _G[mapFrameName]
+ if mf then
+ if mf.NineSlice then mf.NineSlice:Hide() end
+ if mf.backdrop then mf.backdrop:Hide() end
+ if mf.SetBackdrop then mf:SetBackdrop(nil) end
+ end
+ end
+
+ SkinAtlasFrame(AtlasFrame, 'AtlasFrameMapFrame')
+ SkinAtlasFrame(AtlasFrameSmall, 'AtlasFrameSmallMapFrame')
+ -- Keep NineSlice hidden even if Atlas re-shows it on refresh.
+ for _, f in ipairs({ AtlasFrame, AtlasFrameSmall }) do
+ if f and f.NineSlice then
+ f:HookScript('OnShow', function() f.NineSlice:Hide() end)
+ end
+ end
+ -- Raise SmallMapFrame above AtlasFrameSmall's backdrop so it doesn't bleed through
+ local smf = _G['AtlasFrameSmallMapFrame']
+ if smf and AtlasFrameSmall then
+ -- backdrop is placed at parent level-1; children default to parent+1.
+ -- We need smf above the backdrop, so raise it well above AtlasFrameSmall.
+ smf:SetFrameLevel(AtlasFrameSmall:GetFrameLevel() + 10)
+ end
+
+ -- Strip inset border textures and create ElvUI backdrops
+ local function SkinInset(name)
+ local f = _G[name]
+ if not f then return end
+ if f.NineSlice then f.NineSlice:Hide() end
+ local bg = _G[name..'Bg']
+ if bg then bg:Hide() end
+ AS:CreateBackdrop(f)
+ end
+ SkinInset('AtlasFrameTopInset')
+ SkinInset('AtlasFrameBottomInset')
+ -- Hide ScrollBox Shadows in BottomInset (they cover the backdrop making it opaque)
+ do
+ local bi = _G['AtlasFrameBottomInset']
+ if bi then
+ local sbSkinned = false
+ local function FixBotInset()
+ if bi.ScrollBox and bi.ScrollBox.Shadows then
+ bi.ScrollBox.Shadows:Hide()
+ end
+ if bi.backdrop then
+ -- Lighten slightly: ScrollBox content bleeds through at default alpha.
+ local r, g, b, a = bi.backdrop:GetBackdropColor()
+ if r then
+ bi.backdrop:SetBackdropColor(r + 0.06, g + 0.06, b + 0.06, a)
+ end
+ end
+ -- Skin the WowClassicScrollBar and stretch ScrollBox to fill botInset.
+ if not sbSkinned and bi.ScrollBox then
+ local sb
+ for _, child in ipairs({bi:GetChildren()}) do
+ if child.Track and child.GetThumb then
+ sb = child
+ break
+ end
+ end
+ if sb then
+ AS.Skins:HandleTrimScrollBar(sb)
+ -- Stretch both ScrollBox and scrollbar to fill botInset.
+ local sbW = sb:GetWidth()
+ sb:ClearAllPoints()
+ sb:SetPoint('TOPRIGHT', bi, 'TOPRIGHT', -2, -5)
+ sb:SetPoint('BOTTOMRIGHT', bi, 'BOTTOMRIGHT', -2, 5)
+ bi.ScrollBox:ClearAllPoints()
+ bi.ScrollBox:SetPoint('TOPLEFT', bi, 'TOPLEFT', 15, -5)
+ bi.ScrollBox:SetPoint('BOTTOMRIGHT', bi, 'BOTTOMRIGHT', -(sbW+4), 5)
+ sbSkinned = true
+ end
+ end
+ end
+ AtlasFrame:HookScript('OnShow', FixBotInset)
+ FixBotInset()
+ end
+ end
+
+ -- Atlas XML leaves a 6px gap on the right of TopInset/BottomInset.
+ -- Anchor their right edge to the frame edge to match the 2px left margin.
+ local topInset = _G['AtlasFrameTopInset']
+ local botInset = _G['AtlasFrameBottomInset']
+ local atlMapFrame = _G['AtlasFrameMapFrame']
+ if topInset and atlMapFrame and AtlasFrame then
+ topInset:ClearAllPoints()
+ topInset:SetPoint('TOPLEFT', atlMapFrame, 'TOPRIGHT', 0, 0)
+ topInset:SetPoint('TOPRIGHT', AtlasFrame, 'TOPRIGHT', -2, -74)
+ -- Height stays as-is via content; don't set BOTTOM to avoid breaking scroll
+ topInset:SetHeight(120)
+ end
+ if botInset and topInset and AtlasFrame then
+ botInset:ClearAllPoints()
+ botInset:SetPoint('TOPLEFT', topInset, 'BOTTOMLEFT', 0, 0)
+ botInset:SetPoint('BOTTOMRIGHT', AtlasFrame,'BOTTOMRIGHT', -2, 0)
+ end
+
+ Safe(AS.SkinCloseButton, 'AtlasFrameCloseButton')
+ Safe(AS.SkinCloseButton, 'AtlasFrameSmallCloseButton')
+ do
+ local cb = _G['AtlasFrameCloseButton']
+ if cb then cb:SetSize(32, 32) end
+ local cbs = _G['AtlasFrameSmallCloseButton']
+ if cbs then cbs:SetSize(32, 32) end
+ end
+
+ -- AtlasQuestButtonFrame is a 1x1 mouse-capturing frame anchored TOPRIGHT
+ -- that would intercept clicks in the corner; its child AQ_AtlasToggle is
+ -- repositioned into the header row, so the container frame can be hidden.
+ C_Timer.After(1, function()
+ local aqf = _G['AtlasQuestButtonFrame']
+ if aqf then aqf:EnableMouse(false) end
+ end)
+
+ SkinNoGlowBtn(_G['AtlasFrameSwitchButton'])
+ SkinNoGlowBtn(_G['AtlasFrameSmallSwitchButton'])
+
+ local ARROW_LEFT = math.pi / 2
+ local ARROW_RIGHT = -math.pi / 2
+
+ local function SkinCollapseBtn(btn, mf, rotation)
+ if not btn then return end
+ btn:SetSize(20, 20)
+ -- Arrow only, no backdrop, with padding matching other nav buttons
+ local PAD = 4
+ local arrow = btn:CreateTexture(nil, 'OVERLAY', nil, 7)
+ arrow:SetTexture(ARROW_TEX, 'CLAMPTOBLACKADDITIVE', 'CLAMPTOBLACKADDITIVE')
+ arrow:SetRotation(rotation)
+ arrow:SetPoint('TOPLEFT', btn, 'TOPLEFT', PAD, -PAD)
+ arrow:SetPoint('BOTTOMRIGHT', btn, 'BOTTOMRIGHT', -PAD, PAD)
+ btn._arrow = arrow
+ -- Hide all native textures by alpha so WoW restoring them has no effect
+ local function KillNativeTex()
+ local getters = {'GetNormalTexture','GetPushedTexture','GetHighlightTexture','GetDisabledTexture'}
+ for _, g in ipairs(getters) do
+ local t = btn[g] and btn[g](btn)
+ if t and t ~= arrow then t:SetAlpha(0) end
+ end
+ for i = 1, btn:GetNumRegions() do
+ local r = select(i, btn:GetRegions())
+ if r and r ~= arrow and r.IsObjectType and r:IsObjectType('Texture') then
+ r:SetAlpha(0)
+ end
+ end
+ end
+ KillNativeTex()
+ -- Run on every possible state change
+ btn:HookScript('OnShow', KillNativeTex)
+ btn:HookScript('OnMouseDown', KillNativeTex)
+ btn:HookScript('OnMouseUp', KillNativeTex)
+ -- Hover: tint arrow only
+ btn:HookScript('OnEnter', function(self)
+ self._arrow:SetVertexColor(unpack(AS.Color))
+ end)
+ btn:HookScript('OnLeave', function(self)
+ self._arrow:SetVertexColor(1, 1, 1)
+ end)
+ if mf then
+ btn:ClearAllPoints()
+ btn:SetPoint('BOTTOMRIGHT', mf, 'BOTTOMRIGHT', -6, 6)
+ btn:SetFrameLevel(mf:GetFrameLevel() + 25)
+ end
+ end
+
+ local mfMain = _G['AtlasFrameMapFrame']
+ local mfSmall = _G['AtlasFrameSmallMapFrame']
+ -- CollapseButton on large frame: legend visible → arrow points left (collapse)
+ -- ExpandButton on small frame: legend hidden → arrow points right (expand)
+ SkinCollapseBtn(_G['AtlasFrameCollapseButton'], mfMain, ARROW_LEFT)
+ SkinCollapseBtn(_G['AtlasFrameSmallExpandButton'], mfSmall, ARROW_RIGHT)
+
+ for _, names in ipairs({
+ { 'AtlasFramePrevNextContainer', 'AtlasFrameSwitchButton', 'AtlasFrameSwitchDropdown', 'AtlasFrameMapFrame', AtlasFrame },
+ { 'AtlasFrameSmallPrevNextContainer', 'AtlasFrameSmallSwitchButton', 'AtlasFrameSmallSwitchDropdown', 'AtlasFrameSmallMapFrame', AtlasFrameSmall },
+ }) do
+ local container = _G[names[1]]
+ local switchBtn = _G[names[2]]
+ local switchDD = _G[names[3]]
+ local mapFrame = _G[names[4]]
+ local atlasFrame = names[5]
+ local navPrev = container and container.PrevMap
+ local navNext = container and container.NextMap
+ if container then
+ local prev = navPrev
+ local next = navNext
+ local function SkinNav(btn, dir)
+ if not btn then return end
+ AS:SkinArrowButton(btn, dir)
+ btn:SetSize(24, 24)
+ btn._navHovered = false
+ local function applyTint()
+ if not btn._navHovered then return end
+ local t = btn:GetNormalTexture()
+ if t then t:SetVertexColor(unpack(AS.Color)) end
+ if btn.SetBackdropBorderColor then btn:SetBackdropBorderColor(unpack(AS.Color)) end
+ end
+ btn:HookScript('OnEnter', function(self)
+ self._navHovered = true
+ applyTint()
+ end)
+ btn:HookScript('OnLeave', function(self)
+ self._navHovered = false
+ local t = self:GetNormalTexture()
+ if t then t:SetVertexColor(1, 1, 1) end
+ if self.SetBackdropBorderColor then self:SetBackdropBorderColor(unpack(AS.BorderColor)) end
+ end)
+ -- Re-apply tint whenever Atlas resets the texture.
+ hooksecurefunc(btn, 'SetNormalTexture', function() applyTint() end)
+ end
+ SkinNav(prev, 'left')
+ SkinNav(next, 'right')
+ end
+
+ end
+
+ for _, parent in ipairs({AtlasFrame, AtlasFrameSmall}) do
+ if parent then
+ local pn = parent:GetName()
+ local aj = parent.AdventureJournalMap or _G[pn..'AdventureJournalMapButton']
+ local ej = parent.AdventureJournal or _G[pn..'AdventureJournalButton']
+ local al = parent.AtlasLoot or _G[pn..'AtlasLootButton']
+ if aj then AS:SkinIconButton(aj) end
+ if ej then AS:SkinIconButton(ej) end
+ if al then AS:SkinIconButton(al) end
+
+ -- LFG: skin and resize; position is handled in LayoutHeader deferred block.
+ local lfg = _G[pn..'LFGButton']
+ if lfg then
+ SkinTransparentBtn(lfg)
+ local eyeTex = lfg:GetName() and _G[lfg:GetName()..'Texture']
+ if eyeTex then eyeTex:SetAlpha(1); AS:SetInside(eyeTex, lfg) end
+ lfg:SetSize(20, 20)
+ end
+ end
+ end
+
+ local search = _G['AtlasSearchEditBox']
+ if search and AtlasFrame then
+ AS:SkinEditBox(search)
+ search:ClearAllPoints()
+ search:SetSize(180, 20)
+ -- Align vertically with Options/AtlasQuest buttons in the header row.
+ -- Buttons bottom = atlas.top - 66; search is 20px tall so same bottom.
+ -- Keep X position on the right side, just move Y up to header level.
+ C_Timer.After(0.5, function()
+ local ref2 = _G['AtlasFrameDropDown']
+ if ref2 and AtlasFrame then
+ local ddCY = ref2:GetBottom() + ref2:GetHeight() / 2
+ local topOff = ddCY - AtlasFrame:GetTop() + search:GetHeight() / 2
+ search:ClearAllPoints()
+ search:SetPoint('RIGHT', AtlasFrame, 'RIGHT', -10, 0)
+ search:SetPoint('TOP', AtlasFrame, 'TOP', 0, topOff)
+ end
+ end)
+ end
+
+ -- Skin + reposition dropdowns, then lay out the full header row
+ C_Timer.After(0, function()
+ for _, name in ipairs({
+ 'AtlasFrameDropDownType', 'AtlasFrameDropDown',
+ 'AtlasFrameSmallDropDownType', 'AtlasFrameSmallDropDown',
+ }) do
+ SkinWowStyleDropdown(name)
+ end
+
+ for _, f in ipairs({AtlasFrame, AtlasFrameSmall}) do
+ if f then
+ for _, child in ipairs({f:GetChildren()}) do
+ local n = child.GetName and child:GetName()
+ if n and n:find('SwitchDropdown') then SkinWowStyleDropdown(n) end
+ end
+ end
+ end
+
+ if AtlasFrame then LayoutHeader(AtlasFrame) end
+ if AtlasFrameSmall then LayoutHeader(AtlasFrameSmall) end
+ end)
+
+ local function SkinBossButtons()
+ local function SkinSeries(prefix)
+ local i, btn = 1, _G[prefix..1]
+ while btn do
+ if not btn._asSkinned then btn._asSkinned = true; btn.isSkinned = nil; SkinNoGlowBtn(btn) end
+ i = i + 1; btn = _G[prefix..i]
+ end
+ end
+ SkinSeries('AtlasMapBossButton')
+ SkinSeries('AtlasMapBossButtonS')
+ end
+
+ if _G['Atlas_MapRefresh'] then
+ hooksecurefunc('Atlas_MapRefresh', function() C_Timer.After(0, SkinBossButtons) end)
+ end
end
-AS:RegisterSkin('Atlas')
+AS:RegisterSkin('Atlas', AS.Atlas)
\ No newline at end of file
diff --git a/AddOnSkins/Skins/AddOns/AtlasLoot.lua b/AddOnSkins/Skins/AddOns/AtlasLoot.lua
index 1b301ff7..3261038e 100644
--- a/AddOnSkins/Skins/AddOns/AtlasLoot.lua
+++ b/AddOnSkins/Skins/AddOns/AtlasLoot.lua
@@ -1,88 +1,695 @@
-local AS, L, S, R = unpack(AddOnSkins)
-
-function R:AtlasLoot(event, addon)
- S:HandleFrame(AtlasLootTooltip)
- AtlasLootTooltip:HookScript('OnShow', function(self)
- local Link = select(2, self:GetItem())
- local Quality = Link and select(3, GetItemInfo(Link))
- if (Quality and Quality >= 2) then
- R, G, B = GetItemQualityColor(Quality)
- self:SetBackdropBorderColor(R, G, B)
+-- AtlasLootClassic skin for AddOnSkins
+-- Targets the sliccer fork (AtlasLootClassic) used on TBC Anniversary servers.
+-- GUI frames and BiS footer are created lazily, so skinning is deferred and hooked.
+
+local AS = unpack(AddOnSkins)
+
+local skinned = false
+local footerSkinned = false
+
+
+-- Dark backdrop + accent border on hover; no gloss, no highlight texture.
+-- Mirrors ApplyButtonSkin in Atlas.lua for consistent button style.
+local function SkinNoGlowBtn(btn)
+ if not btn then return end
+ if btn.SetNormalTexture then btn:SetNormalTexture('') end
+ if btn.SetHighlightTexture then btn:SetHighlightTexture('') end
+ if btn.SetPushedTexture then btn:SetPushedTexture('') end
+ if btn.SetDisabledTexture then btn:SetDisabledTexture('') end
+ for i = 1, btn:GetNumRegions() do
+ local r = select(i, btn:GetRegions())
+ if r and r.IsObjectType and r:IsObjectType('Texture') then r:Hide() end
+ end
+ if not btn.SetBackdrop and BackdropTemplateMixin then Mixin(btn, BackdropTemplateMixin) end
+ AS.Skins:SetTemplate(btn, nil, false)
+ if not btn._alHoverHooked then
+ btn._alHoverHooked = true
+ btn:HookScript('OnEnter', AS.Skins.SetModifiedBackdrop)
+ btn:HookScript('OnLeave', AS.Skins.SetOriginalBackdrop)
+ end
+end
+
+local function SkinALDropDownPopup()
+ local i = 1
+ while true do
+ local f = _G['AtlasLoot-DropDown-CatFrame'..i]
+ if not f then break end
+ if f:IsShown() then
+ -- Re-apply template every open: SetBackdrop is C-func, can't be hooked.
+ -- Do NOT lock SetBackdropColor - categories use bgColor intentionally.
+ AS:SetTemplate(f)
+ if f.buttons then
+ for _, btn in ipairs(f.buttons) do
+ if not btn._asSkinned then
+ btn._asSkinned = true
+ btn:SetHighlightTexture(AS.NormTex or [[Interface\Buttons\UI-Listbox-Highlight]])
+ local hl = btn:GetHighlightTexture()
+ if hl then hl:SetVertexColor(unpack(AS.Color)); hl:SetAlpha(0.35) end
+ end
+ end
+ end
+ end
+ i = i + 1
+ end
+end
+
+local function SkinALDropDown(widget)
+ if not widget or not widget.frame then return end
+ local f = widget.frame
+ AS:StripTextures(f)
+ AS:SetTemplate(f)
+ if f.title then
+ f.title:ClearAllPoints()
+ f.title:SetPoint('BOTTOMLEFT', f, 'TOPLEFT', 0, 4)
+ end
+ -- Lock backdrop color - AtlasLoot resets it on every SetSelected.
+ -- Guard against recursion: hook calls SetBackdropColor which re-triggers hook.
+ local _lockingBG = false
+ hooksecurefunc(f, 'SetBackdropColor', function(self, r, g, b, a)
+ if _lockingBG then return end
+ local br, bg, bb, ba = unpack(AS.BackdropColor)
+ if r ~= br or g ~= bg or b ~= bb then
+ _lockingBG = true
+ self:SetBackdropColor(br, bg, bb, ba)
+ _lockingBG = false
+ end
+ end)
+
+ if f.button then
+ local btn = f.button
+ -- Hide original button state textures directly - SetNormalTexture('') does not
+ -- clear textures set via C-code on TBC client
+ for _, getter in ipairs({'GetNormalTexture','GetPushedTexture','GetHighlightTexture','GetDisabledTexture'}) do
+ local tex = btn[getter] and btn[getter](btn)
+ if tex then tex:SetTexture(nil) tex:Hide() end
+ end
+ for i = 1, btn:GetNumRegions() do
+ local r = select(i, btn:GetRegions())
+ if r and r.SetTexture then r:SetTexture(nil) r:Hide() end
+ end
+ -- Draw arrow as texture on main frame so hover logic mirrors Atlas dropdowns
+ local arrow = f:CreateTexture(nil, 'OVERLAY')
+ arrow:SetTexture([[Interface\AddOns\AddOnSkins\Media\Textures\Arrow]])
+ arrow:SetRotation(3.14)
+ arrow:SetVertexColor(1, 1, 1)
+ arrow:SetPoint('RIGHT', f, 'RIGHT', -4, 0)
+ arrow:SetSize(12, 12)
+ f._arrow = arrow
+ local function onEnter()
+ arrow:SetVertexColor(unpack(AS.Color))
+ f:SetBackdropBorderColor(unpack(AS.Color))
+ end
+ local function onLeave()
+ arrow:SetVertexColor(1, 1, 1)
+ f:SetBackdropBorderColor(unpack(AS.BorderColor))
+ end
+ f:HookScript('OnEnter', onEnter)
+ f:HookScript('OnLeave', onLeave)
+ -- btn sits on top of f and blocks its OnEnter - hook btn too
+ btn:HookScript('OnEnter', onEnter)
+ btn:HookScript('OnLeave', onLeave)
+ -- Skin popup on open (hook the main frame, not the inner btn)
+ f:HookScript('OnClick', function()
+ C_Timer.After(0, SkinALDropDownPopup)
+ end)
+ end
+end
+
+local selectBtnHooked = {}
+local function SkinALSelectBtn(btn)
+ if not btn or selectBtnHooked[btn] then return end
+ selectBtnHooked[btn] = true
+ -- Kill textures via alpha - hooks on Set* would affect other button types reusing same cache.
+ local hl = btn.GetHighlightTexture and btn:GetHighlightTexture()
+ if hl then hl:SetAlpha(0) end
+ local ct = btn.GetCheckedTexture and btn:GetCheckedTexture()
+ if ct then ct:SetAlpha(0) end
+ if btn.label then
+ btn.label:SetTextColor(1, 1, 1)
+ local function applyState()
+ if btn:GetChecked() then
+ btn.label:SetTextColor(unpack(AS.Color))
+ else
+ btn.label:SetTextColor(1, 1, 1)
+ end
+ end
+ btn:HookScript('OnEnter', function() btn.label:SetTextColor(unpack(AS.Color)) end)
+ btn:HookScript('OnLeave', function() applyState() end)
+ -- Use OnShow to catch state set by UpdateScroll when button is reused from cache.
+ btn:HookScript('OnShow', function() C_Timer.After(0, applyState) end)
+ end
+end
+
+local function SkinALSelect(widget)
+ if not widget or not widget.frame then return end
+ local f = widget.frame
+ AS:StripTextures(f)
+ AS:SetTemplate(f)
+ if f.scrollbar then AS:SkinScrollBar(f.scrollbar) end
+ -- Wrap OnEnterButton/OnLeaveButton on the widget object so SetScript can't kill our hook.
+ widget.OnEnterButton = function(btn)
+ if btn.label then btn.label:SetTextColor(unpack(AS.Color)) end
+ end
+ widget.OnLeaveButton = function(btn)
+ if btn.label then
+ if btn:GetChecked() then
+ btn.label:SetTextColor(unpack(AS.Color))
+ else
+ btn.label:SetTextColor(1, 1, 1)
+ end
+ end
+ end
+ -- Skin existing buttons and hook UpdateContent to catch future ones.
+ for _, btn in ipairs(widget.buttons or {}) do SkinALSelectBtn(btn) end
+ local origUpdate = widget.UpdateContent
+ widget.UpdateContent = function(self, ...)
+ origUpdate(self, ...)
+ for _, btn in ipairs(self.buttons or {}) do SkinALSelectBtn(btn) end
+ end
+end
+
+local function SkinCheckBoxElvUI(cb)
+ if not cb or cb._asSkinned then return end
+ cb._asSkinned = true -- own guard; do NOT set isSkinned here - AS:SkinCheckBox checks it
+ if cb.SetNormalTexture then cb:SetNormalTexture('') end
+ if cb.SetHighlightTexture then cb:SetHighlightTexture('') end
+ if cb.SetPushedTexture then cb:SetPushedTexture('') end
+ if cb.SetDisabledTexture then cb:SetDisabledTexture('') end
+ local function kill(tex)
+ if not tex then return end
+ if tex.SetTexture then tex:SetTexture(nil) end
+ if tex.SetAtlas then tex:SetAtlas('') end
+ tex:SetAlpha(0) tex:Hide()
+ end
+ kill(cb.GetNormalTexture and cb:GetNormalTexture())
+ kill(cb.GetHighlightTexture and cb:GetHighlightTexture())
+ kill(cb.GetPushedTexture and cb:GetPushedTexture())
+ for i = 1, cb:GetNumRegions() do
+ local r = select(i, cb:GetRegions())
+ if r then
+ if r.SetTexture then r:SetTexture(nil) end
+ if r.SetAtlas then r:SetAtlas('') end
+ end
+ end
+ if cb.SetBackdrop then cb:SetBackdrop(nil) end
+ AS:SkinCheckBox(cb)
+ local blankTex = (_G.ElvUI and _G.ElvUI[1].media.blankTex) or [[Interface\Buttons\WHITE8X8]]
+ cb:SetCheckedTexture(blankTex)
+ local ct = cb.GetCheckedTexture and cb:GetCheckedTexture()
+ if ct then
+ ct:SetVertexColor(unpack(AS.Color))
+ ct:SetAlpha(1)
+ if cb.Backdrop then AS:SetInside(ct, cb.Backdrop) end
+ end
+ if cb.Backdrop then
+ cb:HookScript('OnShow', function(f)
+ if f:GetChecked() then
+ f.Backdrop:SetBackdropBorderColor(unpack(AS.Color))
+ else
+ f.Backdrop:SetBackdropBorderColor(unpack(AS.BorderColor))
+ end
+ end)
+ hooksecurefunc(cb, 'SetChecked', function(f, checked)
+ if f.Backdrop then
+ if checked then
+ f.Backdrop:SetBackdropBorderColor(unpack(AS.Color))
+ else
+ f.Backdrop:SetBackdropBorderColor(unpack(AS.BorderColor))
+ end
+ end
+ end)
+ end
+end
+
+local function SkinCheckButtonsInFrame(parent)
+ if not parent then return end
+ -- footer -> centerGroup -> CheckButtons (two levels max)
+ for _, child in ipairs({parent:GetChildren()}) do
+ if child.GetObjectType and child:GetObjectType() == 'CheckButton' then
+ if child:GetScale() ~= 1 then child:SetScale(1) end
+ SkinCheckBoxElvUI(child)
else
- self:SetBackdropBorderColor(unpack(AS.BorderColor))
+ for _, grandchild in ipairs({child:GetChildren()}) do
+ if grandchild.GetObjectType and grandchild:GetObjectType() == 'CheckButton' then
+ if grandchild:GetScale() ~= 1 then grandchild:SetScale(1) end
+ SkinCheckBoxElvUI(grandchild)
+ end
+ end
end
- self:SetBackdropColor(unpack(AS.BackdropColor))
- if _G["AtlasLoot-MountToolTip"] then
- S:HandleFrame(_G["AtlasLoot-MountToolTip"], nil, true)
- S:HandleIcon(_G["AtlasLoot-MountToolTip"].icon)
- _G["AtlasLoot-MountToolTip"]:SetBackdropBorderColor(self:GetBackdropBorderColor())
+ end
+end
+
+local function SkinFooter()
+ if footerSkinned then return end
+ local footer = _G['AtlasLoot_BiS_Footer']
+ if not footer then return end
+ footerSkinned = true
+ AS:StripTextures(footer)
+ AS:CreateBackdrop(footer)
+ -- Footer sits flush under the main frame; suppress the top border so it
+ -- doesn't double up with the main frame's bottom border.
+ if footer.Backdrop then
+ footer.Backdrop:SetBackdropBorderColor(0, 0, 0, 0)
+ end
+ SkinCheckButtonsInFrame(footer)
+
+ -- centerGroup is 44px tall designed for scale(1.5) children inside a 24px footer.
+ -- After resetting child scale to 1, expand footer and re-center the group.
+ footer:SetHeight(60)
+ local cg = ({footer:GetChildren()})[1]
+ if cg and cg:GetNumPoints() > 0 then
+ local _, rel = cg:GetPoint()
+ cg:SetHeight(44)
+ cg:ClearAllPoints()
+ cg:SetPoint('CENTER', rel or footer, 'CENTER', 0, 0)
+ end
+ -- Move footer 1px below main frame so its top border sits just under the main frame's border.
+ local parentFrame = _G['AtlasLoot_GUI-Frame']
+ if parentFrame then
+ footer:ClearAllPoints()
+ footer:SetPoint('TOPLEFT', parentFrame, 'BOTTOMLEFT', 0, -1)
+ footer:SetPoint('TOPRIGHT', parentFrame, 'BOTTOMRIGHT', 0, -1)
+ end
+end
+
+-- Skin the class filter selection popup (created on first right-click)
+local function SkinClassFilterPopup(clasFilterButton)
+ if not clasFilterButton then return end
+ local origOnClick = clasFilterButton:GetScript('OnClick')
+ if not origOnClick then return end
+ clasFilterButton:HookScript('OnClick', function(self, mouseButton)
+ if mouseButton ~= 'RightButton' then return end
+ local sf = self.selectionFrame
+ if not sf or sf._asSkinned then return end
+ sf._asSkinned = true
+ AS:StripTextures(sf)
+ AS:SetTemplate(sf)
+ if sf.buttons then
+ for _, btn in ipairs(sf.buttons) do
+ AS:StripTextures(btn)
+ AS:SetTemplate(btn)
+ if btn.icon then AS:SkinTexture(btn.icon) end
+ btn:SetHighlightTexture(AS.NormTex or [[Interface\Buttons\UI-Listbox-Highlight]])
+ local hl = btn:GetHighlightTexture()
+ if hl then
+ hl:SetVertexColor(unpack(AS.Color))
+ hl:SetAlpha(0.35)
+ end
+ end
end
- if _G["AtlasLoot-PetToolTip"] then
- S:HandleFrame(_G["AtlasLoot-PetToolTip"], nil, true)
- S:HandleIcon(_G["AtlasLoot-PetToolTip"].icon)
- _G["AtlasLoot-PetToolTip"]:SetBackdropBorderColor(self:GetBackdropBorderColor())
+ end)
+end
+
+-- Skin the game version selection popup (created on first click)
+local function SkinGameVersionPopup(gvButton)
+ if not gvButton then return end
+ gvButton:HookScript('OnClick', function(self)
+ local sf = self.selectionFrame
+ if not sf or sf._asSkinned then return end
+ sf._asSkinned = true
+ AS:StripTextures(sf)
+ AS:SetTemplate(sf)
+ for _, btn in ipairs(sf.buttons or {}) do
+ local hl = btn.GetHighlightTexture and btn:GetHighlightTexture()
+ if hl then hl:SetAlpha(0) end
+ AS:CreateBackdrop(btn)
+ local bd = btn.backdrop or btn.Backdrop
+ if bd then
+ btn:HookScript('OnEnter', function(self)
+ local b = self.backdrop or self.Backdrop
+ if b then b:SetBackdropBorderColor(unpack(AS.Color)) end
+ end)
+ btn:HookScript('OnLeave', function(self)
+ local b = self.backdrop or self.Backdrop
+ if b then b:SetBackdropBorderColor(unpack(AS.BorderColor)) end
+ end)
+ end
+ if btn.texture then
+ AS:SkinTexture(btn.texture)
+ AS:SetInside(btn.texture, btn.backdrop or btn.Backdrop or btn)
+ end
end
- if _G["AtlasLoot-FactionToolTip"] then
- S:HandleFrame(_G["AtlasLoot-FactionToolTip"], nil, true)
- S:HandleIcon(_G["AtlasLoot-FactionToolTip"].icon)
- _G["AtlasLoot-FactionToolTip"]:SetBackdropBorderColor(self:GetBackdropBorderColor())
+ end)
+end
+
+local function SkinAtlasLoot()
+ if skinned then return end
+ local ALFrame = _G['AtlasLoot_GUI-Frame']
+ if not ALFrame then return end
+ skinned = true
+
+ local AL = AtlasLoot
+ local GUI = AL and AL.GUI
+
+ -- contentFrame is 510px tall anchored at -70 from top = 580px used; frame is 600px → 20px gap at bottom.
+ ALFrame:SetHeight(ALFrame:GetHeight() - 16)
+ AS:SkinFrame(ALFrame)
+ if ALFrame.titleFrame then
+ AS:StripTextures(ALFrame.titleFrame)
+ if ALFrame.titleFrame.SetBackdrop then ALFrame.titleFrame:SetBackdrop(nil) end
+ -- Tighten titleFrame: remove top gap, reduce height to match Atlas titlebar.
+ ALFrame.titleFrame:ClearAllPoints()
+ ALFrame.titleFrame:SetPoint('TOPLEFT', ALFrame, 'TOPLEFT', 10, -2)
+ ALFrame.titleFrame:SetPoint('TOPRIGHT', ALFrame, 'TOPRIGHT', -30, -2)
+ ALFrame.titleFrame:SetHeight(18)
+ -- Match Atlas title style: same font object as PortraitFrameTemplate TitleText.
+ if ALFrame.titleFrame.text then
+ local ref = AtlasFrame and AtlasFrame.TitleText
+ if ref then
+ local font, size, flags = ref:GetFont()
+ if font then ALFrame.titleFrame.text:SetFont(font, size, flags) end
+ local r, g, b, a = ref:GetTextColor()
+ ALFrame.titleFrame.text:SetTextColor(r, g, b, a)
+ else
+ ALFrame.titleFrame.text:SetFontObject(GameFontNormal)
+ end
+ end
+ if ALFrame.titleFrame.version then
+ local ver = ALFrame.titleFrame.version
+ ver:ClearAllPoints()
+ ver:SetPoint('LEFT', ALFrame.titleFrame, 'LEFT', 8, 0)
+ ver:SetJustifyH('LEFT')
+ end
+ end
+ local closeBtn = _G['AtlasLoot_GUI-Frame-CloseButton']
+ if closeBtn then
+ AS:SkinCloseButton(closeBtn)
+ closeBtn:SetSize(32, 32)
+ end
+ if ALFrame.titleFrame and ALFrame.titleFrame.infoButton then
+ local ib = ALFrame.titleFrame.infoButton
+ if ib.SetHighlightTexture then ib:SetHighlightTexture('') end
+ if ib.SetPushedTexture then ib:SetPushedTexture('') end
+ if ib.SetDisabledTexture then ib:SetDisabledTexture('') end
+ local ht = ib.GetHighlightTexture and ib:GetHighlightTexture()
+ if ht then ht:SetTexture(nil); ht:Hide() end
+
+ ib:SetSize(16, 16)
+ -- Texture is anchored TOPLEFT in XML, not SetAllPoints — fix after resize.
+ local ibtex = ib.texture
+ if ibtex then
+ ibtex:SetAllPoints(ib)
+ -- Block OnMouseDown offset script.
+ ib:HookScript('OnMouseDown', function() ibtex:SetAllPoints(ib) end)
+ ib:HookScript('OnMouseUp', function() ibtex:SetAllPoints(ib) end)
+ end
+ do
+ local bd = CreateFrame('Frame', nil, ib, BackdropTemplateMixin and 'BackdropTemplate' or nil)
+ bd:SetAllPoints(ib)
+ bd:SetFrameLevel(max(0, ib:GetFrameLevel() - 1))
+ AS.Skins:SetTemplate(bd, nil, false)
+ bd:SetBackdropColor(0, 0, 0, 0)
+ bd:SetBackdropBorderColor(0, 0, 0, 0)
+ ib:HookScript('OnEnter', function() bd:SetBackdropBorderColor(unpack(AS.Color)) end)
+ ib:HookScript('OnLeave', function() bd:SetBackdropBorderColor(0, 0, 0, 0) end)
+ end
+ end
+ C_Timer.After(0, function()
+ local tf = ALFrame.titleFrame
+ if not tf then return end
+ local tCentreY = tf:GetTop() - tf:GetHeight() / 2
+ local function yOff(btn)
+ return tCentreY - ALFrame:GetTop() + btn:GetHeight() / 2
+ end
+ if closeBtn then
+ closeBtn:ClearAllPoints()
+ closeBtn:SetPoint('RIGHT', ALFrame, 'RIGHT', 0, 0)
+ closeBtn:SetPoint('TOP', ALFrame, 'TOP', 0, yOff(closeBtn))
+ end
+ local ib = tf.infoButton
+ if ib and closeBtn then
+ ib:ClearAllPoints()
+ ib:SetPoint('CENTER', closeBtn, 'CENTER', -(closeBtn:GetWidth()/2 + 2 + ib:GetWidth()/2), 0)
end
end)
+ if GUI and GUI.frame then
+ SkinALDropDown(GUI.frame.moduleSelect)
+ SkinALDropDown(GUI.frame.subCatSelect)
+ SkinALSelect(GUI.frame.difficulty)
+ SkinALSelect(GUI.frame.boss)
+ SkinALSelect(GUI.frame.extra)
+
+ -- Game version button
+ local gvBtn = GUI.frame.gameVersionButton
+ if gvBtn then
+ if gvBtn.Box then
+ for _, line in ipairs(gvBtn.Box) do line:Hide() end
+ end
+ local gvHl = gvBtn.GetHighlightTexture and gvBtn:GetHighlightTexture()
+ if gvHl then gvHl:SetAlpha(0) end
+ AS:CreateBackdrop(gvBtn)
+ gvBtn:HookScript('OnEnter', function(self)
+ local bd = self.backdrop or self.Backdrop
+ if bd and bd.SetBackdropBorderColor then bd:SetBackdropBorderColor(unpack(AS.Color)) end
+ end)
+ gvBtn:HookScript('OnLeave', function(self)
+ local bd = self.backdrop or self.Backdrop
+ if bd and bd.SetBackdropBorderColor then bd:SetBackdropBorderColor(unpack(AS.BorderColor)) end
+ end)
+ local tex = gvBtn.texture or GUI.frame.gameVersionLogo
+ if tex then AS:SetInside(tex, gvBtn.Backdrop or gvBtn) end
+ SkinGameVersionPopup(gvBtn)
+ end
+ end
- local AtlasLootFrame = _G["AtlasLoot_GUI-Frame"]
- S:HandleFrame(AtlasLootFrame)
- S:HandleCloseButton(AtlasLootFrame.CloseButton)
- S:StripTextures(AtlasLootFrame.titleFrame)
-
- local function SkinDropDown(Frame)
- S:HandleFrame(_G[Frame])
- S:HandleNextPrevButton(_G[Frame..'-button'])
- local a, b, c, d, e = _G[Frame..'-button']:GetPoint()
- _G[Frame..'-button']:SetPoint(a, b, c, d - 4, 0)
- _G[Frame]:HookScript('OnUpdate', function(self)
- for i = 1, 3 do
- local CatFrame = _G['AtlasLoot-DropDown-CatFrame'..i]
- if CatFrame and not CatFrame.IsSkinned then
- local r, g, b = CatFrame:GetBackdropColor()
- S:HandleFrame(CatFrame)
- CatFrame:SetBackdropColor(r, g, b)
-
- CatFrame:HookScript('OnShow', function(self)
- local a, f, c, d, e = self:GetPoint()
- self:SetPoint(a, f, c, d, e - 3)
- end)
-
- CatFrame:GetScript('OnShow')(CatFrame)
- CatFrame.IsSkinned = true
+ local contentFrame = _G['AtlasLoot_GUI-ItemFrame']
+ if contentFrame then
+ AS:CreateBackdrop(contentFrame)
+
+ -- Hide the AtlasLoot background textures; the backdrop replaces them.
+ -- Also hook SetAlpha/SetColorTexture to prevent RefreshContentBackGround from restoring them.
+ for _, key in ipairs({'topBG', 'downBG', 'itemBG'}) do
+ local tex = contentFrame[key]
+ if tex then
+ tex:SetAlpha(0)
+ tex:Hide()
+ hooksecurefunc(tex, 'SetAlpha', function(self) if self:GetAlpha() > 0 then self:Hide() end end)
+ hooksecurefunc(tex, 'SetColorTexture', function(self) self:Hide() end)
+ end
+ end
+
+ -- Unified button height for the bottom bar.
+ -- Text buttons: 22px. Icon buttons: 20px (CreateBackdrop adds 1px border each side).
+ local BTN_H = 22
+ local ICON_H = 20
+
+ local function SkinPageBtn(btn, dir)
+ if not btn then return end
+ AS:SkinArrowButton(btn, dir)
+ btn:SetSize(BTN_H, BTN_H)
+ btn._navHovered = false
+ local function applyTint()
+ if not btn._navHovered then return end
+ local t = btn:GetNormalTexture()
+ if t then t:SetVertexColor(unpack(AS.Color)) end
+ if btn.SetBackdropBorderColor then btn:SetBackdropBorderColor(unpack(AS.Color)) end
+ end
+ btn:HookScript('OnEnter', function(self) self._navHovered = true; applyTint() end)
+ btn:HookScript('OnLeave', function(self)
+ self._navHovered = false
+ local t = self:GetNormalTexture()
+ if t then t:SetVertexColor(1, 1, 1) end
+ if self.SetBackdropBorderColor then self:SetBackdropBorderColor(unpack(AS.BorderColor)) end
+ end)
+ hooksecurefunc(btn, 'SetNormalTexture', function() applyTint() end)
+ end
+ SkinPageBtn(contentFrame.prevPageButton, 'left')
+ SkinPageBtn(contentFrame.nextPageButton, 'right')
+ if contentFrame.itemsButton then SkinNoGlowBtn(contentFrame.itemsButton); contentFrame.itemsButton:SetHeight(BTN_H) end
+ if contentFrame.modelButton then SkinNoGlowBtn(contentFrame.modelButton); contentFrame.modelButton:SetHeight(BTN_H) end
+ if contentFrame.soundsButton then SkinNoGlowBtn(contentFrame.soundsButton); contentFrame.soundsButton:SetHeight(BTN_H) end
+
+ -- Icon buttons: ICON_H size, backdrop with border hover, skinned texture.
+ local function SkinIconBtn(btn, popupFn)
+ if not btn then return end
+ btn:SetSize(ICON_H, ICON_H)
+ local hl = btn.GetHighlightTexture and btn:GetHighlightTexture()
+ if hl then hl:SetAlpha(0) end
+ AS:CreateBackdrop(btn)
+ local function hoverEnter(self)
+ local bd = self.backdrop or self.Backdrop
+ if bd then bd:SetBackdropBorderColor(unpack(AS.Color)) end
+ end
+ local function hoverLeave(self)
+ local bd = self.backdrop or self.Backdrop
+ if bd then bd:SetBackdropBorderColor(unpack(AS.BorderColor)) end
+ end
+ btn:HookScript('OnEnter', hoverEnter)
+ btn:HookScript('OnLeave', hoverLeave)
+ if btn.texture then
+ AS:SkinTexture(btn.texture)
+ AS:SetInside(btn.texture, btn.backdrop or btn.Backdrop or btn)
+ end
+ if popupFn then popupFn(btn) end
+ end
+ SkinIconBtn(contentFrame.clasFilterButton, SkinClassFilterPopup)
+ SkinIconBtn(contentFrame.contentPhaseButton)
+
+ if contentFrame.mapButton then
+ local mb = contentFrame.mapButton
+ SkinIconBtn(mb)
+ if mb.highlight then mb.highlight:Hide() end
+ local tex = mb.texture
+ if tex then
+ tex:ClearAllPoints()
+ local bd = mb.backdrop or mb.Backdrop
+ tex:SetAllPoints(bd or mb)
+ AS:SkinTexture(tex)
+ local function fixTexCoord(self)
+ tex:SetTexCoord(0.125, 0.875, 0.0, 0.5)
+ local b = self.backdrop or self.Backdrop
+ tex:SetAllPoints(b or self)
end
+ mb:HookScript('OnShow', fixTexCoord)
+ mb:HookScript('OnMouseUp', fixTexCoord)
+ fixTexCoord(mb)
+ end
+ -- Add gap between mapButton and modelButton (natively 0px).
+ if contentFrame.modelButton then
+ contentFrame.modelButton:ClearAllPoints()
+ contentFrame.modelButton:SetPoint('RIGHT', mb, 'LEFT', -4, 0)
end
+ end
+
+ if contentFrame.searchBox then
+ AS:SkinEditBox(contentFrame.searchBox)
+ contentFrame.searchBox:SetHeight(20)
+ contentFrame.searchBox:SetWidth(160)
+ end
+ end
+
+ if GUI and GUI.Create then
+ hooksecurefunc(GUI, 'Create', function()
+ C_Timer.After(0, SkinFooter)
end)
end
- SkinDropDown('AtlasLoot-DropDown-1')
- SkinDropDown('AtlasLoot-DropDown-2')
+ SkinFooter()
+end
+
+function AS:AtlasLoot(event, addon)
+ local loaded = (C_AddOns and C_AddOns.IsAddOnLoaded and C_AddOns.IsAddOnLoaded('AtlasLootClassic'))
+ or (_G.IsAddOnLoaded and _G.IsAddOnLoaded('AtlasLootClassic'))
+ if not loaded then return end
- for i = 1, 3 do
- S:HandleFrame(_G['AtlasLoot-Select-'..i])
+ C_Timer.After(0, function()
+ SkinAtlasLoot()
+
+ if not skinned and AtlasLoot and AtlasLoot.GUI and AtlasLoot.GUI.Toggle then
+ hooksecurefunc(AtlasLoot.GUI, 'Toggle', function()
+ SkinAtlasLoot()
+ C_Timer.After(0, SkinFooter)
+ end)
+ end
+ end)
+end
+
+AS:RegisterSkin('AtlasLootClassic', AS.AtlasLoot)
+
+-- -----------------------------------------------------------------------
+-- Atlas integration: "AtlasLoot" button next to AtlasQuest
+-- -----------------------------------------------------------------------
+local alAtlasBtn
+
+local function OpenAtlasLootForCurrentMap()
+ if not AtlasLoot or not AtlasLoot.GUI then return end
+ local atlas = Atlas
+ if not atlas or not atlas.db then return end
+
+ -- Get current zoneID from Atlas dropdown selection.
+ local profile = atlas.db.profile
+ local mod = profile.options.dropdowns.module
+ local zone = profile.options.dropdowns.zone
+ local zoneID = ATLAS_DROPDOWNS and ATLAS_DROPDOWNS[mod] and ATLAS_DROPDOWNS[mod][zone]
+ if not zoneID then return end
+
+ -- Search all AtlasLoot modules for a record whose AtlasMapFile contains zoneID.
+ local foundModule, foundDataID
+ for modName, modData in pairs(AtlasLoot.ItemDB.Storage or {}) do
+ if type(modData) == 'table' then
+ for dataID, entry in pairs(modData) do
+ if type(entry) == 'table' and entry.AtlasMapFile then
+ local files = entry.AtlasMapFile
+ if type(files) == 'string' then files = {files} end
+ for _, f in ipairs(files) do
+ if f == zoneID then
+ foundModule = modName
+ foundDataID = dataID
+ break
+ end
+ end
+ end
+ if foundDataID then break end
+ end
+ end
+ if foundDataID then break end
end
- local AtlasLootItemFrame = _G["AtlasLoot_GUI-ItemFrame"]
- S:CreateBackdrop(AtlasLootItemFrame)
- S:HandleNextPrevButton(AtlasLootItemFrame.nextPageButton)
- S:HandleButton(AtlasLootItemFrame.modelButton)
- S:HandleButton(AtlasLootItemFrame.soundsButton)
- S:HandleNextPrevButton(AtlasLootItemFrame.prevPageButton)
- S:HandleButton(AtlasLootItemFrame.itemsButton)
- S:HandleButton(AtlasLootItemFrame.clasFilterButton)
- S:SetInside(AtlasLootItemFrame.clasFilterButton.texture)
- AtlasLootItemFrame.clasFilterButton:HookScript('OnUpdate', function(self)
- if self.texture:GetTexture() == "Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes" then
- self.texture:SetTexCoord(CLASS_ICON_TCOORDS[AS.MyClass][1] + 0.015, CLASS_ICON_TCOORDS[AS.MyClass][2] - 0.02, CLASS_ICON_TCOORDS[AS.MyClass][3] + 0.018, CLASS_ICON_TCOORDS[AS.MyClass][4] - .02)
- else
- S:HandleIcon(self.texture)
+ local db = AtlasLoot.db.GUI
+ if not AtlasLoot.GUI.frame:IsVisible() then
+ AtlasLoot.GUI.frame:Show()
+ end
+
+ if foundModule and foundDataID then
+ if foundModule ~= db.selected[1] then
+ AtlasLoot.GUI.frame.moduleSelect:SetSelected(foundModule)
+ end
+ if foundDataID ~= db.selected[2] then
+ AtlasLoot.GUI.frame.subCatSelect:SetSelected(foundDataID)
end
+ AtlasLoot.GUI.ItemFrame:Refresh(true)
+ end
+end
+
+local function CreateAtlasLootAtlasButton()
+ if alAtlasBtn then return end
+ local atlas = _G['AtlasFrame']
+ if not atlas then return end
+ local aqBtn = _G['AQ_AtlasToggle']
+ if not aqBtn then return end
+
+ alAtlasBtn = CreateFrame('Button', 'AS_AtlasLootButton', atlas)
+ alAtlasBtn:SetSize(90, 20)
+ alAtlasBtn:SetPoint('LEFT', aqBtn, 'RIGHT', 4, 0)
+ alAtlasBtn:SetPoint('TOP', aqBtn, 'TOP', 0, 0)
+
+ -- FontString (same style as AQ_AtlasToggle which uses UIPanelButtonTemplate)
+ local fs = alAtlasBtn:CreateFontString(nil, 'OVERLAY', 'GameFontNormal')
+ fs:SetAllPoints(alAtlasBtn)
+ fs:SetText('AtlasLoot')
+
+ -- Backdrop as child at frameLevel 0 — draws behind FontString, same as AQ pattern.
+ local bd = CreateFrame('Frame', nil, alAtlasBtn, 'BackdropTemplate')
+ bd:SetAllPoints(alAtlasBtn)
+ bd:SetFrameLevel(0)
+ AS.Skins:SetTemplate(bd, nil, false)
+
+ -- Normal text color from GameFontNormal (ElvUI sets this to orange).
+ local nr, ng, nb = GameFontNormal:GetTextColor()
+ fs:SetTextColor(nr, ng, nb)
+ alAtlasBtn:HookScript('OnEnter', function()
+ bd:SetBackdropBorderColor(unpack(AS.Color))
+ fs:SetTextColor(1, 1, 1)
+ end)
+ alAtlasBtn:HookScript('OnLeave', function()
+ bd:SetBackdropBorderColor(unpack(AS.BorderColor))
+ fs:SetTextColor(nr, ng, nb)
end)
+ alAtlasBtn:SetScript('OnClick', OpenAtlasLootForCurrentMap)
end
-AS:RegisterSkin('AtlasLoot')
+-- Register hook: create button once both Atlas and AtlasLootClassic are loaded.
+local alAtlasFrame = CreateFrame('Frame')
+alAtlasFrame:RegisterEvent('ADDON_LOADED')
+alAtlasFrame:SetScript('OnEvent', function(self, event, name)
+ if name == 'AtlasLootClassic' or name == 'Atlas' or name == 'AtlasQuest' then
+ local atlasLoaded = (C_AddOns and C_AddOns.IsAddOnLoaded or IsAddOnLoaded)('Atlas')
+ local alLoaded = (C_AddOns and C_AddOns.IsAddOnLoaded or IsAddOnLoaded)('AtlasLootClassic')
+ if atlasLoaded and alLoaded then
+ -- Defer until AQ_AtlasToggle exists (AtlasQuest may load slightly later).
+ C_Timer.After(2, CreateAtlasLootAtlasButton)
+ self:UnregisterEvent('ADDON_LOADED')
+ end
+ end
+end)
\ No newline at end of file
diff --git a/AddOnSkins/Skins/AddOns/AtlasQuest.lua b/AddOnSkins/Skins/AddOns/AtlasQuest.lua
new file mode 100644
index 00000000..ad76d599
--- /dev/null
+++ b/AddOnSkins/Skins/AddOns/AtlasQuest.lua
@@ -0,0 +1,198 @@
+-- AtlasQuest skin for AddOnSkins
+-- AtlasQuestFrame inherits BackdropTemplate and is a child of AtlasFrame.
+-- AtlasQuestInsideFrame overlays the map area with quest details.
+
+local AS = unpack(AddOnSkins)
+
+local function Safe(func, name)
+ local f = type(name) == "string" and _G[name] or name
+ if f then func(AS, f) end
+end
+
+-- Clears all button-state textures including Atlas variants used by the retail engine,
+-- then delegates to AS:SkinCheckBox for the inset child backdrop.
+local function SkinCheckBox(cb)
+ if not cb or cb._asSkinned then return end
+ cb._asSkinned = true
+
+ if cb.SetNormalTexture then cb:SetNormalTexture('') end
+ if cb.SetHighlightTexture then cb:SetHighlightTexture('') end
+ if cb.SetPushedTexture then cb:SetPushedTexture('') end
+ if cb.SetDisabledTexture then cb:SetDisabledTexture('') end
+
+ local function kill(tex)
+ if not tex then return end
+ if tex.SetTexture then tex:SetTexture(nil) end
+ if tex.SetAtlas then tex:SetAtlas('') end
+ tex:SetAlpha(0) tex:Hide()
+ end
+ kill(cb.GetNormalTexture and cb:GetNormalTexture())
+ kill(cb.GetHighlightTexture and cb:GetHighlightTexture())
+ kill(cb.GetPushedTexture and cb:GetPushedTexture())
+
+ -- Do NOT SetAlpha(0) on GetRegions() results - CheckedTexture lives there on the retail
+ -- engine and zeroing its alpha persists after AS:SkinCheckBox restores the texture path.
+ for i = 1, cb:GetNumRegions() do
+ local r = select(i, cb:GetRegions())
+ if r then
+ if r.SetTexture then r:SetTexture(nil) end
+ if r.SetAtlas then r:SetAtlas('') end
+ end
+ end
+
+ if cb.SetBackdrop then cb:SetBackdrop(nil) end
+
+ AS:SkinCheckBox(cb)
+
+ local blankTex = (_G.ElvUI and _G.ElvUI[1].media.blankTex) or [[Interface\Buttons\WHITE8X8]]
+ cb:SetCheckedTexture(blankTex)
+ local ct = cb.GetCheckedTexture and cb:GetCheckedTexture()
+ if ct then
+ ct:SetVertexColor(unpack(AS.Color))
+ ct:SetAlpha(1)
+ if cb.Backdrop then AS:SetInside(ct, cb.Backdrop) end
+ end
+ if cb.Backdrop then
+ cb:HookScript('OnShow', function(f)
+ if f:GetChecked() then
+ f.Backdrop:SetBackdropBorderColor(unpack(AS.Color))
+ else
+ f.Backdrop:SetBackdropBorderColor(unpack(AS.BorderColor))
+ end
+ end)
+ hooksecurefunc(cb, 'SetChecked', function(f, checked)
+ if f.Backdrop then
+ if checked then
+ f.Backdrop:SetBackdropBorderColor(unpack(AS.Color))
+ else
+ f.Backdrop:SetBackdropBorderColor(unpack(AS.BorderColor))
+ end
+ end
+ end)
+ end
+end
+
+local function SkinQuestItemFrames()
+ for i = 1, 6 do
+ local item = _G['AQ_QuestItem_'..i]
+ if not item or item._asSkinned then break end
+ item._asSkinned = true
+
+ if item.icon then
+ AS:SkinTexture(item.icon)
+ item.icon:SetSize(24, 24)
+ local iconBD = CreateFrame('Frame', nil, item)
+ iconBD:SetPoint('TOPLEFT', item.icon, -1, 1)
+ iconBD:SetPoint('BOTTOMRIGHT', item.icon, 1, -1)
+ AS:SetTemplate(iconBD)
+ iconBD:SetFrameLevel(item:GetFrameLevel() - 1)
+ item._iconBD = iconBD -- store ref for qualityBorder hook
+ end
+
+ if item.qualityBorder then
+ item.qualityBorder:SetTexture(nil)
+ hooksecurefunc(item.qualityBorder, 'SetVertexColor', function(self, r, g, b)
+ local bd = item._iconBD
+ if bd and bd.SetBackdropBorderColor then
+ bd:SetBackdropBorderColor(r, g, b)
+ end
+ end)
+ end
+ end
+end
+
+local function SkinQuestListButtons()
+ for i = 1, 23 do
+ local btn = _G['AQButton_'..i]
+ if not btn or btn._asSkinned then break end
+ btn._asSkinned = true
+
+ btn:SetHighlightTexture(AS.NormTex or [[Interface\Buttons\UI-Listbox-Highlight]])
+ local hl = btn:GetHighlightTexture()
+ if hl then
+ hl:SetVertexColor(unpack(AS.Color))
+ hl:SetAlpha(0.35)
+ end
+ end
+end
+
+function AS:AtlasQuest(event, addon)
+ local loaded = (C_AddOns and C_AddOns.IsAddOnLoaded and C_AddOns.IsAddOnLoaded('AtlasQuest'))
+ or (_G.IsAddOnLoaded and _G.IsAddOnLoaded('AtlasQuest'))
+ if not loaded then return end
+
+ Safe(AS.SkinFrame, 'AtlasQuestFrame')
+ local aqFrame = _G['AtlasQuestFrame']
+ local atlasFrame = _G['AtlasFrame']
+ if aqFrame and atlasFrame then
+ local function SyncAQ()
+ local h = atlasFrame:GetHeight()
+ if h and h > 0 then aqFrame:SetHeight(h) end
+ -- Re-anchor to centre of Atlas left/right edge instead of corner
+ local side = _G.AtlasQuest and _G.AtlasQuest.db
+ and _G.AtlasQuest.db.profile.shownSide
+ aqFrame:ClearAllPoints()
+ if side == 'right' then
+ aqFrame:SetPoint('LEFT', atlasFrame, 'RIGHT', -2, 0)
+ else
+ aqFrame:SetPoint('RIGHT', atlasFrame, 'LEFT', 0, 0)
+ end
+ end
+ -- Override AQ's own positioning
+ hooksecurefunc(_G.AtlasQuestFrame, 'SetPoint', function(self)
+ if not self._aqSkinLocked then
+ self._aqSkinLocked = true
+ SyncAQ()
+ self._aqSkinLocked = false
+ end
+ end)
+ atlasFrame:HookScript('OnShow', SyncAQ)
+ atlasFrame:HookScript('OnSizeChanged', SyncAQ)
+ aqFrame:HookScript('OnShow', SyncAQ)
+ C_Timer.After(0.3, SyncAQ)
+ end
+ Safe(AS.SkinCloseButton, 'AQ_SidebarClose')
+ local aqOpts = _G['AQ_OptionsButton']
+ if aqOpts and aqFrame and atlasFrame then
+ -- Atlas is a hard dependency of AtlasQuest, so ApplyAtlasButtonSkin is available.
+ if AS.ApplyAtlasButtonSkin then
+ AS.ApplyAtlasButtonSkin(aqOpts, false)
+ end
+ -- Resize to match Entrance button, position centred in bottom strip
+ aqOpts:SetSize(100, 24)
+ local function PlaceAQOpts()
+ -- Use same strip geometry as Entrance: from mapFrame bottom to atlasFrame bottom
+ local mf = _G['AtlasFrameMapFrame']
+ local mfBot = mf and mf:GetBottom()
+ local afBot = atlasFrame:GetBottom()
+ if not mfBot or not afBot then return end
+ local stripH = mfBot - afBot
+ aqOpts:ClearAllPoints()
+ aqOpts:SetPoint('CENTER', aqFrame, 'BOTTOM', 0, stripH / 2)
+ end
+ aqFrame:HookScript('OnShow', PlaceAQOpts)
+ C_Timer.After(0.4, PlaceAQOpts)
+ end
+
+ SkinCheckBox(_G['AQ_AllianceCheck'])
+ SkinCheckBox(_G['AQ_HordeCheck'])
+
+ local insideFrame = _G['AtlasQuestInsideFrame']
+ if insideFrame then
+ AS:StripTextures(insideFrame)
+ AS:SetTemplate(insideFrame)
+ end
+
+ Safe(AS.SkinCloseButton, 'AQ_QuestClose')
+ SkinCheckBox(_G['AQ_FinishedQuestCheck'])
+ -- AQ_AtlasToggle is positioned and skinned by the Atlas skin into the header row.
+ -- Skinning it here again would conflict; skip it.
+
+ -- Quest list buttons and item frames are created in OnEnable, defer skinning
+ C_Timer.After(0.1, function()
+ SkinQuestListButtons()
+ SkinQuestItemFrames()
+ end)
+end
+
+AS:RegisterSkin('AtlasQuest', AS.AtlasQuest)
diff --git a/AddOnSkins/Skins/AddOns/ItemRack.lua b/AddOnSkins/Skins/AddOns/ItemRack.lua
index 720f58fc..aa1679b5 100644
--- a/AddOnSkins/Skins/AddOns/ItemRack.lua
+++ b/AddOnSkins/Skins/AddOns/ItemRack.lua
@@ -1,23 +1,52 @@
local AS, L, S, R = unpack(AddOnSkins)
function R:ItemRack()
- local function SkinButton(idx,itemID)
- if _G["ItemRackMenu"..idx] then
- S:HandleItemButton(_G["ItemRackMenu"..idx])
+ -- ItemRack buttons inherit ActionButtonTemplate. The icon texture is
+ -- $parentIcon (e.g. ItemRackButton0Icon / ItemRackMenu1Icon).
+ -- HandleItemButton calls StripTextures on the whole button which wipes
+ -- the icon before ItemRack has had a chance to set it, and the saved
+ -- texture is nil at hook time. Use a targeted skin instead: backdrop +
+ -- StyleButton only, then locate the icon and hook SetTexture so it
+ -- stays visible after ItemRack updates it.
+ local function SkinRackButton(button)
+ if not button or button._irSkinned then return end
+ button._irSkinned = true
+
+ local name = button:GetName()
+ local icon = name and _G[name .. 'Icon']
+
+ -- Strip only the non-icon regions (border, gloss, etc.).
+ for _, region in next, { button:GetRegions() } do
+ if region and region ~= icon and region.IsObjectType and region:IsObjectType('Texture') then
+ region:SetTexture('')
+ end
+ end
+
+ S:CreateBackdrop(button, nil, true, nil, nil, nil, nil, nil, true)
+ S:StyleButton(button)
+
+ if icon then
+ S:HandleIcon(icon)
+ S:SetInside(icon, button)
+ icon:SetParent(button.backdrop or button)
end
end
- local function SkinButton2()
- for i=0,20 do
- if _G["ItemRackButton"..i] then
- S:HandleItemButton(_G["ItemRackButton"..i])
- end
+
+ local function SkinMenuButton(idx)
+ SkinRackButton(_G['ItemRackMenu' .. idx])
+ end
+
+ local function SkinAllMainButtons()
+ for i = 0, 20 do
+ SkinRackButton(_G['ItemRackButton' .. i])
end
end
- hooksecurefunc(ItemRack, 'CreateMenuButton', SkinButton)
- hooksecurefunc(ItemRack, 'InitButtons', SkinButton2)
- SkinButton(1)
- SkinButton2()
+ hooksecurefunc(ItemRack, 'CreateMenuButton', function(idx) SkinMenuButton(idx) end)
+ hooksecurefunc(ItemRack, 'InitButtons', function() SkinAllMainButtons() end)
+
+ SkinMenuButton(1)
+ SkinAllMainButtons()
end
AS:RegisterSkin('ItemRack')
diff --git a/AddOnSkins/Skins/AddOns/Load_Skins.xml b/AddOnSkins/Skins/AddOns/Load_Skins.xml
index 6f590f1a..aaebad1c 100644
--- a/AddOnSkins/Skins/AddOns/Load_Skins.xml
+++ b/AddOnSkins/Skins/AddOns/Load_Skins.xml
@@ -1,142 +1,157 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AddOnSkins/Skins/AddOns/PallyPower.lua b/AddOnSkins/Skins/AddOns/PallyPower.lua
new file mode 100755
index 00000000..14a97ebe
--- /dev/null
+++ b/AddOnSkins/Skins/AddOns/PallyPower.lua
@@ -0,0 +1,207 @@
+local AS, L, S, R = unpack(AddOnSkins)
+
+local function SkinCheckBox(cb)
+ if not cb or cb._ppSkinned then return end
+ cb._ppSkinned = true
+ for i = 1, cb:GetNumRegions() do
+ local r = select(i, cb:GetRegions())
+ if r and r.SetTexture then r:SetTexture(nil) end
+ end
+ if cb.SetNormalTexture then cb:SetNormalTexture('') end
+ if cb.SetHighlightTexture then cb:SetHighlightTexture('') end
+ if cb.SetPushedTexture then cb:SetPushedTexture('') end
+ if cb.SetBackdrop then cb:SetBackdrop(nil) end
+ S:CreateBackdrop(cb)
+ -- Center a 16x16 backdrop inside the original 26x26 button
+ if cb.backdrop then
+ cb.backdrop:SetSize(16, 16)
+ cb.backdrop:ClearAllPoints()
+ cb.backdrop:SetPoint('CENTER', cb, 'CENTER', 0, 0)
+ end
+ local blankTex = (ElvUI and ElvUI[1].media.blankTex) or [[Interface\Buttons\WHITE8X8]]
+ cb:SetCheckedTexture(blankTex)
+ local ct = cb:GetCheckedTexture()
+ if ct then
+ ct:SetVertexColor(unpack(AS.Color))
+ if cb.backdrop then S:SetInside(ct, cb.backdrop) end
+ end
+ if cb.backdrop then
+ hooksecurefunc(cb, 'SetChecked', function(f, checked)
+ if f.backdrop then
+ if checked then
+ f.backdrop:SetBackdropBorderColor(unpack(AS.Color))
+ else
+ f.backdrop:SetBackdropBorderColor(unpack(AS.BorderColor))
+ end
+ end
+ end)
+ end
+end
+
+-- Strip Blizzard backdrop and apply ElvUI template.
+-- Does NOT touch SetBackdropColor so PallyPower can still color buttons by buff status.
+local function SkinPPButton(btn)
+ if not btn then return end
+ S:StripTextures(btn)
+ S:SetTemplate(btn)
+end
+
+local function SkinMainButtons(PP)
+ SkinPPButton(_G.PallyPowerRF)
+ SkinPPButton(_G.PallyPowerAuto)
+ SkinPPButton(_G.PallyPowerAura)
+
+ for i = 1, PALLYPOWER_MAXCLASSES do
+ local cBtn = PP.classButtons and PP.classButtons[i]
+ if cBtn then
+ SkinPPButton(cBtn)
+ local icon = _G[cBtn:GetName()..'ClassIcon']
+ if icon then S:HandleIcon(icon) end
+ local bIcon = _G[cBtn:GetName()..'BuffIcon']
+ if bIcon then S:HandleIcon(bIcon) end
+ end
+ local pBtns = PP.playerButtons and PP.playerButtons[i]
+ if pBtns then
+ for j = 1, PALLYPOWER_MAXPERCLASS do
+ local pBtn = pBtns[j]
+ if pBtn then
+ SkinPPButton(pBtn)
+ local icon = _G[pBtn:GetName()..'BuffIcon']
+ if icon then S:HandleIcon(icon) end
+ end
+ end
+ end
+ end
+end
+
+local function SkinBlessingsFrame()
+ local BF = _G.PallyPowerBlessingsFrame
+ if not BF or BF._asSkinned then return end
+ BF._asSkinned = true
+
+ S:StripTextures(BF)
+ S:SetTemplate(BF)
+ S:HandleCloseButton(_G.PallyPowerBlessingsFrameCloseButton)
+
+ -- Move title up slightly
+ local title = _G.PallyPowerBlessingsFrameTitle
+ if title then
+ title:ClearAllPoints()
+ title:SetPoint('TOP', BF, 'TOP', 0, -4)
+ end
+
+ -- Bottom action buttons use GameMenuButtonTemplate
+ for _, suffix in ipairs({ 'Options', 'AutoAssign', 'Clear', 'Refresh', 'Preset', 'Report' }) do
+ local btn = _G['PallyPowerBlessingsFrame'..suffix]
+ if btn then S:HandleButton(btn) end
+ end
+
+ -- Free Assignment checkbox
+ local freeAssign = _G['PallyPowerBlessingsFrameFreeAssign']
+ if freeAssign then
+ SkinCheckBox(freeAssign)
+ local freeText = _G['PallyPowerBlessingsFrameFreeAssignText']
+ if freeText and freeAssign.backdrop then
+ freeText:ClearAllPoints()
+ freeText:SetPoint('LEFT', freeAssign.backdrop, 'RIGHT', 4, 0)
+ freeAssign.backdrop:ClearAllPoints()
+ freeAssign.backdrop:SetPoint('LEFT', freeAssign, 'LEFT', 5, 3)
+ end
+ end
+
+ -- Add ElvUI backdrop behind each class icon by creating a sibling frame anchored
+ -- to the ClassButton. Child frames on ClassButton break ClassGroup layout.
+ for i = 1, PALLYPOWER_MAXCLASSES do
+ local btn = _G['PallyPowerBlessingsFrameClassGroup'..i..'ClassButton']
+ local icon = _G['PallyPowerBlessingsFrameClassGroup'..i..'ClassButtonIcon']
+ if btn and icon then
+ icon:Show()
+ if not btn._ppBg then
+ local bg = CreateFrame('Frame', nil, BF)
+ bg:SetFrameLevel(btn:GetFrameLevel() - 1)
+ bg:SetPoint('TOPLEFT', btn, 'TOPLEFT', 0, 0)
+ bg:SetSize(84, 68)
+ S:SetTemplate(bg)
+ bg:SetBackdropColor(0.08, 0.08, 0.08, 0.9)
+ bg:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
+ btn._ppBg = bg
+ end
+ end
+ end
+ -- Same for AuraGroup header button
+ local auraBtn = _G['PallyPowerBlessingsFrameAuraGroup1AuraHeader']
+ if auraBtn and not auraBtn._ppBg then
+ local bg = CreateFrame('Frame', nil, BF)
+ bg:SetFrameLevel(auraBtn:GetFrameLevel() - 1)
+ bg:SetPoint('TOPLEFT', auraBtn, 'TOPLEFT', 0, 0)
+ bg:SetSize(84, 68)
+ S:SetTemplate(bg)
+ bg:SetBackdropColor(0.08, 0.08, 0.08, 0.9)
+ bg:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
+ auraBtn._ppBg = bg
+ end
+
+ -- Recolor all separator lines to ElvUI border color
+ local function recolorLine(line)
+ if not line then return end
+ line:SetColorTexture(0.4, 0.4, 0.4, 1)
+ end
+ for i = 1, PALLYPOWER_MAXCLASSES do
+ recolorLine(_G['PallyPowerBlessingsFrameClassGroup'..i..'Line'])
+ end
+ recolorLine(_G['PallyPowerBlessingsFrameAuraGroup1Line'])
+ for i = 1, PALLYPOWER_MAXPERCLASS do
+ local prefix = 'PallyPowerBlessingsFramePlayer'..i
+ for j = 1, 11 do
+ recolorLine(_G[prefix..'Line'..j])
+ end
+ end
+
+ -- Center player names and sync backdrop heights after every PP grid update
+ hooksecurefunc('PallyPowerBlessingsGrid_Update', function()
+ for i = 1, PALLYPOWER_MAXCLASSES do
+ for j = 1, PALLYPOWER_MAXPERCLASS do
+ local txt = _G['PallyPowerBlessingsFrameClassGroup'..i..'PlayerButton'..j..'Text']
+ if txt and not txt._ppCentered then
+ txt:SetJustifyH('CENTER')
+ txt:ClearAllPoints()
+ txt:SetPoint('LEFT', txt:GetParent(), 'LEFT', 0, 2)
+ txt._ppCentered = true
+ end
+ end
+ -- Use Line height as ground truth - PP sets it to 56 + 13*numMaxClass
+ local btn = _G['PallyPowerBlessingsFrameClassGroup'..i..'ClassButton']
+ local line = _G['PallyPowerBlessingsFrameClassGroup'..i..'Line']
+ if btn and btn._ppBg and line then
+ btn._ppBg:SetHeight(line:GetHeight())
+ end
+ end
+ local auraBtn = _G['PallyPowerBlessingsFrameAuraGroup1AuraHeader']
+ local auraLine = _G['PallyPowerBlessingsFrameAuraGroup1Line']
+ if auraBtn and auraBtn._ppBg and auraLine then
+ auraBtn._ppBg:SetHeight(auraLine:GetHeight())
+ end
+ end)
+end
+
+function AS:PallyPower()
+ local PP = _G.PallyPower
+ if not PP then return end
+
+ -- Re-skin main buttons whenever PP rebuilds its skin (skin option change)
+ hooksecurefunc(PP, 'ApplySkin', function(self)
+ SkinMainButtons(self)
+ end)
+
+ local BF = _G.PallyPowerBlessingsFrame
+ if BF then
+ BF:HookScript('OnShow', SkinBlessingsFrame)
+ end
+
+ C_Timer.After(0, function()
+ SkinMainButtons(PP)
+ if BF and BF:IsShown() then SkinBlessingsFrame() end
+ end)
+end
+
+AS:RegisterSkin('PallyPower', AS.PallyPower)
diff --git a/AddOnSkins/Skins/AddOns/RareScanner.lua b/AddOnSkins/Skins/AddOns/RareScanner.lua
index 146b0102..52dc60bb 100644
--- a/AddOnSkins/Skins/AddOns/RareScanner.lua
+++ b/AddOnSkins/Skins/AddOns/RareScanner.lua
@@ -1,18 +1,40 @@
-local AS, L, S, R = unpack(AddOnSkins)
+local AS = unpack(AddOnSkins)
-function R:RareScanner()
- S:HandleFrame(RARESCANNER_BUTTON, 'Default')
- S:HandleButton(RARESCANNER_BUTTON.CloseButton)
- RARESCANNER_BUTTON.CloseButton:ClearAllPoints()
- RARESCANNER_BUTTON.CloseButton:SetPoint("TOPRIGHT", -5, -5)
- S:HandleButton(RARESCANNER_BUTTON.FilterEntityButton)
- RARESCANNER_BUTTON.FilterEntityButton:SetNormalTexture([[Interface\WorldMap\Dash_64Grey]])
- RARESCANNER_BUTTON.FilterEntityButton:ClearAllPoints()
- RARESCANNER_BUTTON.FilterEntityButton:SetPoint("TOPLEFT", 5, -5)
- S:HandleButton(RARESCANNER_BUTTON.UnfilterEnabledButton)
- RARESCANNER_BUTTON.FilterEnabledTexture:SetTexture([[Interface\WorldMap\Skull_64]])
- RARESCANNER_BUTTON.UnfilterEnabledButton:ClearAllPoints()
- RARESCANNER_BUTTON.UnfilterEnabledButton:SetPoint("TOPLEFT", 5, -5)
+local function SkinRareScanner()
+ local btn = _G['RARESCANNER_BUTTON']
+ if not btn or btn._asSkinned then return end
+ btn._asSkinned = true
+
+ -- Replace parchment background and default tooltip border with ElvUI style
+ btn:SetNormalTexture('')
+ btn:SetPushedTexture('')
+ btn:SetHighlightTexture('')
+ AS:StripTextures(btn)
+ AS:SetTemplate(btn)
+ AS:CreateShadow(btn)
+
+ -- Close button
+ if btn.CloseButton then
+ AS:SkinCloseButton(btn.CloseButton)
+ btn.CloseButton:ClearAllPoints()
+ btn.CloseButton:SetPoint('TOPRIGHT', btn, 'TOPRIGHT', -4, -4)
+ end
+
+ -- Filter buttons use custom icon textures from RareScanner media - only skin the frame border
+ if btn.FilterEntityButton then
+ AS:CreateBackdrop(btn.FilterEntityButton)
+ end
+ if btn.UnFilterEntityButton then
+ AS:CreateBackdrop(btn.UnFilterEntityButton)
+ end
+end
+
+function AS:RareScanner(event, addon)
+ local loaded = (C_AddOns and C_AddOns.IsAddOnLoaded and C_AddOns.IsAddOnLoaded('RareScanner'))
+ or (_G.IsAddOnLoaded and _G.IsAddOnLoaded('RareScanner'))
+ if not loaded then return end
+
+ C_Timer.After(0, SkinRareScanner)
end
-AS:RegisterSkin('RareScanner')
+AS:RegisterSkin('RareScanner', AS.RareScanner)
diff --git a/AddOnSkins/Skins/AddOns/TellMeWhen.lua b/AddOnSkins/Skins/AddOns/TellMeWhen.lua
new file mode 100644
index 00000000..dc86cb94
--- /dev/null
+++ b/AddOnSkins/Skins/AddOns/TellMeWhen.lua
@@ -0,0 +1,359 @@
+-- TellMeWhen skin for AddOnSkins
+
+local AS = unpack(AddOnSkins)
+
+local BLANK_TEX = (_G.ElvUI and _G.ElvUI[1] and _G.ElvUI[1].media.blankTex)
+ or [[Interface\Buttons\WHITE8X8]]
+
+local function HideTMWBorder(f)
+ if f and f.border and f.border.SetColor then
+ f.border:SetColor(0, 0, 0, 0)
+ end
+end
+
+-- CheckBox
+local function SkinTMWCheckBox(cb)
+ if not cb or cb._tmwBorder then return end
+
+ if cb.SetNormalTexture then cb:SetNormalTexture('') end
+ if cb.SetHighlightTexture then cb:SetHighlightTexture('') end
+ if cb.SetPushedTexture then cb:SetPushedTexture('') end
+ if cb.SetDisabledTexture then cb:SetDisabledTexture('') end
+
+ cb:SetCheckedTexture(BLANK_TEX)
+ local ct = cb:GetCheckedTexture()
+ if ct then ct:SetAlpha(0) end
+
+ for i = 1, cb:GetNumRegions() do
+ local r = select(i, cb:GetRegions())
+ if r then
+ local rtype; pcall(function() rtype = r:GetObjectType() end)
+ if rtype ~= 'FontString' then
+ if r.SetTexture then r:SetTexture(nil) end
+ if r.SetAtlas then r:SetAtlas('') end
+ r:SetAlpha(0)
+ if r.Hide then r:Hide() end
+ end
+ end
+ end
+
+ -- Outer border texture (1px, color changes with checked state)
+ local border = cb:CreateTexture(nil, 'BACKGROUND')
+ border:SetPoint('LEFT', cb, 'LEFT', 2, 0)
+ border:SetSize(13, 13)
+ border:SetTexture(BLANK_TEX)
+ border:SetVertexColor(unpack(AS.BorderColor))
+ cb._tmwBorder = border
+
+ -- Fill texture (inner, shown when checked)
+ local fill = cb:CreateTexture(nil, 'ARTWORK')
+ fill:SetPoint('LEFT', cb, 'LEFT', 3, 0)
+ fill:SetSize(11, 11)
+ fill:SetTexture(BLANK_TEX)
+ fill:SetVertexColor(unpack(AS.Color))
+ fill:Hide()
+ cb._tmwFill = fill
+
+ local function UpdateCB(f)
+ if not f._tmwBorder then return end
+ if f:GetChecked() then
+ f._tmwBorder:SetVertexColor(unpack(AS.Color))
+ if f._tmwFill then f._tmwFill:Show() end
+ else
+ f._tmwBorder:SetVertexColor(unpack(AS.BorderColor))
+ if f._tmwFill then f._tmwFill:Hide() end
+ end
+ end
+
+ cb:HookScript('OnClick', UpdateCB)
+ hooksecurefunc(cb, 'SetChecked', function(f) UpdateCB(f) end)
+ C_Timer.After(0, function() UpdateCB(cb) end)
+end
+
+-- TMW DropDown
+local function SkinTMWDropDown(dd)
+ if not dd or dd._tmwDDSkinned then return end
+ dd._tmwDDSkinned = true
+ HideTMWBorder(dd)
+ if dd.Background then dd.Background:SetTexture(nil) end
+ AS:SetTemplate(dd)
+ if dd.Button then
+ local btn = dd.Button
+ for _, getter in ipairs({'GetNormalTexture','GetPushedTexture','GetHighlightTexture','GetDisabledTexture'}) do
+ local tex = btn[getter] and btn[getter](btn)
+ if tex then tex:SetTexture(nil) tex:Hide() end
+ end
+ local arrow = dd:CreateTexture(nil, 'OVERLAY')
+ arrow:SetTexture([[Interface\AddOns\AddOnSkins\Media\Textures\Arrow]])
+ arrow:SetRotation(3.14)
+ arrow:SetVertexColor(1, 1, 1)
+ arrow:SetPoint('RIGHT', dd, 'RIGHT', -4, 0)
+ arrow:SetSize(12, 12)
+ dd:HookScript('OnEnter', function()
+ arrow:SetVertexColor(unpack(AS.Color))
+ if dd.SetBackdropBorderColor then dd:SetBackdropBorderColor(unpack(AS.Color)) end
+ end)
+ dd:HookScript('OnLeave', function()
+ arrow:SetVertexColor(1, 1, 1)
+ if dd.SetBackdropBorderColor then dd:SetBackdropBorderColor(unpack(AS.BorderColor)) end
+ end)
+ end
+end
+
+-- Button
+local function SkinTMWButton(btn)
+ if not btn or btn.isSkinned then return end
+ HideTMWBorder(btn)
+ if btn.Background then btn.Background:SetTexture(nil) end
+ AS:SkinButton(btn)
+end
+
+-- EditBox
+local function SkinTMWEditBox(eb)
+ if not eb or eb.Backdrop then return end
+ HideTMWBorder(eb)
+ if eb.background then eb.background:SetTexture(nil) end
+ AS:SkinEditBox(eb)
+end
+
+-- Recursive scanner
+local function SkinChildren(parent)
+ if not parent then return end
+ local ok, children = pcall(function() return {parent:GetChildren()} end)
+ if not ok then return end
+ for _, child in ipairs(children) do
+ local t
+ pcall(function() t = child:GetObjectType() end)
+ if t == 'CheckButton' then
+ SkinTMWCheckBox(child)
+ elseif child.Background and child.Button and child.Text then
+ SkinTMWDropDown(child)
+ elseif t == 'Button' and child.Background and child.border then
+ SkinTMWButton(child)
+ elseif t == 'EditBox' and (child.background or child.border) then
+ SkinTMWEditBox(child)
+ end
+ SkinChildren(child)
+ end
+end
+
+-- Dialog windows
+local function SkinSimpleDialog(f)
+ if not f or f._tmwDialogSkinned then return end
+ f._tmwDialogSkinned = true
+ HideTMWBorder(f)
+ AS:StripTextures(f)
+ AS:SetTemplate(f)
+ AS:CreateShadow(f)
+ if f.CloseButton then AS:SkinCloseButton(f.CloseButton) end
+end
+
+-- In-game group borders
+local function SkinGroupBorder(frame)
+ if not frame or frame._asBorderSkinned then return end
+ -- border may be a parentKey or a child frame
+ local border = frame.border
+ if not border then
+ for _, child in ipairs({frame:GetChildren()}) do
+ if child.SetColor and child.SetBorderSize then
+ border = child
+ break
+ end
+ end
+ end
+ if not border or not border.SetColor then return end
+ frame._asBorderSkinned = true
+ border:SetColor(unpack(AS.BorderColor))
+end
+
+local function SkinAllGroupBorders()
+ local TMW = _G['TMW']
+ if not TMW then return end
+ for _, child in ipairs({TMW:GetChildren()}) do
+ SkinGroupBorder(child)
+ -- Hook OnShow so newly created groups get skinned when they appear
+ if child.border and not child._tmwGroupHooked then
+ child._tmwGroupHooked = true
+ child:HookScript('OnShow', function(f) SkinGroupBorder(f) end)
+ end
+ end
+ -- Also hook CreateFrame to catch groups created after initial scan
+ if not _G._tmwGroupCreateHooked then
+ _G._tmwGroupCreateHooked = true
+ hooksecurefunc('CreateFrame', function(ftype, fname, parent)
+ if ftype ~= 'Frame' then return end
+ local p = parent
+ while p do
+ if p == TMW then
+ C_Timer.After(0, function()
+ local f = fname and _G[fname]
+ if f then SkinGroupBorder(f) end
+ end)
+ return
+ end
+ p = p.GetParent and p:GetParent()
+ end
+ end)
+ end
+end
+
+-- Global CreateFrame hook for CheckButtons
+local cfHooked = false
+local function HookCreateFrame()
+ if cfHooked then return end
+ cfHooked = true
+ hooksecurefunc('CreateFrame', function(frameType, frameName, parent)
+ if frameType ~= 'CheckButton' then return end
+ C_Timer.After(0, function()
+ local f = frameName and _G[frameName]
+ if not f then return end
+ local p = f:GetParent()
+ while p do
+ local n = p.GetName and p:GetName() or ''
+ if n:find('TellMeWhen', 1, true) or n:find('TMW', 1, true) then
+ SkinTMWCheckBox(f)
+ return
+ end
+ p = p.GetParent and p:GetParent()
+ end
+ end)
+ end)
+end
+
+-- Ticker
+local scanTicker
+local function StopScan() if scanTicker then scanTicker:Cancel() scanTicker = nil end end
+
+local function ScanEditorAndPages(editor)
+ local pages = _G['TellMeWhen_IconEditorPages']
+ SkinChildren(editor)
+ if pages then SkinChildren(pages) end
+end
+
+local function SkinEditorButtons(editor)
+ for _, key in ipairs({'ResetButton','UndoButton','RedoButton','OkayButton'}) do
+ local btn = editor[key]
+ if btn and not btn.isSkinned then
+ AS:SkinButton(btn)
+ end
+ end
+ for _, child in ipairs({editor:GetChildren()}) do
+ if child:GetObjectType() == 'EditBox' and not child.Backdrop then
+ AS:SkinEditBox(child)
+ end
+ end
+end
+
+local function StartEditorScan(editor)
+ SkinSimpleDialog(editor)
+ SkinEditorButtons(editor)
+ ScanEditorAndPages(editor)
+ StopScan()
+ scanTicker = C_Timer.NewTicker(0.25, function()
+ ScanEditorAndPages(editor)
+ if not editor:IsShown() then StopScan() end
+ end)
+end
+
+local tmwOptionsHooked = false
+
+local function SetupTMWOptions()
+ if tmwOptionsHooked then return end
+ local editor = _G['TellMeWhen_IconEditor']
+ if not editor then return end
+ tmwOptionsHooked = true
+
+ editor:HookScript('OnShow', function() StartEditorScan(editor) end)
+ editor:HookScript('OnHide', StopScan)
+ if editor:IsShown() then StartEditorScan(editor) end
+
+ local dialogs = {
+ 'TellMeWhen_ColorPicker',
+ 'TellMeWhen_ConfigWarning',
+ 'TellMeWhen_DBRestoredNofication',
+ 'TellMeWhen_GUIDConflictResolveDialog',
+ 'TellMeWhen_ConfirmImportedLuaDialog',
+ 'TellMeWhen_CpuProfileDialog',
+ }
+ for _, name in ipairs(dialogs) do
+ local f = _G[name]
+ if f then
+ f:HookScript('OnShow', function()
+ SkinSimpleDialog(f)
+ SkinChildren(f)
+ end)
+ if f:IsShown() then
+ SkinSimpleDialog(f)
+ SkinChildren(f)
+ end
+ end
+ end
+end
+
+local function SetTMWIconBorderShown(icon, shown)
+ if icon._tmwConfigBorder then
+ icon._tmwConfigBorder:SetShown(shown)
+ end
+end
+
+local function SkinTMWIcon(icon)
+ if not icon then return end
+ if not TMW or TMW.Locked then return end
+ -- In config mode icons use Disabled.blp texture - add ElvUI border around them
+ if not icon._tmwConfigBorder then
+ local border = CreateFrame('Frame', nil, icon, 'BackdropTemplate')
+ border:SetPoint('TOPLEFT', icon, 'TOPLEFT', -1, 1)
+ border:SetPoint('BOTTOMRIGHT', icon, 'BOTTOMRIGHT', 1, -1)
+ border:SetFrameLevel(icon:GetFrameLevel() - 1)
+ AS:SetTemplate(border)
+ icon._tmwConfigBorder = border
+ end
+ icon._tmwConfigBorder:Show()
+end
+
+local function HookTMWIconSetup()
+ local TMW = _G['TMW']
+ if not TMW or not TMW.RegisterCallback then return end
+ TMW:RegisterCallback('TMW_ICON_SETUP_POST', function(_, icon)
+ -- Show border only in config mode; hide it when locked (normal play)
+ if TMW.Locked then
+ SetTMWIconBorderShown(icon, false)
+ else
+ C_Timer.After(0, function() SkinTMWIcon(icon) end)
+ end
+ end)
+ TMW:RegisterCallback('TMW_LOCK_TOGGLED', function(_, locked)
+ -- Hide all config borders when entering normal mode
+ for _, group in ipairs({TMW:GetChildren()}) do
+ for _, icon in ipairs({group:GetChildren()}) do
+ SetTMWIconBorderShown(icon, not locked)
+ end
+ end
+ end)
+end
+
+-- Entry point
+function AS:TellMeWhen(event, addon)
+ local loaded = (C_AddOns and C_AddOns.IsAddOnLoaded and C_AddOns.IsAddOnLoaded('TellMeWhen'))
+ or (_G.IsAddOnLoaded and _G.IsAddOnLoaded('TellMeWhen'))
+ if not loaded then return end
+
+ HookCreateFrame()
+
+ C_Timer.After(0, function()
+ SkinAllGroupBorders()
+ HookTMWIconSetup()
+ if _G['TellMeWhen_IconEditor'] then
+ SetupTMWOptions()
+ else
+ AS:RegisterEvent('ADDON_LOADED', function(_, addonName)
+ if addonName == 'TellMeWhen_Options' then
+ C_Timer.After(0, SetupTMWOptions)
+ AS:UnregisterEvent('ADDON_LOADED')
+ end
+ end)
+ end
+ end)
+end
+
+AS:RegisterSkin('TellMeWhen', AS.TellMeWhen)
diff --git a/AddOnSkins/Skins/AddOns/TrinketMenu.lua b/AddOnSkins/Skins/AddOns/TrinketMenu.lua
index 7b0a2fac..54f51d8c 100644
--- a/AddOnSkins/Skins/AddOns/TrinketMenu.lua
+++ b/AddOnSkins/Skins/AddOns/TrinketMenu.lua
@@ -2,7 +2,6 @@ local AS, L, S, R = unpack(AddOnSkins)
function R:TrinketMenu()
-- Config Panel
- local TrinketMenu = _G.TrinketMenu
S:HandleFrame(TrinketMenu_OptFrame)
TrinketMenu_OptFrame:SetWidth(380)
S:HandleFrame(TrinketMenu_SubOptFrame)
@@ -65,13 +64,42 @@ function R:TrinketMenu()
S:HandleSliderFrame(slider)
end
- -- Main Frame
- S:HandleItemButton(TrinketMenu_Trinket0)
- S:HandleItemButton(TrinketMenu_Trinket1)
+ -- TrinketMenu buttons inherit ActionButtonTemplate. The icon is $parentIcon
+ -- (e.g. TrinketMenu_Trinket0Icon, TrinketMenu_Menu3Icon).
+ -- HandleItemButton calls StripTextures which wipes the icon before TrinketMenu
+ -- sets it, leaving an empty texture. Skin without touching the icon texture.
+ local function SkinTrinketButton(button)
+ if not button or button._tmSkinned then return end
+ button._tmSkinned = true
+
+ local name = button:GetName()
+ local icon = name and _G[name .. 'Icon']
+
+ -- Strip only non-icon regions.
+ for _, region in next, { button:GetRegions() } do
+ if region and region ~= icon and region.IsObjectType and region:IsObjectType('Texture') then
+ region:SetTexture('')
+ end
+ end
+
+ S:CreateBackdrop(button, nil, true, nil, nil, nil, nil, nil, true)
+ S:StyleButton(button)
+
+ if icon then
+ S:HandleIcon(icon)
+ S:SetInside(icon, button)
+ icon:SetParent(button.backdrop or button)
+ end
+ end
+
+ -- Main Frame (equipped trinkets)
+ SkinTrinketButton(TrinketMenu_Trinket0)
+ SkinTrinketButton(TrinketMenu_Trinket1)
+ -- Menu buttons (inventory trinkets) - created dynamically
+ local TrinketMenu = _G.TrinketMenu
for i = (TrinketMenu.NumberOfTrinkets + 1), TrinketMenu.MaxTrinkets do
- local trinkets = _G['TrinketMenu_Menu'..i]
- S:HandleItemButton(trinkets)
+ SkinTrinketButton(_G['TrinketMenu_Menu'..i])
end
end
diff --git a/AddOnSkins/Skins/AddOns/XToLevel.lua b/AddOnSkins/Skins/AddOns/XToLevel.lua
new file mode 100755
index 00000000..f407fd7c
--- /dev/null
+++ b/AddOnSkins/Skins/AddOns/XToLevel.lua
@@ -0,0 +1,99 @@
+-- XToLevel skin for AddOnSkins
+
+local AS = unpack(AddOnSkins)
+
+-- Background textures are named via $parentBackground, expanding to e.g.
+-- XToLevel_AverageFrame_Blocky_PlayerFrameCounterKillsBackground.
+local COUNTER_NAMES = {
+ 'Kills', 'Quests', 'Dungeons', 'Battles', 'Objectives',
+ 'PetBattles', 'Gathering', 'Digs', 'Progress', 'Timer', 'GuildProgress',
+}
+
+local function HideCounterBackgrounds(playerFrame)
+ local prefix = playerFrame:GetName() .. 'Counter'
+ for _, name in ipairs(COUNTER_NAMES) do
+ local bg = _G[prefix .. name .. 'Background']
+ if bg then bg:SetTexture(nil) end
+ end
+end
+
+local function SkinProgressBar(playerFrame)
+ local prefix = playerFrame:GetName() .. 'Counter'
+
+ -- Bar track: dark backdrop behind the fill texture
+ local bar = _G[prefix .. 'ProgressBar']
+ if bar then
+ AS:SetTemplate(bar)
+ end
+
+ -- Fill: use ElvUI accent color, set texture to solid white so vertex color shows
+ local fill = _G[prefix .. 'ProgressBarColor']
+ if fill then
+ local blankTex = (_G.ElvUI and _G.ElvUI[1] and _G.ElvUI[1].media.blankTex)
+ or [[Interface\Buttons\WHITE8X8]]
+ fill:SetTexture(blankTex)
+ fill:SetVertexColor(unpack(AS.Color))
+ -- Ensure fill draws above the bar backdrop
+ fill:SetDrawLayer('ARTWORK', 1)
+ end
+end
+
+local function CreateBlockyWrapper(playerFrame)
+ local PAD = 4
+ -- Use FrameLevel 0 so the wrapper sits below all counter child frames
+ local wrapper = CreateFrame('Frame', nil, UIParent, 'BackdropTemplate')
+ wrapper:SetFrameStrata(playerFrame:GetFrameStrata())
+ wrapper:SetFrameLevel(0)
+ AS:SetTemplate(wrapper)
+ AS:CreateShadow(wrapper)
+
+ local function Refit()
+ local w, h = playerFrame:GetWidth(), playerFrame:GetHeight()
+ if w < 4 or h < 4 then return end
+ wrapper:SetParent(playerFrame:GetParent())
+ wrapper:ClearAllPoints()
+ wrapper:SetPoint('TOPLEFT', playerFrame, 'TOPLEFT', -PAD, PAD)
+ wrapper:SetPoint('BOTTOMRIGHT', playerFrame, 'BOTTOMRIGHT', PAD, -PAD)
+ wrapper:SetShown(playerFrame:IsShown())
+ end
+
+ playerFrame:HookScript('OnSizeChanged', Refit)
+ playerFrame:HookScript('OnShow', function() wrapper:Show() end)
+ playerFrame:HookScript('OnHide', function() wrapper:Hide() end)
+ Refit()
+end
+
+local function SkinBlockyFrame()
+ local f = _G['XToLevel_AverageFrame_Blocky_PlayerFrame']
+ if not f or f._asSkinned then return end
+ f._asSkinned = true
+
+ HideCounterBackgrounds(f)
+ SkinProgressBar(f)
+ CreateBlockyWrapper(f)
+end
+
+local function SkinClassicFrame()
+ local f = _G['XToLevel_AverageFrame_Classic']
+ if not f or f._asSkinned then return end
+ f._asSkinned = true
+ AS:StripTextures(f)
+ AS:SetTemplate(f)
+ AS:CreateShadow(f)
+ hooksecurefunc(f, 'SetBackdrop', function(self)
+ if self._asSkinned then AS:SetTemplate(self) end
+ end)
+end
+
+function AS:XToLevel(event, addon)
+ local loaded = (C_AddOns and C_AddOns.IsAddOnLoaded and C_AddOns.IsAddOnLoaded('XToLevel'))
+ or (_G.IsAddOnLoaded and _G.IsAddOnLoaded('XToLevel'))
+ if not loaded then return end
+
+ C_Timer.After(0, function()
+ SkinClassicFrame()
+ SkinBlockyFrame()
+ end)
+end
+
+AS:RegisterSkin('XToLevel', AS.XToLevel)
diff --git a/AddOnSkins/Skins/AddOns/Zygor.lua b/AddOnSkins/Skins/AddOns/Zygor.lua
index 857fac0c..fc198b5f 100644
--- a/AddOnSkins/Skins/AddOns/Zygor.lua
+++ b/AddOnSkins/Skins/AddOns/Zygor.lua
@@ -1,12 +1,92 @@
-local AS, L, S, R = unpack(AddOnSkins)
+-- Zygor Guides skin for AddOnSkins (TBC Anniversary: ZygorGuidesViewerClassicTBCAnniv)
+-- Zygor uses a fully custom widget system (UI:Create / SkinData), so we avoid
+-- stripping or restyling internal content frames - doing so breaks Zygor's own
+-- theme rendering. Instead we only override the outer frame border colours and
+-- skin the standard Blizzard-template elements (close button, search backdrop).
-function R:ZygorGuidesViewer()
- S:StripTextures(ZygorGuidesViewerFrame_Border, true)
- S:HandleFrame(ZygorGuidesViewerFrame, nil, nil, true)
+local AS = unpack(AddOnSkins)
- for i = 1, 6 do
- S:HandleFrame(_G['ZygorGuidesViewerFrame_Step'..i], true)
+-- Guide Browser
+-- ZygorGuidesViewer_GuideMenu is the guide-browser window (Home/Featured/…).
+-- Its outer frame uses BackdropTemplate + Zygor's SkinData colours. We just
+-- override the border colour so it matches the ElvUI theme colour, and skin the
+-- close button and search edit back-frame.
+
+local guideMenuSkinned = false
+local function SkinGuideMenuFrame()
+ if guideMenuSkinned then return end
+ local MF = _G['ZygorGuidesViewer_GuideMenu']
+ if not MF then return end
+ guideMenuSkinned = true
+
+ -- Only override the BORDER colour - leave background/texture alone so
+ -- Zygor's own theme (Stealth, Starlight, …) is not broken.
+ MF:SetBackdropBorderColor(unpack(AS.BorderColor))
+
+ -- Close button (standard Blizzard ButtonTemplate child)
+ if MF.Header and MF.Header.CloseButton then
+ AS:SkinCloseButton(MF.Header.CloseButton)
+ end
+
+ -- Search edit box: Zygor EditBox keeps its backdrop in a child .back frame
+ local search = MF.MenuGuides and MF.MenuGuides.SearchEdit
+ if search and search.back then
+ AS:StripTextures(search.back)
+ AS:SetTemplate(search.back)
+ search:SetTextColor(1, 1, 1)
+ end
+end
+
+-- Step Viewer
+-- ZygorGuidesViewerFrame is the visual skin frame (child of FrameMaster).
+-- Its ApplySkin() sets backdrop colours from SkinData. We hook it to override
+-- just the border colour with the ElvUI value without breaking anything else.
+
+local stepViewerHooked = false
+local function HookStepViewer()
+ if stepViewerHooked then return end
+ local ZGV = _G['ZygorGuidesViewer']
+ if not ZGV or not ZGV.Frame then return end
+ stepViewerHooked = true
+
+ local f = ZGV.Frame
+ local function ApplyElvUIBorder()
+ if f.Border then
+ f.Border:SetBackdropBorderColor(unpack(AS.BorderColor))
+ end
+ end
+
+ if f.ApplySkin then
+ hooksecurefunc(f, 'ApplySkin', ApplyElvUIBorder)
end
+ ApplyElvUIBorder()
+end
+
+-- Entry point
+function AS:Zygor(event, addon)
+ local loaded = (C_AddOns and C_AddOns.IsAddOnLoaded and (
+ C_AddOns.IsAddOnLoaded('ZygorGuidesViewer') or
+ C_AddOns.IsAddOnLoaded('ZygorGuidesViewerClassic') or
+ C_AddOns.IsAddOnLoaded('ZygorGuidesViewerClassicTBCAnniv')))
+ or (_G.IsAddOnLoaded and (
+ _G.IsAddOnLoaded('ZygorGuidesViewer') or
+ _G.IsAddOnLoaded('ZygorGuidesViewerClassic') or
+ _G.IsAddOnLoaded('ZygorGuidesViewerClassicTBCAnniv')))
+ if not loaded then return end
+
+ C_Timer.After(0.5, function()
+ HookStepViewer()
+ SkinGuideMenuFrame()
+
+ -- Guide browser may be opened before our timer; also hook Open so we
+ -- catch it if it is first shown after our timer runs.
+ local ZGV = _G['ZygorGuidesViewer']
+ if ZGV and ZGV.GuideMenu and ZGV.GuideMenu.Open then
+ hooksecurefunc(ZGV.GuideMenu, 'Open', function()
+ C_Timer.After(0, SkinGuideMenuFrame)
+ end)
+ end
+ end)
end
-AS:RegisterSkin('ZygorGuidesViewer')
+AS:RegisterSkin('Zygor', AS.Zygor)