You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1778 lines
46 KiB
1778 lines
46 KiB
local MAJOR = "LibBars-1.0"
|
|
local MINOR = 90000 + tonumber(("$Revision: 24 $"):match("%d+")) -- Rarity changed this version to 24 to force an upgrade
|
|
|
|
local lib, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
|
|
if not lib then return end -- No Upgrade needed.
|
|
|
|
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
|
|
|
|
local GetTime = _G.GetTime
|
|
local sin, cos, rad = _G.math.sin, _G.math.cos, _G.math.rad
|
|
local abs, min, max, floor = _G.math.abs, _G.math.min, _G.math.max, _G.math.floor
|
|
local table_sort, tinsert, tremove, tconcat = _G.table.sort, tinsert, tremove, _G.table.concat
|
|
local next, pairs, assert, error, type, xpcall = next, pairs, assert, error, type, xpcall
|
|
|
|
--[[
|
|
xpcall safecall implementation
|
|
]]
|
|
local function errorhandler(err)
|
|
return geterrorhandler()(err)
|
|
end
|
|
|
|
local function CreateDispatcher(argCount)
|
|
local code = [[
|
|
local xpcall, eh = ...
|
|
local method, ARGS
|
|
local function call() return method(ARGS) end
|
|
|
|
local function dispatch(func, ...)
|
|
method = func
|
|
if not method then return end
|
|
ARGS = ...
|
|
return xpcall(call, eh)
|
|
end
|
|
|
|
return dispatch
|
|
]]
|
|
|
|
local ARGS = {}
|
|
for i = 1, argCount do ARGS[i] = "arg"..i end
|
|
code = code:gsub("ARGS", tconcat(ARGS, ", "))
|
|
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
|
|
end
|
|
|
|
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
|
|
local dispatcher = CreateDispatcher(argCount)
|
|
rawset(self, argCount, dispatcher)
|
|
return dispatcher
|
|
end})
|
|
Dispatchers[0] = function(func)
|
|
return xpcall(func, errorhandler)
|
|
end
|
|
|
|
local function safecall(func, ...)
|
|
-- we check to see if the func is passed is actually a function here and don't error when it isn't
|
|
-- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
|
|
-- present execution should continue without hinderance
|
|
if type(func) == "function" then
|
|
return Dispatchers[select('#', ...)](func, ...)
|
|
end
|
|
end
|
|
|
|
local dummyFrame, barFrameMT, barPrototype, barPrototype_mt, barListPrototype
|
|
local barListPrototype_mt
|
|
|
|
lib.LEFT_TO_RIGHT = 1
|
|
lib.BOTTOM_TO_TOP = 2
|
|
lib.RIGHT_TO_LEFT = 3
|
|
lib.TOP_TO_BOTTOM = 4
|
|
|
|
lib.dummyFrame = lib.dummyFrame or CreateFrame("Frame")
|
|
lib.barFrameMT = lib.barFrameMT or {__index = lib.dummyFrame}
|
|
lib.barPrototype = lib.barPrototype or setmetatable({}, lib.barFrameMT)
|
|
lib.barPrototype_mt = lib.barPrototype_mt or {__index = lib.barPrototype}
|
|
lib.barListPrototype = lib.barListPrototype or setmetatable({}, lib.barFrameMT)
|
|
lib.barListPrototype_mt = lib.barListPrototype_mt or {__index = lib.barListPrototype}
|
|
|
|
dummyFrame = lib.dummyFrame
|
|
barFrameMT = lib.barFrameMT
|
|
barPrototype = lib.barPrototype
|
|
barPrototype_mt = lib.barPrototype_mt
|
|
barListPrototype = lib.barListPrototype
|
|
barListPrototype_mt = lib.barListPrototype_mt
|
|
|
|
barPrototype.prototype = barPrototype
|
|
barPrototype.metatable = barPrototype_mt
|
|
barPrototype.super = dummyFrame
|
|
|
|
barListPrototype.prototype = barListPrototype
|
|
barListPrototype.metatable = barListPrototype_mt
|
|
barListPrototype.super = dummyFrame
|
|
|
|
lib.bars = lib.bars or {}
|
|
lib.barLists = lib.barLists or {}
|
|
lib.recycledBars = lib.recycledBars or {}
|
|
lib.embeds = lib.embeds or {}
|
|
local bars = lib.bars
|
|
local barLists = lib.barLists
|
|
local recycledBars = lib.recycledBars
|
|
|
|
local frame_defaults = {
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
inset = 4,
|
|
edgeSize = 8,
|
|
tile = true,
|
|
insets = {left = 2, right = 2, top = 2, bottom = 2}
|
|
}
|
|
|
|
do
|
|
local mixins = { "NewCounterBar", "NewTimerBar", "NewBarFromPrototype", "GetBar", "GetBars", "HasBar", "IterateBars", "NewBarGroup", "ReleaseBar", "GetBarGroup", "GetBarGroups" }
|
|
function lib:Embed(target)
|
|
for k, v in pairs( mixins ) do
|
|
target[v] = self[v]
|
|
end
|
|
lib.embeds[target] = true
|
|
return target
|
|
end
|
|
end
|
|
|
|
local ComputeGradient
|
|
do
|
|
local new, del
|
|
do
|
|
local list = lib.garbageList or setmetatable({}, {__mode='k'})
|
|
lib.garbageList = list
|
|
-- new is always called with the exact same arguments, no need to
|
|
-- iterate over a vararg
|
|
function new(a1, a2, a3, a4, a5)
|
|
local t = next(list)
|
|
if t then
|
|
list[t] = nil
|
|
t[1] = a1
|
|
t[2] = a2
|
|
t[3] = a3
|
|
t[4] = a4
|
|
t[5] = a5
|
|
else
|
|
t = {a1, a2, a3, a4, a5}
|
|
end
|
|
return t
|
|
end
|
|
|
|
-- del is called over the same tables produced from new, no need for
|
|
-- fancy stuff
|
|
function del(t)
|
|
t[1] = nil
|
|
t[2] = nil
|
|
t[3] = nil
|
|
t[4] = nil
|
|
t[5] = nil
|
|
t[''] = true
|
|
t[''] = nil
|
|
list[t] = true
|
|
return nil
|
|
end
|
|
end
|
|
|
|
local function sort_colors(a, b)
|
|
return a[1] < b[1]
|
|
end
|
|
|
|
local colors = {}
|
|
local function getColor(point)
|
|
local lowerBound = colors[1]
|
|
local upperBound = colors[#colors]
|
|
local lowerBoundIndex, upperBoundIndex = 0, 1
|
|
for i = 1, #colors do
|
|
if colors[i][1] >= point then
|
|
if i > 1 then
|
|
lowerBound = colors[i-1]
|
|
lowerBoundIndex = colors[i-1][1]
|
|
end
|
|
upperBound = colors[i]
|
|
upperBoundIndex = colors[i][1]
|
|
break
|
|
end
|
|
end
|
|
local diff = (upperBoundIndex - lowerBoundIndex)
|
|
local pct = 1
|
|
if diff ~= 0 then
|
|
pct = (point - lowerBoundIndex) / diff
|
|
end
|
|
local r = lowerBound[2] + ((upperBound[2] - lowerBound[2]) * pct)
|
|
local g = lowerBound[3] + ((upperBound[3] - lowerBound[3]) * pct)
|
|
local b = lowerBound[4] + ((upperBound[4] - lowerBound[4]) * pct)
|
|
local a = lowerBound[5] + ((upperBound[5] - lowerBound[5]) * pct)
|
|
return r, g, b, a
|
|
end
|
|
|
|
function ComputeGradient(self)
|
|
self.gradMap = self.gradMap or {}
|
|
if not self.colors then return end
|
|
if #self.colors == 0 then
|
|
for k in pairs(self.gradMap) do
|
|
self.gradMap[k] = nil
|
|
end
|
|
return
|
|
end
|
|
|
|
for i = 1, #colors do
|
|
del(tremove(colors))
|
|
end
|
|
for i = 1, #self.colors, 5 do
|
|
tinsert(colors, new(self.colors[i], self.colors[i+1], self.colors[i+2], self.colors[i+3], self.colors[i+4]))
|
|
end
|
|
table_sort(colors, sort_colors)
|
|
|
|
for i = 0, 200 do
|
|
local r, g, b, a = getColor(i / 200)
|
|
self.gradMap[(i*4)] = r
|
|
self.gradMap[(i*4)+1] = g
|
|
self.gradMap[(i*4)+2] = b
|
|
self.gradMap[(i*4)+3] = a
|
|
end
|
|
end
|
|
end
|
|
|
|
function lib:GetBar(name)
|
|
return bars[self] and bars[self][name]
|
|
end
|
|
|
|
function lib:GetBars(name)
|
|
return bars[self]
|
|
end
|
|
|
|
function lib:HasAnyBar()
|
|
return not not (bars[self] and next(bars[self]))
|
|
end
|
|
|
|
do
|
|
local function NOOP() end
|
|
function lib:IterateBars()
|
|
if bars[self] then
|
|
return pairs(bars[self])
|
|
else
|
|
return NOOP
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Convenient method to create a new, empty bar prototype
|
|
function lib:NewBarPrototype(super)
|
|
assert(super == nil or (type(super) == "table" and type(super.metatable) == "table"),
|
|
"!NewBarPrototype: super must either be nil or a valid prototype")
|
|
super = super or barPrototype
|
|
local prototype = setmetatable({}, super.metatable)
|
|
prototype.prototype = prototype
|
|
prototype.super = super
|
|
prototype.metatable = { __index = prototype }
|
|
return prototype
|
|
end
|
|
|
|
--[[ Individual bars ]]--
|
|
|
|
function lib:NewBarFromPrototype(prototype, name, ...)
|
|
assert(self ~= lib, "You may only call :NewBar as an embedded function")
|
|
assert(type(prototype) == "table" and type(prototype.metatable) == "table", "Invalid bar prototype")
|
|
bars[self] = bars[self] or {}
|
|
local bar = bars[self][name]
|
|
local isNew = false
|
|
if not bar then
|
|
isNew = true
|
|
bar = tremove(recycledBars)
|
|
if not bar then
|
|
bar = CreateFrame("Frame")
|
|
else
|
|
bar:Show()
|
|
end
|
|
end
|
|
bar = setmetatable(bar, prototype.metatable)
|
|
bar.name = name
|
|
bar:Create(...)
|
|
bar:SetFont(self.font, self.fontSize, self.fontFlags)
|
|
|
|
bars[self][name] = bar
|
|
|
|
return bar, isNew
|
|
end
|
|
|
|
function lib:NewCounterBar(name, text, value, maxVal, icon, orientation, length, thickness, isTimer)
|
|
return self:NewBarFromPrototype(barPrototype, name, text, value, maxVal, icon, orientation, length, thickness, isTimer)
|
|
end
|
|
|
|
function lib:NewTimerBar(name, text, time, maxTime, icon, orientation,length, thickness)
|
|
return self:NewBarFromPrototype(barPrototype, name, text, time, maxTime, icon, orientation, length, thickness, true)
|
|
end
|
|
|
|
function lib:ReleaseBar(name)
|
|
if not bars[self] then return end
|
|
|
|
local bar
|
|
if type(name) == "string" then
|
|
bar = bars[self][name]
|
|
elseif type(name) == "table" then
|
|
if name.name and bars[self][name.name] == name then
|
|
bar = name
|
|
end
|
|
end
|
|
|
|
if bar then
|
|
bar:OnBarReleased()
|
|
bars[self][bar.name] = nil
|
|
tinsert(recycledBars, bar)
|
|
end
|
|
end
|
|
|
|
---[[ Bar Groups ]]---
|
|
do
|
|
local function move(self)
|
|
if not self:GetParent().locked then
|
|
self.startX = self:GetParent():GetLeft()
|
|
self.startY = self:GetParent():GetTop()
|
|
self:GetParent():StartMoving()
|
|
end
|
|
end
|
|
local function stopMove(self)
|
|
if not self:GetParent().locked then
|
|
self:GetParent():StopMovingOrSizing()
|
|
local endX = self:GetParent():GetLeft()
|
|
local endY = self:GetParent():GetTop()
|
|
if self.startX ~= endX or self.startY ~= endY then
|
|
self:GetParent().callbacks:Fire("AnchorMoved", self:GetParent(), endX, endY)
|
|
end
|
|
end
|
|
end
|
|
local function buttonClick(self, button)
|
|
self:GetParent().callbacks:Fire("AnchorClicked", self:GetParent(), button)
|
|
end
|
|
|
|
local DEFAULT_TEXTURE = [[Interface\TARGETINGFRAME\UI-StatusBar]]
|
|
function lib:NewBarGroup(name, orientation, length, thickness, frameName)
|
|
if self == lib then
|
|
error("You may only call :NewBarGroup as an embedded function")
|
|
end
|
|
|
|
barLists[self] = barLists[self] or {}
|
|
if barLists[self][name] then
|
|
error("A bar list named " .. name .. " already exists.")
|
|
end
|
|
|
|
orientation = orientation or lib.LEFT_TO_RIGHT
|
|
orientation = orientation == "LEFT" and lib.LEFT_TO_RIGHT or orientation
|
|
orientation = orientation == "RIGHT" and lib.RIGHT_TO_LEFT or orientation
|
|
|
|
local list = setmetatable(CreateFrame("Frame", frameName, UIParent, BackdropTemplateMixin and "BackdropTemplate"), barListPrototype_mt)
|
|
list:SetMovable(true)
|
|
list:SetClampedToScreen(true)
|
|
|
|
list.callbacks = list.callbacks or CallbackHandler:New(list)
|
|
barLists[self][name] = list
|
|
list.name = name
|
|
|
|
-- list:SetBackdrop({
|
|
-- bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
-- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
-- inset = 0,
|
|
-- edgeSize = 12,
|
|
-- tile = true
|
|
-- })
|
|
|
|
list.button = CreateFrame("Button", nil, list, BackdropTemplateMixin and "BackdropTemplate")
|
|
list.button:SetBackdrop(frame_defaults)
|
|
|
|
list.button:SetNormalFontObject(ChatFontSmall)
|
|
|
|
list.length = length or 200
|
|
list.thickness = thickness or 15
|
|
list:SetOrientation(orientation)
|
|
|
|
list:UpdateOrientationLayout()
|
|
|
|
list.button:SetScript("OnMouseDown", move)
|
|
list.button:SetScript("OnMouseUp", stopMove)
|
|
list.button:SetBackdropColor(0,0,0,1)
|
|
list.button:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp", "Button4Up", "Button5Up")
|
|
list.button:SetScript("OnClick", buttonClick)
|
|
|
|
list:SetPoint("TOPLEFT", UIParent, "CENTER")
|
|
list:ReverseGrowth(false)
|
|
|
|
list.showIcon = true
|
|
list.showLabel = true
|
|
list.showTimerLabel = true
|
|
|
|
list.lastBar = list
|
|
list.locked = false
|
|
|
|
list.texture = DEFAULT_TEXTURE
|
|
list.spacing = 0
|
|
|
|
return list
|
|
end
|
|
end
|
|
|
|
function lib:GetBarGroups()
|
|
return barLists[self]
|
|
end
|
|
|
|
function lib:GetBarGroup(name)
|
|
return barLists[self] and barLists[self][name]
|
|
end
|
|
|
|
--[[ BarList prototype ]]--
|
|
|
|
function barListPrototype:NewBarFromPrototype(prototype, ...)
|
|
local bar, isNew = lib.NewBarFromPrototype(self, prototype, ...)
|
|
bar:SetTexture(self.texture)
|
|
bar:SetFill(self.fill)
|
|
-- if isNew then bar:SetValue(0) end
|
|
|
|
if self.showIcon then bar:ShowIcon() else bar:HideIcon(bar) end
|
|
if self.showLabel then bar:ShowLabel() else bar:HideLabel(bar) end
|
|
if self.showTimerLabel then bar:ShowTimerLabel() else bar:HideTimerLabel(bar) end
|
|
self:SortBars()
|
|
bar.ownerGroup = self
|
|
bar.RegisterCallback(self, "FadeFinished")
|
|
bar.RegisterCallback(self, "TimerFinished")
|
|
bar:SetParent(self)
|
|
return bar, isNew
|
|
end
|
|
|
|
function barListPrototype:SetWidth(width)
|
|
if self:IsVertical() then
|
|
self:SetThickness(width)
|
|
else
|
|
self:SetLength(width)
|
|
end
|
|
end
|
|
|
|
function barListPrototype:SetHeight(height)
|
|
if self:IsVertical() then
|
|
self:SetLength(height)
|
|
else
|
|
self:SetThickness(height)
|
|
end
|
|
end
|
|
|
|
function barListPrototype:NewCounterBar(name, text, value, maxVal, icon, isTimer)
|
|
return self:NewBarFromPrototype(barPrototype, name, text, value, maxVal, icon, self.orientation, self.length, self.thickness, isTimer)
|
|
end
|
|
|
|
local function startFlashing(bar, time)
|
|
if not bar.flashing then
|
|
bar:Flash(bar.ownerGroup.flashPeriod)
|
|
end
|
|
end
|
|
|
|
function barListPrototype:NewTimerBar(name, text, time, maxTime, icon, flashTrigger)
|
|
local bar, isNew = self:NewBarFromPrototype(barPrototype, name, text, time, maxTime, icon, self.orientation, self.length, self.thickness, true)
|
|
bar:RegisterTimeLeftTrigger(flashTrigger or bar.ownerGroup.flashTrigger or 5, startFlashing)
|
|
return bar, isNew
|
|
end
|
|
|
|
function barListPrototype:Lock()
|
|
self.locked = true
|
|
end
|
|
|
|
function barListPrototype:Unlock()
|
|
self.locked = false
|
|
end
|
|
|
|
function barListPrototype:IsLocked()
|
|
return self.locked
|
|
end
|
|
|
|
-- Max number of bars to display. nil to display all.
|
|
function barListPrototype:SetMaxBars(num)
|
|
self.maxBars = num
|
|
end
|
|
|
|
function barListPrototype:GetMaxBars()
|
|
return self.maxBars
|
|
end
|
|
|
|
function barListPrototype:SetFlashTrigger(t)
|
|
self.flashTrigger = t
|
|
end
|
|
|
|
function barListPrototype:SetFlashPeriod(p)
|
|
self.flashPeriod = p
|
|
end
|
|
|
|
function barListPrototype:SetTexture(tex)
|
|
self.texture = tex
|
|
if bars[self] then
|
|
for k, v in pairs(bars[self]) do
|
|
v:SetTexture(tex)
|
|
end
|
|
end
|
|
end
|
|
|
|
function barListPrototype:SetFont(f, s, m)
|
|
self.font, self.fontSize, self.fontFlags = f, s, m
|
|
if bars[self] then
|
|
for k, v in pairs(bars[self]) do
|
|
v:SetFont(f, s, m)
|
|
end
|
|
end
|
|
end
|
|
|
|
function barListPrototype:SetFill(fill)
|
|
self.fill = fill
|
|
if bars[self] then
|
|
for k, v in pairs(bars[self]) do
|
|
v:SetFill(fill)
|
|
end
|
|
end
|
|
end
|
|
|
|
function barListPrototype:IsFilling()
|
|
return self.fill
|
|
end
|
|
|
|
function barListPrototype:ShowIcon()
|
|
self.showIcon = true
|
|
if not bars[self] then return end
|
|
for name,bar in pairs(bars[self]) do
|
|
bar:ShowIcon()
|
|
end
|
|
end
|
|
|
|
function barListPrototype:HideIcon()
|
|
self.showIcon = false
|
|
if not bars[self] then return end
|
|
for name, bar in pairs(bars[self]) do
|
|
bar:HideIcon()
|
|
end
|
|
end
|
|
|
|
function barListPrototype:IsIconShown()
|
|
return self.showIcon
|
|
end
|
|
|
|
function barListPrototype:ShowLabel()
|
|
self.showLabel = true
|
|
for name,bar in pairs(bars[self]) do
|
|
bar:ShowLabel()
|
|
end
|
|
end
|
|
|
|
function barListPrototype:HideLabel()
|
|
self.showLabel = false
|
|
for name,bar in pairs(bars[self]) do
|
|
bar:HideLabel()
|
|
end
|
|
end
|
|
|
|
function barListPrototype:IsLabelShown()
|
|
return self.showLabel
|
|
end
|
|
|
|
function barListPrototype:ShowTimerLabel()
|
|
self.showTimerLabel = true
|
|
for name,bar in pairs(bars[self]) do
|
|
bar:ShowTimerLabel()
|
|
end
|
|
end
|
|
|
|
function barListPrototype:HideTimerLabel()
|
|
self.showTimerLabel = false
|
|
for name,bar in pairs(bars[self]) do
|
|
bar:HideTimerLabel()
|
|
end
|
|
end
|
|
|
|
function barListPrototype:IsValueLabelShown()
|
|
return self.showTimerLabel
|
|
end
|
|
|
|
function barListPrototype:SetSpacing(spacing)
|
|
self.spacing = spacing
|
|
self:SortBars()
|
|
end
|
|
|
|
function barListPrototype:GetSpacing()
|
|
return self.spacing
|
|
end
|
|
|
|
barListPrototype.GetBar = lib.GetBar
|
|
barListPrototype.GetBars = lib.GetBars
|
|
barListPrototype.HasAnyBar = lib.HasAnyBar
|
|
barListPrototype.IterateBars = lib.IterateBars
|
|
|
|
function barListPrototype:MoveBarToGroup(bar, group)
|
|
if type(bar) ~= "table" then
|
|
bar = bars[self][bar]
|
|
end
|
|
if not bar then
|
|
error("Cannot find bar passed to MoveBarToGroup")
|
|
end
|
|
bars[group] = bars[group] or {}
|
|
if bars[group][bar.name] then
|
|
error("Cannot move " .. bar.name .. " to this group; a bar with that name already exists.")
|
|
end
|
|
for k, v in pairs(bars[self]) do
|
|
if v == bar then
|
|
bars[self][k] = nil
|
|
bar = v
|
|
break
|
|
end
|
|
end
|
|
bar:SetParent(group)
|
|
bar.ownerGroup = group
|
|
bars[group][bar.name] = bar
|
|
end
|
|
|
|
function barListPrototype:RemoveBar(bar)
|
|
lib.ReleaseBar(self, bar)
|
|
end
|
|
|
|
function barListPrototype:SetDisplayMax(val)
|
|
self.displayMax = val
|
|
end
|
|
|
|
function barListPrototype:UpdateColors()
|
|
-- Force a color update on all the bars, particularly the counter bars
|
|
if bars[self] then
|
|
for k, v in pairs(bars[self]) do
|
|
v:UpdateColor()
|
|
-- if not v.isTimer then
|
|
-- v:UpdateColor()
|
|
-- end
|
|
end
|
|
end
|
|
end
|
|
|
|
function barListPrototype:SetColorAt(at, r, g, b, a)
|
|
self.colors = self.colors or {}
|
|
tinsert(self.colors, at)
|
|
tinsert(self.colors, r)
|
|
tinsert(self.colors, g)
|
|
tinsert(self.colors, b)
|
|
tinsert(self.colors, a)
|
|
ComputeGradient(self)
|
|
self:UpdateColors()
|
|
end
|
|
|
|
function barListPrototype:UnsetColorAt(at)
|
|
if not self.colors then return end
|
|
for i = 1, #self.colors, 5 do
|
|
if self.colors[i] == at then
|
|
for j = 1, 5 do
|
|
tremove(self.colors, i)
|
|
end
|
|
ComputeGradient(self)
|
|
self:UpdateColors()
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
function barListPrototype:UnsetAllColors()
|
|
if not self.colors then return end
|
|
for i = 1, #self.colors do
|
|
tremove(self.colors)
|
|
end
|
|
return
|
|
end
|
|
|
|
function barListPrototype:TimerFinished(evt, bar, name)
|
|
bar.ownerGroup.callbacks:Fire("TimerFinished", bar.ownerGroup, bar, name)
|
|
bar:Fade()
|
|
end
|
|
|
|
function barListPrototype:FadeFinished(evt, bar, name)
|
|
local group = bar.ownerGroup
|
|
lib.ReleaseBar(group, bar)
|
|
group:SortBars()
|
|
end
|
|
|
|
function barListPrototype:ShowAnchor()
|
|
self.button:Show()
|
|
self:SortBars()
|
|
end
|
|
|
|
function barListPrototype:HideAnchor()
|
|
self.button:Hide()
|
|
self:SortBars()
|
|
end
|
|
|
|
function barListPrototype:IsAnchorVisible()
|
|
return self.button:IsVisible()
|
|
end
|
|
|
|
function barListPrototype:ToggleAnchor()
|
|
if self.button:IsVisible() then
|
|
self.button:Hide()
|
|
else
|
|
self.button:Show()
|
|
end
|
|
self:SortBars()
|
|
end
|
|
|
|
function barListPrototype:GetBarAttachPoint()
|
|
local vertical, growup, lastBar = (self.orientation % 2 == 0), self.growup, self.lastBar
|
|
if vertical then
|
|
if growup then
|
|
return lastBar:GetLeft() - lastBar:GetWidth(), lastBar:GetTop()
|
|
else
|
|
return lastBar:GetRight() + lastBar:GetWidth(), lastBar:GetTop()
|
|
end
|
|
else
|
|
if growup then
|
|
return lastBar:GetLeft(), lastBar:GetTop() + lastBar:GetHeight()
|
|
else
|
|
return lastBar:GetLeft(), lastBar:GetBottom() - lastBar:GetHeight()
|
|
end
|
|
end
|
|
end
|
|
|
|
function barListPrototype:ReverseGrowth(reverse)
|
|
self.growup = reverse
|
|
self.button:ClearAllPoints()
|
|
if self.orientation % 2 == 0 then
|
|
if reverse then
|
|
self.button:SetPoint("TOPRIGHT", self, "TOPRIGHT")
|
|
self.button:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT")
|
|
else
|
|
self.button:SetPoint("TOPLEFT", self, "TOPLEFT")
|
|
self.button:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT")
|
|
end
|
|
else
|
|
if reverse then
|
|
self.button:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT")
|
|
self.button:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT")
|
|
else
|
|
self.button:SetPoint("TOPLEFT", self, "TOPLEFT")
|
|
self.button:SetPoint("TOPRIGHT", self, "TOPRIGHT")
|
|
end
|
|
end
|
|
self:SortBars()
|
|
end
|
|
|
|
function barListPrototype:HasReverseGrowth()
|
|
return self.growup
|
|
end
|
|
|
|
function barListPrototype:UpdateOrientationLayout()
|
|
local vertical, length, thickness = (self.orientation % 2 == 0), self.length, self.thickness
|
|
if vertical then
|
|
barListPrototype.super.SetWidth(self, thickness)
|
|
barListPrototype.super.SetHeight(self, length)
|
|
self.button:SetWidth(thickness)
|
|
self.button:SetHeight(length)
|
|
else
|
|
barListPrototype.super.SetWidth(self, length)
|
|
barListPrototype.super.SetHeight(self, thickness)
|
|
self.button:SetWidth(length)
|
|
self.button:SetHeight(thickness)
|
|
end
|
|
|
|
self.button:SetText(vertical and "" or self.name)
|
|
self:ReverseGrowth(self.growup)
|
|
-- self.button:SetWidth(vertical and 15 or length)
|
|
-- self.button:SetHeight(vertical and length or 15)
|
|
-- self:SortBars()
|
|
end
|
|
|
|
function barListPrototype:SetLength(length)
|
|
self.length = length
|
|
if bars[self] then
|
|
for k, v in pairs(bars[self]) do
|
|
v:SetLength(length)
|
|
end
|
|
end
|
|
self:UpdateOrientationLayout()
|
|
end
|
|
|
|
function barListPrototype:GetLength()
|
|
return self.length
|
|
end
|
|
|
|
function barListPrototype:SetThickness(thickness)
|
|
self.thickness = thickness
|
|
if bars[self] then
|
|
for k, v in pairs(bars[self]) do
|
|
v:SetThickness(thickness)
|
|
end
|
|
end
|
|
self:UpdateOrientationLayout()
|
|
end
|
|
|
|
function barListPrototype:GetThickness()
|
|
return self.thickness
|
|
end
|
|
|
|
function barListPrototype:SetOrientation(orientation)
|
|
self.orientation = orientation
|
|
if bars[self] then
|
|
for k, v in pairs(bars[self]) do
|
|
v:SetOrientation(orientation)
|
|
end
|
|
end
|
|
self:UpdateOrientationLayout()
|
|
end
|
|
|
|
function barListPrototype:GetOrientation()
|
|
return self.orientation
|
|
end
|
|
|
|
function barListPrototype:IsVertical()
|
|
return self.orientation % 2 == 0
|
|
end
|
|
|
|
function barListPrototype:SetSortFunction(func)
|
|
assert(type(func) == "function")
|
|
self.sortFunc = func
|
|
end
|
|
|
|
-- group:SetSortFunction(group.NOOP) to disable sorting
|
|
function barListPrototype.NOOP() end
|
|
|
|
do
|
|
local values = {}
|
|
local function sortFunc(a, b)
|
|
if a.isTimer ~= b.isTimer then
|
|
return a.isTimer
|
|
end
|
|
|
|
local apct, bpct = a.value / a.maxValue, b.value / b.maxValue
|
|
if apct == bpct then
|
|
if a.maxValue == b.maxValue then
|
|
return a.name > b.name
|
|
else
|
|
return a.maxValue > b.maxValue
|
|
end
|
|
else
|
|
return apct > bpct
|
|
end
|
|
end
|
|
function barListPrototype:SortBars()
|
|
local lastBar = self.button:IsVisible() and self.button or self
|
|
local ct = 0
|
|
if not bars[self] then return end
|
|
for k, v in pairs(bars[self]) do
|
|
if not v.isAnimating then
|
|
ct = ct + 1
|
|
values[ct] = v
|
|
end
|
|
end
|
|
for i = ct + 1, #values do
|
|
values[i] = nil
|
|
end
|
|
|
|
table_sort(values, self.sortFunc or sortFunc)
|
|
|
|
local orientation = self.orientation
|
|
local vertical = orientation % 2 == 0
|
|
local growup = self.growup
|
|
local spacing = self.spacing
|
|
|
|
local from, to
|
|
local thickness, showIcon = self.thickness, self.showIcon
|
|
local x1, y1, x2, y2 = 0, 0, 0, 0
|
|
if vertical then
|
|
if growup then
|
|
from = "RIGHT"
|
|
to = "LEFT"
|
|
x1, x2 = -spacing, -spacing
|
|
else
|
|
from = "LEFT"
|
|
to = "RIGHT"
|
|
x1, x2 = spacing, spacing
|
|
end
|
|
else
|
|
if growup then
|
|
from = "BOTTOM"
|
|
to = "TOP"
|
|
y1, y2 = spacing, spacing
|
|
else
|
|
from = "TOP"
|
|
to = "BOTTOM"
|
|
y1, y2 = -spacing, -spacing
|
|
end
|
|
end
|
|
local totalHeight = 0
|
|
for i = 1, #values do
|
|
local origTo = to
|
|
local v = values[i]
|
|
if lastBar == self or lastBar == self.button then
|
|
if lastBar == self then
|
|
to = from
|
|
end
|
|
if vertical then
|
|
if orientation == 2 then
|
|
y1, y2 = 0, (v.showIcon and thickness or 0)
|
|
else
|
|
y1, y2 = (v.showIcon and -thickness or 0), 0
|
|
end
|
|
else
|
|
if orientation == 1 then
|
|
x1, x2 = (v.showIcon and thickness or 0), 0
|
|
else
|
|
x1, x2 = 0, (v.showIcon and -thickness or 0)
|
|
end
|
|
end
|
|
else
|
|
if vertical then
|
|
y1, y2 = 0, 0
|
|
else
|
|
x1, x2 = 0, 0
|
|
end
|
|
end
|
|
|
|
v:ClearAllPoints()
|
|
if self.maxBars and i > self.maxBars then
|
|
v:Hide()
|
|
else
|
|
v:Show()
|
|
if vertical then
|
|
totalHeight = totalHeight + v:GetWidth() + x1
|
|
v:SetPoint("TOP"..from, lastBar, "TOP"..to, x1, y1)
|
|
v:SetPoint("BOTTOM"..from, lastBar, "BOTTOM"..to, x2, y2)
|
|
else
|
|
totalHeight = totalHeight + v:GetHeight() + y1
|
|
v:SetPoint(from.."LEFT", lastBar, to.."LEFT", x1, y1)
|
|
v:SetPoint(from.."RIGHT", lastBar, to.."RIGHT", x2, y2)
|
|
end
|
|
lastBar = v
|
|
end
|
|
to = origTo
|
|
end
|
|
self.lastBar = lastBar
|
|
-- Todo - use another frame for this; anchoring needs to be left alone
|
|
-- if vertical then
|
|
-- self.super.SetWidth(self, 20)
|
|
-- else
|
|
-- self.super.SetHeight(self, 20)
|
|
-- end
|
|
end
|
|
end
|
|
|
|
--[[
|
|
****************************************************************
|
|
*** Bar methods
|
|
****************************************************************
|
|
]]--
|
|
|
|
--[[ Bar Prototype ]]--
|
|
|
|
local DEFAULT_ICON = [[Interface\ICONS\INV_Misc_QuestionMark]]
|
|
function barPrototype:Create(text, value, maxVal, icon, orientation, length, thickness, isTimer)
|
|
|
|
self.callbacks = self.callbacks or CallbackHandler:New(self)
|
|
|
|
self:SetScript("OnSizeChanged", self.OnSizeChanged)
|
|
|
|
self.texture = self.texture or self:CreateTexture(nil, "ARTWORK")
|
|
|
|
if self.timeLeftTriggers then
|
|
for k, v in pairs(self.timeLeftTriggers) do
|
|
self.timeLeftTriggers[k] = false
|
|
end
|
|
end
|
|
|
|
if not self.spark then
|
|
self.spark = self:CreateTexture(nil, "OVERLAY")
|
|
self.spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
|
|
self.spark:SetWidth(10)
|
|
self.spark:SetHeight(10)
|
|
self.spark:SetBlendMode("ADD")
|
|
end
|
|
|
|
self.bgtexture = self.bgtexture or self:CreateTexture(nil, "BACKGROUND")
|
|
self.bgtexture:SetAllPoints()
|
|
self.bgtexture:SetVertexColor(0.3, 0.3, 0.3, 0.6)
|
|
|
|
self.icon = self.icon or self:CreateTexture(nil, "OVERLAY")
|
|
self.icon:SetPoint("LEFT", self, "LEFT", 0, 0)
|
|
self:SetIcon(icon or DEFAULT_ICON)
|
|
self:ShowIcon()
|
|
|
|
self.label = self.label or self:CreateFontString(nil, "OVERLAY", "ChatFontNormal")
|
|
self.label:SetText(text)
|
|
self.label:ClearAllPoints()
|
|
self.label:SetPoint("LEFT", self, "LEFT", 3, 0)
|
|
self:ShowLabel()
|
|
|
|
local f, s, m = self.label:GetFont()
|
|
self.label:SetFont(f, s or 10, m)
|
|
|
|
self.timerLabel = self.timerLabel or self:CreateFontString(nil, "OVERLAY", "ChatFontNormal")
|
|
self:SetTimerLabel("")
|
|
self.timerLabel:ClearAllPoints()
|
|
self.timerLabel:SetPoint("RIGHT", self, "RIGHT", -6, 0)
|
|
self:HideTimerLabel()
|
|
|
|
local f, s, m = self.timerLabel:GetFont()
|
|
self.timerLabel:SetFont(f, s or 10, m)
|
|
|
|
self.timerFuncs = self.timerFuncs or {}
|
|
for i = 1, #self.timerFuncs do
|
|
tremove(self.timerFuncs)
|
|
end
|
|
|
|
self:SetScale(1)
|
|
self:SetAlpha(1)
|
|
--[[
|
|
self.texture:SetAlpha(1)
|
|
self.bgtexture:SetAlpha(0.6)
|
|
self.icon:SetAlpha(1)
|
|
]]--
|
|
|
|
self.flashing = false
|
|
|
|
self.length = length or 200
|
|
self.thickness = thickness or 15
|
|
self:SetOrientation(orientation or 1)
|
|
|
|
value = value or 1
|
|
maxVal = maxVal or value
|
|
self.value = value
|
|
self.maxValue = maxVal
|
|
self.isTimer = isTimer
|
|
|
|
if not isTimer then
|
|
self:SetMaxValue(maxVal)
|
|
else
|
|
self:SetTimer(value, maxVal)
|
|
end
|
|
self:SetValue(value)
|
|
end
|
|
|
|
barPrototype.SetWidth = barListPrototype.SetWidth
|
|
barPrototype.SetHeight = barListPrototype.SetHeight
|
|
|
|
function barPrototype:OnBarReleased()
|
|
self:StopTimer()
|
|
self:StopFlash()
|
|
self:StopFade()
|
|
|
|
self.callbacks:Fire('BarReleased', self, self.name)
|
|
|
|
-- Reset our attributes
|
|
self.isAnimating = false
|
|
self.isTimer = false
|
|
self.ownerGroup = nil
|
|
self.fill = false
|
|
if self.colors then
|
|
for k, v in pairs(self.colors) do
|
|
self.colors[k] = nil
|
|
end
|
|
end
|
|
if self.gradMap then
|
|
for k, v in pairs(self.gradMap) do
|
|
self.gradMap[k] = nil
|
|
end
|
|
end
|
|
if self.timeLeftTriggers then
|
|
for k, v in pairs(self.timeLeftTriggers) do
|
|
self.timeLeftTriggers[k] = nil
|
|
end
|
|
end
|
|
|
|
-- Reset widget
|
|
self.texture:SetVertexColor(1, 1, 1, 0)
|
|
self:SetScript("OnUpdate", nil)
|
|
self:SetParent(UIParent)
|
|
self:ClearAllPoints()
|
|
self:Hide()
|
|
local f, s, m = ChatFontNormal:GetFont()
|
|
self.label:SetFont(f, s or 10, m)
|
|
self.timerLabel:SetFont(f, s or 10, m)
|
|
|
|
-- Cancel all registered callbacks. CBH doesn't seem to provide a method to do this.
|
|
if self.callbacks.insertQueue then
|
|
for eventname, callbacks in pairs(self.callbacks.insertQueue) do
|
|
for k, v in pairs(callbacks) do
|
|
callbacks[k] = nil
|
|
end
|
|
end
|
|
end
|
|
for eventname, callbacks in pairs(self.callbacks.events) do
|
|
for k, v in pairs(callbacks) do
|
|
callbacks[k] = nil
|
|
end
|
|
if self.callbacks.OnUnused then
|
|
self.callbacks.OnUnused(self.callbacks, target, eventname)
|
|
end
|
|
end
|
|
end
|
|
|
|
function barPrototype:GetGroup()
|
|
return self.ownerGroup
|
|
end
|
|
|
|
function barPrototype:OnSizeChanged()
|
|
self:SetValue(self.value)
|
|
end
|
|
|
|
function barPrototype:SetFont(newFont, newSize, newFlags)
|
|
local t, font, size, flags
|
|
t = self.label
|
|
font, size, flags = t:GetFont()
|
|
t:SetFont(newFont or font, newSize or size, newFlags or flags)
|
|
|
|
t = self.timerLabel
|
|
font, size, flags = t:GetFont()
|
|
t:SetFont(newFont or font, newSize or size, newFlags or flags)
|
|
end
|
|
|
|
function barPrototype:AddOnUpdate(f)
|
|
tinsert(self.timerFuncs, f)
|
|
self:SetScript("OnUpdate", self.OnUpdate)
|
|
end
|
|
|
|
function barPrototype:RemoveOnUpdate(f)
|
|
local timerFuncs = self.timerFuncs
|
|
for i = 1, #timerFuncs do
|
|
if f == timerFuncs[i] then
|
|
tremove(timerFuncs, i)
|
|
if #timerFuncs == 0 then
|
|
self:SetScript("OnUpdate", nil)
|
|
end
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
function barPrototype.OnUpdate(f, t)
|
|
local timerFuncs = f.timerFuncs
|
|
for i = 1, #timerFuncs do
|
|
local func = timerFuncs[i]
|
|
if func then
|
|
func(f, t)
|
|
end
|
|
end
|
|
end
|
|
|
|
function barPrototype:SetIcon(icon)
|
|
if icon then
|
|
-- Starting in Legion (WoW 7.x), SetTexture can accept texture IDs directly. This translation via GetSpellInfo does not work any longer, especially since GetItemInfo now returns a texture ID.
|
|
--if type(icon) == "number" then
|
|
-- icon = select(3, GetSpellInfo(icon))
|
|
--end
|
|
self.icon:SetTexture(icon)
|
|
if self.showIcon then
|
|
self.icon:Show()
|
|
end
|
|
else
|
|
self.icon:Hide()
|
|
end
|
|
self.iconTexture = icon or nil
|
|
end
|
|
|
|
function barPrototype:ShowIcon()
|
|
self.showIcon = true
|
|
if self.iconTexture then
|
|
self.icon:Show()
|
|
end
|
|
end
|
|
|
|
function barPrototype:HideIcon()
|
|
self.showIcon = false
|
|
self.icon:Hide()
|
|
end
|
|
|
|
function barPrototype:IsIconShown()
|
|
return self.showIcon
|
|
end
|
|
|
|
function barPrototype:OnAnimateFinished()
|
|
self.callbacks:Fire("AnimateFinished", self, self.name)
|
|
end
|
|
|
|
local function animate(self, elapsed)
|
|
self.aniST = self.aniST + elapsed
|
|
local amt = min(1, self.aniST / self.aniT)
|
|
local x = self.aniSX + ((self.aniX - self.aniSX) * amt)
|
|
local y = self.aniSY + ((self.aniY - self.aniSY) * amt)
|
|
local s = self.aniSS + ((self.aniS - self.aniSS) * amt)
|
|
self:ClearAllPoints()
|
|
self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", x, y)
|
|
self:SetScale(s)
|
|
|
|
if amt == 1 then
|
|
self.isAnimating = false
|
|
self:RemoveOnUpdate(animate)
|
|
safecall(self.OnAnimateFinished, self)
|
|
if self.ownerGroup then
|
|
self:ClearAllPoints()
|
|
self.ownerGroup:SortBars()
|
|
self:UpdateColor()
|
|
self:SetParent(self.ownerGroup)
|
|
self:SetScale(1)
|
|
end
|
|
end
|
|
end
|
|
|
|
function barPrototype:AnimateTo(x, y, scale, t)
|
|
self.isAnimating = true
|
|
self.aniSX, self.aniSY, self.aniSS, self.aniST = self:GetLeft(), self:GetTop(), self:GetScale(), 0
|
|
self.aniX, self.aniY, self.aniS, self.aniT = x, y, scale, t
|
|
self:AddOnUpdate(animate)
|
|
animate(0)
|
|
end
|
|
|
|
function barPrototype:AnimateToGroup(group)
|
|
self.isAnimating = true
|
|
self.ownerGroup:SortBars()
|
|
self.ownerGroup:MoveBarToGroup(self, group)
|
|
self:SetParent(UIParent)
|
|
|
|
local x, y = group:GetBarAttachPoint()
|
|
x = x / UIParent:GetScale()
|
|
y = y / UIParent:GetScale()
|
|
self:AnimateTo(x, y, group:GetScale(), 0.75)
|
|
end
|
|
|
|
function barPrototype:SetLabel(text)
|
|
self.label:SetText(text)
|
|
end
|
|
|
|
function barPrototype:GetLabel(text)
|
|
return self.label:GetText(text)
|
|
end
|
|
|
|
barPrototype.SetText = barPrototype.SetLabel -- for API compatibility
|
|
barPrototype.GetText = barPrototype.GetLabel -- for API compatibility
|
|
|
|
function barPrototype:ShowLabel()
|
|
self.showLabel = true
|
|
self.label:Show()
|
|
end
|
|
|
|
function barPrototype:HideLabel()
|
|
self.showLabel = false
|
|
self.label:Hide()
|
|
end
|
|
|
|
function barPrototype:IsLabelShown()
|
|
return self.showLabel
|
|
end
|
|
|
|
function barPrototype:SetTimerLabel(text)
|
|
self.timerLabel:SetText(text)
|
|
end
|
|
|
|
function barPrototype:GetTimerLabel(text)
|
|
return self.timerLabel:GetText(text)
|
|
end
|
|
|
|
function barPrototype:ShowTimerLabel()
|
|
self.showTimerLabel = true
|
|
self.timerLabel:Show()
|
|
end
|
|
|
|
function barPrototype:HideTimerLabel()
|
|
self.showTimerLabel = false
|
|
self.timerLabel:Hide()
|
|
end
|
|
|
|
function barPrototype:IsValueLabelShown()
|
|
return self.showTimerLabel
|
|
end
|
|
|
|
function barPrototype:SetTexture(texture)
|
|
self.texture:SetTexture(texture)
|
|
self.bgtexture:SetTexture(texture)
|
|
end
|
|
|
|
-- Added by Ulic
|
|
-- Allows for the setting of background colors for a specific bar
|
|
-- Someday I'll figure out to do it at the group level
|
|
function barPrototype:SetBackgroundColor(r, g, b, a)
|
|
a = a or .6
|
|
if r and g and b and a then
|
|
self.bgtexture:SetVertexColor(r, g, b, a)
|
|
end
|
|
end
|
|
|
|
function barPrototype:SetColorAt(at, r, g, b, a)
|
|
self.colors = self.colors or {}
|
|
tinsert(self.colors, at)
|
|
tinsert(self.colors, r)
|
|
tinsert(self.colors, g)
|
|
tinsert(self.colors, b)
|
|
tinsert(self.colors, a)
|
|
ComputeGradient(self)
|
|
self:UpdateColor()
|
|
end
|
|
|
|
function barPrototype:UnsetColorAt(at)
|
|
if not self.colors then return end
|
|
for i = 1, #self.colors, 5 do
|
|
if self.colors[i] == at then
|
|
for j = 1, 5 do
|
|
tremove(self.colors, i)
|
|
end
|
|
ComputeGradient(self)
|
|
self:UpdateColor()
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
function barPrototype:UnsetAllColors()
|
|
if not self.colors then return end
|
|
for i = 1, #self.colors do
|
|
tremove(self.colors)
|
|
end
|
|
end
|
|
|
|
do
|
|
function barPrototype:UpdateOrientationLayout()
|
|
local o = self.orientation
|
|
local t
|
|
if o == lib.LEFT_TO_RIGHT then
|
|
self.icon:ClearAllPoints()
|
|
self.icon:SetPoint("RIGHT", self, "LEFT", 0, 0)
|
|
|
|
t = self.spark
|
|
t:ClearAllPoints()
|
|
t:SetPoint("TOP", self.texture, "TOPRIGHT", 0, 7)
|
|
t:SetPoint("BOTTOM", self.texture, "BOTTOMRIGHT", 0, -7)
|
|
t:SetTexCoord(0, 1, 0, 1)
|
|
|
|
t = self.texture
|
|
t.SetValue = t.SetWidth
|
|
t:ClearAllPoints()
|
|
t:SetPoint("TOPLEFT", self, "TOPLEFT")
|
|
t:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT")
|
|
-- t:SetTexCoord(0, 1, 0, 1)
|
|
|
|
t = self.timerLabel
|
|
t:ClearAllPoints()
|
|
t:SetPoint("RIGHT", self, "RIGHT", -6, 0)
|
|
t:SetJustifyH("RIGHT")
|
|
t:SetJustifyV("MIDDLE")
|
|
|
|
t = self.label
|
|
t:ClearAllPoints()
|
|
t:SetPoint("LEFT", self, "LEFT", 6, 0)
|
|
t:SetPoint("RIGHT", self.timerLabel, "LEFT", 0, 0)
|
|
t:SetJustifyH("LEFT")
|
|
t:SetJustifyV("MIDDLE")
|
|
|
|
self.bgtexture:SetTexCoord(0, 1, 0, 1)
|
|
elseif o == lib.BOTTOM_TO_TOP then
|
|
self.icon:ClearAllPoints()
|
|
self.icon:SetPoint("TOP", self, "BOTTOM", 0, 0)
|
|
|
|
t = self.spark
|
|
t:ClearAllPoints()
|
|
t:SetPoint("LEFT", self.texture, "TOPLEFT", -7, 0)
|
|
t:SetPoint("RIGHT", self.texture, "TOPRIGHT", 7, 0)
|
|
t:SetTexCoord(0, 1, 1, 1, 0, 0, 1, 0)
|
|
|
|
t = self.texture
|
|
t.SetValue = t.SetHeight
|
|
t:ClearAllPoints()
|
|
t:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT")
|
|
t:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT")
|
|
-- t:SetTexCoord(0, 1, 1, 1, 0, 0, 1, 0)
|
|
|
|
t = self.timerLabel
|
|
t:ClearAllPoints()
|
|
t:SetPoint("TOPLEFT", self, "TOPLEFT", 3, -3)
|
|
t:SetPoint("TOPRIGHT", self, "TOPRIGHT", -3, -3)
|
|
t:SetJustifyH("CENTER")
|
|
t:SetJustifyV("TOP")
|
|
|
|
t = self.label
|
|
t:ClearAllPoints()
|
|
t:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -3, 3)
|
|
t:SetPoint("TOPLEFT", self.timerLabel, "BOTTOMLEFT", 0, 0)
|
|
t:SetJustifyH("CENTER")
|
|
t:SetJustifyV("BOTTOM")
|
|
|
|
self.bgtexture:SetTexCoord(0, 1, 1, 1, 0, 0, 1, 0)
|
|
elseif o == lib.RIGHT_TO_LEFT then
|
|
self.icon:ClearAllPoints()
|
|
self.icon:SetPoint("LEFT", self, "RIGHT", 0, 0)
|
|
|
|
t = self.spark
|
|
t:ClearAllPoints()
|
|
t:SetPoint("TOP", self.texture, "TOPLEFT", 0, 7)
|
|
t:SetPoint("BOTTOM", self.texture, "BOTTOMLEFT", 0, -7)
|
|
t:SetTexCoord(0, 1, 0, 1)
|
|
|
|
t = self.texture
|
|
t.SetValue = t.SetWidth
|
|
t:ClearAllPoints()
|
|
t:SetPoint("TOPRIGHT", self, "TOPRIGHT")
|
|
t:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT")
|
|
-- t:SetTexCoord(0, 1, 0, 1)
|
|
|
|
t = self.timerLabel
|
|
t:ClearAllPoints()
|
|
t:SetPoint("LEFT", self, "LEFT", 6, 0)
|
|
t:SetJustifyH("LEFT")
|
|
t:SetJustifyV("MIDDLE")
|
|
|
|
t = self.label
|
|
t:ClearAllPoints()
|
|
t:SetPoint("RIGHT", self, "RIGHT", -6, 0)
|
|
t:SetPoint("LEFT", self.timerLabel, "RIGHT", 0, 0)
|
|
t:SetJustifyH("RIGHT")
|
|
t:SetJustifyV("MIDDLE")
|
|
|
|
self.bgtexture:SetTexCoord(0, 1, 0, 1)
|
|
elseif o == lib.TOP_TO_BOTTOM then
|
|
self.icon:ClearAllPoints()
|
|
self.icon:SetPoint("BOTTOM", self, "TOP", 0, 0)
|
|
|
|
t = self.spark
|
|
t:ClearAllPoints()
|
|
t:SetPoint("LEFT", self.texture, "BOTTOMLEFT", -7, 0)
|
|
t:SetPoint("RIGHT", self.texture, "BOTTOMRIGHT", 7, 0)
|
|
t:SetTexCoord(0, 1, 1, 1, 0, 0, 1, 0)
|
|
|
|
t = self.texture
|
|
t.SetValue = t.SetHeight
|
|
t:ClearAllPoints()
|
|
t:SetPoint("TOPLEFT", self, "TOPLEFT")
|
|
t:SetPoint("TOPRIGHT", self, "TOPRIGHT")
|
|
-- t:SetTexCoord(0, 1, 1, 1, 0, 0, 1, 0)
|
|
|
|
t = self.timerLabel
|
|
t:ClearAllPoints()
|
|
t:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 3, 3)
|
|
t:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -3, 3)
|
|
t:SetJustifyH("CENTER")
|
|
t:SetJustifyV("BOTTOM")
|
|
|
|
t = self.label
|
|
t:ClearAllPoints()
|
|
t:SetPoint("TOPLEFT", self, "TOPLEFT", 3, -3)
|
|
t:SetPoint("BOTTOMRIGHT", self.timerLabel, "TOPRIGHT", 0, 0)
|
|
t:SetJustifyH("CENTER")
|
|
t:SetJustifyV("TOP")
|
|
|
|
self.bgtexture:SetTexCoord(0, 1, 1, 1, 0, 0, 1, 0)
|
|
end
|
|
self:SetValue(self.value or 0)
|
|
end
|
|
end
|
|
|
|
function barPrototype:GetLength()
|
|
return self.length
|
|
end
|
|
|
|
do
|
|
local function updateSize(self)
|
|
local vertical, thickness, length = self.orientation % 2 == 0, self.thickness, self.length
|
|
local iconSize = self.showIcon and (vertical and length or thickness) or 0
|
|
local width = vertical and thickness or max(0.0001, length - iconSize)
|
|
local height = vertical and max(0.00001,length - iconSize) or thickness
|
|
barPrototype.super.SetWidth(self, width)
|
|
barPrototype.super.SetHeight(self, height)
|
|
self.icon:SetWidth(thickness)
|
|
self.icon:SetHeight(thickness)
|
|
end
|
|
|
|
function barPrototype:SetLength(length)
|
|
self.length = length
|
|
updateSize(self)
|
|
end
|
|
|
|
function barPrototype:SetThickness(thickness)
|
|
self.thickness = thickness
|
|
updateSize(self)
|
|
end
|
|
end
|
|
|
|
function barPrototype:GetThickness()
|
|
return self.thickness
|
|
end
|
|
|
|
function barPrototype:SetOrientation(orientation)
|
|
self.orientation = orientation
|
|
self:UpdateOrientationLayout()
|
|
self:SetThickness(self.thickness)
|
|
end
|
|
|
|
function barPrototype:GetOrientation()
|
|
return self.orientation
|
|
end
|
|
|
|
function barPrototype:IsVertical()
|
|
return self.orientation % 2 == 0
|
|
end
|
|
|
|
function barPrototype:SetValue(val, maxValue)
|
|
assert(val ~= nil, "Value cannot be nil!")
|
|
self.value = val
|
|
if maxValue ~= nil then
|
|
self.maxValue = maxValue
|
|
end
|
|
if not self.maxValue or val > self.maxValue then
|
|
self.maxValue = val
|
|
end
|
|
local ownerGroup = self.ownerGroup
|
|
local displayMax = ownerGroup and ownerGroup.displayMax or self.displayMax
|
|
if displayMax then
|
|
displayMax = min(displayMax, self.maxValue)
|
|
else
|
|
displayMax = self.maxValue
|
|
end
|
|
local amt
|
|
|
|
if val == 0 then
|
|
amt = 0
|
|
else
|
|
amt = min(1, val / displayMax)
|
|
end
|
|
|
|
if amt == 1 or amt == 0 then
|
|
self.spark:Hide()
|
|
else
|
|
self.spark:Show()
|
|
end
|
|
local dist = (ownerGroup and ownerGroup:GetLength()) or self.length
|
|
self:SetTextureValue(max(amt, 0.000001), dist)
|
|
self:UpdateColor()
|
|
end
|
|
|
|
function barPrototype:SetTextureValue(amt, dist)
|
|
dist = max(0.0001, dist - (self.showIcon and self.thickness or 0))
|
|
local t, o = self.texture, self.orientation
|
|
t:SetValue(amt * dist)
|
|
if o == 1 then
|
|
t:SetTexCoord(0, amt, 0, 1)
|
|
elseif o == 2 then
|
|
t:SetTexCoord(1 - amt, 1, 1, 1, 1 - amt, 0, 1, 0)
|
|
elseif o == 3 then
|
|
t:SetTexCoord(1 - amt, 1, 0, 1)
|
|
elseif o == 4 then
|
|
t:SetTexCoord(0, 1, amt, 1, 0, 0, amt, 0)
|
|
end
|
|
end
|
|
|
|
function barPrototype:SetDisplayMax(val)
|
|
self.displayMax = val
|
|
end
|
|
|
|
function barPrototype:SetMaxValue(val)
|
|
self:SetValue(self.value, val)
|
|
end
|
|
|
|
function barPrototype:RegisterTimeLeftTrigger(time, func)
|
|
if time > 0 then
|
|
self.timeLeftTriggers = self.timeLeftTriggers or {}
|
|
self.timeLeftTriggerFuncs = self.timeLeftTriggerFuncs or {}
|
|
self.timeLeftTriggers[time] = false
|
|
self.timeLeftTriggerFuncs[time] = func
|
|
end
|
|
end
|
|
|
|
function barPrototype:OnTimerStarted()
|
|
self.callbacks:Fire("TimerStarted", self, self.name)
|
|
end
|
|
|
|
function barPrototype:OnTimerStopped()
|
|
self.callbacks:Fire("TimerStopped", self, self.name)
|
|
end
|
|
|
|
function barPrototype:OnTimerFinished()
|
|
self.callbacks:Fire("TimerFinished", self, self.name)
|
|
end
|
|
|
|
function barPrototype:SetTimer(remaining, maxVal)
|
|
if not self.isTimer then return end
|
|
self:StopFade()
|
|
self.maxValue = maxVal or self.maxValue
|
|
self:SetValue(self.fill and self.maxValue - remaining or remaining)
|
|
|
|
self.timerLabel:Show()
|
|
self.startTime = GetTime() - (self.maxValue - remaining)
|
|
self.lastElapsed = 0
|
|
self.updateDelay = min(max(self.maxValue, 1) / self.length, 0.05)
|
|
self:UpdateTimer()
|
|
if remaining > 0 then
|
|
self:RemoveOnUpdate(self.UpdateTimer)
|
|
self:AddOnUpdate(self.UpdateTimer)
|
|
if not self.isTimerRunning then
|
|
self.isTimerRunning = true
|
|
safecall(self.OnTimerStarted, self)
|
|
end
|
|
end
|
|
end
|
|
|
|
function barPrototype:StopTimer()
|
|
if self.isTimer and self.isTimerRunning then
|
|
self:RemoveOnUpdate(self.UpdateTimer)
|
|
self.isTimerRunning = false
|
|
safecall(self.OnTimerStopped, self)
|
|
end
|
|
end
|
|
|
|
function barPrototype:SetFill(fill)
|
|
self.fill = fill
|
|
end
|
|
|
|
function barPrototype:UpdateColor()
|
|
local amt = 1
|
|
if self.maxValue ~= 0 then
|
|
amt = floor(self.value / self.maxValue * 200) * 4
|
|
end
|
|
local map
|
|
if self.gradMap and #self.gradMap > 0 then
|
|
map = self.gradMap
|
|
elseif self.ownerGroup and self.ownerGroup.gradMap and #self.ownerGroup.gradMap > 0 then
|
|
map = self.ownerGroup.gradMap
|
|
end
|
|
if map then
|
|
self.texture:SetVertexColor(map[amt], map[amt+1], map[amt+2], map[amt+3])
|
|
end
|
|
end
|
|
|
|
function barPrototype:UpdateTimer(t)
|
|
local t = GetTime()
|
|
local elapsed, elapsedClamped = t - self.startTime, floor(t) - floor(self.startTime)
|
|
self.lastElapsed = self.lastElapsed or 0
|
|
if elapsed - self.lastElapsed <= self.updateDelay then
|
|
return
|
|
end
|
|
self.lastElapsed = elapsed
|
|
|
|
local maxvalue = self.maxValue
|
|
local value, valueClamped, remaining, texcoord
|
|
if not self.fill then
|
|
value = maxvalue - elapsed
|
|
remaining = value
|
|
valueClamped = maxvalue - elapsedClamped
|
|
texcoord = 1 - (elapsed / maxvalue)
|
|
else
|
|
value = elapsed
|
|
remaining = maxvalue - value
|
|
valueClamped = elapsedClamped
|
|
texcoord = elapsed / maxvalue
|
|
end
|
|
if self.timeLeftTriggers then
|
|
for k, v in pairs(self.timeLeftTriggers) do
|
|
if not v and remaining < k then
|
|
self.timeLeftTriggers[k] = true
|
|
self.timeLeftTriggerFuncs[k](self, k, remaining)
|
|
end
|
|
end
|
|
end
|
|
if remaining <= 0 then
|
|
self:RemoveOnUpdate(self.UpdateTimer)
|
|
self.isTimerRunning = false
|
|
safecall(self.OnTimerFinished, self)
|
|
end
|
|
if valueClamped >= 3600 then
|
|
local h, m, s
|
|
h = floor(valueClamped / 3600)
|
|
m = floor((valueClamped - (h * 3600)) / 60)
|
|
s = floor((valueClamped - (h * 3600)) - (m * 60))
|
|
self:SetTimerLabel(("%02.0f:%02.0f:%02.0f"):format(h, m, s))
|
|
elseif valueClamped >= 60 then
|
|
local m, s
|
|
m = floor(valueClamped / 60)
|
|
s = floor(valueClamped - (m * 60))
|
|
self:SetTimerLabel(("%02.0f:%02.0f"):format(m, s))
|
|
elseif valueClamped > 10 then
|
|
self:SetTimerLabel(("%02.0f"):format(valueClamped))
|
|
else
|
|
self:SetTimerLabel(("%02.1f"):format(abs(value)))
|
|
end
|
|
self:SetValue(value)
|
|
|
|
local o = self.orientation
|
|
if o == lib.LEFT_TO_RIGHT then
|
|
self.texture:SetTexCoord(0, value/maxvalue, 0, 1)
|
|
elseif o == lib.RIGHT_TO_LEFT then
|
|
self.texture:SetTexCoord(1-(value/maxvalue), 1, 0, 1)
|
|
elseif o == lib.BOTTOM_TO_TOP then
|
|
self.texture:SetTexCoord(1-(value/maxvalue), 1, 1, 1, 1-value/maxvalue, 0, 1, 0)
|
|
elseif o == lib.TOP_TO_BOTTOM then
|
|
self.texture:SetTexCoord(0, 1, value/maxvalue, 1, 0, 0, value/maxvalue, 0)
|
|
end
|
|
end
|
|
|
|
function barPrototype:OnFadeStarted()
|
|
self.callbacks:Fire("FadeStarted", self, self.name)
|
|
end
|
|
|
|
function barPrototype:OnFadeFinished()
|
|
self.callbacks:Fire("FadeFinished", self, self.name)
|
|
end
|
|
|
|
function barPrototype:OnFadeStopped()
|
|
self.callbacks:Fire("FadeStopped", self, self.name)
|
|
end
|
|
|
|
do
|
|
local function fade(self, elapsed)
|
|
self.fadeElapsed = (self.fadeElapsed or 0) + elapsed
|
|
self:SetAlpha(self.fadeAlpha * (1 - min(1, max(0, self.fadeElapsed / self.fadeTotal))))
|
|
if self.fadeElapsed > self.fadeTotal then
|
|
self:RemoveOnUpdate(fade)
|
|
self.fadeElapsed, self.fadeTotal, self.fadeAlpha, self.fading = nil, nil, nil, false
|
|
safecall(self.OnFadeFinished, self)
|
|
end
|
|
end
|
|
|
|
function barPrototype:Fade(t)
|
|
if self.fading then return end
|
|
self:StopTimer()
|
|
self.fading = true
|
|
t = t or 0.5
|
|
self.fadeTotal = t
|
|
self.fadeElapsed = 0
|
|
self.fadeAlpha = self.flashAlpha or self:GetAlpha()
|
|
self:AddOnUpdate(fade)
|
|
fade(self, 0)
|
|
safecall(self.OnFadeStarted, self)
|
|
end
|
|
|
|
function barPrototype:StopFade()
|
|
if self.fading then
|
|
self:RemoveOnUpdate(fade)
|
|
self:SetAlpha(self.fadeAlpha)
|
|
self.fadeElapsed, self.fadeTotal, self.fadeAlpha, self.fading = nil, nil, nil, false
|
|
safecall(self.OnFadeStopped, self)
|
|
end
|
|
end
|
|
|
|
function barPrototype:IsFading()
|
|
return self.fading
|
|
end
|
|
end
|
|
|
|
function barPrototype:OnFlashStarted()
|
|
self.callbacks:Fire("FlashStarted", self, self.name)
|
|
end
|
|
|
|
function barPrototype:OnFlashStopped()
|
|
self.callbacks:Fire("FlashStopped", self, self.name)
|
|
end
|
|
|
|
do
|
|
local TWOPI = _G.math.pi * 2
|
|
local function flash(self, t)
|
|
self.flashTime = self.flashTime + t
|
|
if self.flashTime > TWOPI then
|
|
self.flashTime = self.flashTime - TWOPI
|
|
if self.flashTimes then
|
|
self.flashedTimes = self.flashedTimes + 1
|
|
if self.flashedTimes >= self.flashTimes then
|
|
self:StopFlash()
|
|
end
|
|
end
|
|
end
|
|
local amt = self.flashAlpha * (cos(self.flashTime / self.flashPeriod) + 1) / 2
|
|
self:SetAlpha(amt)
|
|
end
|
|
|
|
function barPrototype:Flash(period, times)
|
|
self.flashTimes = times
|
|
self.flashTime = 0
|
|
self.flashedTimes = 0
|
|
self.flashPeriod = (period or 1 / 5) or 0.1
|
|
if not self.flashing then
|
|
self.flashing = true
|
|
self.flashAlpha = self.fadeAlpha or self:GetAlpha()
|
|
self:SetAlpha(self.flashAlpha)
|
|
self:AddOnUpdate(flash)
|
|
safecall(self.OnFlashStarted, self)
|
|
end
|
|
end
|
|
|
|
function barPrototype:StopFlash()
|
|
if self.flashing then
|
|
self:SetAlpha(self.flashAlpha)
|
|
self.flashing, self.flashAlpha = false, nil
|
|
self:RemoveOnUpdate(flash)
|
|
safecall(self.OnFlashStopped, self)
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Finally: upgrade our old embeds
|
|
for target, v in pairs(lib.embeds) do
|
|
lib:Embed(target)
|
|
end
|
|
|