991 lines
28 KiB
Lua
991 lines
28 KiB
Lua
-- ***************************************************
|
|
-- ** Deadly Bar Timers **
|
|
-- ** http://www.deadlybossmods.com **
|
|
-- ***************************************************
|
|
--
|
|
-- This addon is written and copyrighted by:
|
|
-- * Paul Emmerich (Tandanu @ EU-Aegwynn) (DBM-Core)
|
|
-- * Martin Verges (Nitram @ EU-Azshara) (DBM-GUI)
|
|
--
|
|
-- The localizations are written by:
|
|
-- * enGB/enUS: Tandanu http://www.deadlybossmods.com
|
|
-- * deDE: Tandanu http://www.deadlybossmods.com
|
|
-- * zhCN: Diablohu http://wow.gamespot.com.cn
|
|
-- * ruRU: BootWin bootwin@gmail.com
|
|
-- * zhTW: Azael/kc10577 kc10577@hotmail.com
|
|
-- * esES: Interplay/1nn7erpLaY http://www.1nn7erpLaY.com
|
|
-- * (add your names here!)
|
|
--
|
|
-- Special thanks to:
|
|
-- * Arta (DBM-Party)
|
|
--
|
|
--
|
|
-- The code of this addon is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 License. (see license.txt)
|
|
-- All included textures and sounds are copyrighted by their respective owners.
|
|
--
|
|
--
|
|
-- You are free:
|
|
-- * to Share ?to copy, distribute, display, and perform the work
|
|
-- * to Remix ?to make derivative works
|
|
-- Under the following conditions:
|
|
-- * Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
|
|
-- * Noncommercial. You may not use this work for commercial purposes.
|
|
-- * Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
|
|
|
|
|
|
---------------
|
|
-- Globals --
|
|
---------------
|
|
DBT = {}
|
|
DBT_SavedOptions = {}
|
|
|
|
|
|
--------------
|
|
-- Locals --
|
|
--------------
|
|
local fCounter = 1
|
|
local barPrototype = {}
|
|
local unusedBars = {}
|
|
local unusedBarObjects = setmetatable({}, {__mode = "kv"})
|
|
local instances = {}
|
|
local updateClickThrough
|
|
local options
|
|
local function stringFromTimer(t)
|
|
if t <= 60 then
|
|
return ("%.1f"):format(t)
|
|
else
|
|
return ("%d:%0.2d"):format(t/60, math.fmod(t, 60))
|
|
end
|
|
end
|
|
|
|
|
|
-----------------------
|
|
-- Default Options --
|
|
-----------------------
|
|
options = {
|
|
BarXOffset = {
|
|
type = "number",
|
|
default = 0,
|
|
},
|
|
BarYOffset = {
|
|
type = "number",
|
|
default = 0,
|
|
},
|
|
HugeBarXOffset = {
|
|
type = "number",
|
|
default = 0,
|
|
},
|
|
HugeBarYOffset = {
|
|
type = "number",
|
|
default = 0,
|
|
},
|
|
ExpandUpwards = {
|
|
type = "boolean",
|
|
default = false,
|
|
},
|
|
Flash = {
|
|
type = "boolean",
|
|
default = true,
|
|
},
|
|
FadeIn = {
|
|
type = "boolean",
|
|
default = true,
|
|
},
|
|
Break = {
|
|
type = "boolean",
|
|
default = true,
|
|
},
|
|
IconLeft = {
|
|
type = "boolean",
|
|
default = true,
|
|
},
|
|
IconRight = {
|
|
type = "boolean",
|
|
default = false,
|
|
},
|
|
Texture = {
|
|
type = "string",
|
|
default = "Interface\\AddOns\\DBM-Core\\textures\\default.tga",
|
|
},
|
|
StartColorR = {
|
|
type = "number",
|
|
default = 1,
|
|
},
|
|
StartColorG = {
|
|
type = "number",
|
|
default = 0.7,
|
|
},
|
|
StartColorB = {
|
|
type = "number",
|
|
default = 0,
|
|
},
|
|
EndColorR = {
|
|
type = "number",
|
|
default = 1,
|
|
},
|
|
EndColorG = {
|
|
type = "number",
|
|
default = 0,
|
|
},
|
|
EndColorB = {
|
|
type = "number",
|
|
default = 0,
|
|
},
|
|
TextColorR = {
|
|
type = "number",
|
|
default = 1,
|
|
},
|
|
TextColorG = {
|
|
type = "number",
|
|
default = 1,
|
|
},
|
|
TextColorB = {
|
|
type = "number",
|
|
default = 1,
|
|
},
|
|
DynamicColor = {
|
|
type = "boolean",
|
|
default = true,
|
|
},
|
|
Width = {
|
|
type = "number",
|
|
default = 183,
|
|
},
|
|
Scale = {
|
|
type = "number",
|
|
default = 0.9,
|
|
},
|
|
HugeBarsEnabled = {
|
|
type = "boolean",
|
|
default = true,
|
|
},
|
|
HugeWidth = {
|
|
type = "number",
|
|
default = 200,
|
|
},
|
|
HugeScale = {
|
|
type = "number",
|
|
default = 1.03,
|
|
},
|
|
TimerPoint = {
|
|
type = "string",
|
|
default = "TOPRIGHT",
|
|
},
|
|
TimerX = {
|
|
type = "number",
|
|
default = -223,
|
|
},
|
|
TimerY = {
|
|
type = "number",
|
|
default = -260,
|
|
},
|
|
HugeTimerPoint = {
|
|
type = "string",
|
|
default = "CENTER",
|
|
},
|
|
HugeTimerX = {
|
|
type = "number",
|
|
default = 0,
|
|
},
|
|
HugeTimerY = {
|
|
type = "number",
|
|
default = -120,
|
|
},
|
|
EnlargeBarsTime = {
|
|
type = "number",
|
|
default = 8,
|
|
},
|
|
EnlargeBarsPercent = {
|
|
type = "number",
|
|
default = 0.125,
|
|
},
|
|
FillUpBars = {
|
|
type = "boolean",
|
|
default = true,
|
|
},
|
|
ClickThrough = {
|
|
type = "boolean",
|
|
default = false,
|
|
},
|
|
Font = {
|
|
type = "string",
|
|
default = STANDARD_TEXT_FONT,
|
|
},
|
|
FontSize = {
|
|
type = "number",
|
|
default = 10
|
|
}
|
|
}
|
|
|
|
--------------------------
|
|
-- Double Linked List --
|
|
--------------------------
|
|
--
|
|
-- this linked list can only contain tables that do not use the fields "prev" and "next"
|
|
-- this restriction especially means that an object must not be in two different linked lists at the same time
|
|
-- but this is sufficient for DBT here, having a wrapper object would just be an unnecessary overhead
|
|
-- special table keys for "prev"/"next" (e.g. userdata values) would add unnecessary complexity
|
|
|
|
local DLL = {}
|
|
DLL.__index = DLL
|
|
|
|
function DLL:Append(obj)
|
|
if self.first == nil then -- list is empty
|
|
self.first = obj
|
|
self.last = obj
|
|
else -- list is not empty
|
|
obj.prev = self.last
|
|
self.last.next = obj
|
|
self.last = obj
|
|
end
|
|
return obj
|
|
end
|
|
|
|
function DLL:Remove(obj)
|
|
if self.first == nil then -- list is empty...
|
|
-- ...meaning the object is not even in the list, nothing we can do here expect for removing the "prev" and "next" entries from obj
|
|
elseif self.first == obj and self.last == obj then -- list has only one element
|
|
self.first = nil
|
|
self.last = nil
|
|
elseif self.first == obj then -- trying to remove the first element
|
|
self.first = obj.next
|
|
self.first.prev = nil
|
|
elseif self.last == obj then -- trying to remove the last element
|
|
self.last = obj.prev
|
|
self.last.next = nil
|
|
elseif obj.prev and obj.next then -- trying to remove something in the middle of the list
|
|
obj.prev.next, obj.next.prev = obj.next, obj.prev
|
|
end
|
|
obj.prev = nil
|
|
obj.next = nil
|
|
end
|
|
|
|
function DLL:New()
|
|
return setmetatable({
|
|
first = nil,
|
|
last = nil
|
|
}, self)
|
|
end
|
|
setmetatable(DLL, {__call = DLL.New})
|
|
|
|
|
|
-------------------------------
|
|
-- DBT Constructor/Options --
|
|
-------------------------------
|
|
do
|
|
local mt = {__index = DBT}
|
|
local optionMT = {
|
|
__index = function(t, k)
|
|
if options[k] then
|
|
return options[k].default
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
}
|
|
|
|
function DBT:New()
|
|
local obj = setmetatable(
|
|
{
|
|
options = setmetatable({}, optionMT),
|
|
defaultOptions = setmetatable({}, optionMT),
|
|
mainAnchor = CreateFrame("Frame", nil, UIParent),
|
|
secAnchor = CreateFrame("Frame", nil, UIParent),
|
|
bars = {},
|
|
smallBars = DLL(),
|
|
hugeBars = DLL()
|
|
},
|
|
mt
|
|
)
|
|
obj.mainAnchor:SetHeight(1)
|
|
obj.mainAnchor:SetWidth(1)
|
|
obj.mainAnchor:SetPoint("TOPRIGHT", 223, -260)
|
|
obj.mainAnchor:SetClampedToScreen(true)
|
|
obj.mainAnchor:SetMovable(true)
|
|
obj.mainAnchor:Show()
|
|
obj.secAnchor:SetHeight(1)
|
|
obj.secAnchor:SetWidth(1)
|
|
obj.secAnchor:SetPoint("CENTER", 0, -120)
|
|
obj.secAnchor:SetClampedToScreen(true)
|
|
obj.secAnchor:SetMovable(true)
|
|
obj.secAnchor:Show()
|
|
table.insert(instances, obj)
|
|
return obj
|
|
end
|
|
|
|
function DBT:LoadOptions(id)
|
|
local savedOptions;
|
|
if type(id) == "table" then
|
|
savedOptions = id;
|
|
else
|
|
DBT_SavedOptions[id] = DBT_SavedOptions[id] or {};
|
|
savedOptions = DBT_SavedOptions[id];
|
|
end
|
|
self.options = setmetatable(savedOptions, optionMT)
|
|
self.mainAnchor:ClearAllPoints()
|
|
self.secAnchor:ClearAllPoints()
|
|
self.mainAnchor:SetPoint(self.options.TimerPoint, UIParent, self.options.TimerPoint, self.options.TimerX, self.options.TimerY)
|
|
self.secAnchor:SetPoint(self.options.HugeTimerPoint, UIParent, self.options.HugeTimerPoint, self.options.HugeTimerX, self.options.HugeTimerY)
|
|
end
|
|
end
|
|
|
|
function DBT:SetOption(option, value)
|
|
if not options[option] then
|
|
error(("Invalid option: %s"):format(tostring(option)), 2)
|
|
elseif options[option].type and type(value) ~= options[option].type then
|
|
error(("The option %s requires a %s value. (tried to assign a %s value)"):format(tostring(option), tostring(options[option].type), tostring(type(value))), 2)
|
|
elseif options[option].checkFunc then
|
|
local ok, errMsg = options[option].checkFunc(self, option, value)
|
|
if not ok then
|
|
error(("Error while setting option %s to %s: %s"):format(tostring(option), tostring(value), tostring(errMsg)), 2)
|
|
end
|
|
end
|
|
local oldValue = self.options[option]
|
|
self.options[option] = value
|
|
if options[option].onChange then
|
|
options[option].onChange(self, value, oldValue)
|
|
end
|
|
self:ApplyStyle()
|
|
end
|
|
|
|
function DBT:GetOption(option)
|
|
return self.options[option]
|
|
end
|
|
|
|
function DBT:GetDefaultOption(option)
|
|
return self.defaultOptions[option]
|
|
end
|
|
|
|
|
|
-----------------------
|
|
-- Bar Constructor --
|
|
-----------------------
|
|
do
|
|
local function createBarFrame(self)
|
|
local frame
|
|
if unusedBars[#unusedBars] then
|
|
frame = unusedBars[#unusedBars]
|
|
unusedBars[#unusedBars] = nil
|
|
frame:Show()
|
|
else
|
|
frame = CreateFrame("Frame", "DBT_Bar_"..fCounter, self.mainAnchor, "DBTBarTemplate")
|
|
fCounter = fCounter + 1
|
|
end
|
|
frame:EnableMouse(not self.options.ClickThrough or self.movable)
|
|
return frame
|
|
end
|
|
local mt = {__index = barPrototype}
|
|
|
|
function DBT:CreateBar(timer, id, icon, huge, small, color, isDummy)
|
|
if timer <= 0 then return end
|
|
if (self.numBars or 0) >= 15 and not isDummy then return end
|
|
local newBar = self:GetBar(id)
|
|
if newBar then -- update an existing bar
|
|
newBar:SetTimer(timer) -- this can kill the timer and the timer methods don't like dead timers
|
|
if newBar.dead then return end
|
|
newBar:SetElapsed(0) -- same
|
|
if newBar.dead then return end
|
|
newBar:ApplyStyle()
|
|
newBar:SetText(id)
|
|
newBar:SetIcon(icon)
|
|
else -- create a new one
|
|
newBar = next(unusedBarObjects, nil)
|
|
local newFrame = createBarFrame(self)
|
|
if newBar then
|
|
unusedBarObjects[newBar] = nil
|
|
newBar.dead = nil -- resurrected it :)
|
|
newBar.frame = newFrame
|
|
newBar.id = id
|
|
newBar.timer = timer
|
|
newBar.totalTime = timer
|
|
newBar.owner = self
|
|
newBar.moving = nil
|
|
newBar.enlarged = nil
|
|
newBar.fadingIn = 0
|
|
newBar.small = small
|
|
newBar.color = color
|
|
newBar.flashing = nil
|
|
else -- duplicate code ;(
|
|
newBar = setmetatable({
|
|
frame = newFrame,
|
|
id = id,
|
|
timer = timer,
|
|
totalTime = timer,
|
|
owner = self,
|
|
moving = nil,
|
|
enlarged = nil,
|
|
fadingIn = 0,
|
|
small = small,
|
|
color = color,
|
|
flashing = nil
|
|
}, mt)
|
|
end
|
|
newFrame.obj = newBar
|
|
self.numBars = (self.numBars or 0) + 1
|
|
if (timer <= self.options.EnlargeBarsTime or huge) and self:GetOption("HugeBarsEnabled") then -- starts enlarged?
|
|
newBar.enlarged = true
|
|
self.hugeBars:Append(newBar)
|
|
else
|
|
self.smallBars:Append(newBar)
|
|
end
|
|
newBar:ApplyStyle()
|
|
newBar:SetText(id)
|
|
newBar:SetIcon(icon)
|
|
newBar:SetPosition()
|
|
newBar:Update(0)
|
|
self.bars[newBar] = true
|
|
end
|
|
return newBar
|
|
end
|
|
end
|
|
|
|
|
|
-----------------
|
|
-- Dummy Bar --
|
|
-----------------
|
|
do
|
|
local dummyBars = 0
|
|
local function dummyCancel(self)
|
|
self.timer = self.totalTime
|
|
self.flashing = nil
|
|
self:Update(0)
|
|
self.flashing = nil
|
|
getglobal(self.frame:GetName().."BarSpark"):SetAlpha(1)
|
|
end
|
|
function DBT:CreateDummyBar()
|
|
dummyBars = dummyBars + 1
|
|
local dummy = self:CreateBar(25, "dummy"..dummyBars, "Interface\\Icons\\Spell_Nature_WispSplode", nil, true, nil, true)
|
|
dummy:SetText("Dummy")
|
|
dummy:Cancel()
|
|
self.bars[dummy] = true
|
|
unusedBars[#unusedBars] = nil
|
|
unusedBarObjects[dummy] = nil
|
|
dummy.frame.obj = dummy
|
|
dummy.frame:SetParent(UIParent)
|
|
dummy.frame:ClearAllPoints()
|
|
dummy.frame:SetScript("OnUpdate", nil)
|
|
dummy.Cancel = dummyCancel
|
|
dummy:ApplyStyle()
|
|
dummy.dummy = true
|
|
return dummy
|
|
end
|
|
end
|
|
|
|
|
|
-----------------------------
|
|
-- General Bar Functions --
|
|
-----------------------------
|
|
--do
|
|
-- local function iterator(self, frame)
|
|
-- return not frame and self.mainFirstBar or frame and frame.next
|
|
-- end
|
|
--
|
|
-- local function reverseIterator(self, frame)
|
|
-- return (not frame and self.mainLastBar) or frame and frame.prev
|
|
-- end
|
|
--
|
|
-- function DBT:GetBarIterator(reverse)
|
|
-- return (reverse and reverseIterator) or iterator, self, nil
|
|
-- end
|
|
--end
|
|
function DBT:GetBarIterator()
|
|
return pairs(self.bars)
|
|
end
|
|
|
|
function DBT:GetBar(id)
|
|
for bar in self:GetBarIterator() do
|
|
if id == bar.id then
|
|
return bar
|
|
end
|
|
end
|
|
end
|
|
|
|
function DBT:CancelBar(id)
|
|
for bar in self:GetBarIterator() do
|
|
if id == bar.id then
|
|
bar:Cancel()
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function DBT:UpdateBar(id, elapsed, totalTime)
|
|
for bar in self:GetBarIterator() do
|
|
if id == bar.id then
|
|
bar:SetTimer(totalTime or bar.totalTime)
|
|
bar:SetElapsed(elapsed or self.totalTime - self.timer)
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
|
|
---------------------------
|
|
-- General Bar Methods --
|
|
---------------------------
|
|
function DBT:ShowTestBars()
|
|
self:CreateBar(10, "Test 1", "Interface\\Icons\\Spell_Nature_WispSplode")
|
|
self:CreateBar(14, "Test 2", "Interface\\Icons\\Spell_Nature_WispSplode")
|
|
self:CreateBar(20, "Test 3", "Interface\\Icons\\Spell_Nature_WispSplode")
|
|
self:CreateBar(12, "Test 4", "Interface\\Icons\\Spell_Nature_WispSplode")
|
|
self:CreateBar(21.5, "Test 5", "Interface\\Icons\\Spell_Nature_WispSplode")
|
|
end
|
|
|
|
function barPrototype:SetTimer(timer)
|
|
self.totalTime = timer
|
|
self:Update(0)
|
|
end
|
|
|
|
function barPrototype:SetElapsed(elapsed)
|
|
self.timer = self.totalTime - elapsed
|
|
if (self.enlarged or self.moving == "enlarge") and not (self.timer <= self.owner.options.EnlargeBarsTime or (self.timer/self.totalTime) <= self.owner.options.EnlargeBarsPercent) then
|
|
local next = self.next
|
|
self:RemoveFromList()
|
|
self.enlarged = nil
|
|
self.moving = nil
|
|
if next then
|
|
next:MoveToNextPosition()
|
|
end
|
|
self.owner.smallBars:Append(self)
|
|
self:SetPosition()
|
|
end
|
|
self:Update(0)
|
|
end
|
|
|
|
function barPrototype:SetText(text)
|
|
getglobal(self.frame:GetName().."BarName"):SetText(text)
|
|
end
|
|
|
|
function barPrototype:SetIcon(icon)
|
|
getglobal(self.frame:GetName().."BarIcon1"):SetTexture("")
|
|
getglobal(self.frame:GetName().."BarIcon1"):SetTexture(icon)
|
|
getglobal(self.frame:GetName().."BarIcon2"):SetTexture("")
|
|
getglobal(self.frame:GetName().."BarIcon2"):SetTexture(icon)
|
|
end
|
|
|
|
function barPrototype:SetColor(color)
|
|
self.color = color
|
|
getglobal(self.frame:GetName().."Bar"):SetStatusBarColor(color.r, color.g, color.b)
|
|
getglobal(self.frame:GetName().."BarSpark"):SetVertexColor(color.r, color.g, color.b)
|
|
end
|
|
|
|
------------------
|
|
-- Bar Update --
|
|
------------------
|
|
function barPrototype:Update(elapsed)
|
|
local frame = self.frame
|
|
local bar = getglobal(frame:GetName().."Bar")
|
|
local texture = getglobal(frame:GetName().."BarTexture")
|
|
local spark = getglobal(frame:GetName().."BarSpark")
|
|
local timer = getglobal(frame:GetName().."BarTimer")
|
|
local obj = self.owner
|
|
self.timer = self.timer - elapsed
|
|
if obj.options.DynamicColor and not self.color then
|
|
local r = obj.options.StartColorR + (obj.options.EndColorR - obj.options.StartColorR) * (1 - self.timer/self.totalTime)
|
|
local g = obj.options.StartColorG + (obj.options.EndColorG - obj.options.StartColorG) * (1 - self.timer/self.totalTime)
|
|
local b = obj.options.StartColorB + (obj.options.EndColorB - obj.options.StartColorB) * (1 - self.timer/self.totalTime)
|
|
bar:SetStatusBarColor(r, g, b)
|
|
spark:SetVertexColor(r, g, b)
|
|
end
|
|
if self.timer <= 0 then
|
|
return self:Cancel()
|
|
else
|
|
if obj.options.FillUpBars then
|
|
bar:SetValue(1 - self.timer/self.totalTime)
|
|
else
|
|
bar:SetValue(self.timer/self.totalTime)
|
|
end
|
|
spark:ClearAllPoints()
|
|
spark:SetPoint("CENTER", bar, "LEFT", bar:GetValue() * bar:GetWidth(), -1)
|
|
timer:SetText(stringFromTimer(self.timer))
|
|
end
|
|
if obj.options.FadeIn and self.fadingIn and self.fadingIn < 0.5 then
|
|
self.fadingIn = self.fadingIn + elapsed
|
|
frame:SetAlpha((self.fadingIn) / 0.5)
|
|
elseif self.fadingIn then
|
|
self.fadingIn = nil
|
|
end
|
|
|
|
if self.timer <= 7.75 and not self.flashing and obj.options.Flash then
|
|
self.flashing = true
|
|
self.ftimer = 0
|
|
end
|
|
if self.flashing then
|
|
local ftime = self.ftimer % 1.25
|
|
if ftime >= 0.5 then
|
|
texture:SetAlpha(1)
|
|
spark:SetAlpha(1)
|
|
elseif ftime >= 0.25 then
|
|
texture:SetAlpha(1 - (0.5 - ftime) / 0.25)
|
|
spark:SetAlpha(1 - (0.5 - ftime) / 0.25)
|
|
else
|
|
texture:SetAlpha(1 - (ftime / 0.25))
|
|
spark:SetAlpha(1 - (ftime / 0.25))
|
|
end
|
|
self.ftimer = self.ftimer + elapsed
|
|
end
|
|
if self.moving == "move" and self.moveElapsed <= 0.5 then
|
|
self.moveElapsed = self.moveElapsed + elapsed
|
|
local newX = self.moveOffsetX + (obj.options.BarXOffset - self.moveOffsetX) * (self.moveElapsed / 0.5)
|
|
local newY
|
|
if self.owner.options.ExpandUpwards then
|
|
newY = self.moveOffsetY + 40 + (obj.options.BarYOffset - self.moveOffsetY) * (self.moveElapsed / 0.5)
|
|
else
|
|
newY = self.moveOffsetY + (-obj.options.BarYOffset - self.moveOffsetY) * (self.moveElapsed / 0.5)
|
|
end
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint(self.movePoint, self.moveAnchor, self.moveRelPoint, newX, newY)
|
|
elseif self.moving == "move" then
|
|
self.moving = nil
|
|
self:SetPosition()
|
|
elseif self.moving == "enlarge" and self.moveElapsed <= 1 then
|
|
self:AnimateEnlarge(elapsed)
|
|
elseif self.moving == "enlarge" then
|
|
self.moving = nil
|
|
self.enlarged = true
|
|
self.owner.hugeBars:Append(self)
|
|
self:ApplyStyle()
|
|
self:SetPosition()
|
|
end
|
|
if (self.timer <= self.owner.options.EnlargeBarsTime or (self.timer/self.totalTime) <= self.owner.options.EnlargeBarsPercent) and (not self.small) and not self.enlarged and self.moving ~= "enlarge" and self.owner:GetOption("HugeBarsEnabled") then
|
|
local next = self.next
|
|
self:RemoveFromList()
|
|
if next then
|
|
local oldX = next.frame:GetRight() - next.frame:GetWidth()/2 -- the next frame's point needs to be cleared before we enlarge the bar to prevent the frame from "jumping around"
|
|
local oldY = next.frame:GetTop() -- so we need to save the old point for :MoveToNextPosition() as :GetTop() and :GetRight() might return nil (sometimes? happened only once in 2 weeks of raiding...but it crashed DBT...) after :ClearAllPoints()
|
|
next.frame:ClearAllPoints()
|
|
end
|
|
self:Enlarge()
|
|
if next then
|
|
next:MoveToNextPosition(oldX, oldY) -- ugly?
|
|
end
|
|
end
|
|
end
|
|
|
|
do
|
|
local frame = CreateFrame("Frame")
|
|
frame:SetScript("OnUpdate", function(self, elapsed)
|
|
if UIParent:IsShown() then return end
|
|
for i, v in ipairs(instances) do
|
|
for bar in v:GetBarIterator() do
|
|
bar:Update(elapsed)
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
|
|
-------------------
|
|
-- Movable Bar --
|
|
-------------------
|
|
function DBT:SavePosition()
|
|
local point, _, _, x, y = self.mainAnchor:GetPoint(1)
|
|
self:SetOption("TimerPoint", point)
|
|
self:SetOption("TimerX", x)
|
|
self:SetOption("TimerY", y)
|
|
local point, _, _, x, y = self.secAnchor:GetPoint(1)
|
|
self:SetOption("HugeTimerPoint", point)
|
|
self:SetOption("HugeTimerX", x)
|
|
self:SetOption("HugeTimerY", y)
|
|
end
|
|
|
|
do
|
|
local function moveEnd(self)
|
|
updateClickThrough(self, self:GetOption("ClickThrough"))
|
|
self.movable = false
|
|
end
|
|
|
|
function DBT:ShowMovableBar(small, large)
|
|
if small or small == nil then
|
|
local bar1 = self:CreateBar(20, "Move1", "Interface\\Icons\\Spell_Nature_WispSplode", nil, true)
|
|
bar1:SetText(DBM_CORE_MOVABLE_BAR)
|
|
end
|
|
if large or large == nil then
|
|
local bar2 = self:CreateBar(20, "Move2", "Interface\\Icons\\Spell_Nature_WispSplode", true)
|
|
bar2:SetText(DBM_CORE_MOVABLE_BAR)
|
|
end
|
|
updateClickThrough(self, false)
|
|
self.movable = true
|
|
DBM:Unschedule(moveEnd, self)
|
|
DBM:Schedule(20, moveEnd, self)
|
|
end
|
|
end
|
|
|
|
|
|
--------------------
|
|
-- Bar Handling --
|
|
--------------------
|
|
function barPrototype:RemoveFromList()
|
|
if self.moving ~= "enlarge" then
|
|
(self.enlarged and self.owner.hugeBars or self.owner.smallBars):Remove(self)
|
|
end
|
|
end
|
|
|
|
|
|
------------------
|
|
-- Bar Cancel --
|
|
------------------
|
|
function barPrototype:Cancel()
|
|
local next = self.next
|
|
table.insert(unusedBars, self.frame)
|
|
self.frame:Hide()
|
|
self.frame.obj = nil
|
|
self:RemoveFromList()
|
|
if next then
|
|
next:MoveToNextPosition()
|
|
end
|
|
self.owner.bars[self] = nil
|
|
unusedBarObjects[self] = self
|
|
self.dead = true
|
|
self.owner.numBars = (self.owner.numBars or 1) - 1
|
|
end
|
|
|
|
|
|
-----------------
|
|
-- Bar Style --
|
|
-----------------
|
|
function DBT:ApplyStyle()
|
|
for bar in self:GetBarIterator() do
|
|
bar:ApplyStyle()
|
|
end
|
|
end
|
|
|
|
function barPrototype:ApplyStyle()
|
|
local frame = self.frame
|
|
local bar = getglobal(frame:GetName().."Bar")
|
|
local spark = getglobal(frame:GetName().."BarSpark")
|
|
local texture = getglobal(frame:GetName().."BarTexture")
|
|
local icon1 = getglobal(frame:GetName().."BarIcon1")
|
|
local icon2 = getglobal(frame:GetName().."BarIcon2")
|
|
local name = getglobal(frame:GetName().."BarName")
|
|
local timer = getglobal(frame:GetName().."BarTimer")
|
|
texture:SetTexture(self.owner.options.Texture)
|
|
if self.color then
|
|
bar:SetStatusBarColor(self.color.r, self.color.g, self.color.b)
|
|
spark:SetVertexColor(self.color.r, self.color.g, self.color.b)
|
|
else
|
|
bar:SetStatusBarColor(self.owner.options.StartColorR, self.owner.options.StartColorG, self.owner.options.StartColorB)
|
|
spark:SetVertexColor(self.owner.options.StartColorR, self.owner.options.StartColorG, self.owner.options.StartColorB)
|
|
end
|
|
name:SetTextColor(self.owner.options.TextColorR, self.owner.options.TextColorG, self.owner.options.TextColorB)
|
|
timer:SetTextColor(self.owner.options.TextColorR, self.owner.options.TextColorG, self.owner.options.TextColorB)
|
|
if self.owner.options.IconLeft then icon1:Show() else icon1:Hide() end
|
|
if self.owner.options.IconRight then icon2:Show() else icon2:Hide() end
|
|
if self.enlarged then frame:SetWidth(self.owner.options.HugeWidth) else frame:SetWidth(self.owner.options.Width) end
|
|
if self.enlarged then bar:SetWidth(self.owner.options.HugeWidth) else bar:SetWidth(self.owner.options.Width) end
|
|
if self.enlarged then frame:SetScale(self.owner.options.HugeScale) else frame:SetScale(self.owner.options.Scale) end
|
|
self.frame:Show()
|
|
spark:SetAlpha(1)
|
|
texture:SetAlpha(1)
|
|
bar:SetAlpha(1)
|
|
frame:SetAlpha(1)
|
|
name:SetFont(self.owner.options.Font, self.owner.options.FontSize)
|
|
timer:SetFont(self.owner.options.Font, self.owner.options.FontSize)
|
|
self:Update(0)
|
|
end
|
|
|
|
local function updateOrientation(self)
|
|
for bar in self:GetBarIterator() do
|
|
if not bar.dummy then
|
|
if bar.moving == "enlarge" then
|
|
bar.enlarged = true
|
|
bar.moving = false
|
|
self.owner.hugeBars:Append(self)
|
|
bar:ApplyStyle()
|
|
end
|
|
bar.moving = nil
|
|
bar:SetPosition()
|
|
end
|
|
end
|
|
end
|
|
options.ExpandUpwards.onChange = updateOrientation
|
|
options.BarYOffset.onChange = updateOrientation
|
|
options.BarXOffset.onChange = updateOrientation
|
|
|
|
function updateClickThrough(self, newValue)
|
|
if not self.movable then
|
|
for bar in self:GetBarIterator() do
|
|
if not bar.dummy then
|
|
bar.frame:EnableMouse(not newValue)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
options.ClickThrough.onChange = updateClickThrough
|
|
|
|
|
|
--------------------
|
|
-- Bar Announce --
|
|
--------------------
|
|
function barPrototype:Announce()
|
|
local msg
|
|
if self.owner.announceHook then
|
|
msg = self.owner.announceHook(self)
|
|
end
|
|
msg = msg or ("%s %d:%02d"):format(getglobal(self.frame:GetName().."BarName"):GetText(), math.floor(self.timer / 60), self.timer % 60)
|
|
local chatWindow = ChatEdit_GetActiveWindow()
|
|
if chatWindow then
|
|
chatWindow:Insert(msg)
|
|
else
|
|
SendChatMessage(msg, (select(2, IsInInstance()) == "pvp" and "BATTLEGROUND") or (GetNumRaidMembers() > 0 and "RAID") or "PARTY")
|
|
end
|
|
end
|
|
|
|
function DBT:SetAnnounceHook(f)
|
|
self.announceHook = f
|
|
end
|
|
|
|
-----------------------
|
|
-- Bar Positioning --
|
|
-----------------------
|
|
function barPrototype:SetPosition()
|
|
if self.moving == "enlarge" then return end
|
|
local anchor = (self.prev and self.prev.frame) or (self.enlarged and self.owner.secAnchor) or self.owner.mainAnchor
|
|
self.frame:ClearAllPoints()
|
|
if self.owner.options.ExpandUpwards then
|
|
self.frame:SetPoint("TOP", anchor, "BOTTOM", self.owner.options.BarXOffset, 40 + self.owner.options.BarYOffset)
|
|
else
|
|
self.frame:SetPoint("TOP", anchor, "BOTTOM", self.owner.options.BarXOffset, -self.owner.options.BarYOffset)
|
|
end
|
|
end
|
|
|
|
function barPrototype:MoveToNextPosition(oldX, oldY)
|
|
if self.moving == "enlarge" then return end
|
|
local newAnchor = (self.prev and self.prev.frame) or (self.enlarged and self.owner.secAnchor) or self.owner.mainAnchor
|
|
local oldX = oldX or (self.frame:GetRight() - self.frame:GetWidth()/2)
|
|
local oldY = oldY or (self.frame:GetTop())
|
|
self.frame:ClearAllPoints()
|
|
if self.owner.options.ExpandUpwards then
|
|
self.frame:SetPoint("TOP", newAnchor, "BOTTOM", self.owner.options.BarXOffset, 40 + self.owner.options.BarYOffset)
|
|
else
|
|
self.frame:SetPoint("TOP", newAnchor, "BOTTOM", self.owner.options.BarXOffset, -self.owner.options.BarYOffset)
|
|
end
|
|
local newX = self.frame:GetRight() - self.frame:GetWidth()/2
|
|
local newY = self.frame:GetTop()
|
|
self.frame:ClearAllPoints()
|
|
self.frame:SetPoint("TOP", newAnchor, "BOTTOM", -(newX - oldX), -(newY - oldY))
|
|
self.moving = "move"
|
|
self.movePoint = "TOP"
|
|
self.moveRelPoint = "BOTTOM"
|
|
self.moveAnchor = newAnchor
|
|
self.moveOffsetX = -(newX - oldX)
|
|
self.moveOffsetY = -(newY - oldY)
|
|
self.moveElapsed = 0
|
|
end
|
|
|
|
function barPrototype:Enlarge()
|
|
local newAnchor = (self.owner.hugeBars.last and self.owner.hugeBars.last.frame) or self.owner.secAnchor
|
|
local oldX = self.frame:GetRight() - self.frame:GetWidth()/2
|
|
local oldY = self.frame:GetTop()
|
|
self.frame:ClearAllPoints()
|
|
if self.owner.options.ExpandUpwards then
|
|
self.frame:SetPoint("TOP", newAnchor, "BOTTOM", self.owner.options.BarXOffset, 40 + self.owner.options.BarYOffset)
|
|
else
|
|
self.frame:SetPoint("TOP", newAnchor, "BOTTOM", self.owner.options.BarXOffset, -self.owner.options.BarYOffset)
|
|
end
|
|
local newX = self.frame:GetRight() - self.frame:GetWidth()/2
|
|
local newY = self.frame:GetTop()
|
|
self.frame:ClearAllPoints()
|
|
self.frame:SetPoint("TOP", newAnchor, "BOTTOM", -(newX - oldX), -(newY - oldY))
|
|
self.moving = "enlarge"
|
|
self.movePoint = "TOP"
|
|
self.moveRelPoint = "BOTTOM"
|
|
self.moveAnchor = newAnchor
|
|
self.moveOffsetX = -(newX - oldX)
|
|
self.moveOffsetY = -(newY - oldY)
|
|
self.moveElapsed = 0
|
|
end
|
|
|
|
|
|
---------------------------
|
|
-- Bar Special Effects --
|
|
---------------------------
|
|
function barPrototype:AnimateEnlarge(elapsed)
|
|
self.moveElapsed = self.moveElapsed + elapsed
|
|
local newX = self.moveOffsetX + (self.owner.options.BarXOffset - self.moveOffsetX) * (self.moveElapsed / 1)
|
|
local newY
|
|
if self.owner.options.ExpandUpwards then
|
|
newY = self.moveOffsetY + 50 + (self.owner.options.BarYOffset - self.moveOffsetY) * (self.moveElapsed / 1)
|
|
else
|
|
newY = self.moveOffsetY + (self.owner.options.BarYOffset - self.moveOffsetY) * (self.moveElapsed / 1)
|
|
end
|
|
local newWidth = self.owner.options.Width + (self.owner.options.HugeWidth - self.owner.options.Width ) * (self.moveElapsed / 1)
|
|
local newScale = self.owner.options.Scale + (self.owner.options.HugeScale - self.owner.options.Scale) * (self.moveElapsed / 1)
|
|
if (self.moveOffsetY > 0 and newY > self.owner.options.BarYOffset) or (self.moveOffsetY < 0 and newY < self.owner.options.BarYOffset) then
|
|
self.frame:ClearAllPoints()
|
|
self.frame:SetPoint(self.movePoint, self.moveAnchor, self.moveRelPoint, newX, newY)
|
|
self.frame:SetScale(newScale)
|
|
self.frame:SetWidth(newWidth)
|
|
getglobal(self.frame:GetName().."Bar"):SetWidth(newWidth)
|
|
else
|
|
self.moving = nil
|
|
self.enlarged = true
|
|
self.owner.hugeBars:Append(self)
|
|
self:ApplyStyle()
|
|
self:SetPosition()
|
|
end
|
|
end
|
|
|
|
--[[
|
|
do
|
|
local breakFrames = {}
|
|
function barPrototype:Break() -- coming soon
|
|
local frame = table.remove(breakTextures, #breakTextures) or CreateFrame("Frame", nil, self.owner.mainAnchor)
|
|
frame:SetParent(self.owner.mainAnchor)
|
|
frame.tex1 = frame.tex1 or frame:CreateTexture(nil, "OVERLAY")
|
|
frame.tex2 = frame.tex2 or frame:CreateTexture(nil, "OVERLAY")
|
|
local tex1 = frame.tex1
|
|
local tex2 = frame.tex2
|
|
tex1:SetTexture(self.owner.options.Texture)
|
|
tex2:SetTexture(self.owner.options.Texture)
|
|
-- tex1:SetTexCoordModifiesRect(true)
|
|
tex1:SetHorizTile(true)
|
|
tex1:SetVertTile(true)
|
|
tex1:SetTexCoord(0, 0.5, 0, 1)
|
|
end
|
|
end
|
|
]]--
|
|
|
|
----------------------------------------
|
|
-- Functions used by the XML Template --
|
|
----------------------------------------
|
|
function DBT_Bar_OnLoad(self)
|
|
self:SetMinMaxValues(0, 1)
|
|
self:SetValue(1)
|
|
end
|
|
|
|
function DBT_Bar_OnUpdate(self, elapsed)
|
|
self.obj:Update(elapsed)
|
|
end
|
|
|
|
function DBT_Bar_OnMouseDown(self, btn)
|
|
if self.obj.owner.movable and btn == "LeftButton" then
|
|
if self.obj.enlarged then
|
|
self.obj.owner.secAnchor:StartMoving()
|
|
else
|
|
self.obj.owner.mainAnchor:StartMoving()
|
|
end
|
|
end
|
|
end
|
|
|
|
function DBT_Bar_OnMouseUp(self, btn)
|
|
self.obj.owner.mainAnchor:StopMovingOrSizing()
|
|
self.obj.owner.secAnchor:StopMovingOrSizing()
|
|
self.obj.owner:SavePosition()
|
|
if btn == "RightButton" then
|
|
self.obj:Cancel()
|
|
elseif btn == "LeftButton" and IsShiftKeyDown() then
|
|
self.obj:Announce()
|
|
end
|
|
end
|
|
|
|
function DBT_Bar_OnHide(self)
|
|
if self.obj then
|
|
self.obj.owner.mainAnchor:StopMovingOrSizing()
|
|
self.obj.owner.secAnchor:StopMovingOrSizing()
|
|
end
|
|
end
|