Files
coa-leatrix-plus/Leatrix_Plus_Library.lua
T
Sattva 1eb7d161d3 FlightPoints - first messy version
For now i only figured and partilly fixed tooltip on the destination node.
However data seems to be different from the WoTLK Classic. And would need to be completely rewritten.
Also i have problem with debug string as it is currently unable to get hops FPs in between start and end nodes correctly...

And it seems that my routestring is bad too. As it is for some reason adds un-needed zeroes between nodes
For example: FP from Orgrimmar to Valormok, no hop in between them, Orgrimmar added twice and a lot of un-necessary zeroes in between.
["0.63:0.56:0.00:0.00:0.63:0.64"] =  -- Orgrimmar, Orgrimmar, Valormok
2023-06-13 16:09:49 +03:00

1679 lines
57 KiB
Lua

-- -- L00: Leatrix Plus Library
-- ----------------------------------------------------------------------
-- -- LibDBIcon 10.0.1:
-- -- 11: LibStub: (?s)-- LibStubStart\R?\K.*?(?=-- LibStubEnd)
-- -- 12: LibCallbackHandler: (?s)-- CallbackStart\R?\K.*?(?=-- CallbackEnd)
-- -- 13: LibDataBroker: (?s)-- DataBrokerStart\R?\K.*?(?=-- DataBrokerEnd)
-- -- 14: LibDBIcon: (?s)-- LibDBIconStart\R?\K.*?(?=-- LibDBIconEnd)
-- -- LibChatAnims 10.0.1:
-- -- 15: LibChatAnims: (?s)-- LibChatAnimsStart\R?\K.*?(?=-- LibChatAnimsEnd)
-- -- LibCandyBar 10.0.1:
-- -- 16: LibCandyBar: (?s)-- LibCandyBarStart\R?\K.*?(?=-- LibCandyBarEnd)
local void, Leatrix_Plus = ...
-- ----------------------------------------------------------------------
-- -- L11: LibDBIcon: LibStub
-- ----------------------------------------------------------------------
-- local function LeaLibStub()
-- -- LibStubStart
-- -- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $
-- -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
-- -- LibStub is hereby placed in the Public Domain
-- -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
-- local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
-- local LibStub = _G[LIBSTUB_MAJOR]
-- -- Check to see is this version of the stub is obsolete
-- if not LibStub or LibStub.minor < LIBSTUB_MINOR then
-- LibStub = LibStub or {libs = {}, minors = {} }
-- _G[LIBSTUB_MAJOR] = LibStub
-- LibStub.minor = LIBSTUB_MINOR
-- -- LibStub:NewLibrary(major, minor)
-- -- major (string) - the major version of the library
-- -- minor (string or number ) - the minor version of the library
-- --
-- -- returns nil if a newer or same version of the lib is already present
-- -- returns empty library object or old library object if upgrade is needed
-- function LibStub:NewLibrary(major, minor)
-- assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
-- minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
-- local oldminor = self.minors[major]
-- if oldminor and oldminor >= minor then return nil end
-- self.minors[major], self.libs[major] = minor, self.libs[major] or {}
-- return self.libs[major], oldminor
-- end
-- -- LibStub:GetLibrary(major, [silent])
-- -- major (string) - the major version of the library
-- -- silent (boolean) - if true, library is optional, silently return nil if its not found
-- --
-- -- throws an error if the library can not be found (except silent is set)
-- -- returns the library object if found
-- function LibStub:GetLibrary(major, silent)
-- if not self.libs[major] and not silent then
-- error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
-- end
-- return self.libs[major], self.minors[major]
-- end
-- -- LibStub:IterateLibraries()
-- --
-- -- Returns an iterator for the currently registered libraries
-- function LibStub:IterateLibraries()
-- return pairs(self.libs)
-- end
-- setmetatable(LibStub, { __call = LibStub.GetLibrary })
-- end
-- -- LibStubEnd
-- end
-- LeaLibStub()
-- ----------------------------------------------------------------------
-- -- L12: LibDBIcon: CallbackHandler
-- ----------------------------------------------------------------------
-- local function LeaCallbackHandler()
-- -- CallbackStart
-- --[[ $Id: CallbackHandler-1.0.lua 26 2022-12-12 15:09:39Z nevcairiel $ ]]
-- local MAJOR, MINOR = "CallbackHandler-1.0", 8
-- local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
-- if not CallbackHandler then return end -- No upgrade needed
-- local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
-- -- Lua APIs
-- local securecallfunction, error = securecallfunction, error
-- local setmetatable, rawget = setmetatable, rawget
-- local next, select, pairs, type, tostring = next, select, pairs, type, tostring
-- local function Dispatch(handlers, ...)
-- local index, method = next(handlers)
-- if not method then return end
-- repeat
-- securecallfunction(method, ...)
-- index, method = next(handlers, index)
-- until not method
-- end
-- --------------------------------------------------------------------------
-- -- CallbackHandler:New
-- --
-- -- target - target object to embed public APIs in
-- -- RegisterName - name of the callback registration API, default "RegisterCallback"
-- -- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
-- -- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
-- function CallbackHandler.New(_self, target, RegisterName, UnregisterName, UnregisterAllName)
-- RegisterName = RegisterName or "RegisterCallback"
-- UnregisterName = UnregisterName or "UnregisterCallback"
-- if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
-- UnregisterAllName = "UnregisterAllCallbacks"
-- end
-- -- we declare all objects and exported APIs inside this closure to quickly gain access
-- -- to e.g. function names, the "target" parameter, etc
-- -- Create the registry object
-- local events = setmetatable({}, meta)
-- local registry = { recurse=0, events=events }
-- -- registry:Fire() - fires the given event/message into the registry
-- function registry:Fire(eventname, ...)
-- if not rawget(events, eventname) or not next(events[eventname]) then return end
-- local oldrecurse = registry.recurse
-- registry.recurse = oldrecurse + 1
-- Dispatch(events[eventname], eventname, ...)
-- registry.recurse = oldrecurse
-- if registry.insertQueue and oldrecurse==0 then
-- -- Something in one of our callbacks wanted to register more callbacks; they got queued
-- for event,callbacks in pairs(registry.insertQueue) do
-- local first = not rawget(events, event) or not next(events[event]) -- test for empty before. not test for one member after. that one member may have been overwritten.
-- for object,func in pairs(callbacks) do
-- events[event][object] = func
-- -- fire OnUsed callback?
-- if first and registry.OnUsed then
-- registry.OnUsed(registry, target, event)
-- first = nil
-- end
-- end
-- end
-- registry.insertQueue = nil
-- end
-- end
-- -- Registration of a callback, handles:
-- -- self["method"], leads to self["method"](self, ...)
-- -- self with function ref, leads to functionref(...)
-- -- "addonId" (instead of self) with function ref, leads to functionref(...)
-- -- all with an optional arg, which, if present, gets passed as first argument (after self if present)
-- target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
-- if type(eventname) ~= "string" then
-- error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
-- end
-- method = method or eventname
-- local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
-- if type(method) ~= "string" and type(method) ~= "function" then
-- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
-- end
-- local regfunc
-- if type(method) == "string" then
-- -- self["method"] calling style
-- if type(self) ~= "table" then
-- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
-- elseif self==target then
-- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
-- elseif type(self[method]) ~= "function" then
-- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
-- end
-- if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
-- local arg=select(1,...)
-- regfunc = function(...) self[method](self,arg,...) end
-- else
-- regfunc = function(...) self[method](self,...) end
-- end
-- else
-- -- function ref with self=object or self="addonId" or self=thread
-- if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
-- error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
-- end
-- if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
-- local arg=select(1,...)
-- regfunc = function(...) method(arg,...) end
-- else
-- regfunc = method
-- end
-- end
-- if events[eventname][self] or registry.recurse<1 then
-- -- if registry.recurse<1 then
-- -- we're overwriting an existing entry, or not currently recursing. just set it.
-- events[eventname][self] = regfunc
-- -- fire OnUsed callback?
-- if registry.OnUsed and first then
-- registry.OnUsed(registry, target, eventname)
-- end
-- else
-- -- we're currently processing a callback in this registry, so delay the registration of this new entry!
-- -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
-- registry.insertQueue = registry.insertQueue or setmetatable({},meta)
-- registry.insertQueue[eventname][self] = regfunc
-- end
-- end
-- -- Unregister a callback
-- target[UnregisterName] = function(self, eventname)
-- if not self or self==target then
-- error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
-- end
-- if type(eventname) ~= "string" then
-- error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
-- end
-- if rawget(events, eventname) and events[eventname][self] then
-- events[eventname][self] = nil
-- -- Fire OnUnused callback?
-- if registry.OnUnused and not next(events[eventname]) then
-- registry.OnUnused(registry, target, eventname)
-- end
-- end
-- if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
-- registry.insertQueue[eventname][self] = nil
-- end
-- end
-- -- OPTIONAL: Unregister all callbacks for given selfs/addonIds
-- if UnregisterAllName then
-- target[UnregisterAllName] = function(...)
-- if select("#",...)<1 then
-- error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
-- end
-- if select("#",...)==1 and ...==target then
-- error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
-- end
-- for i=1,select("#",...) do
-- local self = select(i,...)
-- if registry.insertQueue then
-- for eventname, callbacks in pairs(registry.insertQueue) do
-- if callbacks[self] then
-- callbacks[self] = nil
-- end
-- end
-- end
-- for eventname, callbacks in pairs(events) do
-- if callbacks[self] then
-- callbacks[self] = nil
-- -- Fire OnUnused callback?
-- if registry.OnUnused and not next(callbacks) then
-- registry.OnUnused(registry, target, eventname)
-- end
-- end
-- end
-- end
-- end
-- end
-- return registry
-- end
-- -- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
-- -- try to upgrade old implicit embeds since the system is selfcontained and
-- -- relies on closures to work.
-- -- CallbackEnd
-- end
-- LeaCallbackHandler()
-- ----------------------------------------------------------------------
-- -- L13: LibDBIcon: LibDataBroker
-- ----------------------------------------------------------------------
-- local function LeaDataBroker()
-- -- DataBrokerStart
-- assert(LibStub, "LibDataBroker-1.1 requires LibStub")
-- assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
-- local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4)
-- if not lib then return end
-- oldminor = oldminor or 0
-- lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
-- lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
-- local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
-- if oldminor < 2 then
-- lib.domt = {
-- __metatable = "access denied",
-- __index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
-- }
-- end
-- if oldminor < 3 then
-- lib.domt.__newindex = function(self, key, value)
-- if not attributestorage[self] then attributestorage[self] = {} end
-- if attributestorage[self][key] == value then return end
-- attributestorage[self][key] = value
-- local name = namestorage[self]
-- if not name then return end
-- callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
-- callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
-- callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
-- callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
-- end
-- end
-- if oldminor < 2 then
-- function lib:NewDataObject(name, dataobj)
-- if self.proxystorage[name] then return end
-- if dataobj then
-- assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
-- self.attributestorage[dataobj] = {}
-- for i,v in pairs(dataobj) do
-- self.attributestorage[dataobj][i] = v
-- dataobj[i] = nil
-- end
-- end
-- dataobj = setmetatable(dataobj or {}, self.domt)
-- self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
-- self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
-- return dataobj
-- end
-- end
-- if oldminor < 1 then
-- function lib:DataObjectIterator()
-- return pairs(self.proxystorage)
-- end
-- function lib:GetDataObjectByName(dataobjectname)
-- return self.proxystorage[dataobjectname]
-- end
-- function lib:GetNameByDataObject(dataobject)
-- return self.namestorage[dataobject]
-- end
-- end
-- if oldminor < 4 then
-- local next = pairs(attributestorage)
-- function lib:pairs(dataobject_or_name)
-- local t = type(dataobject_or_name)
-- assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)")
-- local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
-- assert(attributestorage[dataobj], "Data object not found")
-- return next, attributestorage[dataobj], nil
-- end
-- local ipairs_iter = ipairs(attributestorage)
-- function lib:ipairs(dataobject_or_name)
-- local t = type(dataobject_or_name)
-- assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)")
-- local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
-- assert(attributestorage[dataobj], "Data object not found")
-- return ipairs_iter, attributestorage[dataobj], 0
-- end
-- end
-- -- DataBrokerEnd
-- end
-- LeaDataBroker()
-- ----------------------------------------------------------------------
-- -- L14: LibDBIcon: LibDBIcon
-- ----------------------------------------------------------------------
-- local function LeaLibDBIcon()
-- -- LibDBIconStart
-- --@curseforge-project-slug: libdbicon-1-0@
-- -----------------------------------------------------------------------
-- -- LibDBIcon-1.0
-- --
-- -- Allows addons to easily create a lightweight minimap icon as an alternative to heavier LDB displays.
-- --
-- local DBICON10 = "LibDBIcon-1.0"
-- local DBICON10_MINOR = 45 -- Bump on changes
-- if not LibStub then error(DBICON10 .. " requires LibStub.") end
-- local ldb = LibStub("LibDataBroker-1.1", true)
-- if not ldb then error(DBICON10 .. " requires LibDataBroker-1.1.") end
-- local lib = LibStub:NewLibrary(DBICON10, DBICON10_MINOR)
-- if not lib then return end
-- lib.objects = lib.objects or {}
-- lib.callbackRegistered = lib.callbackRegistered or nil
-- lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib)
-- lib.notCreated = lib.notCreated or {}
-- lib.radius = lib.radius or 5
-- local next, Minimap, CreateFrame = next, Minimap, CreateFrame
-- lib.tooltip = lib.tooltip or CreateFrame("GameTooltip", "LibDBIconTooltip", UIParent, "GameTooltipTemplate")
-- local isDraggingButton = false
-- function lib:IconCallback(event, name, key, value)
-- if lib.objects[name] then
-- if key == "icon" then
-- lib.objects[name].icon:SetTexture(value)
-- elseif key == "iconCoords" then
-- lib.objects[name].icon:UpdateCoord()
-- elseif key == "iconR" then
-- local _, g, b = lib.objects[name].icon:GetVertexColor()
-- lib.objects[name].icon:SetVertexColor(value, g, b)
-- elseif key == "iconG" then
-- local r, _, b = lib.objects[name].icon:GetVertexColor()
-- lib.objects[name].icon:SetVertexColor(r, value, b)
-- elseif key == "iconB" then
-- local r, g = lib.objects[name].icon:GetVertexColor()
-- lib.objects[name].icon:SetVertexColor(r, g, value)
-- end
-- end
-- end
-- if not lib.callbackRegistered then
-- ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__icon", "IconCallback")
-- ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconCoords", "IconCallback")
-- ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconR", "IconCallback")
-- ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconG", "IconCallback")
-- ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconB", "IconCallback")
-- lib.callbackRegistered = true
-- end
-- local function getAnchors(frame)
-- local x, y = frame:GetCenter()
-- if not x or not y then return "CENTER" end
-- local hhalf = (x > UIParent:GetWidth()*2/3) and "RIGHT" or (x < UIParent:GetWidth()/3) and "LEFT" or ""
-- local vhalf = (y > UIParent:GetHeight()/2) and "TOP" or "BOTTOM"
-- return vhalf..hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP")..hhalf
-- end
-- local function onEnter(self)
-- if isDraggingButton then return end
-- for _, button in next, lib.objects do
-- if button.showOnMouseover then
-- button.fadeOut:Stop()
-- button:SetAlpha(1)
-- end
-- end
-- local obj = self.dataObject
-- if obj.OnTooltipShow then
-- lib.tooltip:SetOwner(self, "ANCHOR_NONE")
-- lib.tooltip:SetPoint(getAnchors(self))
-- obj.OnTooltipShow(lib.tooltip)
-- lib.tooltip:Show()
-- elseif obj.OnEnter then
-- obj.OnEnter(self)
-- end
-- end
-- local function onLeave(self)
-- lib.tooltip:Hide()
-- if not isDraggingButton then
-- for _, button in next, lib.objects do
-- if button.showOnMouseover then
-- button.fadeOut:Play()
-- end
-- end
-- end
-- local obj = self.dataObject
-- if obj.OnLeave then
-- obj.OnLeave(self)
-- end
-- end
-- --------------------------------------------------------------------------------
-- local onDragStart, updatePosition
-- do
-- local minimapShapes = {
-- ["ROUND"] = {true, true, true, true},
-- ["SQUARE"] = {false, false, false, false},
-- ["CORNER-TOPLEFT"] = {false, false, false, true},
-- ["CORNER-TOPRIGHT"] = {false, false, true, false},
-- ["CORNER-BOTTOMLEFT"] = {false, true, false, false},
-- ["CORNER-BOTTOMRIGHT"] = {true, false, false, false},
-- ["SIDE-LEFT"] = {false, true, false, true},
-- ["SIDE-RIGHT"] = {true, false, true, false},
-- ["SIDE-TOP"] = {false, false, true, true},
-- ["SIDE-BOTTOM"] = {true, true, false, false},
-- ["TRICORNER-TOPLEFT"] = {false, true, true, true},
-- ["TRICORNER-TOPRIGHT"] = {true, false, true, true},
-- ["TRICORNER-BOTTOMLEFT"] = {true, true, false, true},
-- ["TRICORNER-BOTTOMRIGHT"] = {true, true, true, false},
-- }
-- local rad, cos, sin, sqrt, max, min = math.rad, math.cos, math.sin, math.sqrt, math.max, math.min
-- function updatePosition(button, position)
-- local angle = rad(position or 225)
-- local x, y, q = cos(angle), sin(angle), 1
-- if x < 0 then q = q + 1 end
-- if y > 0 then q = q + 2 end
-- local minimapShape = GetMinimapShape and GetMinimapShape() or "ROUND"
-- local quadTable = minimapShapes[minimapShape]
-- local w = (Minimap:GetWidth() / 2) + lib.radius
-- local h = (Minimap:GetHeight() / 2) + lib.radius
-- if quadTable[q] then
-- x, y = x*w, y*h
-- else
-- local diagRadiusW = sqrt(2*(w)^2)-10
-- local diagRadiusH = sqrt(2*(h)^2)-10
-- x = max(-w, min(x*diagRadiusW, w))
-- y = max(-h, min(y*diagRadiusH, h))
-- end
-- button:SetPoint("CENTER", Minimap, "CENTER", x, y)
-- end
-- end
-- local function onClick(self, b)
-- if self.dataObject.OnClick then
-- self.dataObject.OnClick(self, b)
-- end
-- end
-- local function onMouseDown(self)
-- self.isMouseDown = true
-- self.icon:UpdateCoord()
-- end
-- local function onMouseUp(self)
-- self.isMouseDown = false
-- self.icon:UpdateCoord()
-- end
-- do
-- local deg, atan2 = math.deg, math.atan2
-- local function onUpdate(self)
-- local mx, my = Minimap:GetCenter()
-- local px, py = GetCursorPosition()
-- local scale = Minimap:GetEffectiveScale()
-- px, py = px / scale, py / scale
-- local pos = 225
-- if self.db then
-- pos = deg(atan2(py - my, px - mx)) % 360
-- self.db.minimapPos = pos
-- else
-- pos = deg(atan2(py - my, px - mx)) % 360
-- self.minimapPos = pos
-- end
-- updatePosition(self, pos)
-- end
-- function onDragStart(self)
-- self:LockHighlight()
-- self.isMouseDown = true
-- self.icon:UpdateCoord()
-- self:SetScript("OnUpdate", onUpdate)
-- isDraggingButton = true
-- lib.tooltip:Hide()
-- for _, button in next, lib.objects do
-- if button.showOnMouseover then
-- button.fadeOut:Stop()
-- button:SetAlpha(1)
-- end
-- end
-- end
-- end
-- local function onDragStop(self)
-- self:SetScript("OnUpdate", nil)
-- self.isMouseDown = false
-- self.icon:UpdateCoord()
-- self:UnlockHighlight()
-- isDraggingButton = false
-- for _, button in next, lib.objects do
-- if button.showOnMouseover then
-- button.fadeOut:Play()
-- end
-- end
-- end
-- local defaultCoords = {0, 1, 0, 1}
-- local function updateCoord(self)
-- local coords = self:GetParent().dataObject.iconCoords or defaultCoords
-- local deltaX, deltaY = 0, 0
-- if not self:GetParent().isMouseDown then
-- deltaX = (coords[2] - coords[1]) * 0.05
-- deltaY = (coords[4] - coords[3]) * 0.05
-- end
-- self:SetTexCoord(coords[1] + deltaX, coords[2] - deltaX, coords[3] + deltaY, coords[4] - deltaY)
-- end
-- local function createButton(name, object, db)
-- local button = CreateFrame("Button", "LibDBIcon10_"..name, Minimap)
-- button.dataObject = object
-- button.db = db
-- button:SetFrameStrata("MEDIUM")
-- -- button:SetFixedFrameStrata(true)
-- button:SetFrameLevel(8)
-- -- button:SetFixedFrameLevel(true)
-- button:SetSize(31, 31)
-- button:RegisterForClicks("anyUp")
-- button:RegisterForDrag("LeftButton")
-- button:SetHighlightTexture(136477) --"Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight"
-- if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then
-- local overlay = button:CreateTexture(nil, "OVERLAY")
-- overlay:SetSize(50, 50)
-- overlay:SetTexture(136430) --"Interface\\Minimap\\MiniMap-TrackingBorder"
-- overlay:SetPoint("TOPLEFT", button, "TOPLEFT", 0, 0)
-- local background = button:CreateTexture(nil, "BACKGROUND")
-- background:SetSize(24, 24)
-- background:SetTexture(136467) --"Interface\\Minimap\\UI-Minimap-Background"
-- background:SetPoint("CENTER", button, "CENTER", 0, 1)
-- local icon = button:CreateTexture(nil, "ARTWORK")
-- icon:SetSize(18, 18)
-- icon:SetTexture(object.icon)
-- icon:SetPoint("CENTER", button, "CENTER", 0, 1)
-- button.icon = icon
-- else
-- local overlay = button:CreateTexture(nil, "OVERLAY")
-- overlay:SetSize(53, 53)
-- overlay:SetTexture(136430) --"Interface\\Minimap\\MiniMap-TrackingBorder"
-- overlay:SetPoint("TOPLEFT")
-- local background = button:CreateTexture(nil, "BACKGROUND")
-- background:SetSize(20, 20)
-- background:SetTexture(136467) --"Interface\\Minimap\\UI-Minimap-Background"
-- background:SetPoint("TOPLEFT", 7, -5)
-- local icon = button:CreateTexture(nil, "ARTWORK")
-- icon:SetSize(17, 17)
-- icon:SetTexture(object.icon)
-- icon:SetPoint("TOPLEFT", 7, -6)
-- button.icon = icon
-- end
-- button.isMouseDown = false
-- local r, g, b = button.icon:GetVertexColor()
-- button.icon:SetVertexColor(object.iconR or r, object.iconG or g, object.iconB or b)
-- button.icon.UpdateCoord = updateCoord
-- button.icon:UpdateCoord()
-- button:SetScript("OnEnter", onEnter)
-- button:SetScript("OnLeave", onLeave)
-- button:SetScript("OnClick", onClick)
-- if not db or not db.lock then
-- button:SetScript("OnDragStart", onDragStart)
-- button:SetScript("OnDragStop", onDragStop)
-- end
-- button:SetScript("OnMouseDown", onMouseDown)
-- button:SetScript("OnMouseUp", onMouseUp)
-- button.fadeOut = button:CreateAnimationGroup()
-- local animOut = button.fadeOut:CreateAnimation("Alpha")
-- -- animOut:SetOrder(1)
-- -- animOut:SetDuration(0.2)
-- -- animOut:SetFromAlpha(1)
-- -- animOut:SetToAlpha(0)
-- -- animOut:SetStartDelay(1)
-- -- button.fadeOut:SetToFinalAlpha(true)
-- lib.objects[name] = button
-- if lib.loggedIn then
-- updatePosition(button, db and db.minimapPos)
-- if not db or not db.hide then
-- button:Show()
-- else
-- button:Hide()
-- end
-- end
-- lib.callbacks:Fire("LibDBIcon_IconCreated", button, name) -- Fire 'Icon Created' callback
-- end
-- -- We could use a metatable.__index on lib.objects, but then we'd create
-- -- the icons when checking things like :IsRegistered, which is not necessary.
-- local function check(name)
-- if lib.notCreated[name] then
-- createButton(name, lib.notCreated[name][1], lib.notCreated[name][2])
-- lib.notCreated[name] = nil
-- end
-- end
-- -- Wait a bit with the initial positioning to let any GetMinimapShape addons
-- -- load up.
-- if not lib.loggedIn then
-- local f = CreateFrame("Frame")
-- f:SetScript("OnEvent", function(f)
-- for _, button in next, lib.objects do
-- updatePosition(button, button.db and button.db.minimapPos)
-- if not button.db or not button.db.hide then
-- button:Show()
-- else
-- button:Hide()
-- end
-- end
-- lib.loggedIn = true
-- f:SetScript("OnEvent", nil)
-- end)
-- f:RegisterEvent("PLAYER_LOGIN")
-- end
-- local function getDatabase(name)
-- return lib.notCreated[name] and lib.notCreated[name][2] or lib.objects[name].db
-- end
-- function lib:Register(name, object, db)
-- if not object.icon then error("Can't register LDB objects without icons set!") end
-- if lib.objects[name] or lib.notCreated[name] then error(DBICON10.. ": Object '".. name .."' is already registered.") end
-- if not db or not db.hide then
-- createButton(name, object, db)
-- else
-- lib.notCreated[name] = {object, db}
-- end
-- end
-- function lib:Lock(name)
-- if not lib:IsRegistered(name) then return end
-- if lib.objects[name] then
-- lib.objects[name]:SetScript("OnDragStart", nil)
-- lib.objects[name]:SetScript("OnDragStop", nil)
-- end
-- local db = getDatabase(name)
-- if db then
-- db.lock = true
-- end
-- end
-- function lib:Unlock(name)
-- if not lib:IsRegistered(name) then return end
-- if lib.objects[name] then
-- lib.objects[name]:SetScript("OnDragStart", onDragStart)
-- lib.objects[name]:SetScript("OnDragStop", onDragStop)
-- end
-- local db = getDatabase(name)
-- if db then
-- db.lock = nil
-- end
-- end
-- function lib:Hide(name)
-- if not lib.objects[name] then return end
-- lib.objects[name]:Hide()
-- end
-- function lib:Show(name)
-- check(name)
-- local button = lib.objects[name]
-- if button then
-- button:Show()
-- updatePosition(button, button.db and button.db.minimapPos or button.minimapPos)
-- end
-- end
-- function lib:IsRegistered(name)
-- return (lib.objects[name] or lib.notCreated[name]) and true or false
-- end
-- function lib:Refresh(name, db)
-- check(name)
-- local button = lib.objects[name]
-- if db then
-- button.db = db
-- end
-- updatePosition(button, button.db and button.db.minimapPos or button.minimapPos)
-- if not button.db or not button.db.hide then
-- button:Show()
-- else
-- button:Hide()
-- end
-- if not button.db or not button.db.lock then
-- button:SetScript("OnDragStart", onDragStart)
-- button:SetScript("OnDragStop", onDragStop)
-- else
-- button:SetScript("OnDragStart", nil)
-- button:SetScript("OnDragStop", nil)
-- end
-- end
-- function lib:GetMinimapButton(name)
-- return lib.objects[name]
-- end
-- do
-- local function OnMinimapEnter()
-- if isDraggingButton then return end
-- for _, button in next, lib.objects do
-- if button.showOnMouseover then
-- button.fadeOut:Stop()
-- button:SetAlpha(1)
-- end
-- end
-- end
-- local function OnMinimapLeave()
-- if isDraggingButton then return end
-- for _, button in next, lib.objects do
-- if button.showOnMouseover then
-- button.fadeOut:Play()
-- end
-- end
-- end
-- Minimap:HookScript("OnEnter", OnMinimapEnter)
-- Minimap:HookScript("OnLeave", OnMinimapLeave)
-- function lib:ShowOnEnter(name, value)
-- local button = lib.objects[name]
-- if button then
-- if value then
-- button.showOnMouseover = true
-- button.fadeOut:Stop()
-- button:SetAlpha(0)
-- else
-- button.showOnMouseover = false
-- button.fadeOut:Stop()
-- button:SetAlpha(1)
-- end
-- end
-- end
-- end
-- function lib:GetButtonList()
-- local t = {}
-- for name in next, lib.objects do
-- t[#t+1] = name
-- end
-- return t
-- end
-- function lib:SetButtonRadius(radius)
-- if type(radius) == "number" then
-- lib.radius = radius
-- for _, button in next, lib.objects do
-- updatePosition(button, button.db and button.db.minimapPos or button.minimapPos)
-- end
-- end
-- end
-- function lib:SetButtonToPosition(button, position)
-- updatePosition(lib.objects[button] or button, position)
-- end
-- -- Upgrade!
-- for name, button in next, lib.objects do
-- local db = getDatabase(name)
-- if not db or not db.lock then
-- button:SetScript("OnDragStart", onDragStart)
-- button:SetScript("OnDragStop", onDragStop)
-- end
-- button:SetScript("OnEnter", onEnter)
-- button:SetScript("OnLeave", onLeave)
-- button:SetScript("OnClick", onClick)
-- button:SetScript("OnMouseDown", onMouseDown)
-- button:SetScript("OnMouseUp", onMouseUp)
-- if not button.fadeOut then -- Upgrade to 39
-- button.fadeOut = button:CreateAnimationGroup()
-- local animOut = button.fadeOut:CreateAnimation("Alpha")
-- animOut:SetOrder(1)
-- animOut:SetDuration(0.2)
-- animOut:SetFromAlpha(1)
-- animOut:SetToAlpha(0)
-- animOut:SetStartDelay(1)
-- button.fadeOut:SetToFinalAlpha(true)
-- end
-- end
-- lib:SetButtonRadius(lib.radius) -- Upgrade to 40
-- -- LibDBIconEnd
-- end
-- -- LeaLibDBIcon() -- disabled in 3.3.5, was causing red things
-- ----------------------------------------------------------------------
-- -- L15: LibChatAnims (load on demand)
-- ----------------------------------------------------------------------
-- function Leatrix_Plus:LeaPlusLCA()
-- -- LibChatAnimsStart
-- --@curseforge-project-slug: libchatanims@
-- local MAJOR, MINOR = "LibChatAnims", 4 -- Bump minor on changes
-- local LCA = LibStub:NewLibrary(MAJOR, MINOR)
-- if not LCA then return end -- No upgrade needed
-- LCA.animations = LCA.animations or {} -- Animation storage
-- LCA.alerting = LCA.alerting or {} -- Chat tab alerting storage
-- local anims = LCA.animations
-- local alerting = LCA.alerting
-- function LCA:IsAlerting(tab)
-- if alerting[tab] then
-- return true
-- end
-- end
-- ----------------------------------------------------
-- -- Note, most of this code is simply replicated from
-- -- Blizzard's FloatingChatFrame.lua file.
-- -- The only real changes are the creation and use
-- -- of animations vs the use of UIFrameFlash.
-- --
-- --FCFDockOverflowButton_UpdatePulseState = function(self)
-- -- local dock = self:GetParent()
-- -- local shouldPulse = false
-- -- for _, chatFrame in pairs(FCFDock_GetChatFrames(dock)) do
-- -- local chatTab = _G[chatFrame:GetName().."Tab"]
-- -- if ( not chatFrame.isStaticDocked and chatTab.alerting) then
-- -- -- Make sure the rects are valid. (Not always the case when resizing the WoW client
-- -- if ( not chatTab:GetRight() or not dock.scrollFrame:GetRight() ) then
-- -- return false
-- -- end
-- -- -- Check if it's off the screen.
-- -- local DELTA = 3 -- Chosen through experimentation
-- -- if ( chatTab:GetRight() < (dock.scrollFrame:GetLeft() + DELTA) or chatTab:GetLeft() > (dock.scrollFrame:GetRight() - DELTA) ) then
-- -- shouldPulse = true
-- -- break
-- -- end
-- -- end
-- -- end
-- --
-- -- local tex = self:GetHighlightTexture()
-- -- if shouldPulse then
-- -- if not anims[tex] then
-- -- anims[tex] = tex:CreateAnimationGroup()
-- --
-- -- local fade1 = anims[tex]:CreateAnimation("Alpha")
-- -- fade1:SetDuration(1)
-- -- fade1:SetFromAlpha(0)
-- -- fade1:SetToAlpha(1)
-- -- fade1:SetOrder(1)
-- --
-- -- local fade2 = anims[tex]:CreateAnimation("Alpha")
-- -- fade2:SetDuration(1)
-- -- fade2:SetFromAlpha(1)
-- -- fade2:SetToAlpha(0)
-- -- fade2:SetOrder(2)
-- -- end
-- -- tex:Show()
-- -- tex:SetAlpha(0)
-- -- anims[tex]:SetLooping("REPEAT")
-- -- anims[tex]:Play()
-- --
-- -- self:LockHighlight()
-- -- self.alerting = true
-- -- else
-- -- if anims[tex] then
-- -- anims[tex]:Stop()
-- -- end
-- -- self:UnlockHighlight()
-- -- tex:SetAlpha(1)
-- -- tex:Show()
-- -- self.alerting = false
-- -- end
-- --
-- -- if self.list:IsShown() then
-- -- FCFDockOverflowList_Update(self.list, dock)
-- -- end
-- -- return true
-- --end
-- --FCFDockOverflowListButton_SetValue = function(button, chatFrame)
-- -- local chatTab = _G[chatFrame:GetName().."Tab"]
-- -- button.chatFrame = chatFrame
-- -- button:SetText(chatFrame.name)
-- --
-- -- local colorTable = chatTab.selectedColorTable or DEFAULT_TAB_SELECTED_COLOR_TABLE
-- --
-- -- if chatTab.selectedColorTable then
-- -- button:GetFontString():SetTextColor(colorTable.r, colorTable.g, colorTable.b)
-- -- else
-- -- button:GetFontString():SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
-- -- end
-- --
-- -- button.glow:SetVertexColor(colorTable.r, colorTable.g, colorTable.b)
-- --
-- -- if chatTab.conversationIcon then
-- -- button.conversationIcon:SetVertexColor(colorTable.r, colorTable.g, colorTable.b)
-- -- button.conversationIcon:Show()
-- -- else
-- -- button.conversationIcon:Hide()
-- -- end
-- --
-- -- if chatTab.alerting then
-- -- button.alerting = true
-- -- if not anims[button.glow] then
-- -- anims[button.glow] = button.glow:CreateAnimationGroup()
-- --
-- -- local fade1 = anims[button.glow]:CreateAnimation("Alpha")
-- -- fade1:SetDuration(1)
-- -- fade1:SetFromAlpha(0)
-- -- fade1:SetToAlpha(1)
-- -- fade1:SetOrder(1)
-- --
-- -- local fade2 = anims[button.glow]:CreateAnimation("Alpha")
-- -- fade2:SetDuration(1)
-- -- fade2:SetFromAlpha(1)
-- -- fade2:SetToAlpha(0)
-- -- fade2:SetOrder(2)
-- -- end
-- -- button.glow:Show()
-- -- button.glow:SetAlpha(0)
-- -- anims[button.glow]:SetLooping("REPEAT")
-- -- anims[button.glow]:Play()
-- -- else
-- -- button.alerting = false
-- -- if anims[button.glow] then
-- -- anims[button.glow]:Stop()
-- -- end
-- -- button.glow:Hide()
-- -- end
-- -- button:Show()
-- --end
-- FCF_StartAlertFlash = function(chatFrame)
-- local chatTab = _G[chatFrame:GetName().."Tab"]
-- if chatFrame.minFrame then
-- if not anims[chatFrame.minFrame] then
-- anims[chatFrame.minFrame] = chatFrame.minFrame.glow:CreateAnimationGroup()
-- local fade1 = anims[chatFrame.minFrame]:CreateAnimation("Alpha")
-- fade1:SetDuration(1)
-- fade1:SetFromAlpha(0)
-- fade1:SetToAlpha(1)
-- fade1:SetOrder(1)
-- local fade2 = anims[chatFrame.minFrame]:CreateAnimation("Alpha")
-- fade2:SetDuration(1)
-- fade2:SetFromAlpha(1)
-- fade2:SetToAlpha(0)
-- fade2:SetOrder(2)
-- end
-- chatFrame.minFrame.glow:Show()
-- chatFrame.minFrame.glow:SetAlpha(0)
-- anims[chatFrame.minFrame]:SetLooping("REPEAT")
-- anims[chatFrame.minFrame]:Play()
-- --chatFrame.minFrame.alerting = true
-- alerting[chatFrame.minFrame] = true
-- end
-- if not anims[chatTab.glow] then
-- anims[chatTab.glow] = chatTab.glow:CreateAnimationGroup()
-- local fade1 = anims[chatTab.glow]:CreateAnimation("Alpha")
-- fade1:SetDuration(1)
-- fade1:SetFromAlpha(0)
-- fade1:SetToAlpha(1)
-- fade1:SetOrder(1)
-- local fade2 = anims[chatTab.glow]:CreateAnimation("Alpha")
-- fade2:SetDuration(1)
-- fade2:SetFromAlpha(1)
-- fade2:SetToAlpha(0)
-- fade2:SetOrder(2)
-- end
-- chatTab.glow:Show()
-- chatTab.glow:SetAlpha(0)
-- anims[chatTab.glow]:SetLooping("REPEAT")
-- anims[chatTab.glow]:Play()
-- --chatTab.alerting = true
-- alerting[chatTab] = true
-- -- START function FCFTab_UpdateAlpha(chatFrame)
-- local mouseOverAlpha, noMouseAlpha = 0, 0
-- if not chatFrame.isDocked or chatFrame == FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK) then
-- mouseOverAlpha = 1.0 --CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA
-- noMouseAlpha = 0.4 -- CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA
-- else
-- mouseOverAlpha = 1.0 -- CHAT_FRAME_TAB_ALERTING_MOUSEOVER_ALPHA
-- noMouseAlpha = 1.0 -- CHAT_FRAME_TAB_ALERTING_NOMOUSE_ALPHA
-- end
-- if chatFrame.hasBeenFaded then
-- chatTab:SetAlpha(mouseOverAlpha)
-- else
-- chatTab:SetAlpha(noMouseAlpha)
-- end
-- --END function FCFTab_UpdateAlpha(chatFrame)
-- --FCFDockOverflowButton_UpdatePulseState(GENERAL_CHAT_DOCK.overflowButton)
-- end
-- FCF_StopAlertFlash = function(chatFrame)
-- local chatTab = _G[chatFrame:GetName().."Tab"]
-- if chatFrame.minFrame then
-- if anims[chatFrame.minFrame] then
-- anims[chatFrame.minFrame]:Stop()
-- end
-- chatFrame.minFrame.glow:Hide()
-- --chatFrame.minFrame.alerting = false
-- alerting[chatFrame.minFrame] = nil
-- end
-- if anims[chatTab.glow] then
-- anims[chatTab.glow]:Stop()
-- end
-- chatTab.glow:Hide()
-- --chatTab.alerting = false
-- alerting[chatTab] = nil
-- -- START function FCFTab_UpdateAlpha(chatFrame)
-- local mouseOverAlpha, noMouseAlpha = 0, 0
-- if not chatFrame.isDocked or chatFrame == FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK) then
-- mouseOverAlpha = 1.0 --CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA
-- noMouseAlpha = 0.4 -- CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA
-- else
-- mouseOverAlpha = 0.6 --CHAT_FRAME_TAB_NORMAL_MOUSEOVER_ALPHA
-- noMouseAlpha = 0.2 --CHAT_FRAME_TAB_NORMAL_NOMOUSE_ALPHA
-- end
-- if chatFrame.hasBeenFaded then
-- chatTab:SetAlpha(mouseOverAlpha)
-- else
-- chatTab:SetAlpha(noMouseAlpha)
-- end
-- --END function FCFTab_UpdateAlpha(chatFrame)
-- --FCFDockOverflowButton_UpdatePulseState(GENERAL_CHAT_DOCK.overflowButton)
-- end
-- -- LibChatAnimsEnd
-- end
-- ----------------------------------------------------------------------
-- -- L16: LibDBIcon: LibCandyBar
-- ----------------------------------------------------------------------
function Leatrix_Plus:LeaPlusCandyBar()
-- LibCandyBarStart
--@curseforge-project-slug: libcandybar-3-0@
--- **LibCandyBar-3.0** provides elegant timerbars with icons for use in addons.
-- It is based of the original ideas of the CandyBar and CandyBar-2.0 library.
-- In contrary to the earlier libraries LibCandyBar-3.0 provides you with a timerbar object with a simple API.
--
-- Creating a new timerbar using the ':New' function will return a new timerbar object. This timerbar object inherits all of the barPrototype functions listed here. \\
--
-- @usage
-- local candy = LibStub("LibCandyBar-3.0")
-- local texture = "Interface\\AddOns\\MyAddOn\\statusbar"
-- local mybar = candy:New(texture, 100, 16)
-- mybar:SetLabel("Yay!")
-- mybar:SetDuration(60)
-- mybar:Start()
-- @class file
-- @name LibCandyBar-3.0
local GetTime, floor, next = GetTime, floor, next
local CreateFrame, error, setmetatable, UIParent = CreateFrame, error, setmetatable, UIParent
if not LibStub then error("LibCandyBar-3.0 requires LibStub.") end
local cbh = LibStub:GetLibrary("CallbackHandler-1.0")
if not cbh then error("LibCandyBar-3.0 requires CallbackHandler-1.0") end
local lib = LibStub:NewLibrary("LibCandyBar-3.0", 100) -- Bump minor on changes
if not lib then return end
lib.callbacks = lib.callbacks or cbh:New(lib)
local cb = lib.callbacks
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.barCache = lib.barCache or {}
local barPrototype = lib.barPrototype
local barPrototype_meta = lib.barPrototype_mt
local barCache = lib.barCache
local scripts = {
"OnUpdate", "OnDragStart", "OnDragStop",
"OnEnter", "OnLeave", "OnHide",
"OnShow", "OnMouseDown", "OnMouseUp",
"OnMouseWheel", "OnSizeChanged", "OnEvent"
}
local numScripts = #scripts
local GameFontHighlightSmallOutline = GameFontHighlightSmallOutline
local _fontName, _fontSize = GameFontHighlightSmallOutline:GetFont()
local _fontShadowX, _fontShadowY = GameFontHighlightSmallOutline:GetShadowOffset()
-- local _fontShadowR, _fontShadowG, _fontShadowB, _fontShadowA = GameFontHighlightSmallOutline:GetShadowColor()
local _fontShadowR, _fontShadowG, _fontShadowB, _fontShadowA = nil
local SetWidth, SetHeight, SetSize = lib.dummyFrame.SetWidth, lib.dummyFrame.SetHeight, lib.dummyFrame.SetSize
local function stopBar(bar)
bar.updater:Stop()
bar.data = nil
bar.funcs = nil
bar.running = nil
bar.paused = nil
bar:Hide()
bar:SetParent(UIParent)
end
local tformat1 = "%d:%02d:%02d"
local tformat2 = "%d:%02d"
local tformat3 = "%.1f"
local tformat4 = "%.0f"
local function barUpdate(updater)
local bar = updater.parent
local t = GetTime()
if t >= bar.exp then
bar:Stop()
else
local time = bar.exp - t
bar.remaining = time
bar.candyBarBar:SetValue(bar.fill and (t-bar.start)+bar.gap or time)
if time > 3599.9 then -- > 1 hour
local h = floor(time/3600)
local m = floor((time - (h*3600))/60)
local s = (time - (m*60)) - (h*3600)
bar.candyBarDuration:SetFormattedText(tformat1, h, m, s)
elseif time > 59.9 then -- 1 minute to 1 hour
local m = floor(time/60)
local s = time - (m*60)
bar.candyBarDuration:SetFormattedText(tformat2, m, s)
elseif time < 10 then -- 0 to 10 seconds
bar.candyBarDuration:SetFormattedText(tformat3, time)
else -- 10 seconds to one minute
bar.candyBarDuration:SetFormattedText(tformat4, time)
end
if bar.funcs then
for i = 1, #bar.funcs do
bar.funcs[i](bar)
end
end
end
end
local atformat1 = "~%d:%02d:%02d"
local atformat2 = "~%d:%02d"
local atformat3 = "~%.1f"
local atformat4 = "~%.0f"
local function barUpdateApprox(updater)
local bar = updater.parent
local t = GetTime()
if t >= bar.exp then
bar:Stop()
else
local time = bar.exp - t
bar.remaining = time
bar.candyBarBar:SetValue(bar.fill and (t-bar.start)+bar.gap or time)
if time > 3599.9 then -- > 1 hour
local h = floor(time/3600)
local m = floor((time - (h*3600))/60)
local s = (time - (m*60)) - (h*3600)
bar.candyBarDuration:SetFormattedText(atformat1, h, m, s)
elseif time > 59.9 then -- 1 minute to 1 hour
local m = floor(time/60)
local s = time - (m*60)
bar.candyBarDuration:SetFormattedText(atformat2, m, s)
elseif time < 10 then -- 0 to 10 seconds
bar.candyBarDuration:SetFormattedText(atformat3, time)
else -- 10 seconds to one minute
bar.candyBarDuration:SetFormattedText(atformat4, time)
end
if bar.funcs then
for i = 1, #bar.funcs do
bar.funcs[i](bar)
end
end
end
end
-- ------------------------------------------------------------------------------
-- Bar functions
--
local function restyleBar(self)
if not self.running then return end
self.candyBarIconFrame:ClearAllPoints()
self.candyBarBar:ClearAllPoints()
-- In the past we used a :GetTexture check here, but as of WoW v5 it randomly returns nil, so use our own trustworthy variable.
if self.candyBarIconFrame.icon then
self.candyBarIconFrame:SetWidth(self.height)
if self.iconPosition == "RIGHT" then
self.candyBarIconFrame:SetPoint("TOPRIGHT", self)
self.candyBarIconFrame:SetPoint("BOTTOMRIGHT", self)
self.candyBarBar:SetPoint("TOPRIGHT", self.candyBarIconFrame, "TOPLEFT")
self.candyBarBar:SetPoint("BOTTOMRIGHT", self.candyBarIconFrame, "BOTTOMLEFT")
self.candyBarBar:SetPoint("TOPLEFT", self)
self.candyBarBar:SetPoint("BOTTOMLEFT", self)
else
self.candyBarIconFrame:SetPoint("TOPLEFT")
self.candyBarIconFrame:SetPoint("BOTTOMLEFT")
self.candyBarBar:SetPoint("TOPLEFT", self.candyBarIconFrame, "TOPRIGHT")
self.candyBarBar:SetPoint("BOTTOMLEFT", self.candyBarIconFrame, "BOTTOMRIGHT")
self.candyBarBar:SetPoint("TOPRIGHT", self)
self.candyBarBar:SetPoint("BOTTOMRIGHT", self)
end
self.candyBarIconFrame:Show()
else
self.candyBarBar:SetPoint("TOPLEFT", self)
self.candyBarBar:SetPoint("BOTTOMRIGHT", self)
self.candyBarIconFrame:Hide()
end
if self.showLabel and self.candyBarLabel.text then
self.candyBarLabel:Show()
else
self.candyBarLabel:Hide()
end
if self.showTime then
self.candyBarDuration:Show()
else
self.candyBarDuration:Hide()
end
end
--- Set whether the bar should drain (default) or fill up.
-- @param fill Boolean true/false
function barPrototype:SetFill(fill)
self.fill = fill
end
--- Adds a function to the timerbar. The function will run every update and will receive the bar as a parameter.
-- @param func Function to run every update.
-- @usage
-- -- The example below will print the time remaining to the chatframe every update. Yes, that's a whole lot of spam
-- mybar:AddUpdateFunction( function(bar) print(bar.remaining) end )
function barPrototype:AddUpdateFunction(func) if not self.funcs then self.funcs = {} end; self.funcs[#self.funcs+1] = func end
--- Sets user data in the timerbar object.
-- @param key Key to use for the data storage.
-- @param data Data to store.
function barPrototype:Set(key, data) if not self.data then self.data = {} end; self.data[key] = data end
--- Retrieves user data from the timerbar object.
-- @param key Key to retrieve
function barPrototype:Get(key) return self.data and self.data[key] end
--- Sets the color of the bar.
-- This is basically a wrapper to SetStatusBarColor.
-- @paramsig r, g, b, a
-- @param r Red component (0-1)
-- @param g Green component (0-1)
-- @param b Blue component (0-1)
-- @param a Alpha (0-1)
function barPrototype:SetColor(...) self.candyBarBar:SetStatusBarColor(...) end
--- Sets the color of the bar label and bar duration text.
-- @paramsig r, g, b, a
-- @param r Red component (0-1)
-- @param g Green component (0-1)
-- @param b Blue component (0-1)
-- @param a Alpha (0-1)
function barPrototype:SetTextColor(...)
self.candyBarLabel:SetTextColor(...)
self.candyBarDuration:SetTextColor(...)
end
--- Sets the shadow color of the bar label and bar duration text.
-- @paramsig r, g, b, a
-- @param r Red component (0-1)
-- @param g Green component (0-1)
-- @param b Blue component (0-1)
-- @param a Alpha (0-1)
function barPrototype:SetShadowColor(...)
self.candyBarLabel:SetShadowColor(...)
self.candyBarDuration:SetShadowColor(...)
end
--- Sets the texture of the bar.
-- This should only be needed on running bars that get changed on the fly.
-- @param texture Path to the bar texture.
function barPrototype:SetTexture(texture)
self.candyBarBar:SetStatusBarTexture(texture)
self.candyBarBackground:SetTexture(texture)
end
--- Sets the width of the bar.
-- This should only be needed on running bars that get changed on the fly.
-- @param width Width of the bar.
function barPrototype:SetWidth(width)
self.width = width
SetWidth(self, width)
end
--- Sets the height of the bar.
-- This should only be needed on running bars that get changed on the fly.
-- @param height Height of the bar.
function barPrototype:SetHeight(height)
self.height = height
SetHeight(self, height)
restyleBar(self)
end
--- Sets the size of the bar.
-- This should only be needed on running bars that get changed on the fly.
-- @param width Width of the bar.
-- @param height Height of the bar.
function barPrototype:SetSize(width, height)
self.width = width
self.height = height
SetSize(self, width, height)
restyleBar(self)
end
--- Returns the label (text) currently set on the bar.
function barPrototype:GetLabel()
return self.candyBarLabel.text
end
--- Sets the label on the bar.
-- @param text Label text.
function barPrototype:SetLabel(text)
self.candyBarLabel.text = text
self.candyBarLabel:SetText(text)
if text then
self.candyBarLabel:Show()
else
self.candyBarLabel:Hide()
end
end
--- Returns the icon texture path currently set on the bar, if it has an icon set.
function barPrototype:GetIcon()
return self.candyBarIconFrame.icon
end
--- Sets the icon next to the bar.
-- @param icon Path to the icon texture or nil to not display an icon.
-- @param ... Optional icon coordinates for texture trimming.
function barPrototype:SetIcon(icon, ...)
self.candyBarIconFrame.icon = icon
self.candyBarIconFrame:SetTexture(icon)
if ... then
self.candyBarIconFrame:SetTexCoord(...)
else
self.candyBarIconFrame:SetTexCoord(0.07, 0.93, 0.07, 0.93)
end
restyleBar(self)
end
--- Sets which side of the bar the icon should appear.
-- @param position Position of the icon according to the bar, either "LEFT" or "RIGHT" as a string. Set to "LEFT" by default.
function barPrototype:SetIconPosition(position)
self.iconPosition = position
restyleBar(self)
end
--- Sets wether or not the time indicator on the right of the bar should be shown.
-- Time is shown by default.
-- @param bool true to show the time, false/nil to hide the time.
function barPrototype:SetTimeVisibility(bool)
self.showTime = bool
if bool then
self.candyBarDuration:Show()
else
self.candyBarDuration:Hide()
end
end
--- Sets wether or not the label on the left of the bar should be shown.
-- label is shown by default.
-- @param bool true to show the label, false/nil to hide the label.
function barPrototype:SetLabelVisibility(bool)
self.showLabel = bool
if bool then
self.candyBarLabel:Show()
else
self.candyBarLabel:Hide()
end
end
--- Sets the duration of the bar.
-- This can also be used while the bar is running to adjust the time remaining, within the bounds of the original duration.
-- @param duration Duration of the bar in seconds.
-- @param isApprox Boolean. True if you wish the time display to be an approximate "~5" instead of "5"
function barPrototype:SetDuration(duration, isApprox) self.remaining = duration; self.isApproximate = isApprox end
--- Shows the bar and starts it.
-- @param maxValue Number. If you don't wish your bar to start full, you can set a max value. A maxValue of 10 on a bar with a duration of 5 would start it at 50%.
function barPrototype:Start(maxValue)
self.running = true
local time = self.remaining
self.gap = maxValue and maxValue-time or 0
restyleBar(self)
self.start = GetTime()
self.exp = self.start + time
self.candyBarBar:SetMinMaxValues(0, maxValue or time)
self.candyBarBar:SetValue(self.fill and 0 or time)
if self.isApproximate then
if time > 3599.9 then -- > 1 hour
local h = floor(time/3600)
local m = floor((time - (h*3600))/60)
local s = (time - (m*60)) - (h*3600)
self.candyBarDuration:SetFormattedText(atformat1, h, m, s)
elseif time > 59.9 then -- 1 minute to 1 hour
local m = floor(time/60)
local s = time - (m*60)
self.candyBarDuration:SetFormattedText(atformat2, m, s)
elseif time < 10 then -- 0 to 10 seconds
self.candyBarDuration:SetFormattedText(atformat3, time)
else -- 10 seconds to one minute
self.candyBarDuration:SetFormattedText(atformat4, time)
end
self.updater:SetScript("OnLoop", barUpdateApprox)
else
if time > 3599.9 then -- > 1 hour
local h = floor(time/3600)
local m = floor((time - (h*3600))/60)
local s = (time - (m*60)) - (h*3600)
self.candyBarDuration:SetFormattedText(tformat1, h, m, s)
elseif time > 59.9 then -- 1 minute to 1 hour
local m = floor(time/60)
local s = time - (m*60)
self.candyBarDuration:SetFormattedText(tformat2, m, s)
elseif time < 10 then -- 0 to 10 seconds
self.candyBarDuration:SetFormattedText(tformat3, time)
else -- 10 seconds to one minute
self.candyBarDuration:SetFormattedText(tformat4, time)
end
self.updater:SetScript("OnLoop", barUpdate)
end
self.updater:Play()
self:Show()
end
--- Pauses a running bar
function barPrototype:Pause()
if not self.paused then
self.updater:Pause()
self.paused = GetTime()
end
end
--- Resumes a paused bar
function barPrototype:Resume()
if self.paused then
local t = GetTime()
self.exp = t + self.remaining
self.start = self.start + (t-self.paused)
self.updater:Play()
self.paused = nil
end
end
--- Stops the bar.
-- This will stop the bar, fire the LibCandyBar_Stop callback, and recycle the bar into the candybar pool.
-- Note: make sure you remove all references to the bar in your addon upon receiving the LibCandyBar_Stop callback.
-- @usage
-- -- The example below shows the use of the LibCandyBar_Stop callback by printing the contents of the label in the chatframe
-- local function barstopped( callback, bar )
-- print( bar:GetLabel(), "stopped")
-- end
-- LibStub("LibCandyBar-3.0"):RegisterCallback(myaddonobject, "LibCandyBar_Stop", barstopped)
-- @param ... Optional args to pass across in the LibCandyBar_Stop callback.
function barPrototype:Stop(...)
cb:Fire("LibCandyBar_Stop", self, ...)
stopBar(self)
barCache[self] = true
end
-- ------------------------------------------------------------------------------
-- Library functions
--
--- Creates a new timerbar object and returns it. Don't forget to set the duration, label and :Start the timer bar after you get a hold of it!
-- @paramsig texture, width, height
-- @param texture Path to the texture used for the bar.
-- @param width Width of the bar.
-- @param height Height of the bar.
-- @usage
-- mybar = LibStub("LibCandyBar-3.0"):New("Interface\\AddOns\\MyAddOn\\media\\statusbar", 100, 16)
function lib:New(texture, width, height)
local bar = next(barCache)
if not bar then
local frame = CreateFrame("Frame", nil, UIParent)
bar = setmetatable(frame, barPrototype_meta)
local icon = bar:CreateTexture()
icon:SetPoint("TOPLEFT")
icon:SetPoint("BOTTOMLEFT")
icon:Show()
bar.candyBarIconFrame = icon
local statusbar = CreateFrame("StatusBar", nil, bar)
statusbar:SetPoint("TOPRIGHT")
statusbar:SetPoint("BOTTOMRIGHT")
bar.candyBarBar = statusbar
local bg = statusbar:CreateTexture(nil, "BACKGROUND")
bg:SetAllPoints()
bar.candyBarBackground = bg
local backdrop = CreateFrame("Frame", nil, bar, "BackdropTemplate") -- Used by bar stylers for backdrops
backdrop:SetFrameLevel(0)
bar.candyBarBackdrop = backdrop
local iconBackdrop = CreateFrame("Frame", nil, bar, "BackdropTemplate") -- Used by bar stylers for backdrops
iconBackdrop:SetFrameLevel(0)
bar.candyBarIconFrameBackdrop = iconBackdrop
local duration = statusbar:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmallOutline")
duration:SetPoint("TOPLEFT", statusbar, "TOPLEFT", 2, 0)
duration:SetPoint("BOTTOMRIGHT", statusbar, "BOTTOMRIGHT", -2, 0)
bar.candyBarDuration = duration
local label = statusbar:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmallOutline")
label:SetPoint("TOPLEFT", statusbar, "TOPLEFT", 2, 0)
label:SetPoint("BOTTOMRIGHT", statusbar, "BOTTOMRIGHT", -2, 0)
bar.candyBarLabel = label
local updater = bar:CreateAnimationGroup()
updater:SetLooping("REPEAT")
updater.parent = bar
local anim = updater:CreateAnimation()
anim:SetDuration(0.04)
bar.updater = updater
bar.repeater = anim
else
barCache[bar] = nil
end
bar:SetFrameStrata("MEDIUM")
bar:SetFrameLevel(100) -- Lots of room to create above or below this level
bar.candyBarBar:SetStatusBarTexture(texture)
bar.candyBarBackground:SetTexture(texture)
bar.width = width
bar.height = height
-- RESET ALL THE THINGS!
bar.fill = nil
bar.showTime = true
bar.showLabel = true
bar.iconPosition = nil
for i = 1, numScripts do -- Update if scripts table is changed, faster than doing #scripts
bar:SetScript(scripts[i], nil)
end
bar.candyBarBackground:SetVertexColor(0.5, 0.5, 0.5, 0.3)
bar.candyBarBar:SetStatusBarColor(0.5, 0.5, 0.5, 1)
bar:ClearAllPoints()
SetWidth(bar, width)
SetHeight(bar, height)
bar:SetMovable(1)
bar:SetScale(1)
bar:SetAlpha(1)
bar:SetClampedToScreen(false)
bar:EnableMouse(false)
bar.candyBarLabel:SetTextColor(1,1,1,1)
bar.candyBarLabel:SetJustifyH("LEFT")
bar.candyBarLabel:SetJustifyV("MIDDLE")
bar.candyBarLabel:SetFont(_fontName, _fontSize)
bar.candyBarLabel:SetShadowOffset(_fontShadowX, _fontShadowY)
bar.candyBarLabel:SetShadowColor(_fontShadowR, _fontShadowG, _fontShadowB, _fontShadowA)
bar.candyBarDuration:SetTextColor(1,1,1,1)
bar.candyBarDuration:SetJustifyH("RIGHT")
bar.candyBarDuration:SetJustifyV("MIDDLE")
bar.candyBarDuration:SetFont(_fontName, _fontSize)
bar.candyBarDuration:SetShadowOffset(_fontShadowX, _fontShadowY)
bar.candyBarDuration:SetShadowColor(_fontShadowR, _fontShadowG, _fontShadowB, _fontShadowA)
bar:SetLabel()
bar:SetIcon()
bar:SetDuration()
return bar
end
-- LibCandyBarEnd
end
-- L17: End