382 lines
13 KiB
Lua
382 lines
13 KiB
Lua
-- Helper function to generate ElvUI-style backdrop and shadow border
|
|
function SFrames:ApplyBackdropStyle(frame, opts)
|
|
opts = opts or {}
|
|
local radius = tonumber(opts.cornerRadius) or 0
|
|
local showBorder = opts.showBorder ~= false
|
|
local useRounded = radius and radius > 0
|
|
|
|
if useRounded then
|
|
local edgeSize = math.max(8, math.min(18, math.floor(radius + 0.5)))
|
|
frame:SetBackdrop({
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile = showBorder and "Interface\\Tooltips\\UI-Tooltip-Border" or nil,
|
|
tile = true, tileSize = 16, edgeSize = edgeSize,
|
|
insets = { left = 3, right = 3, top = 3, bottom = 3 }
|
|
})
|
|
else
|
|
frame:SetBackdrop({
|
|
bgFile = "Interface\\Buttons\\WHITE8X8",
|
|
edgeFile = showBorder and "Interface\\Buttons\\WHITE8X8" or nil,
|
|
tile = false, tileSize = 0, edgeSize = 1,
|
|
insets = { left = 1, right = 1, top = 1, bottom = 1 }
|
|
})
|
|
end
|
|
|
|
local A = SFrames.ActiveTheme
|
|
local bgAlpha = opts.bgAlpha
|
|
if A and A.panelBg then
|
|
frame:SetBackdropColor(A.panelBg[1], A.panelBg[2], A.panelBg[3], bgAlpha or A.panelBg[4] or 0.9)
|
|
if showBorder then
|
|
frame:SetBackdropBorderColor(A.panelBorder[1], A.panelBorder[2], A.panelBorder[3], A.panelBorder[4] or 1)
|
|
else
|
|
frame:SetBackdropBorderColor(0, 0, 0, 0)
|
|
end
|
|
else
|
|
frame:SetBackdropColor(0.1, 0.1, 0.1, bgAlpha or 0.9)
|
|
if showBorder then
|
|
frame:SetBackdropBorderColor(0, 0, 0, 1)
|
|
else
|
|
frame:SetBackdropBorderColor(0, 0, 0, 0)
|
|
end
|
|
end
|
|
end
|
|
|
|
function SFrames:CreateBackdrop(frame)
|
|
self:ApplyBackdropStyle(frame)
|
|
end
|
|
|
|
function SFrames:CreateRoundBackdrop(frame)
|
|
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 A = SFrames.ActiveTheme
|
|
if A and A.panelBg then
|
|
frame:SetBackdropColor(A.panelBg[1], A.panelBg[2], A.panelBg[3], A.panelBg[4] or 0.95)
|
|
frame:SetBackdropBorderColor(A.panelBorder[1], A.panelBorder[2], A.panelBorder[3], A.panelBorder[4] or 0.9)
|
|
else
|
|
frame:SetBackdropColor(0.08, 0.08, 0.10, 0.95)
|
|
frame:SetBackdropBorderColor(0.3, 0.3, 0.35, 1)
|
|
end
|
|
end
|
|
|
|
function SFrames:CreateUnitBackdrop(frame)
|
|
SFrames:CreateBackdrop(frame)
|
|
frame:SetBackdropBorderColor(0, 0, 0, 1)
|
|
end
|
|
|
|
function SFrames:ApplyConfiguredUnitBackdrop(frame, prefix, isPortrait)
|
|
if not frame then return end
|
|
local db = SFramesDB or {}
|
|
local bgAlphaKey = prefix .. (isPortrait and "PortraitBgAlpha" or "BgAlpha")
|
|
self:ApplyBackdropStyle(frame, {
|
|
showBorder = false,
|
|
cornerRadius = 0,
|
|
bgAlpha = tonumber(db[bgAlphaKey]) or (isPortrait and tonumber(db[prefix .. "BgAlpha"]) or nil),
|
|
})
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Frame Style Preset helpers
|
|
--------------------------------------------------------------------------------
|
|
|
|
function SFrames:GetFrameStylePreset()
|
|
return (SFramesDB and SFramesDB.frameStylePreset) or "classic"
|
|
end
|
|
|
|
function SFrames:IsGradientStyle()
|
|
return self:GetFrameStylePreset() == "gradient"
|
|
end
|
|
|
|
-- Apply a gradient darkening overlay on a StatusBar.
|
|
-- Uses a separate Texture on OVERLAY layer with purple-black vertex color
|
|
-- and alpha gradient from 0 (left) to ~0.6 (right).
|
|
-- This approach does NOT touch the StatusBar texture itself,
|
|
-- so it survives SetStatusBarColor calls.
|
|
function SFrames:ApplyGradientStyle(bar)
|
|
if not bar then return end
|
|
if not bar._gradOverlay then
|
|
local ov = bar:CreateTexture(nil, "OVERLAY")
|
|
ov:SetTexture("Interface\\Buttons\\WHITE8X8")
|
|
bar._gradOverlay = ov
|
|
end
|
|
local ov = bar._gradOverlay
|
|
ov:ClearAllPoints()
|
|
ov:SetAllPoints(bar:GetStatusBarTexture())
|
|
-- Dark purple-ish tint color
|
|
ov:SetVertexColor(0.04, 0.0, 0.08, 1)
|
|
-- Alpha gradient: left fully transparent → right 65% opaque
|
|
if ov.SetGradientAlpha then
|
|
ov:SetGradientAlpha("HORIZONTAL",
|
|
1, 1, 1, 0,
|
|
1, 1, 1, 0.65)
|
|
end
|
|
ov:Show()
|
|
end
|
|
|
|
function SFrames:RemoveGradientStyle(bar)
|
|
if not bar then return end
|
|
if bar._gradOverlay then
|
|
bar._gradOverlay:Hide()
|
|
end
|
|
end
|
|
|
|
-- No-op wrappers kept for compatibility with unit files
|
|
function SFrames:ApplyBarGradient(bar)
|
|
-- Gradient is now persistent overlay; no per-color-update needed
|
|
end
|
|
function SFrames:ClearBarGradient(bar)
|
|
self:RemoveGradientStyle(bar)
|
|
end
|
|
|
|
-- Strip backdrop from a frame (used in gradient style)
|
|
function SFrames:ClearBackdrop(frame)
|
|
if not frame then return end
|
|
if frame.SetBackdrop then
|
|
frame:SetBackdrop(nil)
|
|
end
|
|
end
|
|
|
|
-- Generator for StatusBars
|
|
function SFrames:CreateStatusBar(parent, name)
|
|
local bar = CreateFrame("StatusBar", name, parent)
|
|
bar:SetStatusBarTexture(SFrames:GetTexture())
|
|
|
|
if (not SFramesDB or SFramesDB.smoothBars ~= false) and SmoothBar then
|
|
SmoothBar(bar)
|
|
end
|
|
|
|
return bar
|
|
end
|
|
|
|
function SFrames:ApplyStatusBarTexture(bar, settingKey, fallbackKey)
|
|
if not bar or not bar.SetStatusBarTexture then return end
|
|
bar:SetStatusBarTexture(self:ResolveBarTexture(settingKey, fallbackKey))
|
|
end
|
|
|
|
-- Generator for FontStrings
|
|
function SFrames:CreateFontString(parent, size, justifyH)
|
|
local fs = parent:CreateFontString(nil, "OVERLAY")
|
|
fs:SetFont(SFrames:GetFont(), size or 12, SFrames.Media.fontOutline)
|
|
fs:SetJustifyH(justifyH or "CENTER")
|
|
fs:SetTextColor(1, 1, 1)
|
|
return fs
|
|
end
|
|
|
|
function SFrames:ApplyFontString(fs, size, fontSettingKey, fallbackFontKey, outlineSettingKey, fallbackOutlineKey)
|
|
if not fs or not fs.SetFont then return end
|
|
local fontPath = self:ResolveFont(fontSettingKey, fallbackFontKey)
|
|
local outline = self:ResolveFontOutline(outlineSettingKey, fallbackOutlineKey)
|
|
fs:SetFont(fontPath, size or 12, outline)
|
|
end
|
|
|
|
function SFrames:FormatCompactNumber(value)
|
|
local num = tonumber(value) or 0
|
|
local sign = num < 0 and "-" or ""
|
|
num = math.abs(num)
|
|
if num >= 1000000 then
|
|
return string.format("%s%.1fM", sign, num / 1000000)
|
|
elseif num >= 10000 then
|
|
return string.format("%s%.1fK", sign, num / 1000)
|
|
end
|
|
return sign .. tostring(math.floor(num + 0.5))
|
|
end
|
|
|
|
function SFrames:FormatCompactPair(currentValue, maxValue)
|
|
return self:FormatCompactNumber(currentValue) .. " / " .. self:FormatCompactNumber(maxValue)
|
|
end
|
|
|
|
-- Generator for 3D Portraits
|
|
function SFrames:CreatePortrait(parent, name)
|
|
local portrait = CreateFrame("PlayerModel", name, parent)
|
|
return portrait
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Class Icon (circular class portraits from UI-Classes-Circles.tga)
|
|
--------------------------------------------------------------------------------
|
|
local CLASS_ICON_PATH = "Interface\\AddOns\\Nanami-UI\\img\\UI-Classes-Circles"
|
|
|
|
SFrames.CLASS_ICON_TCOORDS = {
|
|
["WARRIOR"] = { 0, 0.25, 0, 0.25 },
|
|
["MAGE"] = { 0.25, 0.49609375, 0, 0.25 },
|
|
["ROGUE"] = { 0.49609375, 0.7421875, 0, 0.25 },
|
|
["DRUID"] = { 0.7421875, 0.98828125, 0, 0.25 },
|
|
["HUNTER"] = { 0, 0.25, 0.25, 0.5 },
|
|
["SHAMAN"] = { 0.25, 0.49609375, 0.25, 0.5 },
|
|
["PRIEST"] = { 0.49609375, 0.7421875, 0.25, 0.5 },
|
|
["WARLOCK"] = { 0.7421875, 0.98828125, 0.25, 0.5 },
|
|
["PALADIN"] = { 0, 0.25, 0.5, 0.75 },
|
|
}
|
|
|
|
function SFrames:CreateClassIcon(parent, size)
|
|
local sz = size or 20
|
|
local overlay = CreateFrame("Frame", nil, parent)
|
|
overlay:SetFrameLevel((parent:GetFrameLevel() or 0) + 3)
|
|
overlay:SetWidth(sz)
|
|
overlay:SetHeight(sz)
|
|
|
|
local icon = overlay:CreateTexture(nil, "OVERLAY")
|
|
icon:SetTexture(CLASS_ICON_PATH)
|
|
icon:SetAllPoints(overlay)
|
|
icon:Hide()
|
|
|
|
icon.overlay = overlay
|
|
return icon
|
|
end
|
|
|
|
function SFrames:SetClassIcon(icon, class)
|
|
if not icon then return end
|
|
local coords = self.CLASS_ICON_TCOORDS[class]
|
|
if coords then
|
|
icon:SetTexCoord(coords[1], coords[2], coords[3], coords[4])
|
|
icon:Show()
|
|
if icon.overlay then icon.overlay:Show() end
|
|
else
|
|
icon:Hide()
|
|
if icon.overlay then icon.overlay:Hide() end
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- UI Icon helpers (icon.tga sprite sheet)
|
|
-- SFrames.ICON_PATH and SFrames.ICON_TCOORDS are defined in IconMap.lua
|
|
--------------------------------------------------------------------------------
|
|
|
|
local ICON_SET_VALID = {
|
|
["icon"] = true, ["icon2"] = true, ["icon3"] = true, ["icon4"] = true,
|
|
["icon5"] = true, ["icon6"] = true, ["icon7"] = true, ["icon8"] = true,
|
|
}
|
|
|
|
local function GetIconPath()
|
|
local set = SFramesDB and SFramesDB.Theme and SFramesDB.Theme.iconSet
|
|
if set and ICON_SET_VALID[set] then
|
|
return "Interface\\AddOns\\Nanami-UI\\img\\" .. set
|
|
end
|
|
return "Interface\\AddOns\\Nanami-UI\\img\\icon"
|
|
end
|
|
|
|
local ICON_TEX = GetIconPath()
|
|
|
|
local ICON_TC_FALLBACK = {
|
|
["logo"] = { 0, 0.125, 0, 0.125 },
|
|
["save"] = { 0.125, 0.25, 0, 0.125 },
|
|
["close"] = { 0.25, 0.375, 0, 0.125 },
|
|
["offline"] = { 0.375, 0.5, 0, 0.125 },
|
|
["chat"] = { 0, 0.125, 0.125, 0.25 },
|
|
["settings"] = { 0.125, 0.25, 0.125, 0.25 },
|
|
["ai"] = { 0.25, 0.375, 0.125, 0.25 },
|
|
["backpack"] = { 0.375, 0.5, 0.125, 0.25 },
|
|
["exit"] = { 0, 0.125, 0.25, 0.375 },
|
|
["party"] = { 0.125, 0.25, 0.25, 0.375 },
|
|
["loot"] = { 0.25, 0.375, 0.25, 0.375 },
|
|
["dragon"] = { 0.375, 0.5, 0.25, 0.375 },
|
|
["casting"] = { 0, 0.125, 0.375, 0.5 },
|
|
["attack"] = { 0.125, 0.25, 0.375, 0.5 },
|
|
["damage"] = { 0.25, 0.375, 0.375, 0.5 },
|
|
["latency"] = { 0.375, 0.5, 0.375, 0.5 },
|
|
["admin"] = { 0, 0.125, 0.125, 0.25 },
|
|
["bank"] = { 0.25, 0.375, 0.25, 0.375 },
|
|
["perf"] = { 0.25, 0.375, 0.375, 0.5 },
|
|
}
|
|
|
|
local ICON_TC = SFrames.ICON_TCOORDS or ICON_TC_FALLBACK
|
|
|
|
function SFrames:CreateIcon(parent, iconKey, size)
|
|
local sz = size or 16
|
|
local tex = parent:CreateTexture(nil, "ARTWORK")
|
|
tex:SetTexture(GetIconPath())
|
|
tex:SetWidth(sz)
|
|
tex:SetHeight(sz)
|
|
|
|
local coords = ICON_TC[iconKey]
|
|
if not coords and self.ICON_TCOORDS then
|
|
coords = self.ICON_TCOORDS[iconKey]
|
|
end
|
|
if coords then
|
|
tex:SetTexCoord(coords[1], coords[2], coords[3], coords[4])
|
|
end
|
|
return tex
|
|
end
|
|
|
|
function SFrames:SetIcon(tex, iconKey)
|
|
if not tex then return end
|
|
tex:SetTexture(GetIconPath())
|
|
local coords = ICON_TC[iconKey]
|
|
if not coords and self.ICON_TCOORDS then
|
|
coords = self.ICON_TCOORDS[iconKey]
|
|
end
|
|
if coords then
|
|
tex:SetTexCoord(coords[1], coords[2], coords[3], coords[4])
|
|
tex:Show()
|
|
else
|
|
tex:Hide()
|
|
end
|
|
end
|
|
|
|
function SFrames:CreateIconButton(parent, iconKey, iconSize, label, width, height, onClick)
|
|
local A = SFrames.ActiveTheme
|
|
local btn = CreateFrame("Button", nil, parent)
|
|
btn:SetWidth(width or 100)
|
|
btn:SetHeight(height or 24)
|
|
|
|
btn:SetBackdrop({
|
|
bgFile = "Interface\\Buttons\\WHITE8X8",
|
|
edgeFile = "Interface\\Buttons\\WHITE8X8",
|
|
tile = false, tileSize = 0, edgeSize = 1,
|
|
insets = { left = 1, right = 1, top = 1, bottom = 1 }
|
|
})
|
|
|
|
local bgC = (A and A.panelBg) or { 0.12, 0.06, 0.10, 0.9 }
|
|
local bdC = (A and A.sepColor) or { 0.45, 0.25, 0.35, 0.8 }
|
|
local hvC = (A and A.buttonHoverBg) or { 0.22, 0.12, 0.18, 0.95 }
|
|
local hvB = (A and A.accent) or { 0.70, 0.40, 0.55, 1 }
|
|
local dnC = (A and A.buttonDownBg) or { 0.08, 0.04, 0.06, 0.95 }
|
|
local txC = (A and A.buttonText) or { 0.90, 0.76, 0.84 }
|
|
local txH = (A and A.buttonActiveText) or { 1, 0.92, 0.96 }
|
|
|
|
btn:SetBackdropColor(bgC[1], bgC[2], bgC[3], bgC[4] or 0.9)
|
|
btn:SetBackdropBorderColor(bdC[1], bdC[2], bdC[3], bdC[4] or 0.8)
|
|
|
|
local iSz = iconSize or 14
|
|
local ico = self:CreateIcon(btn, iconKey, iSz)
|
|
ico:SetPoint("LEFT", btn, "LEFT", 6, 0)
|
|
btn.icon = ico
|
|
|
|
if label and label ~= "" then
|
|
local fs = btn:CreateFontString(nil, "OVERLAY")
|
|
fs:SetFont(self:GetFont(), 10, self.Media.fontOutline or "OUTLINE")
|
|
fs:SetPoint("LEFT", ico, "RIGHT", 4, 0)
|
|
fs:SetPoint("RIGHT", btn, "RIGHT", -6, 0)
|
|
fs:SetJustifyH("LEFT")
|
|
fs:SetTextColor(txC[1], txC[2], txC[3])
|
|
fs:SetText(label)
|
|
btn.label = fs
|
|
end
|
|
|
|
btn:SetScript("OnEnter", function()
|
|
this:SetBackdropColor(hvC[1], hvC[2], hvC[3], hvC[4] or 0.95)
|
|
this:SetBackdropBorderColor(hvB[1], hvB[2], hvB[3], hvB[4] or 1)
|
|
if this.label then this.label:SetTextColor(txH[1], txH[2], txH[3]) end
|
|
end)
|
|
btn:SetScript("OnLeave", function()
|
|
this:SetBackdropColor(bgC[1], bgC[2], bgC[3], bgC[4] or 0.9)
|
|
this:SetBackdropBorderColor(bdC[1], bdC[2], bdC[3], bdC[4] or 0.8)
|
|
if this.label then this.label:SetTextColor(txC[1], txC[2], txC[3]) end
|
|
end)
|
|
btn:SetScript("OnMouseDown", function()
|
|
this:SetBackdropColor(dnC[1], dnC[2], dnC[3], dnC[4] or 0.95)
|
|
end)
|
|
btn:SetScript("OnMouseUp", function()
|
|
this:SetBackdropColor(hvC[1], hvC[2], hvC[3], hvC[4] or 0.95)
|
|
end)
|
|
|
|
if onClick then
|
|
btn:SetScript("OnClick", onClick)
|
|
end
|
|
|
|
return btn
|
|
end
|