From 0784e2e5bb971666eebdc84647712d74c5448df9 Mon Sep 17 00:00:00 2001 From: OEVG <950+oevg@noreply.octowow.st> Date: Tue, 3 Nov 2026 07:52:40 +0000 Subject: [PATCH] Golden UI: Forever-brown window title bars; mail inbox gets the send page's stationery (3.7.3 hotfix) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_019W3rwusM4i1CYaHQAYixJ7 --- CHANGELOG.md | 2 + mods/dark-ui-elements.lua | 128 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4fd34c..e136bfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This fork is based on [Dusk/ShaguTweaks-ClassicAPI](https://octowow.st/git/Dusk/ ### 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). +- **Golden UI** darkens the window title bars to WoW Forever's red-brown (`goldmode.bar`, default .8, .63, .62): world map, character, spellbook, quest log, merchant, friends, mail and RollFor's classic loot window. Where the title sits in the same layer as the art, the title is drawn again on top of the bar; the quest log's white title now uses the same gold as the others, and the lighter patch in the world map's stone art is evened out. +- **Darkened UI and Golden UI** give the mail inbox the same stationery page as the send page. Its parchment art turned strongly red under Golden UI. - **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. diff --git a/mods/dark-ui-elements.lua b/mods/dark-ui-elements.lua index bbc0673..556840c 100644 --- a/mods/dark-ui-elements.lua +++ b/mods/dark-ui-elements.lua @@ -28,6 +28,7 @@ local golden = ShaguTweaks:register({ ["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 }, + ["goldmode.bar"] = { r = .8, g = .63, b = .62, a = 1 }, } }) @@ -78,6 +79,9 @@ local backgrounds = { ["^QuestLogDetailScrollFrame$"] = { QuestLogDetailScrollChildFrame:GetWidth(), QuestLogDetailScrollChildFrame:GetHeight(), 0, 0 }, ["^QuestFrame(.+)Panel$"] = { 300, 330, 24, -82 }, ["^GossipFrameGreetingPanel$"] = { 300, 330, 24, -82 }, + -- the mail inbox uses the same parchment art as ItemTextFrame; the send + -- page already has its own stationery on top + ["^InboxFrame$"] = { 300, 355, 24, -74 }, } local borders = { @@ -371,6 +375,7 @@ end local function RecolorOnShow(frame) if not frame or frame.stRecolorOnShow then return end frame.stRecolorOnShow = true + if golden.rollforLoot and frame:GetName() == "RollForLootFrameHeader" then golden.rollforLoot(frame) end ShaguTweaks.HookScript(frame, "OnShow", function() DarkenFrame(frame) if _G.C_Timer and _G.C_Timer.After then @@ -645,6 +650,125 @@ module.enable = function(self) Apply(module.config["darkmode.color"], module.config["darkmode.color"], true) end +-- Title bars: the dark strips the window titles sit on. Golden UI +-- multiplies them toward WoW Forever's red-brown with a MOD layer. Measured +-- from the window art: rows below the frame's top edge, and how far the strip +-- runs from the left (after the portrait) and from the right (before the +-- close button). +local STRIP_A = { 72, -16, -60, -34 } -- character, spellbook, mail, quest log art +local STRIP_B = { 72, -15, -62, -33 } -- merchant, friends art + +local function Shade(parent, layer, color) + local shade = parent:CreateTexture(nil, layer) + shade:SetTexture(1, 1, 1, 1) + shade:SetVertexColor(tonumber(color.r) or .8, tonumber(color.g) or .63, tonumber(color.b) or .62, 1) + shade:SetBlendMode("MOD") + return shade +end + +local function PlaceStrip(shade, frame, strip) + shade:ClearAllPoints() + shade:SetPoint("TOPLEFT", frame, "TOPLEFT", strip[1], strip[2]) + shade:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", strip[3], strip[4]) +end + +-- The shade has to sit above the window art, which would darken a title +-- that is drawn in the same frame. Those titles are drawn again on top and +-- the original is kept, invisible, for its position and text. +local function RedrawTitle(holder, title, gold) + if not title then return end + local copy = holder:CreateFontString(nil, "OVERLAY", "GameFontNormal") + local font = not gold and title.GetFontObject and title:GetFontObject() + if font then copy:SetFontObject(font) end + -- titles drawn in white (Turtle's quest log) get the same gold as the rest + if gold and NORMAL_FONT_COLOR then + copy:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b) + end + copy:SetAllPoints(title) + if title.GetJustifyH then copy:SetJustifyH(title:GetJustifyH()) end + copy:SetText(title:GetText()) + title:SetAlpha(0) + + local setText = title.SetText + title.SetText = function(self, text) + setText(self, text) + copy:SetText(text) + end + return copy +end + +local function ShadeTitleBar(frame, strip, title, color, level, gold) + if not frame or frame.stTitleBar then return end + local bar = CreateFrame("Frame", nil, frame) + bar:SetAllPoints(frame) + if level then bar:SetFrameLevel(level) end + frame.stTitleBar = bar + bar.shade = Shade(bar, "BACKGROUND", color) + PlaceStrip(bar.shade, frame, strip) + bar.title = RedrawTitle(bar, title, gold) + return bar +end + +-- frames whose titles live in child frames (or above the art layer): the +-- shade is a plain texture in the window itself, nothing to redraw +local function ShadeStripInFrame(frame, strip, layer, color) + if not frame or frame.stTitleShade then return end + frame.stTitleShade = Shade(frame, layer, color) + PlaceStrip(frame.stTitleShade, frame, strip) +end + +local function ShadeTitleBars(color) + -- world map: its strip is 3 to 21 px below the top of its art (384 above + -- the frame center), from the left corner to the window buttons + if WorldMapFrame and WorldMapFrameTitle and not WorldMapFrame.stTitleBar then + local bar = ShadeTitleBar(WorldMapFrame, { 0, 0, 0, 0 }, WorldMapFrameTitle, color) + bar.shade:ClearAllPoints() + bar.shade:SetPoint("TOPLEFT", WorldMapFrame, "CENTER", -510, 381) + bar.shade:SetPoint("BOTTOMRIGHT", WorldMapFrame, "CENTER", 455, 363) + + -- the stone art is lighter around the seam of its first two pieces + -- (measured in 8 px columns): darken those columns a bit more so the + -- bar comes out even + local even = { + { -272, .81 }, { -264, .76 }, + { -256, .66 }, { -248, .52 }, { -240, .49 }, { -232, .47 }, { -224, .53 }, { -216, .54 }, + { -208, .52 }, { -200, .58 }, { -192, .69 }, { -184, .76 }, { -176, .68 }, { -168, .68 }, + { -160, .69 }, { -152, .71 }, { -144, .78 }, { -136, .86 }, + } + for i = 1, table.getn(even) do + local x, f = even[i][1], even[i][2] + local fix = Shade(bar, "BACKGROUND", { r = f, g = f, b = f }) + fix:SetPoint("TOPLEFT", WorldMapFrame, "CENTER", x, 381) + fix:SetPoint("BOTTOMRIGHT", WorldMapFrame, "CENTER", x + 8, 363) + end + end + + ShadeTitleBar(MerchantFrame, STRIP_B, MerchantNameText, color) + ShadeTitleBar(SpellBookFrame, STRIP_A, SpellBookTitleText, color) + ShadeTitleBar(FriendsFrame, STRIP_B, FriendsFrameTitleText, color) + -- the quest log is wider: its strip ends before the close button + ShadeTitleBar(QuestLogFrame, { 72, -16, -121, -34 }, QuestLogTitleText, color, nil, true) + + -- mail: the art is on the BORDER layer, the titles are on the page frames + ShadeStripInFrame(MailFrame, STRIP_A, "ARTWORK", color) + + -- character: the art is on the tab pages (PaperDollFrame and the others), + -- the name on CharacterNameFrame. The shade goes between the two. + if CharacterFrame and PaperDollFrame and CharacterNameFrame then + local level = PaperDollFrame:GetFrameLevel() + 1 + if CharacterNameFrame:GetFrameLevel() <= level then CharacterNameFrame:SetFrameLevel(level + 1) end + ShadeTitleBar(CharacterFrame, STRIP_A, nil, color, level) + end +end + +-- RollFor's classic loot window: the art is on the BACKGROUND layer and the +-- "Items" title on ARTWORK, so the shade fits between them. The strip runs +-- 12 to 30 px down, from the portrait to 25 px before the right edge (the +-- window width changes with the item names). +local function ShadeRollForLoot(frame, color) + ShadeStripInFrame(frame, { 68, -12, -25, -30 }, "BORDER", color) +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 @@ -663,4 +787,8 @@ golden.enable = function(self) local font = _G[fonts[i]] if font and font.SetTextColor then font:SetTextColor(r, g, b) end end + + ShadeTitleBars(golden.config["goldmode.bar"]) + golden.rollforLoot = function(frame) ShadeRollForLoot(frame, golden.config["goldmode.bar"]) end + if _G.RollForLootFrameHeader then golden.rollforLoot(_G.RollForLootFrameHeader) end end