聊天重做前缓存

This commit is contained in:
rucky
2026-04-09 09:46:47 +08:00
parent 6e18269bfd
commit e915bbd74a
39 changed files with 8501 additions and 2308 deletions

242
Focus.lua
View File

@@ -327,17 +327,23 @@ function SFrames.Focus:CreateFocusFrame()
if SFramesDB and SFramesDB.Positions and SFramesDB.Positions["FocusFrame"] then
local pos = SFramesDB.Positions["FocusFrame"]
-- Validate: if GetTop would be near 0 or negative, position is bad
f:SetPoint(pos.point or "LEFT", UIParent, pos.relativePoint or "LEFT", pos.xOfs or 250, pos.yOfs or 0)
-- After setting, check if visible on screen
local fScale = f:GetEffectiveScale() / UIParent:GetEffectiveScale()
if fScale > 0.01 and math.abs(fScale - 1) > 0.001 then
f:SetPoint(pos.point or "LEFT", UIParent, pos.relativePoint or "LEFT",
(pos.xOfs or 250) / fScale, (pos.yOfs or 0) / fScale)
else
f:SetPoint(pos.point or "LEFT", UIParent, pos.relativePoint or "LEFT",
pos.xOfs or 250, pos.yOfs or 0)
end
local top = f:GetTop()
local left = f:GetLeft()
if not top or not left or top < 50 or left < 0 then
-- Bad position, reset
f:ClearAllPoints()
f:SetPoint("LEFT", UIParent, "LEFT", 250, 0)
SFramesDB.Positions["FocusFrame"] = nil
end
elseif SFramesTargetFrame then
f:SetPoint("TOPLEFT", SFramesTargetFrame, "BOTTOMLEFT", 0, -75)
else
f:SetPoint("LEFT", UIParent, "LEFT", 250, 0)
end
@@ -352,6 +358,11 @@ function SFrames.Focus:CreateFocusFrame()
if not SFramesDB then SFramesDB = {} end
if not SFramesDB.Positions then SFramesDB.Positions = {} end
local point, _, relativePoint, xOfs, yOfs = this:GetPoint()
local fScale = this:GetEffectiveScale() / UIParent:GetEffectiveScale()
if fScale > 0.01 and math.abs(fScale - 1) > 0.001 then
xOfs = (xOfs or 0) * fScale
yOfs = (yOfs or 0) * fScale
end
SFramesDB.Positions["FocusFrame"] = { point = point, relativePoint = relativePoint, xOfs = xOfs, yOfs = yOfs }
end)
@@ -546,37 +557,27 @@ function SFrames.Focus:CreateFocusFrame()
SFrames:CreateUnitBackdrop(f)
-- Portrait (right side) — EnableMouse(false) so clicks pass through to main Button
local showPortrait = not (SFramesDB and SFramesDB.focusShowPortrait == false)
f.portrait = CreateFrame("PlayerModel", nil, f)
-- Portrait placeholder (hidden, focus frame does not use 3D portraits)
f.portrait = CreateFrame("Frame", nil, f)
f.portrait:SetWidth(pWidth)
f.portrait:SetHeight(totalH - 2)
f.portrait:SetPoint("RIGHT", f, "RIGHT", -1, 0)
f.portrait:EnableMouse(false)
f.portrait:Hide()
local pbg = CreateFrame("Frame", nil, f)
pbg:SetPoint("TOPLEFT", f.portrait, "TOPLEFT", -1, 0)
pbg:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
pbg:SetFrameLevel(f:GetFrameLevel())
SFrames:CreateUnitBackdrop(pbg)
f.portraitBG = pbg
pbg:EnableMouse(false)
pbg:Hide()
if not showPortrait then
f.portrait:Hide()
pbg:Hide()
end
-- Health bar
-- Health bar (full width, no portrait)
f.health = SFrames:CreateStatusBar(f, "SFramesFocusHealth")
f.health:EnableMouse(false)
if showPortrait then
f.health:SetPoint("TOPLEFT", f, "TOPLEFT", 1, -1)
f.health:SetPoint("TOPRIGHT", f.portrait, "TOPLEFT", -1, 0)
else
f.health:SetPoint("TOPLEFT", f, "TOPLEFT", 1, -1)
f.health:SetPoint("TOPRIGHT", f, "TOPRIGHT", -1, 0)
end
f.health:SetPoint("TOPLEFT", f, "TOPLEFT", 1, -1)
f.health:SetPoint("TOPRIGHT", f, "TOPRIGHT", -1, 0)
f.health:SetHeight(hHeight)
local hbg = CreateFrame("Frame", nil, f)
@@ -596,11 +597,7 @@ function SFrames.Focus:CreateFocusFrame()
f.power = SFrames:CreateStatusBar(f, "SFramesFocusPower")
f.power:EnableMouse(false)
f.power:SetPoint("TOPLEFT", f.health, "BOTTOMLEFT", 0, -1)
if showPortrait then
f.power:SetPoint("BOTTOMRIGHT", f.portrait, "BOTTOMLEFT", -1, 0)
else
f.power:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -1, 1)
end
f.power:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -1, 1)
local powerbg = CreateFrame("Frame", nil, f)
powerbg:SetPoint("TOPLEFT", f.power, "TOPLEFT", -1, 1)
@@ -615,9 +612,9 @@ function SFrames.Focus:CreateFocusFrame()
f.power.bg:SetTexture(SFrames:GetTexture())
f.power.bg:SetVertexColor(_A.slotBg[1], _A.slotBg[2], _A.slotBg[3], _A.slotBg[4] or 1)
-- Class icon
-- Class icon (anchored to frame top-right corner)
f.classIcon = SFrames:CreateClassIcon(f, 14)
f.classIcon.overlay:SetPoint("CENTER", f.portrait, "TOPRIGHT", 0, 0)
f.classIcon.overlay:SetPoint("CENTER", f, "TOPRIGHT", 0, 0)
f.classIcon.overlay:EnableMouse(false)
-- Texts
@@ -747,12 +744,7 @@ function SFrames.Focus:CreateCastbar()
local cb = SFrames:CreateStatusBar(self.frame, "SFramesFocusCastbar")
cb:SetHeight(cbH)
cb:SetPoint("BOTTOMLEFT", self.frame, "TOPLEFT", 0, 6)
local showPortrait = not (SFramesDB and SFramesDB.focusShowPortrait == false)
if showPortrait then
cb:SetPoint("BOTTOMRIGHT", self.frame.portrait, "TOPRIGHT", -(cbH + 6), 6)
else
cb:SetPoint("BOTTOMRIGHT", self.frame, "TOPRIGHT", -(cbH + 6), 6)
end
cb:SetPoint("BOTTOMRIGHT", self.frame, "TOPRIGHT", -(cbH + 6), 6)
local cbbg = CreateFrame("Frame", nil, self.frame)
cbbg:SetPoint("TOPLEFT", cb, "TOPLEFT", -1, 1)
@@ -816,7 +808,6 @@ function SFrames.Focus:UpdateAll()
self.frame.power:SetMinMaxValues(0, 1)
self.frame.power:SetValue(0)
self.frame.powerText:SetText("")
if self.frame.portrait then self.frame.portrait:Hide() end
if self.frame.classIcon then self.frame.classIcon:Hide(); if self.frame.classIcon.overlay then self.frame.classIcon.overlay:Hide() end end
self.frame.raidIcon:Hide()
self:HideAuras()
@@ -830,19 +821,6 @@ function SFrames.Focus:UpdateAll()
self:UpdateRaidIcon()
self:UpdateAuras()
local showPortrait = not (SFramesDB and SFramesDB.focusShowPortrait == false)
if showPortrait and self.frame.portrait then
-- Only reset portrait model on first load / focus change (not every update)
if not self.frame._lastPortraitUID or self.frame._lastPortraitUID ~= uid then
self.frame.portrait:SetUnit(uid)
self.frame.portrait:SetCamera(0)
self.frame.portrait:Hide()
self.frame.portrait:Show()
self.frame.portrait:SetPosition(-1.0, 0, 0)
self.frame._lastPortraitUID = uid
end
end
local name = UnitName(uid) or ""
local level = UnitLevel(uid)
local levelText = level
@@ -888,6 +866,7 @@ function SFrames.Focus:UpdateAll()
-- Color by class or reaction
local useClassColor = not (SFramesDB and SFramesDB.classColorHealth == false)
if SFrames:IsGradientStyle() then useClassColor = true end
if UnitIsPlayer(uid) and useClassColor then
local _, class = UnitClass(uid)
if class and SFrames.Config.colors.class[class] then
@@ -911,6 +890,9 @@ function SFrames.Focus:UpdateAll()
self.frame.nameText:SetText(formattedLevel .. name)
self.frame.nameText:SetTextColor(r, g, b)
end
if SFrames:IsGradientStyle() then
SFrames:ApplyBarGradient(self.frame.health)
end
end
function SFrames.Focus:HideAuras()
@@ -933,7 +915,7 @@ function SFrames.Focus:UpdateHealth()
self.frame.health:SetValue(hp)
if maxHp > 0 then
local pct = math.floor(hp / maxHp * 100)
self.frame.healthText:SetText(hp .. " / " .. maxHp .. " (" .. pct .. "%)")
self.frame.healthText:SetText(SFrames:FormatCompactPair(hp, maxHp) .. " (" .. pct .. "%)")
else
self.frame.healthText:SetText("")
end
@@ -950,6 +932,9 @@ function SFrames.Focus:UpdatePowerType()
else
self.frame.power:SetStatusBarColor(0, 0, 1)
end
if SFrames:IsGradientStyle() then
SFrames:ApplyBarGradient(self.frame.power)
end
end
-- STUB: UpdatePower
@@ -961,10 +946,11 @@ function SFrames.Focus:UpdatePower()
self.frame.power:SetMinMaxValues(0, maxPower)
self.frame.power:SetValue(power)
if maxPower > 0 then
self.frame.powerText:SetText(power .. " / " .. maxPower)
self.frame.powerText:SetText(SFrames:FormatCompactPair(power, maxPower))
else
self.frame.powerText:SetText("")
end
SFrames:UpdateRainbowBar(self.frame.power, power, maxPower, uid)
end
-- STUB: UpdateRaidIcon
@@ -1045,8 +1031,8 @@ function SFrames.Focus:CastbarOnUpdate()
-- 1) Native UnitCastingInfo / UnitChannelInfo (if available)
if uid then
local _UCI = UnitCastingInfo or (CastingInfo and function(u) return CastingInfo(u) end)
local _UCH = UnitChannelInfo or (ChannelInfo and function(u) return ChannelInfo(u) end)
local _UCI = UnitCastingInfo or CastingInfo
local _UCH = UnitChannelInfo or ChannelInfo
if _UCI then
local ok, cSpell, _, _, cIcon, cStart, cEnd = pcall(_UCI, uid)
if ok and cSpell and cStart then
@@ -1177,7 +1163,6 @@ function SFrames.Focus:OnFocusChanged()
local name = self:GetFocusName()
if name then
self.frame:Show()
self.frame._lastPortraitUID = nil -- Force portrait refresh on focus change
self:UpdateAll()
else
self.frame:Hide()
@@ -1206,9 +1191,28 @@ function SFrames.Focus:ApplySettings()
local bgAlpha = tonumber(SFramesDB and SFramesDB.focusBgAlpha) or 0.9
local nameFontSize = tonumber(SFramesDB and SFramesDB.focusNameFontSize) or 11
local valueFontSize = tonumber(SFramesDB and SFramesDB.focusValueFontSize) or 10
local showPortrait = not (SFramesDB and SFramesDB.focusShowPortrait == false)
local showCastBar = not (SFramesDB and SFramesDB.focusShowCastBar == false)
local showAuras = not (SFramesDB and SFramesDB.focusShowAuras == false)
local powerOnTop = SFramesDB and SFramesDB.focusPowerOnTop == true
local gradientStyle = SFrames:IsGradientStyle()
local defaultPowerWidth = width - 2
if defaultPowerWidth < 60 then
defaultPowerWidth = 60
end
local rawPowerWidth = tonumber(SFramesDB and SFramesDB.focusPowerWidth)
local legacyFullWidth = tonumber(SFramesDB and SFramesDB.focusFrameWidth) or width
local maxPowerWidth = gradientStyle and width or (width - 2)
local powerWidth
if gradientStyle then
powerWidth = width
elseif not rawPowerWidth or math.abs(rawPowerWidth - legacyFullWidth) < 0.5 then
powerWidth = defaultPowerWidth
else
powerWidth = rawPowerWidth
end
powerWidth = math.floor(powerWidth + 0.5)
if powerWidth < 60 then powerWidth = 60 end
if powerWidth > maxPowerWidth then powerWidth = maxPowerWidth end
-- Main frame size & scale
f:SetWidth(width)
@@ -1222,40 +1226,75 @@ function SFrames.Focus:ApplySettings()
f:SetBackdropColor(r, g, b, bgAlpha)
end
-- Portrait
if f.portrait then
f.portrait:SetWidth(pWidth)
f.portrait:SetHeight(totalH - 2)
if showPortrait then
f.portrait:Show()
if f.portraitBG then f.portraitBG:Show() end
else
f.portrait:Hide()
if f.portraitBG then f.portraitBG:Hide() end
end
end
-- Portrait always hidden (focus frame uses class icon only)
if f.portrait then f.portrait:Hide() end
if f.portraitBG then f.portraitBG:Hide() end
-- Health bar anchors
-- Health bar anchors (always full width, no portrait)
if f.health then
f.health:ClearAllPoints()
f.health:SetPoint("TOPLEFT", f, "TOPLEFT", 1, -1)
if showPortrait then
f.health:SetPoint("TOPRIGHT", f.portrait, "TOPLEFT", -1, 0)
else
f.health:SetPoint("TOPRIGHT", f, "TOPRIGHT", -1, 0)
end
f.health:SetPoint("TOPRIGHT", f, "TOPRIGHT", -1, 0)
f.health:SetHeight(hHeight)
end
-- Power bar anchors
if f.power then
f.power:ClearAllPoints()
f.power:SetPoint("TOPLEFT", f.health, "BOTTOMLEFT", 0, -1)
if showPortrait then
f.power:SetPoint("BOTTOMRIGHT", f.portrait, "BOTTOMLEFT", -1, 0)
else
f.power:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -1, 1)
f.power:SetPoint("TOPLEFT", f.health, "BOTTOMLEFT", tonumber(SFramesDB and SFramesDB.focusPowerOffsetX) or 0, -1 + (tonumber(SFramesDB and SFramesDB.focusPowerOffsetY) or 0))
f.power:SetWidth(powerWidth)
f.power:SetHeight(pHeight)
end
if f.health and f.power then
local healthLevel = f:GetFrameLevel() + 2
local powerLevel = powerOnTop and (healthLevel + 1) or (healthLevel - 1)
f.health:SetFrameLevel(healthLevel)
f.power:SetFrameLevel(powerLevel)
end
if SFrames:IsGradientStyle() then
SFrames:ClearBackdrop(f)
SFrames:ClearBackdrop(f.healthBGFrame)
SFrames:ClearBackdrop(f.powerBGFrame)
if f.health then
f.health:ClearAllPoints()
f.health:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
f.health:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0)
f.health:SetHeight(hHeight)
end
if f.power then
f.power:ClearAllPoints()
f.power:SetPoint("TOPLEFT", f.health, "BOTTOMLEFT", tonumber(SFramesDB and SFramesDB.focusPowerOffsetX) or 0, -2 + (tonumber(SFramesDB and SFramesDB.focusPowerOffsetY) or 0))
f.power:SetWidth(powerWidth)
f.power:SetHeight(pHeight)
end
SFrames:ApplyGradientStyle(f.health)
SFrames:ApplyGradientStyle(f.power)
if f.healthBGFrame then
f.healthBGFrame:ClearAllPoints()
f.healthBGFrame:SetPoint("TOPLEFT", f.health, "TOPLEFT", 0, 0)
f.healthBGFrame:SetPoint("BOTTOMRIGHT", f.health, "BOTTOMRIGHT", 0, 0)
f.healthBGFrame:Hide()
end
if f.powerBGFrame then
f.powerBGFrame:ClearAllPoints()
f.powerBGFrame:SetPoint("TOPLEFT", f.power, "TOPLEFT", 0, 0)
f.powerBGFrame:SetPoint("BOTTOMRIGHT", f.power, "BOTTOMRIGHT", 0, 0)
f.powerBGFrame:Hide()
end
if f.health and f.health.bg then f.health.bg:Hide() end
if f.power and f.power.bg then f.power.bg:Hide() end
else
SFrames:ApplyConfiguredUnitBackdrop(f, "focus")
if f.healthBGFrame then SFrames:ApplyConfiguredUnitBackdrop(f.healthBGFrame, "focus") end
if f.powerBGFrame then SFrames:ApplyConfiguredUnitBackdrop(f.powerBGFrame, "focus") end
SFrames:RemoveGradientStyle(f.health)
SFrames:RemoveGradientStyle(f.power)
if f.healthBGFrame then f.healthBGFrame:Show() end
if f.powerBGFrame then f.powerBGFrame:Show() end
if f.health and f.health.bg then f.health.bg:Show() end
if f.power and f.power.bg then f.power.bg:Show() end
end
-- Castbar anchors
@@ -1264,11 +1303,7 @@ function SFrames.Focus:ApplySettings()
local cbH = 12
f.castbar:SetHeight(cbH)
f.castbar:SetPoint("BOTTOMLEFT", f, "TOPLEFT", 0, 6)
if showPortrait then
f.castbar:SetPoint("BOTTOMRIGHT", f.portrait, "TOPRIGHT", -(cbH + 6), 6)
else
f.castbar:SetPoint("BOTTOMRIGHT", f, "TOPRIGHT", -(cbH + 6), 6)
end
f.castbar:SetPoint("BOTTOMRIGHT", f, "TOPRIGHT", -(cbH + 6), 6)
if not showCastBar then
f.castbar:Hide()
if f.castbar.cbbg then f.castbar.cbbg:Hide() end
@@ -1298,8 +1333,6 @@ function SFrames.Focus:ApplySettings()
self:UpdateAuras()
end
-- Force portrait refresh
f._lastPortraitUID = nil
if self:GetFocusName() then
self:UpdateAll()
end
@@ -1336,7 +1369,6 @@ function SFrames.Focus:Initialize()
ef:RegisterEvent("UNIT_MAXRAGE")
ef:RegisterEvent("UNIT_DISPLAYPOWER")
ef:RegisterEvent("UNIT_AURA")
ef:RegisterEvent("UNIT_PORTRAIT_UPDATE")
ef:RegisterEvent("UNIT_TARGET")
ef:RegisterEvent("RAID_TARGET_UPDATE")
-- Combat log events for castbar detection (non-SuperWoW fallback)
@@ -1378,7 +1410,6 @@ function SFrames.Focus:Initialize()
if event == "PLAYER_TARGET_CHANGED" then
local focusName = focusSelf:GetFocusName()
if focusName and UnitExists("target") and UnitName("target") == focusName then
focusSelf.frame._lastPortraitUID = nil
focusSelf:UpdateAll()
-- Try to grab GUID while we have target
if UnitGUID then
@@ -1512,7 +1543,7 @@ function SFrames.Focus:Initialize()
focusSelf.frame.health:SetValue(hp)
if maxHp > 0 then
local pct = math.floor(hp / maxHp * 100)
focusSelf.frame.healthText:SetText(hp .. " / " .. maxHp .. " (" .. pct .. "%)")
focusSelf.frame.healthText:SetText(SFrames:FormatCompactPair(hp, maxHp) .. " (" .. pct .. "%)")
else
focusSelf.frame.healthText:SetText("")
end
@@ -1526,7 +1557,7 @@ function SFrames.Focus:Initialize()
focusSelf.frame.power:SetMinMaxValues(0, maxPower)
focusSelf.frame.power:SetValue(power)
if maxPower > 0 then
focusSelf.frame.powerText:SetText(power .. " / " .. maxPower)
focusSelf.frame.powerText:SetText(SFrames:FormatCompactPair(power, maxPower))
else
focusSelf.frame.powerText:SetText("")
end
@@ -1545,22 +1576,13 @@ function SFrames.Focus:Initialize()
focusSelf.frame.power:SetMinMaxValues(0, maxPower)
focusSelf.frame.power:SetValue(power)
if maxPower > 0 then
focusSelf.frame.powerText:SetText(power .. " / " .. maxPower)
focusSelf.frame.powerText:SetText(SFrames:FormatCompactPair(power, maxPower))
else
focusSelf.frame.powerText:SetText("")
end
end
elseif event == "UNIT_AURA" then
focusSelf:UpdateAuras()
elseif event == "UNIT_PORTRAIT_UPDATE" then
local showPortrait = not (SFramesDB and SFramesDB.focusShowPortrait == false)
if showPortrait and focusSelf.frame.portrait and evtUID then
focusSelf.frame._lastPortraitUID = nil
focusSelf.frame.portrait:SetUnit(evtUID)
focusSelf.frame.portrait:SetCamera(0)
focusSelf.frame.portrait:SetPosition(-1.0, 0, 0)
focusSelf.frame._lastPortraitUID = evtUID
end
end
end
end)
@@ -1585,8 +1607,6 @@ function SFrames.Focus:Initialize()
focusSelf.frame:Show()
end
-- Re-scan for a valid unitID every poll cycle
-- This catches cases where focus becomes target/party/raid dynamically
local uid = focusSelf:GetUnitID()
if uid then
focusSelf:UpdateHealth()
@@ -1594,31 +1614,19 @@ function SFrames.Focus:Initialize()
focusSelf:UpdatePower()
focusSelf:UpdateAuras()
focusSelf:UpdateRaidIcon()
-- Only refresh portrait when unitID changes (prevents 3D model flicker)
local showPortrait = not (SFramesDB and SFramesDB.focusShowPortrait == false)
if showPortrait and focusSelf.frame.portrait then
if uid ~= ef.lastUID then
focusSelf.frame.portrait:SetUnit(uid)
focusSelf.frame.portrait:SetCamera(0)
focusSelf.frame.portrait:SetPosition(-1.0, 0, 0)
focusSelf.frame.portrait:Show()
ef.lastUID = uid
end
end
else
ef.lastUID = nil
end
end)
-- Register mover
-- Register mover (Y aligned with pet frame, X aligned with target frame)
if SFrames.Movers and SFrames.Movers.RegisterMover then
if SFramesTargetFrame then
SFrames.Movers:RegisterMover("FocusFrame", self.frame, "焦点",
"TOPLEFT", "SFramesTargetFrame", "BOTTOMLEFT", 0, -10)
"TOPLEFT", "SFramesTargetFrame", "BOTTOMLEFT", 0, -75,
nil, { alwaysShowInLayout = true })
else
SFrames.Movers:RegisterMover("FocusFrame", self.frame, "焦点",
"LEFT", "UIParent", "LEFT", 250, 0)
"LEFT", "UIParent", "LEFT", 250, 0,
nil, { alwaysShowInLayout = true })
end
end