annotate Libs/AceGUI-3.0/AceGUI-3.0.lua @ 100:c1996b3376ed

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