annotate Libs/AceGUI-3.0/AceGUI-3.0.lua @ 59:8a4c1438dbdf

Added tag v8.0.1.058 for changeset 0682d738499b
author Tercio
date Fri, 20 Jul 2018 19:04:38 -0300
parents 52973d00a183
children
rev   line source
Tercio@23 1 --- **AceGUI-3.0** provides access to numerous widgets which can be used to create GUIs.
Tercio@23 2 -- AceGUI is used by AceConfigDialog to create the option GUIs, but you can use it by itself
Tercio@23 3 -- to create any custom GUI. There are more extensive examples in the test suite in the Ace3
Tercio@23 4 -- stand-alone distribution.
Tercio@23 5 --
Tercio@23 6 -- **Note**: When using AceGUI-3.0 directly, please do not modify the frames of the widgets directly,
Tercio@23 7 -- as any "unknown" change to the widgets will cause addons that get your widget out of the widget pool
Tercio@23 8 -- to misbehave. If you think some part of a widget should be modifiable, please open a ticket, and we"ll
Tercio@23 9 -- implement a proper API to modify it.
Tercio@23 10 -- @usage
Tercio@23 11 -- local AceGUI = LibStub("AceGUI-3.0")
Tercio@23 12 -- -- Create a container frame
Tercio@23 13 -- local f = AceGUI:Create("Frame")
Tercio@23 14 -- f:SetCallback("OnClose",function(widget) AceGUI:Release(widget) end)
Tercio@23 15 -- f:SetTitle("AceGUI-3.0 Example")
Tercio@23 16 -- f:SetStatusText("Status Bar")
Tercio@23 17 -- f:SetLayout("Flow")
Tercio@23 18 -- -- Create a button
Tercio@23 19 -- local btn = AceGUI:Create("Button")
Tercio@23 20 -- btn:SetWidth(170)
Tercio@23 21 -- btn:SetText("Button !")
Tercio@23 22 -- btn:SetCallback("OnClick", function() print("Click!") end)
Tercio@23 23 -- -- Add the button to the container
Tercio@23 24 -- f:AddChild(btn)
Tercio@23 25 -- @class file
Tercio@23 26 -- @name AceGUI-3.0
Tercio@23 27 -- @release $Id: AceGUI-3.0.lua 1102 2013-10-25 14:15:23Z nevcairiel $
Tercio@23 28 local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 34
Tercio@23 29 local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
Tercio@23 30
Tercio@23 31 if not AceGUI then return end -- No upgrade needed
Tercio@23 32
Tercio@23 33 -- Lua APIs
Tercio@23 34 local tconcat, tremove, tinsert = table.concat, table.remove, table.insert
Tercio@23 35 local select, pairs, next, type = select, pairs, next, type
Tercio@23 36 local error, assert, loadstring = error, assert, loadstring
Tercio@23 37 local setmetatable, rawget, rawset = setmetatable, rawget, rawset
Tercio@23 38 local math_max = math.max
Tercio@23 39
Tercio@23 40 -- WoW APIs
Tercio@23 41 local UIParent = UIParent
Tercio@23 42
Tercio@23 43 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
Tercio@23 44 -- List them here for Mikk's FindGlobals script
Tercio@23 45 -- GLOBALS: geterrorhandler, LibStub
Tercio@23 46
Tercio@23 47 --local con = LibStub("AceConsole-3.0",true)
Tercio@23 48
Tercio@23 49 AceGUI.WidgetRegistry = AceGUI.WidgetRegistry or {}
Tercio@23 50 AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
Tercio@23 51 AceGUI.WidgetBase = AceGUI.WidgetBase or {}
Tercio@23 52 AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
Tercio@23 53 AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
Tercio@23 54
Tercio@23 55 -- local upvalues
Tercio@23 56 local WidgetRegistry = AceGUI.WidgetRegistry
Tercio@23 57 local LayoutRegistry = AceGUI.LayoutRegistry
Tercio@23 58 local WidgetVersions = AceGUI.WidgetVersions
Tercio@23 59
Tercio@23 60 --[[
Tercio@23 61 xpcall safecall implementation
Tercio@23 62 ]]
Tercio@23 63 local xpcall = xpcall
Tercio@23 64
Tercio@23 65 local function errorhandler(err)
Tercio@23 66 return geterrorhandler()(err)
Tercio@23 67 end
Tercio@23 68
Tercio@23 69 local function CreateDispatcher(argCount)
Tercio@23 70 local code = [[
Tercio@23 71 local xpcall, eh = ...
Tercio@23 72 local method, ARGS
Tercio@23 73 local function call() return method(ARGS) end
Tercio@23 74
Tercio@23 75 local function dispatch(func, ...)
Tercio@23 76 method = func
Tercio@23 77 if not method then return end
Tercio@23 78 ARGS = ...
Tercio@23 79 return xpcall(call, eh)
Tercio@23 80 end
Tercio@23 81
Tercio@23 82 return dispatch
Tercio@23 83 ]]
Tercio@23 84
Tercio@23 85 local ARGS = {}
Tercio@23 86 for i = 1, argCount do ARGS[i] = "arg"..i end
Tercio@23 87 code = code:gsub("ARGS", tconcat(ARGS, ", "))
Tercio@23 88 return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
Tercio@23 89 end
Tercio@23 90
Tercio@23 91 local Dispatchers = setmetatable({}, {__index=function(self, argCount)
Tercio@23 92 local dispatcher = CreateDispatcher(argCount)
Tercio@23 93 rawset(self, argCount, dispatcher)
Tercio@23 94 return dispatcher
Tercio@23 95 end})
Tercio@23 96 Dispatchers[0] = function(func)
Tercio@23 97 return xpcall(func, errorhandler)
Tercio@23 98 end
Tercio@23 99
Tercio@23 100 local function safecall(func, ...)
Tercio@23 101 return Dispatchers[select("#", ...)](func, ...)
Tercio@23 102 end
Tercio@23 103
Tercio@23 104 -- Recycling functions
Tercio@23 105 local newWidget, delWidget
Tercio@23 106 do
Tercio@23 107 -- Version Upgrade in Minor 29
Tercio@23 108 -- Internal Storage of the objects changed, from an array table
Tercio@23 109 -- to a hash table, and additionally we introduced versioning on
Tercio@23 110 -- the widgets which would discard all widgets from a pre-29 version
Tercio@23 111 -- anyway, so we just clear the storage now, and don't try to
Tercio@23 112 -- convert the storage tables to the new format.
Tercio@23 113 -- This should generally not cause *many* widgets to end up in trash,
Tercio@23 114 -- since once dialogs are opened, all addons should be loaded already
Tercio@23 115 -- and AceGUI should be on the latest version available on the users
Tercio@23 116 -- setup.
Tercio@23 117 -- -- nevcairiel - Nov 2nd, 2009
Tercio@23 118 if oldminor and oldminor < 29 and AceGUI.objPools then
Tercio@23 119 AceGUI.objPools = nil
Tercio@23 120 end
Tercio@23 121
Tercio@23 122 AceGUI.objPools = AceGUI.objPools or {}
Tercio@23 123 local objPools = AceGUI.objPools
Tercio@23 124 --Returns a new instance, if none are available either returns a new table or calls the given contructor
Tercio@23 125 function newWidget(type)
Tercio@23 126 if not WidgetRegistry[type] then
Tercio@23 127 error("Attempt to instantiate unknown widget type", 2)
Tercio@23 128 end
Tercio@23 129
Tercio@23 130 if not objPools[type] then
Tercio@23 131 objPools[type] = {}
Tercio@23 132 end
Tercio@23 133
Tercio@23 134 local newObj = next(objPools[type])
Tercio@23 135 if not newObj then
Tercio@23 136 newObj = WidgetRegistry[type]()
Tercio@23 137 newObj.AceGUIWidgetVersion = WidgetVersions[type]
Tercio@23 138 else
Tercio@23 139 objPools[type][newObj] = nil
Tercio@23 140 -- if the widget is older then the latest, don't even try to reuse it
Tercio@23 141 -- just forget about it, and grab a new one.
Tercio@23 142 if not newObj.AceGUIWidgetVersion or newObj.AceGUIWidgetVersion < WidgetVersions[type] then
Tercio@23 143 return newWidget(type)
Tercio@23 144 end
Tercio@23 145 end
Tercio@23 146 return newObj
Tercio@23 147 end
Tercio@23 148 -- Releases an instance to the Pool
Tercio@23 149 function delWidget(obj,type)
Tercio@23 150 if not objPools[type] then
Tercio@23 151 objPools[type] = {}
Tercio@23 152 end
Tercio@23 153 if objPools[type][obj] then
Tercio@23 154 error("Attempt to Release Widget that is already released", 2)
Tercio@23 155 end
Tercio@23 156 objPools[type][obj] = true
Tercio@23 157 end
Tercio@23 158 end
Tercio@23 159
Tercio@23 160
Tercio@23 161 -------------------
Tercio@23 162 -- API Functions --
Tercio@23 163 -------------------
Tercio@23 164
Tercio@23 165 -- Gets a widget Object
Tercio@23 166
Tercio@23 167 --- Create a new Widget of the given type.
Tercio@23 168 -- This function will instantiate a new widget (or use one from the widget pool), and call the
Tercio@23 169 -- OnAcquire function on it, before returning.
Tercio@23 170 -- @param type The type of the widget.
Tercio@23 171 -- @return The newly created widget.
Tercio@23 172 function AceGUI:Create(type)
Tercio@23 173 if WidgetRegistry[type] then
Tercio@23 174 local widget = newWidget(type)
Tercio@23 175
Tercio@23 176 if rawget(widget, "Acquire") then
Tercio@23 177 widget.OnAcquire = widget.Acquire
Tercio@23 178 widget.Acquire = nil
Tercio@23 179 elseif rawget(widget, "Aquire") then
Tercio@23 180 widget.OnAcquire = widget.Aquire
Tercio@23 181 widget.Aquire = nil
Tercio@23 182 end
Tercio@23 183
Tercio@23 184 if rawget(widget, "Release") then
Tercio@23 185 widget.OnRelease = rawget(widget, "Release")
Tercio@23 186 widget.Release = nil
Tercio@23 187 end
Tercio@23 188
Tercio@23 189 if widget.OnAcquire then
Tercio@23 190 widget:OnAcquire()
Tercio@23 191 else
Tercio@23 192 error(("Widget type %s doesn't supply an OnAcquire Function"):format(type))
Tercio@23 193 end
Tercio@23 194 -- Set the default Layout ("List")
Tercio@23 195 safecall(widget.SetLayout, widget, "List")
Tercio@23 196 safecall(widget.ResumeLayout, widget)
Tercio@23 197 return widget
Tercio@23 198 end
Tercio@23 199 end
Tercio@23 200
Tercio@23 201 --- Releases a widget Object.
Tercio@23 202 -- This function calls OnRelease on the widget and places it back in the widget pool.
Tercio@23 203 -- Any data on the widget is being erased, and the widget will be hidden.\\
Tercio@23 204 -- If this widget is a Container-Widget, all of its Child-Widgets will be releases as well.
Tercio@23 205 -- @param widget The widget to release
Tercio@23 206 function AceGUI:Release(widget)
Tercio@23 207 safecall(widget.PauseLayout, widget)
Tercio@23 208 widget:Fire("OnRelease")
Tercio@23 209 safecall(widget.ReleaseChildren, widget)
Tercio@23 210
Tercio@23 211 if widget.OnRelease then
Tercio@23 212 widget:OnRelease()
Tercio@23 213 -- else
Tercio@23 214 -- error(("Widget type %s doesn't supply an OnRelease Function"):format(widget.type))
Tercio@23 215 end
Tercio@23 216 for k in pairs(widget.userdata) do
Tercio@23 217 widget.userdata[k] = nil
Tercio@23 218 end
Tercio@23 219 for k in pairs(widget.events) do
Tercio@23 220 widget.events[k] = nil
Tercio@23 221 end
Tercio@23 222 widget.width = nil
Tercio@23 223 widget.relWidth = nil
Tercio@23 224 widget.height = nil
Tercio@23 225 widget.relHeight = nil
Tercio@23 226 widget.noAutoHeight = nil
Tercio@23 227 widget.frame:ClearAllPoints()
Tercio@23 228 widget.frame:Hide()
Tercio@23 229 widget.frame:SetParent(UIParent)
Tercio@23 230 widget.frame.width = nil
Tercio@23 231 widget.frame.height = nil
Tercio@23 232 if widget.content then
Tercio@23 233 widget.content.width = nil
Tercio@23 234 widget.content.height = nil
Tercio@23 235 end
Tercio@23 236 delWidget(widget, widget.type)
Tercio@23 237 end
Tercio@23 238
Tercio@23 239 -----------
Tercio@23 240 -- Focus --
Tercio@23 241 -----------
Tercio@23 242
Tercio@23 243
Tercio@23 244 --- Called when a widget has taken focus.
Tercio@23 245 -- e.g. Dropdowns opening, Editboxes gaining kb focus
Tercio@23 246 -- @param widget The widget that should be focused
Tercio@23 247 function AceGUI:SetFocus(widget)
Tercio@23 248 if self.FocusedWidget and self.FocusedWidget ~= widget then
Tercio@23 249 safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
Tercio@23 250 end
Tercio@23 251 self.FocusedWidget = widget
Tercio@23 252 end
Tercio@23 253
Tercio@23 254
Tercio@23 255 --- Called when something has happened that could cause widgets with focus to drop it
Tercio@23 256 -- e.g. titlebar of a frame being clicked
Tercio@23 257 function AceGUI:ClearFocus()
Tercio@23 258 if self.FocusedWidget then
Tercio@23 259 safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
Tercio@23 260 self.FocusedWidget = nil
Tercio@23 261 end
Tercio@23 262 end
Tercio@23 263
Tercio@23 264 -------------
Tercio@23 265 -- Widgets --
Tercio@23 266 -------------
Tercio@23 267 --[[
Tercio@23 268 Widgets must provide the following functions
Tercio@23 269 OnAcquire() - Called when the object is acquired, should set everything to a default hidden state
Tercio@23 270
Tercio@23 271 And the following members
Tercio@23 272 frame - the frame or derivitive object that will be treated as the widget for size and anchoring purposes
Tercio@23 273 type - the type of the object, same as the name given to :RegisterWidget()
Tercio@23 274
Tercio@23 275 Widgets contain a table called userdata, this is a safe place to store data associated with the wigdet
Tercio@23 276 It will be cleared automatically when a widget is released
Tercio@23 277 Placing values directly into a widget object should be avoided
Tercio@23 278
Tercio@23 279 If the Widget can act as a container for other Widgets the following
Tercio@23 280 content - frame or derivitive that children will be anchored to
Tercio@23 281
Tercio@23 282 The Widget can supply the following Optional Members
Tercio@23 283 :OnRelease() - Called when the object is Released, should remove any additional anchors and clear any data
Tercio@23 284 :OnWidthSet(width) - Called when the width of the widget is changed
Tercio@23 285 :OnHeightSet(height) - Called when the height of the widget is changed
Tercio@23 286 Widgets should not use the OnSizeChanged events of thier frame or content members, use these methods instead
Tercio@23 287 AceGUI already sets a handler to the event
Tercio@23 288 :LayoutFinished(width, height) - called after a layout has finished, the width and height will be the width and height of the
Tercio@23 289 area used for controls. These can be nil if the layout used the existing size to layout the controls.
Tercio@23 290
Tercio@23 291 ]]
Tercio@23 292
Tercio@23 293 --------------------------
Tercio@23 294 -- Widget Base Template --
Tercio@23 295 --------------------------
Tercio@23 296 do
Tercio@23 297 local WidgetBase = AceGUI.WidgetBase
Tercio@23 298
Tercio@23 299 WidgetBase.SetParent = function(self, parent)
Tercio@23 300 local frame = self.frame
Tercio@23 301 frame:SetParent(nil)
Tercio@23 302 frame:SetParent(parent.content)
Tercio@23 303 self.parent = parent
Tercio@23 304 end
Tercio@23 305
Tercio@23 306 WidgetBase.SetCallback = function(self, name, func)
Tercio@23 307 if type(func) == "function" then
Tercio@23 308 self.events[name] = func
Tercio@23 309 end
Tercio@23 310 end
Tercio@23 311
Tercio@23 312 WidgetBase.Fire = function(self, name, ...)
Tercio@23 313 if self.events[name] then
Tercio@23 314 local success, ret = safecall(self.events[name], self, name, ...)
Tercio@23 315 if success then
Tercio@23 316 return ret
Tercio@23 317 end
Tercio@23 318 end
Tercio@23 319 end
Tercio@23 320
Tercio@23 321 WidgetBase.SetWidth = function(self, width)
Tercio@23 322 self.frame:SetWidth(width)
Tercio@23 323 self.frame.width = width
Tercio@23 324 if self.OnWidthSet then
Tercio@23 325 self:OnWidthSet(width)
Tercio@23 326 end
Tercio@23 327 end
Tercio@23 328
Tercio@23 329 WidgetBase.SetRelativeWidth = function(self, width)
Tercio@23 330 if width <= 0 or width > 1 then
Tercio@23 331 error(":SetRelativeWidth(width): Invalid relative width.", 2)
Tercio@23 332 end
Tercio@23 333 self.relWidth = width
Tercio@23 334 self.width = "relative"
Tercio@23 335 end
Tercio@23 336
Tercio@23 337 WidgetBase.SetHeight = function(self, height)
Tercio@23 338 self.frame:SetHeight(height)
Tercio@23 339 self.frame.height = height
Tercio@23 340 if self.OnHeightSet then
Tercio@23 341 self:OnHeightSet(height)
Tercio@23 342 end
Tercio@23 343 end
Tercio@23 344
Tercio@23 345 --[[ WidgetBase.SetRelativeHeight = function(self, height)
Tercio@23 346 if height <= 0 or height > 1 then
Tercio@23 347 error(":SetRelativeHeight(height): Invalid relative height.", 2)
Tercio@23 348 end
Tercio@23 349 self.relHeight = height
Tercio@23 350 self.height = "relative"
Tercio@23 351 end ]]
Tercio@23 352
Tercio@23 353 WidgetBase.IsVisible = function(self)
Tercio@23 354 return self.frame:IsVisible()
Tercio@23 355 end
Tercio@23 356
Tercio@23 357 WidgetBase.IsShown= function(self)
Tercio@23 358 return self.frame:IsShown()
Tercio@23 359 end
Tercio@23 360
Tercio@23 361 WidgetBase.Release = function(self)
Tercio@23 362 AceGUI:Release(self)
Tercio@23 363 end
Tercio@23 364
Tercio@23 365 WidgetBase.SetPoint = function(self, ...)
Tercio@23 366 return self.frame:SetPoint(...)
Tercio@23 367 end
Tercio@23 368
Tercio@23 369 WidgetBase.ClearAllPoints = function(self)
Tercio@23 370 return self.frame:ClearAllPoints()
Tercio@23 371 end
Tercio@23 372
Tercio@23 373 WidgetBase.GetNumPoints = function(self)
Tercio@23 374 return self.frame:GetNumPoints()
Tercio@23 375 end
Tercio@23 376
Tercio@23 377 WidgetBase.GetPoint = function(self, ...)
Tercio@23 378 return self.frame:GetPoint(...)
Tercio@23 379 end
Tercio@23 380
Tercio@23 381 WidgetBase.GetUserDataTable = function(self)
Tercio@23 382 return self.userdata
Tercio@23 383 end
Tercio@23 384
Tercio@23 385 WidgetBase.SetUserData = function(self, key, value)
Tercio@23 386 self.userdata[key] = value
Tercio@23 387 end
Tercio@23 388
Tercio@23 389 WidgetBase.GetUserData = function(self, key)
Tercio@23 390 return self.userdata[key]
Tercio@23 391 end
Tercio@23 392
Tercio@23 393 WidgetBase.IsFullHeight = function(self)
Tercio@23 394 return self.height == "fill"
Tercio@23 395 end
Tercio@23 396
Tercio@23 397 WidgetBase.SetFullHeight = function(self, isFull)
Tercio@23 398 if isFull then
Tercio@23 399 self.height = "fill"
Tercio@23 400 else
Tercio@23 401 self.height = nil
Tercio@23 402 end
Tercio@23 403 end
Tercio@23 404
Tercio@23 405 WidgetBase.IsFullWidth = function(self)
Tercio@23 406 return self.width == "fill"
Tercio@23 407 end
Tercio@23 408
Tercio@23 409 WidgetBase.SetFullWidth = function(self, isFull)
Tercio@23 410 if isFull then
Tercio@23 411 self.width = "fill"
Tercio@23 412 else
Tercio@23 413 self.width = nil
Tercio@23 414 end
Tercio@23 415 end
Tercio@23 416
Tercio@23 417 -- local function LayoutOnUpdate(this)
Tercio@23 418 -- this:SetScript("OnUpdate",nil)
Tercio@23 419 -- this.obj:PerformLayout()
Tercio@23 420 -- end
Tercio@23 421
Tercio@23 422 local WidgetContainerBase = AceGUI.WidgetContainerBase
Tercio@23 423
Tercio@23 424 WidgetContainerBase.PauseLayout = function(self)
Tercio@23 425 self.LayoutPaused = true
Tercio@23 426 end
Tercio@23 427
Tercio@23 428 WidgetContainerBase.ResumeLayout = function(self)
Tercio@23 429 self.LayoutPaused = nil
Tercio@23 430 end
Tercio@23 431
Tercio@23 432 WidgetContainerBase.PerformLayout = function(self)
Tercio@23 433 if self.LayoutPaused then
Tercio@23 434 return
Tercio@23 435 end
Tercio@23 436 safecall(self.LayoutFunc, self.content, self.children)
Tercio@23 437 end
Tercio@23 438
Tercio@23 439 --call this function to layout, makes sure layed out objects get a frame to get sizes etc
Tercio@23 440 WidgetContainerBase.DoLayout = function(self)
Tercio@23 441 self:PerformLayout()
Tercio@23 442 -- if not self.parent then
Tercio@23 443 -- self.frame:SetScript("OnUpdate", LayoutOnUpdate)
Tercio@23 444 -- end
Tercio@23 445 end
Tercio@23 446
Tercio@23 447 WidgetContainerBase.AddChild = function(self, child, beforeWidget)
Tercio@23 448 if beforeWidget then
Tercio@23 449 local siblingIndex = 1
Tercio@23 450 for _, widget in pairs(self.children) do
Tercio@23 451 if widget == beforeWidget then
Tercio@23 452 break
Tercio@23 453 end
Tercio@23 454 siblingIndex = siblingIndex + 1
Tercio@23 455 end
Tercio@23 456 tinsert(self.children, siblingIndex, child)
Tercio@23 457 else
Tercio@23 458 tinsert(self.children, child)
Tercio@23 459 end
Tercio@23 460 child:SetParent(self)
Tercio@23 461 child.frame:Show()
Tercio@23 462 self:DoLayout()
Tercio@23 463 end
Tercio@23 464
Tercio@23 465 WidgetContainerBase.AddChildren = function(self, ...)
Tercio@23 466 for i = 1, select("#", ...) do
Tercio@23 467 local child = select(i, ...)
Tercio@23 468 tinsert(self.children, child)
Tercio@23 469 child:SetParent(self)
Tercio@23 470 child.frame:Show()
Tercio@23 471 end
Tercio@23 472 self:DoLayout()
Tercio@23 473 end
Tercio@23 474
Tercio@23 475 WidgetContainerBase.ReleaseChildren = function(self)
Tercio@23 476 local children = self.children
Tercio@23 477 for i = 1,#children do
Tercio@23 478 AceGUI:Release(children[i])
Tercio@23 479 children[i] = nil
Tercio@23 480 end
Tercio@23 481 end
Tercio@23 482
Tercio@23 483 WidgetContainerBase.SetLayout = function(self, Layout)
Tercio@23 484 self.LayoutFunc = AceGUI:GetLayout(Layout)
Tercio@23 485 end
Tercio@23 486
Tercio@23 487 WidgetContainerBase.SetAutoAdjustHeight = function(self, adjust)
Tercio@23 488 if adjust then
Tercio@23 489 self.noAutoHeight = nil
Tercio@23 490 else
Tercio@23 491 self.noAutoHeight = true
Tercio@23 492 end
Tercio@23 493 end
Tercio@23 494
Tercio@23 495 local function FrameResize(this)
Tercio@23 496 local self = this.obj
Tercio@23 497 if this:GetWidth() and this:GetHeight() then
Tercio@23 498 if self.OnWidthSet then
Tercio@23 499 self:OnWidthSet(this:GetWidth())
Tercio@23 500 end
Tercio@23 501 if self.OnHeightSet then
Tercio@23 502 self:OnHeightSet(this:GetHeight())
Tercio@23 503 end
Tercio@23 504 end
Tercio@23 505 end
Tercio@23 506
Tercio@23 507 local function ContentResize(this)
Tercio@23 508 if this:GetWidth() and this:GetHeight() then
Tercio@23 509 this.width = this:GetWidth()
Tercio@23 510 this.height = this:GetHeight()
Tercio@23 511 this.obj:DoLayout()
Tercio@23 512 end
Tercio@23 513 end
Tercio@23 514
Tercio@23 515 setmetatable(WidgetContainerBase, {__index=WidgetBase})
Tercio@23 516
Tercio@23 517 --One of these function should be called on each Widget Instance as part of its creation process
Tercio@23 518
Tercio@23 519 --- Register a widget-class as a container for newly created widgets.
Tercio@23 520 -- @param widget The widget class
Tercio@23 521 function AceGUI:RegisterAsContainer(widget)
Tercio@23 522 widget.children = {}
Tercio@23 523 widget.userdata = {}
Tercio@23 524 widget.events = {}
Tercio@23 525 widget.base = WidgetContainerBase
Tercio@23 526 widget.content.obj = widget
Tercio@23 527 widget.frame.obj = widget
Tercio@23 528 widget.content:SetScript("OnSizeChanged", ContentResize)
Tercio@23 529 widget.frame:SetScript("OnSizeChanged", FrameResize)
Tercio@23 530 setmetatable(widget, {__index = WidgetContainerBase})
Tercio@23 531 widget:SetLayout("List")
Tercio@23 532 return widget
Tercio@23 533 end
Tercio@23 534
Tercio@23 535 --- Register a widget-class as a widget.
Tercio@23 536 -- @param widget The widget class
Tercio@23 537 function AceGUI:RegisterAsWidget(widget)
Tercio@23 538 widget.userdata = {}
Tercio@23 539 widget.events = {}
Tercio@23 540 widget.base = WidgetBase
Tercio@23 541 widget.frame.obj = widget
Tercio@23 542 widget.frame:SetScript("OnSizeChanged", FrameResize)
Tercio@23 543 setmetatable(widget, {__index = WidgetBase})
Tercio@23 544 return widget
Tercio@23 545 end
Tercio@23 546 end
Tercio@23 547
Tercio@23 548
Tercio@23 549
Tercio@23 550
Tercio@23 551 ------------------
Tercio@23 552 -- Widget API --
Tercio@23 553 ------------------
Tercio@23 554
Tercio@23 555 --- Registers a widget Constructor, this function returns a new instance of the Widget
Tercio@23 556 -- @param Name The name of the widget
Tercio@23 557 -- @param Constructor The widget constructor function
Tercio@23 558 -- @param Version The version of the widget
Tercio@23 559 function AceGUI:RegisterWidgetType(Name, Constructor, Version)
Tercio@23 560 assert(type(Constructor) == "function")
Tercio@23 561 assert(type(Version) == "number")
Tercio@23 562
Tercio@23 563 local oldVersion = WidgetVersions[Name]
Tercio@23 564 if oldVersion and oldVersion >= Version then return end
Tercio@23 565
Tercio@23 566 WidgetVersions[Name] = Version
Tercio@23 567 WidgetRegistry[Name] = Constructor
Tercio@23 568 end
Tercio@23 569
Tercio@23 570 --- Registers a Layout Function
Tercio@23 571 -- @param Name The name of the layout
Tercio@23 572 -- @param LayoutFunc Reference to the layout function
Tercio@23 573 function AceGUI:RegisterLayout(Name, LayoutFunc)
Tercio@23 574 assert(type(LayoutFunc) == "function")
Tercio@23 575 if type(Name) == "string" then
Tercio@23 576 Name = Name:upper()
Tercio@23 577 end
Tercio@23 578 LayoutRegistry[Name] = LayoutFunc
Tercio@23 579 end
Tercio@23 580
Tercio@23 581 --- Get a Layout Function from the registry
Tercio@23 582 -- @param Name The name of the layout
Tercio@23 583 function AceGUI:GetLayout(Name)
Tercio@23 584 if type(Name) == "string" then
Tercio@23 585 Name = Name:upper()
Tercio@23 586 end
Tercio@23 587 return LayoutRegistry[Name]
Tercio@23 588 end
Tercio@23 589
Tercio@23 590 AceGUI.counts = AceGUI.counts or {}
Tercio@23 591
Tercio@23 592 --- A type-based counter to count the number of widgets created.
Tercio@23 593 -- This is used by widgets that require a named frame, e.g. when a Blizzard
Tercio@23 594 -- Template requires it.
Tercio@23 595 -- @param type The widget type
Tercio@23 596 function AceGUI:GetNextWidgetNum(type)
Tercio@23 597 if not self.counts[type] then
Tercio@23 598 self.counts[type] = 0
Tercio@23 599 end
Tercio@23 600 self.counts[type] = self.counts[type] + 1
Tercio@23 601 return self.counts[type]
Tercio@23 602 end
Tercio@23 603
Tercio@23 604 --- Return the number of created widgets for this type.
Tercio@23 605 -- In contrast to GetNextWidgetNum, the number is not incremented.
Tercio@23 606 -- @param type The widget type
Tercio@23 607 function AceGUI:GetWidgetCount(type)
Tercio@23 608 return self.counts[type] or 0
Tercio@23 609 end
Tercio@23 610
Tercio@23 611 --- Return the version of the currently registered widget type.
Tercio@23 612 -- @param type The widget type
Tercio@23 613 function AceGUI:GetWidgetVersion(type)
Tercio@23 614 return WidgetVersions[type]
Tercio@23 615 end
Tercio@23 616
Tercio@23 617 -------------
Tercio@23 618 -- Layouts --
Tercio@23 619 -------------
Tercio@23 620
Tercio@23 621 --[[
Tercio@23 622 A Layout is a func that takes 2 parameters
Tercio@23 623 content - the frame that widgets will be placed inside
Tercio@23 624 children - a table containing the widgets to layout
Tercio@23 625 ]]
Tercio@23 626
Tercio@23 627 -- Very simple Layout, Children are stacked on top of each other down the left side
Tercio@23 628 AceGUI:RegisterLayout("List",
Tercio@23 629 function(content, children)
Tercio@23 630 local height = 0
Tercio@23 631 local width = content.width or content:GetWidth() or 0
Tercio@23 632 for i = 1, #children do
Tercio@23 633 local child = children[i]
Tercio@23 634
Tercio@23 635 local frame = child.frame
Tercio@23 636 frame:ClearAllPoints()
Tercio@23 637 frame:Show()
Tercio@23 638 if i == 1 then
Tercio@23 639 frame:SetPoint("TOPLEFT", content)
Tercio@23 640 else
Tercio@23 641 frame:SetPoint("TOPLEFT", children[i-1].frame, "BOTTOMLEFT")
Tercio@23 642 end
Tercio@23 643
Tercio@23 644 if child.width == "fill" then
Tercio@23 645 child:SetWidth(width)
Tercio@23 646 frame:SetPoint("RIGHT", content)
Tercio@23 647
Tercio@23 648 if child.DoLayout then
Tercio@23 649 child:DoLayout()
Tercio@23 650 end
Tercio@23 651 elseif child.width == "relative" then
Tercio@23 652 child:SetWidth(width * child.relWidth)
Tercio@23 653
Tercio@23 654 if child.DoLayout then
Tercio@23 655 child:DoLayout()
Tercio@23 656 end
Tercio@23 657 end
Tercio@23 658
Tercio@23 659 height = height + (frame.height or frame:GetHeight() or 0)
Tercio@23 660 end
Tercio@23 661 safecall(content.obj.LayoutFinished, content.obj, nil, height)
Tercio@23 662 end)
Tercio@23 663
Tercio@23 664 -- A single control fills the whole content area
Tercio@23 665 AceGUI:RegisterLayout("Fill",
Tercio@23 666 function(content, children)
Tercio@23 667 if children[1] then
Tercio@23 668 children[1]:SetWidth(content:GetWidth() or 0)
Tercio@23 669 children[1]:SetHeight(content:GetHeight() or 0)
Tercio@23 670 children[1].frame:SetAllPoints(content)
Tercio@23 671 children[1].frame:Show()
Tercio@23 672 safecall(content.obj.LayoutFinished, content.obj, nil, children[1].frame:GetHeight())
Tercio@23 673 end
Tercio@23 674 end)
Tercio@23 675
Tercio@23 676 local layoutrecursionblock = nil
Tercio@23 677 local function safelayoutcall(object, func, ...)
Tercio@23 678 layoutrecursionblock = true
Tercio@23 679 object[func](object, ...)
Tercio@23 680 layoutrecursionblock = nil
Tercio@23 681 end
Tercio@23 682
Tercio@23 683 AceGUI:RegisterLayout("Flow",
Tercio@23 684 function(content, children)
Tercio@23 685 if layoutrecursionblock then return end
Tercio@23 686 --used height so far
Tercio@23 687 local height = 0
Tercio@23 688 --width used in the current row
Tercio@23 689 local usedwidth = 0
Tercio@23 690 --height of the current row
Tercio@23 691 local rowheight = 0
Tercio@23 692 local rowoffset = 0
Tercio@23 693 local lastrowoffset
Tercio@23 694
Tercio@23 695 local width = content.width or content:GetWidth() or 0
Tercio@23 696
Tercio@23 697 --control at the start of the row
Tercio@23 698 local rowstart
Tercio@23 699 local rowstartoffset
Tercio@23 700 local lastrowstart
Tercio@23 701 local isfullheight
Tercio@23 702
Tercio@23 703 local frameoffset
Tercio@23 704 local lastframeoffset
Tercio@23 705 local oversize
Tercio@23 706 for i = 1, #children do
Tercio@23 707 local child = children[i]
Tercio@23 708 oversize = nil
Tercio@23 709 local frame = child.frame
Tercio@23 710 local frameheight = frame.height or frame:GetHeight() or 0
Tercio@23 711 local framewidth = frame.width or frame:GetWidth() or 0
Tercio@23 712 lastframeoffset = frameoffset
Tercio@23 713 -- HACK: Why did we set a frameoffset of (frameheight / 2) ?
Tercio@23 714 -- That was moving all widgets half the widgets size down, is that intended?
Tercio@23 715 -- Actually, it seems to be neccessary for many cases, we'll leave it in for now.
Tercio@23 716 -- If widgets seem to anchor weirdly with this, provide a valid alignoffset for them.
Tercio@23 717 -- TODO: Investigate moar!
Tercio@23 718 frameoffset = child.alignoffset or (frameheight / 2)
Tercio@23 719
Tercio@23 720 if child.width == "relative" then
Tercio@23 721 framewidth = width * child.relWidth
Tercio@23 722 end
Tercio@23 723
Tercio@23 724 frame:Show()
Tercio@23 725 frame:ClearAllPoints()
Tercio@23 726 if i == 1 then
Tercio@23 727 -- anchor the first control to the top left
Tercio@23 728 frame:SetPoint("TOPLEFT", content)
Tercio@23 729 rowheight = frameheight
Tercio@23 730 rowoffset = frameoffset
Tercio@23 731 rowstart = frame
Tercio@23 732 rowstartoffset = frameoffset
Tercio@23 733 usedwidth = framewidth
Tercio@23 734 if usedwidth > width then
Tercio@23 735 oversize = true
Tercio@23 736 end
Tercio@23 737 else
Tercio@23 738 -- if there isn't available width for the control start a new row
Tercio@23 739 -- if a control is "fill" it will be on a row of its own full width
Tercio@23 740 if usedwidth == 0 or ((framewidth) + usedwidth > width) or child.width == "fill" then
Tercio@23 741 if isfullheight then
Tercio@23 742 -- a previous row has already filled the entire height, there's nothing we can usefully do anymore
Tercio@23 743 -- (maybe error/warn about this?)
Tercio@23 744 break
Tercio@23 745 end
Tercio@23 746 --anchor the previous row, we will now know its height and offset
Tercio@23 747 rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
Tercio@23 748 height = height + rowheight + 3
Tercio@23 749 --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
Tercio@23 750 rowstart = frame
Tercio@23 751 rowstartoffset = frameoffset
Tercio@23 752 rowheight = frameheight
Tercio@23 753 rowoffset = frameoffset
Tercio@23 754 usedwidth = framewidth
Tercio@23 755 if usedwidth > width then
Tercio@23 756 oversize = true
Tercio@23 757 end
Tercio@23 758 -- put the control on the current row, adding it to the width and checking if the height needs to be increased
Tercio@23 759 else
Tercio@23 760 --handles cases where the new height is higher than either control because of the offsets
Tercio@23 761 --math.max(rowheight-rowoffset+frameoffset, frameheight-frameoffset+rowoffset)
Tercio@23 762
Tercio@23 763 --offset is always the larger of the two offsets
Tercio@23 764 rowoffset = math_max(rowoffset, frameoffset)
Tercio@23 765 rowheight = math_max(rowheight, rowoffset + (frameheight / 2))
Tercio@23 766
Tercio@23 767 frame:SetPoint("TOPLEFT", children[i-1].frame, "TOPRIGHT", 0, frameoffset - lastframeoffset)
Tercio@23 768 usedwidth = framewidth + usedwidth
Tercio@23 769 end
Tercio@23 770 end
Tercio@23 771
Tercio@23 772 if child.width == "fill" then
Tercio@23 773 safelayoutcall(child, "SetWidth", width)
Tercio@23 774 frame:SetPoint("RIGHT", content)
Tercio@23 775
Tercio@23 776 usedwidth = 0
Tercio@23 777 rowstart = frame
Tercio@23 778 rowstartoffset = frameoffset
Tercio@23 779
Tercio@23 780 if child.DoLayout then
Tercio@23 781 child:DoLayout()
Tercio@23 782 end
Tercio@23 783 rowheight = frame.height or frame:GetHeight() or 0
Tercio@23 784 rowoffset = child.alignoffset or (rowheight / 2)
Tercio@23 785 rowstartoffset = rowoffset
Tercio@23 786 elseif child.width == "relative" then
Tercio@23 787 safelayoutcall(child, "SetWidth", width * child.relWidth)
Tercio@23 788
Tercio@23 789 if child.DoLayout then
Tercio@23 790 child:DoLayout()
Tercio@23 791 end
Tercio@23 792 elseif oversize then
Tercio@23 793 if width > 1 then
Tercio@23 794 frame:SetPoint("RIGHT", content)
Tercio@23 795 end
Tercio@23 796 end
Tercio@23 797
Tercio@23 798 if child.height == "fill" then
Tercio@23 799 frame:SetPoint("BOTTOM", content)
Tercio@23 800 isfullheight = true
Tercio@23 801 end
Tercio@23 802 end
Tercio@23 803
Tercio@23 804 --anchor the last row, if its full height needs a special case since its height has just been changed by the anchor
Tercio@23 805 if isfullheight then
Tercio@23 806 rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -height)
Tercio@23 807 elseif rowstart then
Tercio@23 808 rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
Tercio@23 809 end
Tercio@23 810
Tercio@23 811 height = height + rowheight + 3
Tercio@23 812 safecall(content.obj.LayoutFinished, content.obj, nil, height)
Tercio@23 813 end)