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