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