Relintais-Enemy-Kooldown-Tr.../lib/AceGUI-3.0/AceGUI-3.0.lua

704 lines
18 KiB
Lua
Raw Normal View History

--[[ $Id: AceGUI-3.0.lua 81438 2008-09-06 13:44:36Z nevcairiel $ ]]
local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 16
2016-05-06 15:25:00 +02:00
local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
if not AceGUI then return end -- No upgrade needed
--local con = LibStub("AceConsole-3.0",true)
AceGUI.WidgetRegistry = AceGUI.WidgetRegistry or {}
AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
AceGUI.WidgetBase = AceGUI.WidgetBase or {}
AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
-- local upvalues
local WidgetRegistry = AceGUI.WidgetRegistry
local LayoutRegistry = AceGUI.LayoutRegistry
local WidgetVersions = AceGUI.WidgetVersions
local pcall = pcall
local select = select
local pairs = pairs
local ipairs = ipairs
local type = type
local assert = assert
local tinsert = tinsert
local tremove = tremove
local CreateFrame = CreateFrame
local UIParent = UIParent
2016-05-06 15:25:00 +02:00
--[[
xpcall safecall implementation
]]
local xpcall = xpcall
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", table.concat(ARGS, ", "))
2016-05-06 15:25:00 +02:00
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, ...)
return Dispatchers[select('#', ...)](func, ...)
2016-05-06 15:25:00 +02:00
end
-- Recycling functions
local new, del
2016-05-06 15:25:00 +02:00
do
AceGUI.objPools = AceGUI.objPools or {}
local objPools = AceGUI.objPools
--Returns a new instance, if none are available either returns a new table or calls the given contructor
function new(type,constructor,...)
if not type then
type = "table"
2016-05-06 15:25:00 +02:00
end
if not objPools[type] then
objPools[type] = {}
end
local newObj = tremove(objPools[type])
2016-05-06 15:25:00 +02:00
if not newObj then
newObj = constructor and constructor(...) or {}
2016-05-06 15:25:00 +02:00
end
return newObj
end
-- Releases an instance to the Pool
function del(obj,type)
if not type then
type = "table"
end
2016-05-06 15:25:00 +02:00
if not objPools[type] then
objPools[type] = {}
end
for i,v in ipairs(objPools[type]) do
if v == obj then
error("Attempt to Release Widget that is already released")
return
end
2016-05-06 15:25:00 +02:00
end
tinsert(objPools[type],obj)
2016-05-06 15:25:00 +02:00
end
end
-------------------
-- API Functions --
-------------------
-- Gets a widget Object
function AceGUI:Create(type)
local reg = WidgetRegistry
if reg[type] then
local widget = new(type,reg[type])
2016-05-06 15:25:00 +02:00
if rawget(widget,'Acquire') then
2016-05-06 15:25:00 +02:00
widget.OnAcquire = widget.Acquire
widget.Acquire = nil
elseif rawget(widget,'Aquire') then
2016-05-06 15:25:00 +02:00
widget.OnAcquire = widget.Aquire
widget.Aquire = nil
end
if rawget(widget,'Release') then
widget.OnRelease = rawget(widget,'Release')
2016-05-06 15:25:00 +02:00
widget.Release = nil
end
if widget.OnAcquire then
widget:OnAcquire()
else
error(("Widget type %s doesn't supply an OnAcquire Function"):format(type))
end
2016-05-06 15:25:00 +02:00
safecall(widget.ResumeLayout, widget)
return widget
end
end
-- Releases a widget Object
2016-05-06 15:25:00 +02:00
function AceGUI:Release(widget)
safecall( widget.PauseLayout, widget )
2016-05-06 15:25:00 +02:00
widget:Fire("OnRelease")
safecall( widget.ReleaseChildren, widget )
2016-05-06 15:25:00 +02:00
if widget.OnRelease then
widget:OnRelease()
else
error(("Widget type %s doesn't supply an OnRelease Function"):format(type))
2016-05-06 15:25:00 +02:00
end
for k in pairs(widget.userdata) do
widget.userdata[k] = nil
end
for k in pairs(widget.events) do
widget.events[k] = nil
end
widget.width = nil
--widget.frame:SetParent(nil)
2016-05-06 15:25:00 +02:00
widget.frame:ClearAllPoints()
widget.frame:Hide()
widget.frame:SetParent(nil)
2016-05-06 15:25:00 +02:00
if widget.content then
widget.content.width = nil
widget.content.height = nil
end
del(widget,widget.type)
2016-05-06 15:25:00 +02:00
end
-----------
-- Focus --
-----------
-----
-- Called when a widget has taken focus
2016-05-06 15:25:00 +02:00
-- e.g. Dropdowns opening, Editboxes gaining kb focus
-----
2016-05-06 15:25:00 +02:00
function AceGUI:SetFocus(widget)
if self.FocusedWidget and self.FocusedWidget ~= widget then
safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
end
self.FocusedWidget = widget
end
-----
-- Called when something has happened that could cause widgets with focus to drop it
2016-05-06 15:25:00 +02:00
-- e.g. titlebar of a frame being clicked
-----
2016-05-06 15:25:00 +02:00
function AceGUI:ClearFocus()
if self.FocusedWidget then
safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
self.FocusedWidget = nil
end
end
-------------
-- Widgets --
-------------
--[[
Widgets must provide the following functions
OnAcquire() - Called when the object is acquired, should set everything to a default hidden state
OnRelease() - Called when the object is Released, should remove any anchors and hide the Widget
2016-05-06 15:25:00 +02:00
And the following members
frame - the frame or derivitive object that will be treated as the widget for size and anchoring purposes
type - the type of the object, same as the name given to :RegisterWidget()
Widgets contain a table called userdata, this is a safe place to store data associated with the wigdet
It will be cleared automatically when a widget is released
Placing values directly into a widget object should be avoided
If the Widget can act as a container for other Widgets the following
content - frame or derivitive that children will be anchored to
The Widget can supply the following Optional Members
:OnWidthSet(width) - Called when the width of the widget is changed
:OnHeightSet(height) - Called when the height of the widget is changed
Widgets should not use the OnSizeChanged events of thier frame or content members, use these methods instead
AceGUI already sets a handler to the event
:OnLayoutFinished(width, height) - called after a layout has finished, the width and height will be the width and height of the
2016-05-06 15:25:00 +02:00
area used for controls. These can be nil if the layout used the existing size to layout the controls.
]]
--------------------------
-- Widget Base Template --
--------------------------
do
local function fixlevels(parent,...)
local i = 1
local child = select(i, ...)
while child do
child:SetFrameLevel(parent:GetFrameLevel()+1)
fixlevels(child, child:GetChildren())
i = i + 1
child = select(i, ...)
end
end
2016-05-06 15:25:00 +02:00
local WidgetBase = AceGUI.WidgetBase
WidgetBase.SetParent = function(self, parent)
local frame = self.frame
frame:SetParent(nil)
frame:SetParent(parent.content)
self.parent = parent
fixlevels(parent.frame,parent.frame:GetChildren())
2016-05-06 15:25:00 +02:00
end
WidgetBase.SetCallback = function(self, name, func)
if type(func) == "function" then
self.events[name] = func
end
end
WidgetBase.Fire = function(self, name, ...)
if self.events[name] then
local success, ret = safecall(self.events[name], self, name, ...)
if success then
return ret
end
end
end
WidgetBase.SetWidth = function(self, width)
self.frame:SetWidth(width)
self.frame.width = width
if self.OnWidthSet then
self:OnWidthSet(width)
end
end
WidgetBase.SetHeight = function(self, height)
self.frame:SetHeight(height)
self.frame.height = height
if self.OnHeightSet then
self:OnHeightSet(height)
end
end
WidgetBase.IsVisible = function(self)
return self.frame:IsVisible()
end
WidgetBase.IsShown= function(self)
return self.frame:IsShown()
end
WidgetBase.Release = function(self)
AceGUI:Release(self)
end
WidgetBase.SetPoint = function(self, ...)
return self.frame:SetPoint(...)
end
WidgetBase.ClearAllPoints = function(self)
return self.frame:ClearAllPoints()
end
WidgetBase.GetNumPoints = function(self)
return self.frame:GetNumPoints()
end
WidgetBase.GetPoint = function(self, ...)
return self.frame:GetPoint(...)
end
WidgetBase.GetUserDataTable = function(self)
return self.userdata
end
WidgetBase.SetUserData = function(self, key, value)
self.userdata[key] = value
end
WidgetBase.GetUserData = function(self, key)
return self.userdata[key]
end
WidgetBase.IsFullHeight = function(self)
return self.height == "fill"
end
WidgetBase.SetFullHeight = function(self, isFull)
if isFull then
self.height = "fill"
else
self.height = nil
end
end
WidgetBase.IsFullWidth = function(self)
return self.width == "fill"
end
WidgetBase.SetFullWidth = function(self, isFull)
if isFull then
self.width = "fill"
else
self.width = nil
end
end
-- local function LayoutOnUpdate(this)
-- this:SetScript("OnUpdate",nil)
-- this.obj:PerformLayout()
-- end
local WidgetContainerBase = AceGUI.WidgetContainerBase
WidgetContainerBase.PauseLayout = function(self)
self.LayoutPaused = true
end
WidgetContainerBase.ResumeLayout = function(self)
self.LayoutPaused = nil
end
WidgetContainerBase.PerformLayout = function(self)
if self.LayoutPaused then
return
end
safecall(self.LayoutFunc,self.content, self.children)
2016-05-06 15:25:00 +02:00
end
--call this function to layout, makes sure layed out objects get a frame to get sizes etc
WidgetContainerBase.DoLayout = function(self)
self:PerformLayout()
-- if not self.parent then
-- self.frame:SetScript("OnUpdate", LayoutOnUpdate)
-- end
end
WidgetContainerBase.AddChild = function(self, child)
tinsert(self.children,child)
2016-05-06 15:25:00 +02:00
child:SetParent(self)
child.frame:Show()
self:DoLayout()
end
WidgetContainerBase.ReleaseChildren = function(self)
local children = self.children
for i in ipairs(children) do
2016-05-06 15:25:00 +02:00
AceGUI:Release(children[i])
children[i] = nil
end
end
WidgetContainerBase.SetLayout = function(self, Layout)
self.LayoutFunc = AceGUI:GetLayout(Layout)
end
local function FrameResize(this)
local self = this.obj
if this:GetWidth() and this:GetHeight() then
if self.OnWidthSet then
self:OnWidthSet(this:GetWidth())
end
if self.OnHeightSet then
self:OnHeightSet(this:GetHeight())
end
end
end
local function ContentResize(this)
if this:GetWidth() and this:GetHeight() then
this.width = this:GetWidth()
this.height = this:GetHeight()
this.obj:DoLayout()
end
end
setmetatable(WidgetContainerBase,{__index=WidgetBase})
2016-05-06 15:25:00 +02:00
--One of these function should be called on each Widget Instance as part of its creation process
function AceGUI:RegisterAsContainer(widget)
widget.children = {}
widget.userdata = {}
widget.events = {}
widget.base = WidgetContainerBase
widget.content.obj = widget
widget.frame.obj = widget
widget.content:SetScript("OnSizeChanged",ContentResize)
widget.frame:SetScript("OnSizeChanged",FrameResize)
setmetatable(widget,{__index=WidgetContainerBase})
2016-05-06 15:25:00 +02:00
widget:SetLayout("List")
end
function AceGUI:RegisterAsWidget(widget)
widget.userdata = {}
widget.events = {}
widget.base = WidgetBase
widget.frame.obj = widget
widget.frame:SetScript("OnSizeChanged",FrameResize)
setmetatable(widget,{__index=WidgetBase})
2016-05-06 15:25:00 +02:00
end
end
------------------
-- Widget API --
------------------
-- Registers a widget Constructor, this function returns a new instance of the Widget
2016-05-06 15:25:00 +02:00
function AceGUI:RegisterWidgetType(Name, Constructor, Version)
assert(type(Constructor) == "function")
assert(type(Version) == "number")
local oldVersion = WidgetVersions[Name]
if oldVersion and oldVersion >= Version then return end
WidgetVersions[Name] = Version
WidgetRegistry[Name] = Constructor
end
-- Registers a Layout Function
2016-05-06 15:25:00 +02:00
function AceGUI:RegisterLayout(Name, LayoutFunc)
assert(type(LayoutFunc) == "function")
if type(Name) == "string" then
Name = Name:upper()
end
LayoutRegistry[Name] = LayoutFunc
end
function AceGUI:GetLayout(Name)
if type(Name) == "string" then
Name = Name:upper()
end
return LayoutRegistry[Name]
end
AceGUI.counts = AceGUI.counts or {}
function AceGUI:GetNextWidgetNum(type)
if not self.counts[type] then
self.counts[type] = 0
end
self.counts[type] = self.counts[type] + 1
return self.counts[type]
end
--[[ Widget Template
--------------------------
-- Widget Name --
--------------------------
do
local Type = "Type"
local function OnAcquire(self)
end
local function OnRelease(self)
self.frame:ClearAllPoints()
self.frame:Hide()
end
local function Constructor()
local frame = CreateFrame("Frame",nil,UIParent)
local self = {}
self.type = Type
2016-05-06 15:25:00 +02:00
self.OnRelease = OnRelease
self.OnAcquire = OnAcquire
self.frame = frame
frame.obj = self
--Container Support
--local content = CreateFrame("Frame",nil,frame)
--self.content = content
--AceGUI:RegisterAsContainer(self)
AceGUI:RegisterAsWidget(self)
return self
end
AceGUI:RegisterWidgetType(Type,Constructor)
2016-05-06 15:25:00 +02:00
end
]]
2016-05-06 15:25:00 +02:00
-------------
-- Layouts --
-------------
--[[
A Layout is a func that takes 2 parameters
content - the frame that widgets will be placed inside
children - a table containing the widgets to layout
2016-05-06 15:25:00 +02:00
]]
-- Very simple Layout, Children are stacked on top of each other down the left side
AceGUI:RegisterLayout("List",
function(content, children)
local height = 0
local width = content.width or content:GetWidth() or 0
for i, child in ipairs(children) do
2016-05-06 15:25:00 +02:00
local frame = child.frame
frame:ClearAllPoints()
frame:Show()
if i == 1 then
frame:SetPoint("TOPLEFT",content,"TOPLEFT",0,0)
2016-05-06 15:25:00 +02:00
else
frame:SetPoint("TOPLEFT",children[i-1].frame,"BOTTOMLEFT",0,0)
2016-05-06 15:25:00 +02:00
end
if child.width == "fill" then
child:SetWidth(width)
frame:SetPoint("RIGHT",content,"RIGHT")
if child.OnWidthSet then
child:OnWidthSet(content.width or content:GetWidth())
2016-05-06 15:25:00 +02:00
end
if child.DoLayout then
child:DoLayout()
end
end
height = height + (frame.height or frame:GetHeight() or 0)
end
safecall( content.obj.LayoutFinished, content.obj, nil, height )
end
)
2016-05-06 15:25:00 +02:00
-- A single control fills the whole content area
AceGUI:RegisterLayout("Fill",
function(content, children)
2016-05-06 15:25:00 +02:00
if children[1] then
children[1]:SetWidth(content:GetWidth() or 0)
children[1]:SetHeight(content:GetHeight() or 0)
children[1].frame:SetAllPoints(content)
children[1].frame:Show()
safecall( content.obj.LayoutFinished, content.obj, nil, children[1].frame:GetHeight() )
2016-05-06 15:25:00 +02:00
end
end
)
2016-05-06 15:25:00 +02:00
AceGUI:RegisterLayout("Flow",
function(content, children)
--used height so far
local height = 0
--width used in the current row
local usedwidth = 0
--height of the current row
local rowheight = 0
local rowoffset = 0
local lastrowoffset
local width = content.width or content:GetWidth() or 0
--control at the start of the row
local rowstart
2016-05-06 15:25:00 +02:00
local rowstartoffset
local lastrowstart
local isfullheight
local frameoffset
local lastframeoffset
local oversize
for i, child in ipairs(children) do
2016-05-06 15:25:00 +02:00
oversize = nil
local frame = child.frame
local frameheight = frame.height or frame:GetHeight() or 0
local framewidth = frame.width or frame:GetWidth() or 0
lastframeoffset = frameoffset
frameoffset = child.alignoffset or (frameheight / 2)
frame:Show()
frame:ClearAllPoints()
if i == 1 then
-- anchor the first control to the top left
--frame:SetPoint("TOPLEFT",content,"TOPLEFT",0,0)
2016-05-06 15:25:00 +02:00
rowheight = frameheight
rowoffset = frameoffset
rowstart = frame
rowstartoffset = frameoffset
usedwidth = framewidth
if usedwidth > width then
oversize = true
end
else
-- if there isn't available width for the control start a new row
-- if a control is "fill" it will be on a row of its own full width
if usedwidth == 0 or ((framewidth) + usedwidth > width) or child.width == "fill" then
--anchor the previous row, we will now know its height and offset
rowstart:SetPoint("TOPLEFT",content,"TOPLEFT",0,-(height+(rowoffset-rowstartoffset)+3))
2016-05-06 15:25:00 +02:00
height = height + rowheight + 3
--save this as the rowstart so we can anchor it after the row is complete and we have the max height and offset of controls in it
rowstart = frame
rowstartoffset = frameoffset
rowheight = frameheight
rowoffset = frameoffset
usedwidth = frame.width or frame:GetWidth()
2016-05-06 15:25:00 +02:00
if usedwidth > width then
oversize = true
end
-- put the control on the current row, adding it to the width and checking if the height needs to be increased
else
--handles cases where the new height is higher than either control because of the offsets
--math.max(rowheight-rowoffset+frameoffset, frameheight-frameoffset+rowoffset)
--offset is always the larger of the two offsets
rowoffset = math.max(rowoffset, frameoffset)
2016-05-06 15:25:00 +02:00
rowheight = math.max(rowheight,rowoffset+(frameheight/2))
frame:SetPoint("TOPLEFT",children[i-1].frame,"TOPRIGHT",0,frameoffset-lastframeoffset)
2016-05-06 15:25:00 +02:00
usedwidth = framewidth + usedwidth
end
end
if child.width == "fill" then
child:SetWidth(width)
frame:SetPoint("RIGHT",content,"RIGHT",0,0)
2016-05-06 15:25:00 +02:00
usedwidth = 0
rowstart = frame
rowstartoffset = frameoffset
if child.DoLayout then
child:DoLayout()
end
rowheight = frame.height or frame:GetHeight() or 0
rowoffset = child.alignoffset or (rowheight / 2)
rowstartoffset = rowoffset
elseif oversize then
if width > 1 then
frame:SetPoint("RIGHT",content,"RIGHT",0,0)
2016-05-06 15:25:00 +02:00
end
end
if child.height == "fill" then
frame:SetPoint("BOTTOM",content,"BOTTOM")
2016-05-06 15:25:00 +02:00
isfullheight = true
break
2016-05-06 15:25:00 +02:00
end
end
--anchor the last row, if its full height needs a special case since its height has just been changed by the anchor
if isfullheight then
rowstart:SetPoint("TOPLEFT",content,"TOPLEFT",0,-height)
2016-05-06 15:25:00 +02:00
elseif rowstart then
rowstart:SetPoint("TOPLEFT",content,"TOPLEFT",0,-(height+(rowoffset-rowstartoffset)+3))
2016-05-06 15:25:00 +02:00
end
height = height + rowheight + 3
safecall( content.obj.LayoutFinished, content.obj, nil, height )
end
)