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 ) |