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 @@ - -