617d5dc70797529392a37d06bea7342d3d469939
[wowui.git] / libs / AceGUI-3.0 / widgets / AceGUIContainer-TreeGroup.lua
1 --[[-----------------------------------------------------------------------------
2 TreeGroup Container
3 Container that uses a tree control to switch between groups.
4 -------------------------------------------------------------------------------]]
5 local Type, Version = "TreeGroup", 40
6 local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
7 if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
8
9 -- Lua APIs
10 local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
11 local math_min, math_max, floor = math.min, math.max, floor
12 local select, tremove, unpack, tconcat = select, table.remove, unpack, table.concat
13
14 -- WoW APIs
15 local CreateFrame, UIParent = CreateFrame, UIParent
16
17 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
18 -- List them here for Mikk's FindGlobals script
19 -- GLOBALS: GameTooltip, FONT_COLOR_CODE_CLOSE
20
21 -- Recycling functions
22 local new, del
23 do
24         local pool = setmetatable({},{__mode='k'})
25         function new()
26                 local t = next(pool)
27                 if t then
28                         pool[t] = nil
29                         return t
30                 else
31                         return {}
32                 end
33         end
34         function del(t)
35                 for k in pairs(t) do
36                         t[k] = nil
37                 end     
38                 pool[t] = true
39         end
40 end
41
42 local DEFAULT_TREE_WIDTH = 175
43 local DEFAULT_TREE_SIZABLE = true
44
45 --[[-----------------------------------------------------------------------------
46 Support functions
47 -------------------------------------------------------------------------------]]
48 local function GetButtonUniqueValue(line)
49         local parent = line.parent
50         if parent and parent.value then
51                 return GetButtonUniqueValue(parent).."\001"..line.value
52         else
53                 return line.value
54         end
55 end
56
57 local function UpdateButton(button, treeline, selected, canExpand, isExpanded)
58         local self = button.obj
59         local toggle = button.toggle
60         local frame = self.frame
61         local text = treeline.text or ""
62         local icon = treeline.icon
63         local iconCoords = treeline.iconCoords
64         local level = treeline.level
65         local value = treeline.value
66         local uniquevalue = treeline.uniquevalue
67         local disabled = treeline.disabled
68         
69         button.treeline = treeline
70         button.value = value
71         button.uniquevalue = uniquevalue
72         if selected then
73                 button:LockHighlight()
74                 button.selected = true
75         else
76                 button:UnlockHighlight()
77                 button.selected = false
78         end
79         local normalTexture = button:GetNormalTexture()
80         local line = button.line
81         button.level = level
82         if ( level == 1 ) then
83                 button:SetNormalFontObject("GameFontNormal")
84                 button:SetHighlightFontObject("GameFontHighlight")
85                 button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2)
86         else
87                 button:SetNormalFontObject("GameFontHighlightSmall")
88                 button:SetHighlightFontObject("GameFontHighlightSmall")
89                 button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2)
90         end
91         
92         if disabled then
93                 button:EnableMouse(false)
94                 button.text:SetText("|cff808080"..text..FONT_COLOR_CODE_CLOSE)
95         else
96                 button.text:SetText(text)
97                 button:EnableMouse(true)
98         end
99         
100         if icon then
101                 button.icon:SetTexture(icon)
102                 button.icon:SetPoint("LEFT", 8 * level, (level == 1) and 0 or 1)
103         else
104                 button.icon:SetTexture(nil)
105         end
106         
107         if iconCoords then
108                 button.icon:SetTexCoord(unpack(iconCoords))
109         else
110                 button.icon:SetTexCoord(0, 1, 0, 1)
111         end
112         
113         if canExpand then
114                 if not isExpanded then
115                         toggle:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-UP")
116                         toggle:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-DOWN")
117                 else
118                         toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP")
119                         toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-DOWN")
120                 end
121                 toggle:Show()
122         else
123                 toggle:Hide()
124         end
125 end
126
127 local function ShouldDisplayLevel(tree)
128         local result = false
129         for k, v in ipairs(tree) do
130                 if v.children == nil and v.visible ~= false then
131                         result = true
132                 elseif v.children then
133                         result = result or ShouldDisplayLevel(v.children)
134                 end
135                 if result then return result end
136         end
137         return false
138 end
139
140 local function addLine(self, v, tree, level, parent)
141         local line = new()
142         line.value = v.value
143         line.text = v.text
144         line.icon = v.icon
145         line.iconCoords = v.iconCoords
146         line.disabled = v.disabled
147         line.tree = tree
148         line.level = level
149         line.parent = parent
150         line.visible = v.visible
151         line.uniquevalue = GetButtonUniqueValue(line)
152         if v.children then
153                 line.hasChildren = true
154         else
155                 line.hasChildren = nil
156         end
157         self.lines[#self.lines+1] = line
158         return line
159 end
160
161 --fire an update after one frame to catch the treeframes height
162 local function FirstFrameUpdate(frame)
163         local self = frame.obj
164         frame:SetScript("OnUpdate", nil)
165         self:RefreshTree()
166 end
167
168 local function BuildUniqueValue(...)
169         local n = select('#', ...)
170         if n == 1 then
171                 return ...
172         else
173                 return (...).."\001"..BuildUniqueValue(select(2,...))
174         end
175 end
176
177 --[[-----------------------------------------------------------------------------
178 Scripts
179 -------------------------------------------------------------------------------]]
180 local function Expand_OnClick(frame)
181         local button = frame.button
182         local self = button.obj
183         local status = (self.status or self.localstatus).groups
184         status[button.uniquevalue] = not status[button.uniquevalue]
185         self:RefreshTree()
186 end
187
188 local function Button_OnClick(frame)
189         local self = frame.obj
190         self:Fire("OnClick", frame.uniquevalue, frame.selected)
191         if not frame.selected then
192                 self:SetSelected(frame.uniquevalue)
193                 frame.selected = true
194                 frame:LockHighlight()
195                 self:RefreshTree()
196         end
197         AceGUI:ClearFocus()
198 end
199
200 local function Button_OnDoubleClick(button)
201         local self = button.obj
202         local status = self.status or self.localstatus
203         local status = (self.status or self.localstatus).groups
204         status[button.uniquevalue] = not status[button.uniquevalue]
205         self:RefreshTree()
206 end
207
208 local function Button_OnEnter(frame)
209         local self = frame.obj
210         self:Fire("OnButtonEnter", frame.uniquevalue, frame)
211
212         if self.enabletooltips then
213                 GameTooltip:SetOwner(frame, "ANCHOR_NONE")
214                 GameTooltip:SetPoint("LEFT",frame,"RIGHT")
215                 GameTooltip:SetText(frame.text:GetText() or "", 1, .82, 0, true)
216
217                 GameTooltip:Show()
218         end
219 end
220
221 local function Button_OnLeave(frame)
222         local self = frame.obj
223         self:Fire("OnButtonLeave", frame.uniquevalue, frame)
224
225         if self.enabletooltips then
226                 GameTooltip:Hide()
227         end
228 end
229
230 local function OnScrollValueChanged(frame, value)
231         if frame.obj.noupdate then return end
232         local self = frame.obj
233         local status = self.status or self.localstatus
234         status.scrollvalue = floor(value + 0.5)
235         self:RefreshTree()
236         AceGUI:ClearFocus()
237 end
238
239 local function Tree_OnSizeChanged(frame)
240         frame.obj:RefreshTree()
241 end
242
243 local function Tree_OnMouseWheel(frame, delta)
244         local self = frame.obj
245         if self.showscroll then
246                 local scrollbar = self.scrollbar
247                 local min, max = scrollbar:GetMinMaxValues()
248                 local value = scrollbar:GetValue()
249                 local newvalue = math_min(max,math_max(min,value - delta))
250                 if value ~= newvalue then
251                         scrollbar:SetValue(newvalue)
252                 end
253         end
254 end
255
256 local function Dragger_OnLeave(frame)
257         frame:SetBackdropColor(1, 1, 1, 0)
258 end
259
260 local function Dragger_OnEnter(frame)
261         frame:SetBackdropColor(1, 1, 1, 0.8)
262 end
263
264 local function Dragger_OnMouseDown(frame)
265         local treeframe = frame:GetParent()
266         treeframe:StartSizing("RIGHT")
267 end
268
269 local function Dragger_OnMouseUp(frame)
270         local treeframe = frame:GetParent()
271         local self = treeframe.obj
272         local frame = treeframe:GetParent()
273         treeframe:StopMovingOrSizing()
274         --treeframe:SetScript("OnUpdate", nil)
275         treeframe:SetUserPlaced(false)
276         --Without this :GetHeight will get stuck on the current height, causing the tree contents to not resize
277         treeframe:SetHeight(0)
278         treeframe:SetPoint("TOPLEFT", frame, "TOPLEFT",0,0)
279         treeframe:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT",0,0)
280         
281         local status = self.status or self.localstatus
282         status.treewidth = treeframe:GetWidth()
283         
284         treeframe.obj:Fire("OnTreeResize",treeframe:GetWidth())
285         -- recalculate the content width
286         treeframe.obj:OnWidthSet(status.fullwidth)
287         -- update the layout of the content
288         treeframe.obj:DoLayout()
289 end
290
291 --[[-----------------------------------------------------------------------------
292 Methods
293 -------------------------------------------------------------------------------]]
294 local methods = {
295         ["OnAcquire"] = function(self)
296                 self:SetTreeWidth(DEFAULT_TREE_WIDTH, DEFAULT_TREE_SIZABLE)
297                 self:EnableButtonTooltips(true)
298                 self.frame:SetScript("OnUpdate", FirstFrameUpdate)
299         end,
300
301         ["OnRelease"] = function(self)
302                 self.status = nil
303                 for k, v in pairs(self.localstatus) do
304                         if k == "groups" then
305                                 for k2 in pairs(v) do
306                                         v[k2] = nil
307                                 end
308                         else
309                                 self.localstatus[k] = nil
310                         end
311                 end
312                 self.localstatus.scrollvalue = 0
313                 self.localstatus.treewidth = DEFAULT_TREE_WIDTH
314                 self.localstatus.treesizable = DEFAULT_TREE_SIZABLE
315         end,
316
317         ["EnableButtonTooltips"] = function(self, enable)
318                 self.enabletooltips = enable
319         end,
320
321         ["CreateButton"] = function(self)
322                 local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
323                 local button = CreateFrame("Button", ("AceGUI30TreeButton%d"):format(num), self.treeframe, "OptionsListButtonTemplate")
324                 button.obj = self
325
326                 local icon = button:CreateTexture(nil, "OVERLAY")
327                 icon:SetWidth(14)
328                 icon:SetHeight(14)
329                 button.icon = icon
330
331                 button:SetScript("OnClick",Button_OnClick)
332                 button:SetScript("OnDoubleClick", Button_OnDoubleClick)
333                 button:SetScript("OnEnter",Button_OnEnter)
334                 button:SetScript("OnLeave",Button_OnLeave)
335
336                 button.toggle.button = button
337                 button.toggle:SetScript("OnClick",Expand_OnClick)
338
339                 button.text:SetHeight(14) -- Prevents text wrapping
340
341                 return button
342         end,
343
344         ["SetStatusTable"] = function(self, status)
345                 assert(type(status) == "table")
346                 self.status = status
347                 if not status.groups then
348                         status.groups = {}
349                 end
350                 if not status.scrollvalue then
351                         status.scrollvalue = 0
352                 end
353                 if not status.treewidth then
354                         status.treewidth = DEFAULT_TREE_WIDTH
355                 end
356                 if status.treesizable == nil then
357                         status.treesizable = DEFAULT_TREE_SIZABLE
358                 end
359                 self:SetTreeWidth(status.treewidth,status.treesizable)
360                 self:RefreshTree()
361         end,
362
363         --sets the tree to be displayed
364         ["SetTree"] = function(self, tree, filter)
365                 self.filter = filter
366                 if tree then 
367                         assert(type(tree) == "table") 
368                 end
369                 self.tree = tree
370                 self:RefreshTree()
371         end,
372
373         ["BuildLevel"] = function(self, tree, level, parent)
374                 local groups = (self.status or self.localstatus).groups
375                 local hasChildren = self.hasChildren
376                 
377                 for i, v in ipairs(tree) do
378                         if v.children then
379                                 if not self.filter or ShouldDisplayLevel(v.children) then
380                                         local line = addLine(self, v, tree, level, parent)
381                                         if groups[line.uniquevalue] then
382                                                 self:BuildLevel(v.children, level+1, line)
383                                         end
384                                 end
385                         elseif v.visible ~= false or not self.filter then
386                                 addLine(self, v, tree, level, parent)
387                         end
388                 end
389         end,
390
391         ["RefreshTree"] = function(self,scrollToSelection)
392                 local buttons = self.buttons 
393                 local lines = self.lines
394
395                 for i, v in ipairs(buttons) do
396                         v:Hide()
397                 end
398                 while lines[1] do
399                         local t = tremove(lines)
400                         for k in pairs(t) do
401                                 t[k] = nil
402                         end
403                         del(t)
404                 end
405
406                 if not self.tree then return end
407                 --Build the list of visible entries from the tree and status tables
408                 local status = self.status or self.localstatus
409                 local groupstatus = status.groups
410                 local tree = self.tree
411
412                 local treeframe = self.treeframe
413                 
414                 status.scrollToSelection = status.scrollToSelection or scrollToSelection        -- needs to be cached in case the control hasn't been drawn yet (code bails out below)
415
416                 self:BuildLevel(tree, 1)
417
418                 local numlines = #lines
419
420                 local maxlines = (floor(((self.treeframe:GetHeight()or 0) - 20 ) / 18))
421                 if maxlines <= 0 then return end
422
423                 local first, last
424                 
425                 scrollToSelection = status.scrollToSelection
426                 status.scrollToSelection = nil
427
428                 if numlines <= maxlines then
429                         --the whole tree fits in the frame
430                         status.scrollvalue = 0
431                         self:ShowScroll(false)
432                         first, last = 1, numlines
433                 else
434                         self:ShowScroll(true)
435                         --scrolling will be needed
436                         self.noupdate = true
437                         self.scrollbar:SetMinMaxValues(0, numlines - maxlines)
438                         --check if we are scrolled down too far
439                         if numlines - status.scrollvalue < maxlines then
440                                 status.scrollvalue = numlines - maxlines
441                         end
442                         self.noupdate = nil
443                         first, last = status.scrollvalue+1, status.scrollvalue + maxlines
444                         --show selection?
445                         if scrollToSelection and status.selected then
446                                 local show
447                                 for i,line in ipairs(lines) do  -- find the line number
448                                         if line.uniquevalue==status.selected then
449                                                 show=i
450                                         end
451                                 end
452                                 if not show then
453                                         -- selection was deleted or something?
454                                 elseif show>=first and show<=last then
455                                         -- all good
456                                 else
457                                         -- scrolling needed!
458                                         if show<first then
459                                                 status.scrollvalue = show-1
460                                         else
461                                                 status.scrollvalue = show-maxlines
462                                         end
463                                         first, last = status.scrollvalue+1, status.scrollvalue + maxlines
464                                 end
465                         end
466                         if self.scrollbar:GetValue() ~= status.scrollvalue then
467                                 self.scrollbar:SetValue(status.scrollvalue)
468                         end
469                 end
470
471                 local buttonnum = 1
472                 for i = first, last do
473                         local line = lines[i]
474                         local button = buttons[buttonnum]
475                         if not button then
476                                 button = self:CreateButton()
477
478                                 buttons[buttonnum] = button
479                                 button:SetParent(treeframe)
480                                 button:SetFrameLevel(treeframe:GetFrameLevel()+1)
481                                 button:ClearAllPoints()
482                                 if buttonnum == 1 then
483                                         if self.showscroll then
484                                                 button:SetPoint("TOPRIGHT", -22, -10)
485                                                 button:SetPoint("TOPLEFT", 0, -10)
486                                         else
487                                                 button:SetPoint("TOPRIGHT", 0, -10)
488                                                 button:SetPoint("TOPLEFT", 0, -10)
489                                         end
490                                 else
491                                         button:SetPoint("TOPRIGHT", buttons[buttonnum-1], "BOTTOMRIGHT",0,0)
492                                         button:SetPoint("TOPLEFT", buttons[buttonnum-1], "BOTTOMLEFT",0,0)
493                                 end
494                         end
495
496                         UpdateButton(button, line, status.selected == line.uniquevalue, line.hasChildren, groupstatus[line.uniquevalue] )
497                         button:Show()
498                         buttonnum = buttonnum + 1
499                 end
500                 
501         end,
502         
503         ["SetSelected"] = function(self, value)
504                 local status = self.status or self.localstatus
505                 if status.selected ~= value then
506                         status.selected = value
507                         self:Fire("OnGroupSelected", value)
508                 end
509         end,
510
511         ["Select"] = function(self, uniquevalue, ...)
512                 self.filter = false
513                 local status = self.status or self.localstatus
514                 local groups = status.groups
515                 local path = {...}
516                 for i = 1, #path do
517                         groups[tconcat(path, "\001", 1, i)] = true
518                 end
519                 status.selected = uniquevalue
520                 self:RefreshTree(true)
521                 self:Fire("OnGroupSelected", uniquevalue)
522         end,
523
524         ["SelectByPath"] = function(self, ...)
525                 self:Select(BuildUniqueValue(...), ...)
526         end,
527
528         ["SelectByValue"] = function(self, uniquevalue)
529                 self:Select(uniquevalue, ("\001"):split(uniquevalue))
530         end,
531
532         ["ShowScroll"] = function(self, show)
533                 self.showscroll = show
534                 if show then
535                         self.scrollbar:Show()
536                         if self.buttons[1] then
537                                 self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",-22,-10)
538                         end
539                 else
540                         self.scrollbar:Hide()
541                         if self.buttons[1] then
542                                 self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",0,-10)
543                         end
544                 end
545         end,
546
547         ["OnWidthSet"] = function(self, width)
548                 local content = self.content
549                 local treeframe = self.treeframe
550                 local status = self.status or self.localstatus
551                 status.fullwidth = width
552                 
553                 local contentwidth = width - status.treewidth - 20
554                 if contentwidth < 0 then
555                         contentwidth = 0
556                 end
557                 content:SetWidth(contentwidth)
558                 content.width = contentwidth
559                 
560                 local maxtreewidth = math_min(400, width - 50)
561                 
562                 if maxtreewidth > 100 and status.treewidth > maxtreewidth then
563                         self:SetTreeWidth(maxtreewidth, status.treesizable)
564                 end
565                 treeframe:SetMaxResize(maxtreewidth, 1600)
566         end,
567
568         ["OnHeightSet"] = function(self, height)
569                 local content = self.content
570                 local contentheight = height - 20
571                 if contentheight < 0 then
572                         contentheight = 0
573                 end
574                 content:SetHeight(contentheight)
575                 content.height = contentheight
576         end,
577
578         ["SetTreeWidth"] = function(self, treewidth, resizable)
579                 if not resizable then
580                         if type(treewidth) == 'number' then
581                                 resizable = false
582                         elseif type(treewidth) == 'boolean' then
583                                 resizable = treewidth
584                                 treewidth = DEFAULT_TREE_WIDTH
585                         else
586                                 resizable = false
587                                 treewidth = DEFAULT_TREE_WIDTH 
588                         end
589                 end
590                 self.treeframe:SetWidth(treewidth)
591                 self.dragger:EnableMouse(resizable)
592                 
593                 local status = self.status or self.localstatus
594                 status.treewidth = treewidth
595                 status.treesizable = resizable
596                 
597                 -- recalculate the content width
598                 if status.fullwidth then
599                         self:OnWidthSet(status.fullwidth)
600                 end
601         end,
602
603         ["GetTreeWidth"] = function(self)
604                 local status = self.status or self.localstatus
605                 return status.treewidth or DEFAULT_TREE_WIDTH
606         end,
607
608         ["LayoutFinished"] = function(self, width, height)
609                 if self.noAutoHeight then return end
610                 self:SetHeight((height or 0) + 20)
611         end
612 }
613
614 --[[-----------------------------------------------------------------------------
615 Constructor
616 -------------------------------------------------------------------------------]]
617 local PaneBackdrop  = {
618         bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
619         edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
620         tile = true, tileSize = 16, edgeSize = 16,
621         insets = { left = 3, right = 3, top = 5, bottom = 3 }
622 }
623
624 local DraggerBackdrop  = {
625         bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
626         edgeFile = nil,
627         tile = true, tileSize = 16, edgeSize = 0,
628         insets = { left = 3, right = 3, top = 7, bottom = 7 }
629 }
630
631 local function Constructor()
632         local num = AceGUI:GetNextWidgetNum(Type)
633         local frame = CreateFrame("Frame", nil, UIParent)
634
635         local treeframe = CreateFrame("Frame", nil, frame)
636         treeframe:SetPoint("TOPLEFT")
637         treeframe:SetPoint("BOTTOMLEFT")
638         treeframe:SetWidth(DEFAULT_TREE_WIDTH)
639         treeframe:EnableMouseWheel(true)
640         treeframe:SetBackdrop(PaneBackdrop)
641         treeframe:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
642         treeframe:SetBackdropBorderColor(0.4, 0.4, 0.4)
643         treeframe:SetResizable(true)
644         treeframe:SetMinResize(100, 1)
645         treeframe:SetMaxResize(400, 1600)
646         treeframe:SetScript("OnUpdate", FirstFrameUpdate)
647         treeframe:SetScript("OnSizeChanged", Tree_OnSizeChanged)
648         treeframe:SetScript("OnMouseWheel", Tree_OnMouseWheel)
649
650         local dragger = CreateFrame("Frame", nil, treeframe)
651         dragger:SetWidth(8)
652         dragger:SetPoint("TOP", treeframe, "TOPRIGHT")
653         dragger:SetPoint("BOTTOM", treeframe, "BOTTOMRIGHT")
654         dragger:SetBackdrop(DraggerBackdrop)
655         dragger:SetBackdropColor(1, 1, 1, 0)
656         dragger:SetScript("OnEnter", Dragger_OnEnter)
657         dragger:SetScript("OnLeave", Dragger_OnLeave)
658         dragger:SetScript("OnMouseDown", Dragger_OnMouseDown)
659         dragger:SetScript("OnMouseUp", Dragger_OnMouseUp)
660
661         local scrollbar = CreateFrame("Slider", ("AceConfigDialogTreeGroup%dScrollBar"):format(num), treeframe, "UIPanelScrollBarTemplate")
662         scrollbar:SetScript("OnValueChanged", nil)
663         scrollbar:SetPoint("TOPRIGHT", -10, -26)
664         scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
665         scrollbar:SetMinMaxValues(0,0)
666         scrollbar:SetValueStep(1)
667         scrollbar:SetValue(0)
668         scrollbar:SetWidth(16)
669         scrollbar:SetScript("OnValueChanged", OnScrollValueChanged)
670
671         local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
672         scrollbg:SetAllPoints(scrollbar)
673         scrollbg:SetColorTexture(0,0,0,0.4)
674
675         local border = CreateFrame("Frame",nil,frame)
676         border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT")
677         border:SetPoint("BOTTOMRIGHT")
678         border:SetBackdrop(PaneBackdrop)
679         border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
680         border:SetBackdropBorderColor(0.4, 0.4, 0.4)
681
682         --Container Support
683         local content = CreateFrame("Frame", nil, border)
684         content:SetPoint("TOPLEFT", 10, -10)
685         content:SetPoint("BOTTOMRIGHT", -10, 10)
686
687         local widget = {
688                 frame        = frame,
689                 lines        = {},
690                 levels       = {},
691                 buttons      = {},
692                 hasChildren  = {},
693                 localstatus  = { groups = {}, scrollvalue = 0 },
694                 filter       = false,
695                 treeframe    = treeframe,
696                 dragger      = dragger,
697                 scrollbar    = scrollbar,
698                 border       = border,
699                 content      = content,
700                 type         = Type
701         }
702         for method, func in pairs(methods) do
703                 widget[method] = func
704         end
705         treeframe.obj, dragger.obj, scrollbar.obj = widget, widget, widget
706
707         return AceGUI:RegisterAsContainer(widget)
708 end
709
710 AceGUI:RegisterWidgetType(Type, Constructor, Version)