425 lines
14 KiB
Lua
425 lines
14 KiB
Lua
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
|
|
local UF = E:GetModule("UnitFrames")
|
|
|
|
--Lua functions
|
|
local unpack = unpack
|
|
local abs, min = math.abs, math.min
|
|
--WoW API / Variables
|
|
local CreateFrame = CreateFrame
|
|
local UnitIsPlayer = UnitIsPlayer
|
|
local UnitReaction = UnitReaction
|
|
local UnitCanAttack = UnitCanAttack
|
|
|
|
local _, ns = ...
|
|
local ElvUF = ns.oUF
|
|
assert(ElvUF, "ElvUI was unable to locate oUF.")
|
|
|
|
local INVERT_ANCHORPOINT = {
|
|
TOPLEFT = "BOTTOMRIGHT",
|
|
LEFT = "RIGHT",
|
|
BOTTOMLEFT = "TOPRIGHT",
|
|
RIGHT = "LEFT",
|
|
TOPRIGHT = "BOTTOMLEFT",
|
|
BOTTOMRIGHT = "TOPLEFT",
|
|
CENTER = "CENTER",
|
|
TOP = "BOTTOM",
|
|
BOTTOM = "TOP"
|
|
}
|
|
|
|
local ticks = {}
|
|
|
|
function UF:Construct_Castbar(frame, moverName)
|
|
local castbar = CreateFrame("StatusBar", nil, frame)
|
|
castbar:SetFrameLevel(frame.RaisedElementParent:GetFrameLevel() + 30) --Make it appear above everything else
|
|
self.statusbars[castbar] = true
|
|
castbar.CustomDelayText = self.CustomCastDelayText
|
|
castbar.CustomTimeText = self.CustomTimeText
|
|
castbar.PostCastStart = self.PostCastStart
|
|
castbar.PostCastStop = self.PostCastStop
|
|
castbar.PostCastInterruptible = self.PostCastInterruptible
|
|
castbar:SetClampedToScreen(true)
|
|
castbar:CreateBackdrop(nil, nil, nil, self.thinBorders, true)
|
|
|
|
castbar.Time = castbar:CreateFontString(nil, "OVERLAY")
|
|
self:Configure_FontString(castbar.Time)
|
|
castbar.Time:Point("RIGHT", castbar, "RIGHT", -4, 0)
|
|
castbar.Time:SetTextColor(0.84, 0.75, 0.65)
|
|
castbar.Time:SetJustifyH("RIGHT")
|
|
|
|
castbar.Text = castbar:CreateFontString(nil, "OVERLAY")
|
|
self:Configure_FontString(castbar.Text)
|
|
castbar.Text:Point("LEFT", castbar, "LEFT", 4, 0)
|
|
castbar.Text:SetTextColor(0.84, 0.75, 0.65)
|
|
castbar.Text:SetJustifyH("LEFT")
|
|
castbar.Text:SetWordWrap(false)
|
|
|
|
castbar.Spark_ = castbar:CreateTexture(nil, "OVERLAY")
|
|
castbar.Spark_:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
|
|
castbar.Spark_:SetBlendMode("ADD")
|
|
castbar.Spark_:SetVertexColor(1, 1, 1)
|
|
castbar.Spark_:Size(20, 40)
|
|
|
|
--Set to castbar.SafeZone
|
|
castbar.LatencyTexture = castbar:CreateTexture(nil, "OVERLAY")
|
|
castbar.LatencyTexture:SetTexture(E.media.blankTex)
|
|
castbar.LatencyTexture:SetVertexColor(0.69, 0.31, 0.31, 0.75)
|
|
|
|
castbar.bg = castbar:CreateTexture(nil, "BORDER")
|
|
castbar.bg:SetAllPoints()
|
|
castbar.bg:SetTexture(E.media.blankTex)
|
|
castbar.bg:Show()
|
|
|
|
local button = CreateFrame("Frame", nil, castbar)
|
|
local holder = CreateFrame("Frame", nil, castbar)
|
|
button:SetTemplate(nil, nil, nil, self.thinBorders, true)
|
|
|
|
castbar.Holder = holder
|
|
--these are placeholder so the mover can be created.. it will be changed.
|
|
castbar.Holder:Point("TOPLEFT", frame, "BOTTOMLEFT", 0, -(frame.BORDER - frame.SPACING))
|
|
castbar:Point("BOTTOMLEFT", castbar.Holder, "BOTTOMLEFT", frame.BORDER, frame.BORDER)
|
|
button:Point("RIGHT", castbar, "LEFT", -E.Spacing*3, 0)
|
|
|
|
if moverName then
|
|
local name = frame:GetName()
|
|
local configName = string.lower(string.gsub(name, "^ElvUF_", ""))
|
|
E:CreateMover(castbar.Holder, name.."CastbarMover", moverName, nil, -6, nil, "ALL,SOLO", nil, "unitframe,"..configName..",castbar")
|
|
end
|
|
|
|
local icon = button:CreateTexture(nil, "ARTWORK")
|
|
local offset = frame.BORDER --use frame.BORDER since it may be different from E.Border due to forced thin borders
|
|
icon:SetInside(nil, offset, offset)
|
|
icon.bg = button
|
|
|
|
--Set to castbar.Icon
|
|
castbar.ButtonIcon = icon
|
|
|
|
return castbar
|
|
end
|
|
|
|
function UF:Configure_Castbar(frame)
|
|
if not frame.VARIABLES_SET then return end
|
|
local castbar = frame.Castbar
|
|
local db = frame.db
|
|
|
|
if db.castbar.enable then
|
|
if not frame:IsElementEnabled("Castbar") then
|
|
frame:EnableElement("Castbar")
|
|
end
|
|
|
|
castbar:Width(db.castbar.width - ((frame.BORDER+frame.SPACING)*2))
|
|
castbar:Height(db.castbar.height - ((frame.BORDER+frame.SPACING)*2))
|
|
castbar.Holder:Width(db.castbar.width)
|
|
castbar.Holder:Height(db.castbar.height)
|
|
|
|
local color = E.db.unitframe.colors.borderColor
|
|
castbar.ButtonIcon.bg:SetBackdropBorderColor(color.r, color.g, color.b)
|
|
|
|
local oSC = castbar.Holder:GetScript("OnSizeChanged")
|
|
if oSC then oSC(castbar.Holder) end
|
|
|
|
if db.castbar.strataAndLevel and db.castbar.strataAndLevel.useCustomStrata then
|
|
castbar:SetFrameStrata(db.castbar.strataAndLevel.frameStrata)
|
|
end
|
|
|
|
if db.castbar.strataAndLevel and db.castbar.strataAndLevel.useCustomLevel then
|
|
castbar:SetFrameLevel(db.castbar.strataAndLevel.frameLevel)
|
|
end
|
|
|
|
castbar.timeToHold = db.castbar.timeToHold
|
|
|
|
--Latency
|
|
if db.castbar.latency then
|
|
castbar.SafeZone = castbar.LatencyTexture
|
|
castbar.LatencyTexture:Show()
|
|
else
|
|
castbar.SafeZone = nil
|
|
castbar.LatencyTexture:Hide()
|
|
end
|
|
|
|
--Icon
|
|
if db.castbar.icon then
|
|
castbar.Icon = castbar.ButtonIcon
|
|
castbar.Icon:SetTexCoord(unpack(E.TexCoords))
|
|
|
|
if not db.castbar.iconAttached then
|
|
castbar.Icon.bg:Size(db.castbar.iconSize)
|
|
else
|
|
if db.castbar.insideInfoPanel and frame.USE_INFO_PANEL then
|
|
castbar.Icon.bg:Size(db.infoPanel.height - frame.SPACING*2)
|
|
else
|
|
castbar.Icon.bg:Size(db.castbar.height - frame.SPACING*2)
|
|
end
|
|
|
|
castbar:Width(db.castbar.width - castbar.Icon.bg:GetWidth() - (frame.BORDER + frame.SPACING*5))
|
|
end
|
|
|
|
castbar.Icon.bg:Show()
|
|
else
|
|
castbar.ButtonIcon.bg:Hide()
|
|
castbar.Icon = nil
|
|
end
|
|
|
|
if db.castbar.spark then
|
|
castbar.Spark = castbar.Spark_
|
|
castbar.Spark:Point("CENTER", castbar:GetStatusBarTexture(), "RIGHT", 0, 0)
|
|
castbar.Spark:Height(db.castbar.height * 2)
|
|
elseif castbar.Spark then
|
|
castbar.Spark:Hide()
|
|
castbar.Spark = nil
|
|
end
|
|
|
|
castbar:ClearAllPoints()
|
|
if db.castbar.insideInfoPanel and frame.USE_INFO_PANEL then
|
|
if not db.castbar.iconAttached then
|
|
castbar:SetInside(frame.InfoPanel, 0, 0)
|
|
else
|
|
local iconWidth = db.castbar.icon and (castbar.Icon.bg:GetWidth() - frame.BORDER) or 0
|
|
if frame.ORIENTATION == "RIGHT" then
|
|
castbar:Point("TOPLEFT", frame.InfoPanel, "TOPLEFT")
|
|
castbar:Point("BOTTOMRIGHT", frame.InfoPanel, "BOTTOMRIGHT", -iconWidth - frame.SPACING*3, 0)
|
|
else
|
|
castbar:Point("TOPLEFT", frame.InfoPanel, "TOPLEFT", iconWidth + frame.SPACING*3, 0)
|
|
castbar:Point("BOTTOMRIGHT", frame.InfoPanel, "BOTTOMRIGHT")
|
|
end
|
|
end
|
|
|
|
if db.castbar.spark then
|
|
castbar.Spark:Height(db.infoPanel and db.infoPanel.height * 2) -- Grab the height from the infopanel.
|
|
end
|
|
|
|
if castbar.Holder.mover then
|
|
E:DisableMover(castbar.Holder.mover:GetName())
|
|
end
|
|
else
|
|
local isMoved = E:HasMoverBeenMoved(frame:GetName().."CastbarMover") or not castbar.Holder.mover
|
|
if not isMoved then
|
|
castbar.Holder.mover:ClearAllPoints()
|
|
end
|
|
|
|
castbar:ClearAllPoints()
|
|
if frame.ORIENTATION ~= "RIGHT" then
|
|
castbar:Point("BOTTOMRIGHT", castbar.Holder, "BOTTOMRIGHT", -(frame.BORDER+frame.SPACING), frame.BORDER+frame.SPACING)
|
|
if not isMoved then
|
|
castbar.Holder.mover:Point("TOPRIGHT", frame, "BOTTOMRIGHT", 0, -(frame.BORDER - frame.SPACING))
|
|
end
|
|
else
|
|
castbar:Point("BOTTOMLEFT", castbar.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
|
|
if not isMoved then
|
|
castbar.Holder.mover:Point("TOPLEFT", frame, "BOTTOMLEFT", 0, -(frame.BORDER - frame.SPACING))
|
|
end
|
|
end
|
|
|
|
if castbar.Holder.mover then
|
|
E:EnableMover(castbar.Holder.mover:GetName())
|
|
end
|
|
end
|
|
|
|
if not db.castbar.iconAttached and db.castbar.icon then
|
|
local attachPoint = db.castbar.iconAttachedTo == "Frame" and frame or frame.Castbar
|
|
local anchorPoint = db.castbar.iconPosition
|
|
castbar.Icon.bg:ClearAllPoints()
|
|
castbar.Icon.bg:Point(INVERT_ANCHORPOINT[anchorPoint], attachPoint, anchorPoint, db.castbar.iconXOffset, db.castbar.iconYOffset)
|
|
elseif db.castbar.icon then
|
|
castbar.Icon.bg:ClearAllPoints()
|
|
if frame.ORIENTATION == "RIGHT" then
|
|
castbar.Icon.bg:Point("LEFT", castbar, "RIGHT", frame.SPACING*3, 0)
|
|
else
|
|
castbar.Icon.bg:Point("RIGHT", castbar, "LEFT", -frame.SPACING*3, 0)
|
|
end
|
|
end
|
|
|
|
--Adjust tick heights
|
|
castbar.tickHeight = castbar:GetHeight()
|
|
|
|
if db.castbar.ticks then --Only player unitframe has this
|
|
--Set tick width and color
|
|
castbar.tickWidth = db.castbar.tickWidth
|
|
castbar.tickColor = db.castbar.tickColor
|
|
|
|
for i = 1, #ticks do
|
|
ticks[i]:SetVertexColor(castbar.tickColor.r, castbar.tickColor.g, castbar.tickColor.b, castbar.tickColor.a)
|
|
ticks[i]:Width(castbar.tickWidth)
|
|
end
|
|
end
|
|
|
|
castbar.custom_backdrop = UF.db.colors.customcastbarbackdrop and UF.db.colors.castbar_backdrop
|
|
UF:ToggleTransparentStatusBar(UF.db.colors.transparentCastbar, castbar, castbar.bg, nil, UF.db.colors.invertCastbar)
|
|
else
|
|
if not db.castbar.enable and frame:IsElementEnabled("Castbar") then
|
|
frame:DisableElement("Castbar")
|
|
|
|
if castbar.Holder.mover then
|
|
E:DisableMover(castbar.Holder.mover:GetName())
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function UF:CustomCastDelayText(duration)
|
|
local db = self:GetParent().db
|
|
if not (db and db.castbar) then return end
|
|
db = db.castbar.format
|
|
|
|
if self.channeling then
|
|
if db == "CURRENT" then
|
|
self.Time:SetFormattedText("%.1f |cffaf5050%.2f|r", abs(duration - self.max), self.delay)
|
|
elseif db == "CURRENTMAX" then
|
|
self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%.2f|r", abs(duration - self.max), self.max, self.delay)
|
|
elseif db == "REMAINING" then
|
|
self.Time:SetFormattedText("%.1f |cffaf5050%.2f|r", duration, self.delay)
|
|
elseif db == "REMAININGMAX" then
|
|
self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%.2f|r", duration, self.max, self.delay)
|
|
end
|
|
else
|
|
if db == "CURRENT" then
|
|
self.Time:SetFormattedText("%.1f |cffaf5050%s %.2f|r", duration, "+", self.delay)
|
|
elseif db == "CURRENTMAX" then
|
|
self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%s %.2f|r", duration, self.max, "+", self.delay)
|
|
elseif db == "REMAINING" then
|
|
self.Time:SetFormattedText("%.1f |cffaf5050%s %.2f|r", abs(duration - self.max), "+", self.delay)
|
|
elseif db == "REMAININGMAX" then
|
|
self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%s %.2f|r", abs(duration - self.max), self.max, "+", self.delay)
|
|
end
|
|
end
|
|
end
|
|
|
|
function UF:CustomTimeText(duration)
|
|
local db = self:GetParent().db
|
|
if not (db and db.castbar) then return end
|
|
db = db.castbar.format
|
|
|
|
if self.channeling then
|
|
if db == "CURRENT" then
|
|
self.Time:SetFormattedText("%.1f", abs(duration - self.max))
|
|
elseif db == "CURRENTMAX" then
|
|
self.Time:SetFormattedText("%.1f / %.2f", abs(duration - self.max), self.max)
|
|
elseif db == "REMAINING" then
|
|
self.Time:SetFormattedText("%.1f", duration)
|
|
elseif db == "REMAININGMAX" then
|
|
self.Time:SetFormattedText("%.1f / %.2f", duration, self.max)
|
|
end
|
|
else
|
|
if db == "CURRENT" then
|
|
self.Time:SetFormattedText("%.1f", duration)
|
|
elseif db == "CURRENTMAX" then
|
|
self.Time:SetFormattedText("%.1f / %.2f", duration, self.max)
|
|
elseif db == "REMAINING" then
|
|
self.Time:SetFormattedText("%.1f", abs(duration - self.max))
|
|
elseif db == "REMAININGMAX" then
|
|
self.Time:SetFormattedText("%.1f / %.2f", abs(duration - self.max), self.max)
|
|
end
|
|
end
|
|
end
|
|
|
|
function UF:HideTicks()
|
|
for i = 1, #ticks do
|
|
ticks[i]:Hide()
|
|
end
|
|
end
|
|
|
|
function UF:SetCastTicks(frame, numTicks)
|
|
UF:HideTicks()
|
|
if numTicks and numTicks <= 0 then return end
|
|
local w = frame:GetWidth()
|
|
local d = w / numTicks
|
|
|
|
for i = 1, numTicks do
|
|
if not ticks[i] then
|
|
ticks[i] = frame:CreateTexture(nil, "OVERLAY")
|
|
ticks[i]:SetTexture(E.media.normTex)
|
|
E:RegisterStatusBar(ticks[i])
|
|
ticks[i]:SetVertexColor(frame.tickColor.r, frame.tickColor.g, frame.tickColor.b, frame.tickColor.a)
|
|
ticks[i]:Width(frame.tickWidth)
|
|
end
|
|
|
|
ticks[i]:Height(frame.tickHeight)
|
|
ticks[i]:ClearAllPoints()
|
|
ticks[i]:Point("RIGHT", frame, "LEFT", d * i, 0)
|
|
ticks[i]:Show()
|
|
end
|
|
end
|
|
|
|
function UF:PostCastStart(unit)
|
|
local db = self:GetParent().db
|
|
if not db or not db.castbar then return end
|
|
|
|
if unit == "vehicle" then unit = "player" end
|
|
|
|
if db.castbar.displayTarget and self.curTarget then
|
|
self.Text:SetText(self.spellName.." > "..self.curTarget)
|
|
end
|
|
|
|
-- Get length of Time, then calculate available length for Text
|
|
local timeWidth = self.Time:GetStringWidth()
|
|
local textWidth = self:GetWidth() - timeWidth - 10
|
|
local textStringWidth = self.Text:GetStringWidth()
|
|
|
|
if timeWidth == 0 or textStringWidth == 0 then
|
|
E:Delay(0.05, function() -- Delay may need tweaking
|
|
textWidth = self:GetWidth() - self.Time:GetStringWidth() - 10
|
|
textStringWidth = self.Text:GetStringWidth()
|
|
if textWidth > 0 then self.Text:Width(min(textWidth, textStringWidth)) end
|
|
end)
|
|
else
|
|
self.Text:Width(min(textWidth, textStringWidth))
|
|
end
|
|
|
|
self.unit = unit
|
|
|
|
if self.channeling and db.castbar.ticks and unit == "player" then
|
|
local unitframe = E.global.unitframe
|
|
local baseTicks = unitframe.ChannelTicks[self.spellName]
|
|
|
|
if baseTicks then
|
|
UF:SetCastTicks(self, baseTicks)
|
|
self.hadTicks = true
|
|
else
|
|
UF:HideTicks()
|
|
end
|
|
end
|
|
|
|
local colors = ElvUF.colors
|
|
local r, g, b = colors.castColor[1], colors.castColor[2], colors.castColor[3]
|
|
|
|
if (self.notInterruptible and unit ~= "player") and UnitCanAttack("player", unit) then
|
|
r, g, b = colors.castNoInterrupt[1], colors.castNoInterrupt[2], colors.castNoInterrupt[3]
|
|
elseif UF.db.colors.castClassColor and UnitIsPlayer(unit) then
|
|
local _, class = UnitClass(unit)
|
|
local t = UnitIsUnit("player", unit) and E.media.herocolor or RAID_CLASS_COLORS[class]
|
|
if t then r, g, b = t.r, t.g, t.b end
|
|
elseif UF.db.colors.castReactionColor then
|
|
local Reaction = UnitReaction(unit, "player")
|
|
local t = Reaction and ElvUF.colors.reaction[Reaction]
|
|
if t then r, g, b = t[1], t[2], t[3] end
|
|
end
|
|
|
|
self:SetStatusBarColor(r, g, b)
|
|
end
|
|
|
|
function UF:PostCastStop(unit)
|
|
if self.hadTicks and unit == "player" then
|
|
UF:HideTicks()
|
|
self.hadTicks = false
|
|
end
|
|
end
|
|
|
|
function UF:PostCastInterruptible(unit)
|
|
if unit == "vehicle" or unit == "player" then return end
|
|
|
|
local colors = ElvUF.colors
|
|
local r, g, b = colors.castColor[1], colors.castColor[2], colors.castColor[3]
|
|
|
|
if self.notInterruptible and UnitCanAttack("player", unit) then
|
|
r, g, b = colors.castNoInterrupt[1], colors.castNoInterrupt[2], colors.castNoInterrupt[3]
|
|
elseif UF.db.colors.castClassColor and UnitIsPlayer(unit) then
|
|
local _, class = UnitClass(unit)
|
|
local t = UnitIsUnit("player", unit) and E.media.herocolor or RAID_CLASS_COLORS[class]
|
|
if t then r, g, b = t.r, t.g, t.b end
|
|
elseif UF.db.colors.castReactionColor then
|
|
local Reaction = UnitReaction(unit, "player")
|
|
local t = Reaction and ElvUF.colors.reaction[Reaction]
|
|
if t then r, g, b = t[1], t[2], t[3] end
|
|
end
|
|
|
|
self:SetStatusBarColor(r, g, b)
|
|
end |