diff --git a/CHANGELOG.md b/CHANGELOG.md index fd211a4..c4fd34c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ Changes in this fork (OEVG/ShaguTweaks-ClassicAPI), newest first. Each entry is This fork is based on [Dusk/ShaguTweaks-ClassicAPI](https://octowow.st/git/Dusk/ShaguTweaks-ClassicAPI) at commit `4391564` (2026-09-08). Earlier changes are in that repository's history. +## 3.7.3 — 2026-11-03 — Golden UI + +### Added + +- **Golden UI** (Interface, off): the Darkened UI recolor with a gold palette, like the WoW Forever client. Frame art is tinted gold (`goldmode.color`, default 1, .78, .4), and backdrop borders, tooltip borders and the borders around buttons get a softer gold (`goldmode.border`, default .8, .62, .32). Tooltip and dialog backgrounds keep their own colors. Both colors can be changed with `/st`. If Darkened UI is also enabled, Darkened UI wins and Golden UI does nothing. + +### Changed + +- **Golden UI** also turns the stock bright yellow text (titles, names, labels: everything in the normal gold font) into WoW Forever's softer, browner gold (`goldmode.text`, default .84, .72, .48). +- **Darkened UI and Golden UI** tint the round border of addon minimap buttons (the stock tracking border, as on RollFor's button), also when the addon makes its button after login. +- **Darkened UI and Golden UI** now keep these addons' borders in the palette too, even when they set their colors again later or open a window after login: ShaguDPS, Bagshui, Outfitter, SoulstoneTracker, TrinketMenu, OctoBus, RollFor and VCB. Outfitter's own window art and the lower half of Artisan's profession window (its own textures, which stayed silver) are tinted too, VCB's buff and weapon-buff buttons get a border like the Blizzard buff buttons, the loot window, and RollFor's classic loot window (its own art plus the item rows), are recolored each time they open, and Loot Quality draws common (white) items with the palette's border color. Only light grey, white and silver borders change; colored ones (item quality, hover highlights, class or theme colors) and dark ones stay as the addon draws them. No change is needed in those addons. +- **Darkened UI:** works the same, but now shares its recolor code with Golden UI. Big Health's replacement unit frame art follows whichever of the two is on. + +### Fixed + +- **Tooltip Details:** the health numbers sit centered on the tooltip's health bar instead of sticking out over its top border. + ## 3.7.2 — 2026-11-02 — Loss of Control Alert, Totem Timers and Movable Cast Bar ### Added diff --git a/README.md b/README.md index f2c7cab..8ae2771 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This is an English-only customization of [Dusk/ShaguTweaks-ClassicAPI](https://o > This fork requires ClassicAPI and targets **Turtle WoW-like server/client environments**. -**Version 3.7.2.** What changed in each update: see the [changelog](CHANGELOG.md). +**Version 3.7.3.** What changed in each update: see the [changelog](CHANGELOG.md). > **Upgrading to 3.7:** the modules of the separate *ShaguTweaks Extras ClassicAPI* addon are now built into ShaguTweaks. **Disable or delete `ShaguTweaks-extras`** after updating, otherwise its older copies replace the built-in ones. Your on/off settings carry over. Raid Frames, Bag Item Click, Bag Search Bar and Auction Alt-Buy were not merged. See [Docs/EXTRAS_MERGE.md](Docs/EXTRAS_MERGE.md) for where each module went and why some were left out. @@ -231,6 +231,7 @@ Names match the in-game options list. Modules marked *(off)* are disabled until ### Interface - Darkened UI *(off)* +- Golden UI *(off)*: gold borders, tooltips and dialogs like the WoW Forever client. Darkened UI and Golden UI also recolor the borders of ShaguDPS, Bagshui, Outfitter, SoulstoneTracker, TrinketMenu, OctoBus, RollFor and VCB, and of addon minimap buttons; Golden UI also uses WoW Forever's softer gold for titles and labels. - Hide Errors *(off)* - Smaller Error Frame *(off)* - Loss of Control Alert *(off)* diff --git a/ShaguTweaks.toc b/ShaguTweaks.toc index 0d9eddf..4eede0e 100644 --- a/ShaguTweaks.toc +++ b/ShaguTweaks.toc @@ -2,7 +2,7 @@ ## Title: |cffffcc00Shagu|cffffffffTweaks |cffcccccc[ClassicAPI] ## Author: Shagu ## Notes: A collection of tweaks and enhancements to the Default UI -## Version: 3.7.2 +## Version: 3.7.3 ## Dependencies: !!!ClassicAPI ## SavedVariables: ShaguTweaks_player_cache, ShaguTweaks_social_cache ## SavedVariablesPerCharacter: ShaguTweaks_config, ShaguTweaks_cache diff --git a/locales/translations_enUS.lua b/locales/translations_enUS.lua index e5dd256..678a842 100644 --- a/locales/translations_enUS.lua +++ b/locales/translations_enUS.lua @@ -23,6 +23,8 @@ ShaguTweaks_translation["enUS"] = { ["Copy website URLs from the chat, transforms CLINKs into real items and handles quest and player links."] = nil, ["Cursor"] = nil, ["Darkened UI"] = nil, + ["Golden UI"] = nil, + ["Turns the borders of the interface, tooltips and dialogs gold, like the WoW Forever client. Darkened UI takes priority when both are enabled."] = nil, ["Debuff Timer"] = nil, ["Display health, class color, guild name, guild rank and current target on unit tooltips."] = nil, ["Display the remaining duration as text on every cooldown."] = nil, diff --git a/mods/dark-ui-elements.lua b/mods/dark-ui-elements.lua index ee31f3c..bbc0673 100644 --- a/mods/dark-ui-elements.lua +++ b/mods/dark-ui-elements.lua @@ -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 diff --git a/mods/loot-quality.lua b/mods/loot-quality.lua index 0ff713f..51ff24d 100755 --- a/mods/loot-quality.lua +++ b/mods/loot-quality.lua @@ -89,8 +89,14 @@ module.enable = function(self) return end - self.border:SetVertexColor(color.r, color.g, color.b) - self.highlight:SetVertexColor(color.r, color.g, color.b) + -- Common (white) items get the Darkened/Golden UI border color instead + -- of white; every other quality keeps its color. + local r, g, b = color.r, color.g, color.b + local edge = ShaguTweaks.UIBorder + if edge and r > .9 and g > .9 and b > .9 then r, g, b = edge.r, edge.g, edge.b end + + self.border:SetVertexColor(r, g, b) + self.highlight:SetVertexColor(r, g, b) self.border:Show() self.highlight:Show() diff --git a/mods/tooltip-details.lua b/mods/tooltip-details.lua index 6475ffe..07a6154 100644 --- a/mods/tooltip-details.lua +++ b/mods/tooltip-details.lua @@ -283,7 +283,8 @@ module.enable = function(self) "Status", "DIALOG", "GameFontWhite") GameTooltipStatusBar.backdrop.health:SetFont( STANDARD_TEXT_FONT, 12, "OUTLINE") - GameTooltipStatusBar.backdrop.health:SetPoint("TOP", 0, 4) + -- centered on the bar: anchored to the top it stuck out over the border + GameTooltipStatusBar.backdrop.health:SetPoint("CENTER", GameTooltipStatusBar, "CENTER", 0, 1) GameTooltipStatusBar.backdrop.health:SetNonSpaceWrap(false) -- Preserve the real statusbar method for Blizzard and other addons. A diff --git a/mods/unitframes-bighealth.lua b/mods/unitframes-bighealth.lua index 7ced019..2d08ee4 100644 --- a/mods/unitframes-bighealth.lua +++ b/mods/unitframes-bighealth.lua @@ -32,16 +32,9 @@ module.enable = function(self) -- Apply the configured dark tint directly to our replacement textures so the -- result is deterministic without adding any permanent OnUpdate work. local function ApplyDarkModeTextures() - if not ShaguTweaks.DarkMode then return end - - local darkModule = ShaguTweaks.mods[T["Darkened UI"]] - local color = ShaguTweaks_config - and ShaguTweaks_config.overwrites - and ShaguTweaks_config.overwrites["darkmode.color"] - - color = color - or (darkModule and darkModule.config and darkModule.config["darkmode.color"]) - + -- Darkened UI or Golden UI publish their texture tint here, with the + -- /st overwrites already applied. + local color = ShaguTweaks.UITint if not color then return end local r = tonumber(color.r) or color.r