annotate Libs/AceGUI-3.0/AceGUI-3.0.lua @ 155:3ac4915a2e41 v73

New races, Crucible of Storms auto-logging.
author yellowfive
date Tue, 12 Mar 2019 11:16:36 -0700
parents e31b02b24488
children
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@124 27 -- @release $Id: AceGUI-3.0.lua 1177 2018-06-25 12:12:48Z nevcairiel $
yellowfive@124 28 local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 36
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)
yellowfive@124 814
yellowfive@124 815 -- Get alignment method and value. Possible alignment methods are a callback, a number, "start", "middle", "end", "fill" or "TOPLEFT", "BOTTOMRIGHT" etc.
yellowfive@124 816 local GetCellAlign = function (dir, tableObj, colObj, cellObj, cell, child)
yellowfive@124 817 local fn = cellObj and (cellObj["align" .. dir] or cellObj.align)
yellowfive@124 818 or colObj and (colObj["align" .. dir] or colObj.align)
yellowfive@124 819 or tableObj["align" .. dir] or tableObj.align
yellowfive@124 820 or "CENTERLEFT"
yellowfive@124 821 local child, cell, val = child or 0, cell or 0, nil
yellowfive@124 822
yellowfive@124 823 if type(fn) == "string" then
yellowfive@124 824 fn = fn:lower()
yellowfive@124 825 fn = dir == "V" and (fn:sub(1, 3) == "top" and "start" or fn:sub(1, 6) == "bottom" and "end" or fn:sub(1, 6) == "center" and "middle")
yellowfive@124 826 or dir == "H" and (fn:sub(-4) == "left" and "start" or fn:sub(-5) == "right" and "end" or fn:sub(-6) == "center" and "middle")
yellowfive@124 827 or fn
yellowfive@124 828 val = (fn == "start" or fn == "fill") and 0 or fn == "end" and cell - child or (cell - child) / 2
yellowfive@124 829 elseif type(fn) == "function" then
yellowfive@124 830 val = fn(child or 0, cell, dir)
yellowfive@124 831 else
yellowfive@124 832 val = fn
yellowfive@124 833 end
yellowfive@124 834
yellowfive@124 835 return fn, max(0, min(val, cell))
yellowfive@124 836 end
yellowfive@124 837
yellowfive@124 838 -- Get width or height for multiple cells combined
yellowfive@124 839 local GetCellDimension = function (dir, laneDim, from, to, space)
yellowfive@124 840 local dim = 0
yellowfive@124 841 for cell=from,to do
yellowfive@124 842 dim = dim + (laneDim[cell] or 0)
yellowfive@124 843 end
yellowfive@124 844 return dim + max(0, to - from) * (space or 0)
yellowfive@124 845 end
yellowfive@124 846
yellowfive@124 847 --[[ Options
yellowfive@124 848 ============
yellowfive@124 849 Container:
yellowfive@124 850 - columns ({col, col, ...}): Column settings. "col" can be a number (<= 0: content width, <1: rel. width, <10: weight, >=10: abs. width) or a table with column setting.
yellowfive@124 851 - space, spaceH, spaceV: Overall, horizontal and vertical spacing between cells.
yellowfive@124 852 - align, alignH, alignV: Overall, horizontal and vertical cell alignment. See GetCellAlign() for possible values.
yellowfive@124 853 Columns:
yellowfive@124 854 - width: Fixed column width (nil or <=0: content width, <1: rel. width, >=1: abs. width).
yellowfive@124 855 - min or 1: Min width for content based width
yellowfive@124 856 - max or 2: Max width for content based width
yellowfive@124 857 - weight: Flexible column width. The leftover width after accounting for fixed-width columns is distributed to weighted columns according to their weights.
yellowfive@124 858 - align, alignH, alignV: Overwrites the container setting for alignment.
yellowfive@124 859 Cell:
yellowfive@124 860 - colspan: Makes a cell span multiple columns.
yellowfive@124 861 - rowspan: Makes a cell span multiple rows.
yellowfive@124 862 - align, alignH, alignV: Overwrites the container and column setting for alignment.
yellowfive@124 863 ]]
yellowfive@124 864 AceGUI:RegisterLayout("Table",
yellowfive@124 865 function (content, children)
yellowfive@124 866 local obj = content.obj
yellowfive@124 867 obj:PauseLayout()
yellowfive@124 868
yellowfive@124 869 local tableObj = obj:GetUserData("table")
yellowfive@124 870 local cols = tableObj.columns
yellowfive@124 871 local spaceH = tableObj.spaceH or tableObj.space or 0
yellowfive@124 872 local spaceV = tableObj.spaceV or tableObj.space or 0
yellowfive@124 873 local totalH = (content:GetWidth() or content.width or 0) - spaceH * (#cols - 1)
yellowfive@124 874
yellowfive@124 875 -- We need to reuse these because layout events can come in very frequently
yellowfive@124 876 local layoutCache = obj:GetUserData("layoutCache")
yellowfive@124 877 if not layoutCache then
yellowfive@124 878 layoutCache = {{}, {}, {}, {}, {}, {}}
yellowfive@124 879 obj:SetUserData("layoutCache", layoutCache)
yellowfive@124 880 end
yellowfive@124 881 local t, laneH, laneV, rowspans, rowStart, colStart = unpack(layoutCache)
yellowfive@124 882
yellowfive@124 883 -- Create the grid
yellowfive@124 884 local n, slotFound = 0
yellowfive@124 885 for i,child in ipairs(children) do
yellowfive@124 886 if child:IsShown() then
yellowfive@124 887 repeat
yellowfive@124 888 n = n + 1
yellowfive@124 889 local col = (n - 1) % #cols + 1
yellowfive@124 890 local row = ceil(n / #cols)
yellowfive@124 891 local rowspan = rowspans[col]
yellowfive@124 892 local cell = rowspan and rowspan.child or child
yellowfive@124 893 local cellObj = cell:GetUserData("cell")
yellowfive@124 894 slotFound = not rowspan
yellowfive@124 895
yellowfive@124 896 -- Rowspan
yellowfive@124 897 if not rowspan and cellObj and cellObj.rowspan then
yellowfive@124 898 rowspan = {child = child, from = row, to = row + cellObj.rowspan - 1}
yellowfive@124 899 rowspans[col] = rowspan
yellowfive@124 900 end
yellowfive@124 901 if rowspan and i == #children then
yellowfive@124 902 rowspan.to = row
yellowfive@124 903 end
yellowfive@124 904
yellowfive@124 905 -- Colspan
yellowfive@124 906 local colspan = max(0, min((cellObj and cellObj.colspan or 1) - 1, #cols - col))
yellowfive@124 907 n = n + colspan
yellowfive@124 908
yellowfive@124 909 -- Place the cell
yellowfive@124 910 if not rowspan or rowspan.to == row then
yellowfive@124 911 t[n] = cell
yellowfive@124 912 rowStart[cell] = rowspan and rowspan.from or row
yellowfive@124 913 colStart[cell] = col
yellowfive@124 914
yellowfive@124 915 if rowspan then
yellowfive@124 916 rowspans[col] = nil
yellowfive@124 917 end
yellowfive@124 918 end
yellowfive@124 919 until slotFound
yellowfive@124 920 end
yellowfive@124 921 end
yellowfive@124 922
yellowfive@124 923 local rows = ceil(n / #cols)
yellowfive@124 924
yellowfive@124 925 -- Determine fixed size cols and collect weights
yellowfive@124 926 local extantH, totalWeight = totalH, 0
yellowfive@124 927 for col,colObj in ipairs(cols) do
yellowfive@124 928 laneH[col] = 0
yellowfive@124 929
yellowfive@124 930 if type(colObj) == "number" then
yellowfive@124 931 colObj = {[colObj >= 1 and colObj < 10 and "weight" or "width"] = colObj}
yellowfive@124 932 cols[col] = colObj
yellowfive@124 933 end
yellowfive@124 934
yellowfive@124 935 if colObj.weight then
yellowfive@124 936 -- Weight
yellowfive@124 937 totalWeight = totalWeight + (colObj.weight or 1)
yellowfive@124 938 else
yellowfive@124 939 if not colObj.width or colObj.width <= 0 then
yellowfive@124 940 -- Content width
yellowfive@124 941 for row=1,rows do
yellowfive@124 942 local child = t[(row - 1) * #cols + col]
yellowfive@124 943 if child then
yellowfive@124 944 local f = child.frame
yellowfive@124 945 f:ClearAllPoints()
yellowfive@124 946 local childH = f:GetWidth() or 0
yellowfive@124 947
yellowfive@124 948 laneH[col] = max(laneH[col], childH - GetCellDimension("H", laneH, colStart[child], col - 1, spaceH))
yellowfive@124 949 end
yellowfive@124 950 end
yellowfive@124 951
yellowfive@124 952 laneH[col] = max(colObj.min or colObj[1] or 0, min(laneH[col], colObj.max or colObj[2] or laneH[col]))
yellowfive@124 953 else
yellowfive@124 954 -- Rel./Abs. width
yellowfive@124 955 laneH[col] = colObj.width < 1 and colObj.width * totalH or colObj.width
yellowfive@124 956 end
yellowfive@124 957 extantH = max(0, extantH - laneH[col])
yellowfive@124 958 end
yellowfive@124 959 end
yellowfive@124 960
yellowfive@124 961 -- Determine sizes based on weight
yellowfive@124 962 local scale = totalWeight > 0 and extantH / totalWeight or 0
yellowfive@124 963 for col,colObj in pairs(cols) do
yellowfive@124 964 if colObj.weight then
yellowfive@124 965 laneH[col] = scale * colObj.weight
yellowfive@124 966 end
yellowfive@124 967 end
yellowfive@124 968
yellowfive@124 969 -- Arrange children
yellowfive@124 970 for row=1,rows do
yellowfive@124 971 local rowV = 0
yellowfive@124 972
yellowfive@124 973 -- Horizontal placement and sizing
yellowfive@124 974 for col=1,#cols do
yellowfive@124 975 local child = t[(row - 1) * #cols + col]
yellowfive@124 976 if child then
yellowfive@124 977 local colObj = cols[colStart[child]]
yellowfive@124 978 local cellObj = child:GetUserData("cell")
yellowfive@124 979 local offsetH = GetCellDimension("H", laneH, 1, colStart[child] - 1, spaceH) + (colStart[child] == 1 and 0 or spaceH)
yellowfive@124 980 local cellH = GetCellDimension("H", laneH, colStart[child], col, spaceH)
yellowfive@124 981
yellowfive@124 982 local f = child.frame
yellowfive@124 983 f:ClearAllPoints()
yellowfive@124 984 local childH = f:GetWidth() or 0
yellowfive@124 985
yellowfive@124 986 local alignFn, align = GetCellAlign("H", tableObj, colObj, cellObj, cellH, childH)
yellowfive@124 987 f:SetPoint("LEFT", content, offsetH + align, 0)
yellowfive@124 988 if child:IsFullWidth() or alignFn == "fill" or childH > cellH then
yellowfive@124 989 f:SetPoint("RIGHT", content, "LEFT", offsetH + align + cellH, 0)
yellowfive@124 990 end
yellowfive@124 991
yellowfive@124 992 if child.DoLayout then
yellowfive@124 993 child:DoLayout()
yellowfive@124 994 end
yellowfive@124 995
yellowfive@124 996 rowV = max(rowV, (f:GetHeight() or 0) - GetCellDimension("V", laneV, rowStart[child], row - 1, spaceV))
yellowfive@124 997 end
yellowfive@124 998 end
yellowfive@124 999
yellowfive@124 1000 laneV[row] = rowV
yellowfive@124 1001
yellowfive@124 1002 -- Vertical placement and sizing
yellowfive@124 1003 for col=1,#cols do
yellowfive@124 1004 local child = t[(row - 1) * #cols + col]
yellowfive@124 1005 if child then
yellowfive@124 1006 local colObj = cols[colStart[child]]
yellowfive@124 1007 local cellObj = child:GetUserData("cell")
yellowfive@124 1008 local offsetV = GetCellDimension("V", laneV, 1, rowStart[child] - 1, spaceV) + (rowStart[child] == 1 and 0 or spaceV)
yellowfive@124 1009 local cellV = GetCellDimension("V", laneV, rowStart[child], row, spaceV)
yellowfive@124 1010
yellowfive@124 1011 local f = child.frame
yellowfive@124 1012 local childV = f:GetHeight() or 0
yellowfive@124 1013
yellowfive@124 1014 local alignFn, align = GetCellAlign("V", tableObj, colObj, cellObj, cellV, childV)
yellowfive@124 1015 if child:IsFullHeight() or alignFn == "fill" then
yellowfive@124 1016 f:SetHeight(cellV)
yellowfive@124 1017 end
yellowfive@124 1018 f:SetPoint("TOP", content, 0, -(offsetV + align))
yellowfive@124 1019 end
yellowfive@124 1020 end
yellowfive@124 1021 end
yellowfive@124 1022
yellowfive@124 1023 -- Calculate total height
yellowfive@124 1024 local totalV = GetCellDimension("V", laneV, 1, #laneV, spaceV)
yellowfive@124 1025
yellowfive@124 1026 -- Cleanup
yellowfive@124 1027 for _,v in pairs(layoutCache) do wipe(v) end
yellowfive@124 1028
yellowfive@124 1029 safecall(obj.LayoutFinished, obj, nil, totalV)
yellowfive@124 1030 obj:ResumeLayout()
yellowfive@124 1031 end)