Add Golden UI, a gold recolor sharing Darkened UI's code (3.7.3)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019W3rwusM4i1CYaHQAYixJ7
This commit is contained in:
2026-11-03 06:04:52 +00:00
co-authored by Claude Opus 5.5
parent 9ef84b50fe
commit 767b458aa6
8 changed files with 305 additions and 34 deletions
+270 -19
View File
@@ -15,6 +15,26 @@ local module = ShaguTweaks:register({
}
})
-- Golden UI runs the same recolor pass with a gold palette (like the WoW
-- Forever client): textures are tinted gold, borders and tooltip edges get a
-- softer gold, and backgrounds keep their own colors.
local golden = ShaguTweaks:register({
title = T["Golden UI"],
description = T["Turns the borders of the interface, tooltips and dialogs gold, like the WoW Forever client. Darkened UI takes priority when both are enabled."],
expansions = { ["vanilla"] = true },
category = T["Interface"],
enabled = nil,
config = {
["goldmode.color"] = { r = 1, g = .78, b = .4, a = 1 },
["goldmode.border"] = { r = .8, g = .62, b = .32, a = 1 },
["goldmode.text"] = { r = .84, g = .72, b = .48, a = 1 },
}
})
-- Active palette, set by whichever of the two modules is enabled:
-- tint goes on textures, edge on backdrop borders and added button borders.
local tint, edge
local blacklist = {
["Solid Texture"] = true,
["WHITE8X8"] = true,
@@ -81,6 +101,9 @@ local borders = {
["ChatFrame(.+)Button"] = -2,
["PetFrameHappiness"] = 2,
["MicroButton"] = { -21, 0, 0, 0 },
-- VCB's buff and weapon-buff buttons, like the Blizzard buff buttons
["^VCB_BF_BUFF_BUTTON%d+$"] = 3,
["^VCB_BF_WEAPON_BUTTON%d+$"] = 3,
}
local addonframes = {
@@ -97,6 +120,7 @@ local addonframes = {
["Blizzard_RaidUI"] = { "ReadyCheckFrame" },
["Blizzard_TradeSkillUI"] = { "TradeSkillFrame" },
["Blizzard_TrainerUI"] = { "ClassTrainerFrame" },
["Artisan"] = { "ArtisanFrame" },
}
-- Turtle WoW exposes these extra inspect pages. Keep them out of the generic
@@ -117,11 +141,34 @@ if GetExpansion() == "tbc" then
borders["MicroButton"] = { -21, 0, 0, 0 }
end
-- Frame art that ships inside an addon (the "AddOns" entry above skips
-- addon textures, which are mostly icons) but should follow the palette.
local whitelist = {
"outfitter\\textures\\outfitterframe",
"outfitter\\textures\\scrollbartrench",
-- Artisan swaps in its own lower half of the profession window
"artisan\\textures\\bottomleft",
"artisan\\textures\\bottomright",
-- RollFor's classic loot window
"rollfor\\assets\\og-loot-frame",
}
-- Addon windows that build their rows while opening: recolored every time
-- they are shown (and once more on the next frame, after the rows exist).
local showframes = {
["RollForLootFrameHeader"] = true,
}
local function IsBlacklisted(texture)
local name = texture:GetName()
local texture = texture:GetTexture()
if not texture then return true end
local lower = string.lower(texture)
for i = 1, table.getn(whitelist) do
if string.find(lower, whitelist[i], 1, true) then return nil end
end
if name then
for entry in pairs(blacklist) do
if string.find(name, entry, 1) then return true end
@@ -145,12 +192,12 @@ local function AddSpecialBackground(frame, w, h, x, y)
end
local function DarkenFrame(frame, r, g, b, a)
-- dont't do anything if disabled
if not ShaguTweaks.DarkMode then return end
-- dont't do anything if neither Darkened UI nor Golden UI is enabled
if not tint then return end
-- set defaults
if not r and not g and not b then
r, g, b, a = module.config["darkmode.color"].r, module.config["darkmode.color"].g, module.config["darkmode.color"].b, module.config["darkmode.color"].a
r, g, b, a = tint.r, tint.g, tint.b, tint.a
end
-- iterate through all subframes
@@ -165,8 +212,8 @@ local function DarkenFrame(frame, r, g, b, a)
-- read name
local name = frame.GetName and frame:GetName()
-- set a dark backdrop border color everywhere
frame:SetBackdropBorderColor(module.config["darkmode.color"].r, module.config["darkmode.color"].g, module.config["darkmode.color"].b, module.config["darkmode.color"].a)
-- set the palette's backdrop border color everywhere
frame:SetBackdropBorderColor(edge.r, edge.g, edge.b, edge.a)
-- add special backgrounds to quests and such
for pattern, inset in pairs(backgrounds) do
@@ -175,7 +222,7 @@ local function DarkenFrame(frame, r, g, b, a)
-- add black borders around specified buttons
for pattern, inset in pairs(borders) do
if name and string.find(name, pattern) then AddBorder(frame, inset, module.config["darkmode.color"]) end
if name and string.find(name, pattern) then AddBorder(frame, inset, edge) end
end
-- scan through all regions (textures)
@@ -201,8 +248,178 @@ end
-- register darken frame to global
ShaguTweaks.DarkenFrame = DarkenFrame
module.enable = function(self)
ShaguTweaks.DarkMode = true
-- Other addons that draw their own tooltip-style borders. Their frames (and
-- everything inside them) keep following the palette even when the addon
-- sets its border color again later, or builds a window only when opened.
local ADDON_PREFIXES = {
"ShaguDPS", "Bagshui", "Outfitter", "SoulstoneTracker", "SSWarlock",
"SSTClassic", "SSTracker", "TrinketMenu", "OctoBus", "RollFor", "VCB_",
}
local function IsAddonFrameName(name)
if not name then return end
for i = 1, table.getn(ADDON_PREFIXES) do
if string.find(name, ADDON_PREFIXES[i], 1, true) == 1 then return true end
end
end
-- Only light grey/white/silver borders follow the palette. Colored borders
-- (item quality, hover highlights, class or theme colors) and dark ones stay
-- as the addon set them.
local function IsLightNeutral(r, g, b)
r, g, b = tonumber(r) or 0, tonumber(g) or 0, tonumber(b) or 0
local hi, lo = math.max(r, g, b), math.min(r, g, b)
return hi - lo < .1 and hi >= .35
end
local function LockBorder(frame)
if not frame or frame.stBorderLock or not frame.SetBackdropBorderColor then return end
frame.stBorderLock = true
local setColor, setBackdrop = frame.SetBackdropBorderColor, frame.SetBackdrop
frame.SetBackdropBorderColor = function(self, r, g, b, a)
if IsLightNeutral(r, g, b) then
setColor(self, edge.r, edge.g, edge.b, a or 1)
else
setColor(self, r, g, b, a)
end
end
-- a new backdrop starts with a white border
if setBackdrop then
frame.SetBackdrop = function(self, backdrop)
setBackdrop(self, backdrop)
if backdrop and backdrop.edgeFile then setColor(self, edge.r, edge.g, edge.b, 1) end
end
end
-- run the current color through the filter once
if frame.GetBackdropBorderColor then
local ok, r, g, b, a = pcall(frame.GetBackdropBorderColor, frame)
if ok and r then frame:SetBackdropBorderColor(r, g, b, a) end
end
end
-- Border textures (VCB's buff and weapon borders): same rule, on the
-- texture's vertex color.
local function LockTextureBorder(texture)
if texture.stBorderLock or not texture.SetVertexColor then return end
texture.stBorderLock = true
local setColor = texture.SetVertexColor
texture.SetVertexColor = function(self, r, g, b, a)
if IsLightNeutral(r, g, b) then
setColor(self, edge.r, edge.g, edge.b, a or 1)
else
setColor(self, r, g, b, a)
end
end
if texture.GetVertexColor then
local ok, r, g, b, a = pcall(texture.GetVertexColor, texture)
if ok and r then texture:SetVertexColor(r, g, b, a) end
end
end
local function LockTree(frame)
if not frame then return end
LockBorder(frame)
if frame.GetRegions then
local regions = { frame:GetRegions() }
for i = 1, table.getn(regions) do
local region = regions[i]
local name = region.GetName and region:GetName()
if name and string.find(name, "Border$") and region.GetObjectType and region:GetObjectType() == "Texture" then
LockTextureBorder(region)
end
end
end
if frame.GetChildren then
local children = { frame:GetChildren() }
for i = 1, table.getn(children) do LockTree(children[i]) end
end
end
-- find the addon frames that exist already, anywhere below UIParent
local function FindAddonFrames(frame)
local children = { frame:GetChildren() }
for i = 1, table.getn(children) do
local child = children[i]
if IsAddonFrameName(child.GetName and child:GetName()) then
LockTree(child)
else
FindAddonFrames(child)
end
end
end
-- The round border of addon minimap buttons (most use the stock tracking
-- border texture). Those buttons are often made after login.
local function TintMinimapButton(frame)
if not frame or not frame.GetRegions then return end
local regions = { frame:GetRegions() }
for i = 1, table.getn(regions) do
local region = regions[i]
local texture = region.GetTexture and region:GetTexture()
if texture and string.find(string.lower(texture), "minimap%-trackingborder") then
region:SetVertexColor(tint.r, tint.g, tint.b, 1)
end
end
end
local function RecolorOnShow(frame)
if not frame or frame.stRecolorOnShow then return end
frame.stRecolorOnShow = true
ShaguTweaks.HookScript(frame, "OnShow", function()
DarkenFrame(frame)
if _G.C_Timer and _G.C_Timer.After then
_G.C_Timer.After(0, function() DarkenFrame(frame) end)
end
end)
if frame:IsShown() then DarkenFrame(frame) end
end
local function LockAddonFrames()
FindAddonFrames(UIParent)
for name in pairs(showframes) do RecolorOnShow(_G[name]) end
if Minimap then
local buttons = { Minimap:GetChildren() }
for i = 1, table.getn(buttons) do TintMinimapButton(buttons[i]) end
end
-- frames those addons create later: named after the addon, or created
-- inside one of their frames (templates bring their children along)
local create = CreateFrame
CreateFrame = function(a1, a2, a3, a4, a5, a6)
local frame = create(a1, a2, a3, a4, a5, a6)
if frame and (IsAddonFrameName(a2) or (type(a3) == "table" and a3.stBorderLock)) then
LockTree(frame)
end
if frame and type(a2) == "string" and showframes[a2] then RecolorOnShow(frame) end
-- buttons that get an extra border (VCB buffs made after login)
if frame and type(a2) == "string" then
for pattern, inset in pairs(borders) do
if string.find(a2, pattern) then AddBorder(frame, inset, edge) end
end
end
-- minimap buttons get their border texture right after they are made
if frame and a3 and a3 == Minimap then
if _G.C_Timer and _G.C_Timer.After then
_G.C_Timer.After(0, function() TintMinimapButton(frame) end)
end
end
return frame
end
end
local function Apply(tintColor, edgeColor, darkBackgrounds)
if tint then return end
tint, edge = tintColor, edgeColor
ShaguTweaks.UITint = tint
ShaguTweaks.UIBorder = edge
local name, original, r, g, b
local hookBuffButton_Update = BuffButton_Update
@@ -220,23 +437,32 @@ module.enable = function(self)
elseif not original and _G[name] then
-- tbc buff buttons don't have borders, so we
-- need to manually add a dark one.
AddBorder(_G[name], 2, module.config["darkmode.color"])
AddBorder(_G[name], 2, edge)
end
end
TOOLTIP_DEFAULT_COLOR.r = module.config["darkmode.color"].r
TOOLTIP_DEFAULT_COLOR.g = module.config["darkmode.color"].g
TOOLTIP_DEFAULT_COLOR.b = module.config["darkmode.color"].b
TOOLTIP_DEFAULT_COLOR.r = edge.r
TOOLTIP_DEFAULT_COLOR.g = edge.g
TOOLTIP_DEFAULT_COLOR.b = edge.b
TOOLTIP_DEFAULT_BACKGROUND_COLOR.r = module.config["darkmode.color"].r
TOOLTIP_DEFAULT_BACKGROUND_COLOR.g = module.config["darkmode.color"].g
TOOLTIP_DEFAULT_BACKGROUND_COLOR.b = module.config["darkmode.color"].b
-- Darkened UI also greys the tooltip background; Golden UI keeps it.
if darkBackgrounds then
TOOLTIP_DEFAULT_BACKGROUND_COLOR.r = tint.r
TOOLTIP_DEFAULT_BACKGROUND_COLOR.g = tint.g
TOOLTIP_DEFAULT_BACKGROUND_COLOR.b = tint.b
end
DarkenFrame(UIParent)
DarkenFrame(WorldMapFrame)
DarkenFrame(DropDownList1)
DarkenFrame(DropDownList2)
DarkenFrame(DropDownList3)
LockAddonFrames()
-- the loot window gets its art set again when it opens
if LootFrame then
ShaguTweaks.HookScript(LootFrame, "OnShow", function() DarkenFrame(LootFrame) end)
end
-- align all actionbutton textures
local bars = { "Action", "BonusAction", "MultiBarBottomLeft", "MultiBarBottomRight", "MultiBarLeft", "MultiBarRight", "Shapeshift" }
@@ -259,7 +485,7 @@ module.enable = function(self)
if button[func] then
local tex = button[func](button)
if tex then
tex:SetVertexColor(module.config["darkmode.color"].r+.2, module.config["darkmode.color"].g+.2, module.config["darkmode.color"].b+.2, 1)
tex:SetVertexColor(math.min(tint.r+.2, 1), math.min(tint.g+.2, 1), math.min(tint.b+.2, 1), 1)
end
end
end
@@ -268,12 +494,12 @@ module.enable = function(self)
HookAddonOrVariable("Blizzard_AuctionUI", function()
for i = 1, 15 do
local tex = _G["AuctionFilterButton"..i]:GetNormalTexture()
tex:SetVertexColor(module.config["darkmode.color"].r, module.config["darkmode.color"].g, module.config["darkmode.color"].b, 1)
tex:SetVertexColor(tint.r, tint.g, tint.b, 1)
end
for i = 1, 8 do
_G["BrowseButton"..i.."Left"]:SetVertexColor(module.config["darkmode.color"].r, module.config["darkmode.color"].g, module.config["darkmode.color"].b, 1)
_G["BrowseButton"..i.."Right"]:SetVertexColor(module.config["darkmode.color"].r, module.config["darkmode.color"].g, module.config["darkmode.color"].b, 1)
_G["BrowseButton"..i.."Left"]:SetVertexColor(tint.r, tint.g, tint.b, 1)
_G["BrowseButton"..i.."Right"]:SetVertexColor(tint.r, tint.g, tint.b, 1)
end
end)
@@ -413,3 +639,28 @@ module.enable = function(self)
table.insert(ShaguTweaks.libnameplate.OnShow, ReapplyShaguDarkMode)
end
end
module.enable = function(self)
ShaguTweaks.DarkMode = true
Apply(module.config["darkmode.color"], module.config["darkmode.color"], true)
end
golden.enable = function(self)
-- Both recolor the same textures; Darkened UI wins when both are ticked.
if ShaguTweaks_config and ShaguTweaks_config[T["Darkened UI"]] == 1 then return end
ShaguTweaks.GoldMode = true
Apply(golden.config["goldmode.color"], golden.config["goldmode.border"], false)
-- the softer, browner gold of WoW Forever's titles and labels instead of
-- the stock bright yellow (every text that uses the "normal" gold font)
local text = golden.config["goldmode.text"]
local r, g, b = tonumber(text.r) or .84, tonumber(text.g) or .72, tonumber(text.b) or .48
if NORMAL_FONT_COLOR then
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b = r, g, b
end
local fonts = { "GameFontNormal", "GameFontNormalSmall", "GameFontNormalLarge", "GameFontNormalHuge" }
for i = 1, table.getn(fonts) do
local font = _G[fonts[i]]
if font and font.SetTextColor then font:SetTextColor(r, g, b) end
end
end