-------------------------------------------------------------------------------- -- Nanami-UI: Game Menu (GameMenu.lua) -- Reskins the ESC menu (GameMenuFrame) with pink cat-paw theme -------------------------------------------------------------------------------- SFrames.GameMenu = {} local GM = SFrames.GameMenu -------------------------------------------------------------------------------- -- Theme: Pink Cat-Paw -------------------------------------------------------------------------------- local T = SFrames.ActiveTheme local BUTTON_W = 170 local BUTTON_H = 26 local BUTTON_GAP = 5 local SIDE_PAD = 16 local HEADER_H = 32 -------------------------------------------------------------------------------- -- Helpers -------------------------------------------------------------------------------- local function GetFont() if SFrames and SFrames.GetFont then return SFrames:GetFont() end return "Fonts\\ARIALN.TTF" end local function SetRoundBackdrop(frame, bgColor, borderColor) frame:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 16, edgeSize = 14, insets = { left = 3, right = 3, top = 3, bottom = 3 }, }) local bg = bgColor or T.panelBg local bd = borderColor or T.panelBorder frame:SetBackdropColor(bg[1], bg[2], bg[3], bg[4] or 1) frame:SetBackdropBorderColor(bd[1], bd[2], bd[3], bd[4] or 1) end local function CreateShadow(parent, size) local s = CreateFrame("Frame", nil, parent) local sz = size or 4 s:SetPoint("TOPLEFT", parent, "TOPLEFT", -sz, sz) s:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", sz, -sz) s:SetFrameLevel(math.max(parent:GetFrameLevel() - 1, 0)) s:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 16, edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4 }, }) s:SetBackdropColor(0, 0, 0, 0.55) s:SetBackdropBorderColor(0, 0, 0, 0.4) return s end local function HideTexture(tex) if not tex then return end if tex.SetTexture then tex:SetTexture(nil) end if tex.SetAlpha then tex:SetAlpha(0) end if tex.Hide then tex:Hide() end end -------------------------------------------------------------------------------- -- Button Styling -------------------------------------------------------------------------------- local MENU_BUTTON_ICONS = { ["GameMenuButtonContinue"] = "exit", ["GameMenuButtonOptions"] = "settings", ["GameMenuButtonSoundOptions"] = "sound", ["GameMenuButtonUIOptions"] = "talent", ["GameMenuButtonKeybindings"] = "menu", ["GameMenuButtonRatings"] = "backpack", ["GameMenuButtonMacros"] = "ai", ["GameMenuButtonLogout"] = "close", ["GameMenuButtonQuit"] = "logout", } local function StyleMenuButton(btn) if not btn or btn.nanamiStyled then return end btn.nanamiStyled = true HideTexture(btn:GetNormalTexture()) HideTexture(btn:GetPushedTexture()) HideTexture(btn:GetHighlightTexture()) HideTexture(btn:GetDisabledTexture()) local name = btn:GetName() or "" for _, suffix in ipairs({ "Left", "Right", "Middle" }) do local tex = _G[name .. suffix] if tex then tex:SetAlpha(0); tex:Hide() end end SetRoundBackdrop(btn, T.btnBg, T.btnBorder) btn:SetWidth(BUTTON_W) btn:SetHeight(BUTTON_H) local iconKey = MENU_BUTTON_ICONS[name] local icoSize = 12 local gap = 4 local fs = btn:GetFontString() if fs then fs:SetFont(GetFont(), 11, "OUTLINE") fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3]) fs:ClearAllPoints() if iconKey and SFrames and SFrames.CreateIcon then local ico = SFrames:CreateIcon(btn, iconKey, icoSize) ico:SetDrawLayer("OVERLAY") ico:SetVertexColor(T.btnText[1], T.btnText[2], T.btnText[3]) fs:SetPoint("CENTER", btn, "CENTER", (icoSize + gap) / 2, 0) ico:SetPoint("RIGHT", fs, "LEFT", -gap, 0) btn.nanamiIcon = ico else fs:SetPoint("CENTER", btn, "CENTER", 0, 0) end end local origEnter = btn:GetScript("OnEnter") local origLeave = btn:GetScript("OnLeave") local origDown = btn:GetScript("OnMouseDown") local origUp = btn:GetScript("OnMouseUp") btn:SetScript("OnEnter", function() if origEnter then origEnter() end this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4]) this:SetBackdropBorderColor(T.btnHoverBorder[1], T.btnHoverBorder[2], T.btnHoverBorder[3], T.btnHoverBorder[4]) local txt = this:GetFontString() if txt then txt:SetTextColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3]) end if this.nanamiIcon then this.nanamiIcon:SetVertexColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3]) end end) btn:SetScript("OnLeave", function() if origLeave then origLeave() end this:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4]) this:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4]) local txt = this:GetFontString() if txt then txt:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3]) end if this.nanamiIcon then this.nanamiIcon:SetVertexColor(T.btnText[1], T.btnText[2], T.btnText[3]) end end) btn:SetScript("OnMouseDown", function() if origDown then origDown() end this:SetBackdropColor(T.btnDownBg[1], T.btnDownBg[2], T.btnDownBg[3], T.btnDownBg[4]) end) btn:SetScript("OnMouseUp", function() if origUp then origUp() end this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4]) end) end -------------------------------------------------------------------------------- -- Create Settings Button -------------------------------------------------------------------------------- local settingsBtn local function CreateSettingsButton(parent) if settingsBtn then return settingsBtn end local btn = CreateFrame("Button", "GameMenuButtonNanamiUI", parent) btn:SetWidth(BUTTON_W) btn:SetHeight(BUTTON_H) SetRoundBackdrop(btn, T.btnBg, T.btnBorder) local icoSize = 14 local gap = 4 local fs = btn:CreateFontString(nil, "OVERLAY") fs:SetFont(GetFont(), 11, "OUTLINE") fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3]) fs:SetPoint("CENTER", btn, "CENTER", (icoSize + gap) / 2, 0) fs:SetText("Nanami-UI 设置") local ico = SFrames:CreateIcon(btn, "logo", icoSize) ico:SetDrawLayer("OVERLAY") ico:SetVertexColor(T.btnText[1], T.btnText[2], T.btnText[3]) ico:SetPoint("RIGHT", fs, "LEFT", -gap, 0) btn.nanamiIcon = ico btn:SetScript("OnClick", function() HideUIPanel(GameMenuFrame) if SFrames.ConfigUI and SFrames.ConfigUI.Build then SFrames.ConfigUI:Build("ui") end end) btn:SetScript("OnEnter", function() this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4]) this:SetBackdropBorderColor(T.btnHoverBorder[1], T.btnHoverBorder[2], T.btnHoverBorder[3], T.btnHoverBorder[4]) fs:SetTextColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3]) ico:SetVertexColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3]) end) btn:SetScript("OnLeave", function() this:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4]) this:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4]) fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3]) ico:SetVertexColor(T.btnText[1], T.btnText[2], T.btnText[3]) end) btn:SetScript("OnMouseDown", function() this:SetBackdropColor(T.btnDownBg[1], T.btnDownBg[2], T.btnDownBg[3], T.btnDownBg[4]) end) btn:SetScript("OnMouseUp", function() this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4]) end) btn.nanamiStyled = true settingsBtn = btn return btn end -------------------------------------------------------------------------------- -- Known button priority order (covers vanilla + Turtle WoW extras) -------------------------------------------------------------------------------- local BUTTON_ORDER = { "GameMenuButtonContinue", "__NANAMI_SETTINGS__", "GameMenuButtonOptions", "GameMenuButtonSoundOptions", "GameMenuButtonUIOptions", "GameMenuButtonKeybindings", "GameMenuButtonRatings", "GameMenuButtonMacros", "GameMenuButtonLogout", "GameMenuButtonQuit", } -------------------------------------------------------------------------------- -- Frame Styling (called once at PLAYER_LOGIN, before first show) -------------------------------------------------------------------------------- local styled = false local function StyleGameMenuFrame() if styled then return end if not GameMenuFrame then return end styled = true -- Hide all default background textures and header text local regions = { GameMenuFrame:GetRegions() } for _, region in ipairs(regions) do if region then local otype = region:GetObjectType() if otype == "Texture" then region:SetTexture(nil) region:SetAlpha(0) region:Hide() elseif otype == "FontString" then region:SetAlpha(0) region:Hide() end end end SetRoundBackdrop(GameMenuFrame, T.panelBg, T.panelBorder) CreateShadow(GameMenuFrame, 5) -- Title local title = GameMenuFrame:CreateFontString(nil, "OVERLAY") title:SetFont(GetFont(), 13, "OUTLINE") title:SetTextColor(T.titleColor[1], T.titleColor[2], T.titleColor[3]) title:SetPoint("TOP", GameMenuFrame, "TOP", 0, -11) title:SetText("Nanami-UI") -- Create settings button local sBt = CreateSettingsButton(GameMenuFrame) -- Build a lookup of known names for quick check local knownSet = {} for _, name in ipairs(BUTTON_ORDER) do if name ~= "__NANAMI_SETTINGS__" then knownSet[name] = true end end -- Collect all child buttons that are NOT the settings button local children = { GameMenuFrame:GetChildren() } local unknownBtns = {} for _, child in ipairs(children) do if child and child:GetObjectType() == "Button" and child ~= sBt then local cname = child:GetName() if cname and not knownSet[cname] then table.insert(unknownBtns, child) end end end -- Build final ordered button list from BUTTON_ORDER local orderedBtns = {} for _, name in ipairs(BUTTON_ORDER) do if name == "__NANAMI_SETTINGS__" then table.insert(orderedBtns, sBt) else local btn = _G[name] if btn then StyleMenuButton(btn) table.insert(orderedBtns, btn) end end end -- Append unknown / Turtle WoW extra buttons before Logout & Quit local insertBefore = table.getn(orderedBtns) for i = table.getn(orderedBtns), 1, -1 do local bname = orderedBtns[i]:GetName() or "" if bname == "GameMenuButtonLogout" or bname == "GameMenuButtonQuit" then insertBefore = i else break end end for _, btn in ipairs(unknownBtns) do StyleMenuButton(btn) table.insert(orderedBtns, insertBefore, btn) insertBefore = insertBefore + 1 end -- Layout vertically local numBtns = table.getn(orderedBtns) local totalH = numBtns * BUTTON_H + (numBtns - 1) * BUTTON_GAP local frameH = HEADER_H + SIDE_PAD + totalH + SIDE_PAD local frameW = BUTTON_W + SIDE_PAD * 2 GameMenuFrame:SetWidth(frameW) GameMenuFrame:SetHeight(frameH) local startY = -(HEADER_H + SIDE_PAD) for i, btn in ipairs(orderedBtns) do btn:ClearAllPoints() btn:SetPoint("TOP", GameMenuFrame, "TOP", 0, startY - (i - 1) * (BUTTON_H + BUTTON_GAP)) end end -------------------------------------------------------------------------------- -- Hook: style at login, BEFORE any show (avoids OnShow size-change issues) -------------------------------------------------------------------------------- local hookFrame = CreateFrame("Frame") hookFrame:RegisterEvent("PLAYER_LOGIN") hookFrame:SetScript("OnEvent", function() if GameMenuFrame then StyleGameMenuFrame() end end)