Asa@0
|
1 local AceGUI = LibStub("AceGUI-3.0")
|
Asa@0
|
2
|
Asa@0
|
3 -- Lua APIs
|
Asa@0
|
4 local pairs, ipairs, assert, type = pairs, ipairs, assert, type
|
Asa@0
|
5
|
Asa@0
|
6 -- WoW APIs
|
Asa@0
|
7 local CreateFrame, UIParent = CreateFrame, UIParent
|
Asa@0
|
8 local _G = _G
|
Asa@0
|
9
|
Asa@0
|
10 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
Asa@0
|
11 -- List them here for Mikk's FindGlobals script
|
Asa@0
|
12 -- GLOBALS: PanelTemplates_TabResize, PanelTemplates_SetDisabledTabState, PanelTemplates_SelectTab, PanelTemplates_DeselectTab
|
Asa@0
|
13
|
Asa@0
|
14 -------------
|
Asa@0
|
15 -- Widgets --
|
Asa@0
|
16 -------------
|
Asa@0
|
17 --[[
|
Asa@0
|
18 Widgets must provide the following functions
|
Asa@0
|
19 Acquire() - Called when the object is aquired, should set everything to a default hidden state
|
Asa@0
|
20 Release() - Called when the object is Released, should remove any anchors and hide the Widget
|
Asa@0
|
21
|
Asa@0
|
22 And the following members
|
Asa@0
|
23 frame - the frame or derivitive object that will be treated as the widget for size and anchoring purposes
|
Asa@0
|
24 type - the type of the object, same as the name given to :RegisterWidget()
|
Asa@0
|
25
|
Asa@0
|
26 Widgets contain a table called userdata, this is a safe place to store data associated with the wigdet
|
Asa@0
|
27 It will be cleared automatically when a widget is released
|
Asa@0
|
28 Placing values directly into a widget object should be avoided
|
Asa@0
|
29
|
Asa@0
|
30 If the Widget can act as a container for other Widgets the following
|
Asa@0
|
31 content - frame or derivitive that children will be anchored to
|
Asa@0
|
32
|
Asa@0
|
33 The Widget can supply the following Optional Members
|
Asa@0
|
34
|
Asa@0
|
35
|
Asa@0
|
36 ]]
|
Asa@0
|
37
|
Asa@0
|
38 --------------------------
|
Asa@0
|
39 -- Tab Group --
|
Asa@0
|
40 --------------------------
|
Asa@0
|
41
|
Asa@0
|
42 do
|
Asa@0
|
43 local Type = "TabGroup"
|
Asa@0
|
44 local Version = 24
|
Asa@0
|
45
|
Asa@0
|
46 local PaneBackdrop = {
|
Asa@0
|
47 bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
Asa@0
|
48 edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
Asa@0
|
49 tile = true, tileSize = 16, edgeSize = 16,
|
Asa@0
|
50 insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
Asa@0
|
51 }
|
Asa@0
|
52
|
Asa@0
|
53 local function OnAcquire(self)
|
Asa@0
|
54
|
Asa@0
|
55 end
|
Asa@0
|
56
|
Asa@0
|
57 local function OnRelease(self)
|
Asa@0
|
58 self.frame:ClearAllPoints()
|
Asa@0
|
59 self.frame:Hide()
|
Asa@0
|
60 self.status = nil
|
Asa@0
|
61 for k in pairs(self.localstatus) do
|
Asa@0
|
62 self.localstatus[k] = nil
|
Asa@0
|
63 end
|
Asa@0
|
64 self.tablist = nil
|
Asa@0
|
65 for _, tab in pairs(self.tabs) do
|
Asa@0
|
66 tab:Hide()
|
Asa@0
|
67 end
|
Asa@0
|
68 self:SetTitle()
|
Asa@0
|
69 end
|
Asa@0
|
70
|
Asa@0
|
71 local function Tab_SetText(self, text)
|
Asa@0
|
72 self:_SetText(text)
|
Asa@0
|
73 local width = self.obj.frame.width or self.obj.frame:GetWidth() or 0
|
Asa@0
|
74 PanelTemplates_TabResize(self, 0, nil, width)
|
Asa@0
|
75 end
|
Asa@0
|
76
|
Asa@0
|
77 local function UpdateTabLook(self)
|
Asa@0
|
78 if self.disabled then
|
Asa@0
|
79 PanelTemplates_SetDisabledTabState(self)
|
Asa@0
|
80 elseif self.selected then
|
Asa@0
|
81 PanelTemplates_SelectTab(self)
|
Asa@0
|
82 else
|
Asa@0
|
83 PanelTemplates_DeselectTab(self)
|
Asa@0
|
84 end
|
Asa@0
|
85 end
|
Asa@0
|
86
|
Asa@0
|
87 local function Tab_SetSelected(self, selected)
|
Asa@0
|
88 self.selected = selected
|
Asa@0
|
89 UpdateTabLook(self)
|
Asa@0
|
90 end
|
Asa@0
|
91
|
Asa@0
|
92 local function Tab_OnClick(self)
|
Asa@0
|
93 if not (self.selected or self.disabled) then
|
Asa@0
|
94 self.obj:SelectTab(self.value)
|
Asa@0
|
95 end
|
Asa@0
|
96 end
|
Asa@0
|
97
|
Asa@0
|
98 local function Tab_SetDisabled(self, disabled)
|
Asa@0
|
99 self.disabled = disabled
|
Asa@0
|
100 UpdateTabLook(self)
|
Asa@0
|
101 end
|
Asa@0
|
102
|
Asa@0
|
103 local function Tab_OnEnter(this)
|
Asa@0
|
104 local self = this.obj
|
Asa@0
|
105 self:Fire("OnTabEnter", self.tabs[this.id].value, this)
|
Asa@0
|
106 end
|
Asa@0
|
107
|
Asa@0
|
108 local function Tab_OnLeave(this)
|
Asa@0
|
109 local self = this.obj
|
Asa@0
|
110 self:Fire("OnTabLeave", self.tabs[this.id].value, this)
|
Asa@0
|
111 end
|
Asa@0
|
112
|
Asa@0
|
113 local function Tab_OnShow(this)
|
Asa@0
|
114 _G[this:GetName().."HighlightTexture"]:SetWidth(this:GetTextWidth() + 30)
|
Asa@0
|
115 end
|
Asa@0
|
116
|
Asa@0
|
117 local function CreateTab(self, id)
|
Asa@0
|
118 local tabname = "AceGUITabGroup"..self.num.."Tab"..id
|
Asa@0
|
119 local tab = CreateFrame("Button",tabname,self.border,"OptionsFrameTabButtonTemplate")
|
Asa@0
|
120 tab.obj = self
|
Asa@0
|
121 tab.id = id
|
Asa@0
|
122
|
Asa@0
|
123 tab.text = _G[tabname .. "Text"]
|
Asa@0
|
124 tab.text:ClearAllPoints()
|
Asa@0
|
125 tab.text:SetPoint("LEFT", tab, "LEFT", 14, -3)
|
Asa@0
|
126 tab.text:SetPoint("RIGHT", tab, "RIGHT", -12, -3)
|
Asa@0
|
127
|
Asa@0
|
128 tab:SetScript("OnClick",Tab_OnClick)
|
Asa@0
|
129 tab:SetScript("OnEnter",Tab_OnEnter)
|
Asa@0
|
130 tab:SetScript("OnLeave",Tab_OnLeave)
|
Asa@0
|
131 tab:SetScript("OnShow", Tab_OnShow)
|
Asa@0
|
132
|
Asa@0
|
133 tab._SetText = tab.SetText
|
Asa@0
|
134 tab.SetText = Tab_SetText
|
Asa@0
|
135 tab.SetSelected = Tab_SetSelected
|
Asa@0
|
136 tab.SetDisabled = Tab_SetDisabled
|
Asa@0
|
137
|
Asa@0
|
138 return tab
|
Asa@0
|
139 end
|
Asa@0
|
140
|
Asa@0
|
141 local function SetTitle(self, text)
|
Asa@0
|
142 self.titletext:SetText(text or "")
|
Asa@0
|
143 if text and text ~= "" then
|
Asa@0
|
144 self.alignoffset = 25
|
Asa@0
|
145 else
|
Asa@0
|
146 self.alignoffset = 18
|
Asa@0
|
147 end
|
Asa@0
|
148 self:BuildTabs()
|
Asa@0
|
149 end
|
Asa@0
|
150
|
Asa@0
|
151 -- called to set an external table to store status in
|
Asa@0
|
152 local function SetStatusTable(self, status)
|
Asa@0
|
153 assert(type(status) == "table")
|
Asa@0
|
154 self.status = status
|
Asa@0
|
155 end
|
Asa@0
|
156
|
Asa@0
|
157 local function SelectTab(self, value)
|
Asa@0
|
158 local status = self.status or self.localstatus
|
Asa@0
|
159
|
Asa@0
|
160 local found
|
Asa@0
|
161 for i, v in ipairs(self.tabs) do
|
Asa@0
|
162 if v.value == value then
|
Asa@0
|
163 v:SetSelected(true)
|
Asa@0
|
164 found = true
|
Asa@0
|
165 else
|
Asa@0
|
166 v:SetSelected(false)
|
Asa@0
|
167 end
|
Asa@0
|
168 end
|
Asa@0
|
169 status.selected = value
|
Asa@0
|
170 if found then
|
Asa@0
|
171 self:Fire("OnGroupSelected",value)
|
Asa@0
|
172 end
|
Asa@0
|
173 end
|
Asa@0
|
174
|
Asa@0
|
175 local function SetTabs(self, tabs)
|
Asa@0
|
176 self.tablist = tabs
|
Asa@0
|
177 self:BuildTabs()
|
Asa@0
|
178 end
|
Asa@0
|
179
|
Asa@0
|
180
|
Asa@0
|
181 local widths = {}
|
Asa@0
|
182 local rowwidths = {}
|
Asa@0
|
183 local rowends = {}
|
Asa@0
|
184 local function BuildTabs(self)
|
Asa@0
|
185 local hastitle = (self.titletext:GetText() and self.titletext:GetText() ~= "")
|
Asa@0
|
186 local status = self.status or self.localstatus
|
Asa@0
|
187 local tablist = self.tablist
|
Asa@0
|
188 local tabs = self.tabs
|
Asa@0
|
189
|
Asa@0
|
190 if not tablist then return end
|
Asa@0
|
191
|
Asa@0
|
192 local width = self.frame.width or self.frame:GetWidth() or 0
|
Asa@0
|
193
|
Asa@0
|
194 for i = #widths, 1, -1 do
|
Asa@0
|
195 widths[i] = nil
|
Asa@0
|
196 end
|
Asa@0
|
197 for i = #rowwidths, 1, -1 do
|
Asa@0
|
198 rowwidths[i] = nil
|
Asa@0
|
199 end
|
Asa@0
|
200 for i = #rowends, 1, -1 do
|
Asa@0
|
201 rowends[i] = nil
|
Asa@0
|
202 end
|
Asa@0
|
203
|
Asa@0
|
204 --Place Text into tabs and get thier initial width
|
Asa@0
|
205 for i, v in ipairs(tablist) do
|
Asa@0
|
206 local tab = tabs[i]
|
Asa@0
|
207 if not tab then
|
Asa@0
|
208 tab = self:CreateTab(i)
|
Asa@0
|
209 tabs[i] = tab
|
Asa@0
|
210 end
|
Asa@0
|
211
|
Asa@0
|
212 tab:Show()
|
Asa@0
|
213 tab:SetText(v.text)
|
Asa@0
|
214 tab:SetDisabled(v.disabled)
|
Asa@0
|
215 tab.value = v.value
|
Asa@0
|
216
|
Asa@0
|
217 widths[i] = tab:GetWidth() - 6 --tabs are anchored 10 pixels from the right side of the previous one to reduce spacing, but add a fixed 4px padding for the text
|
Asa@0
|
218 end
|
Asa@0
|
219
|
Asa@0
|
220 for i = (#tablist)+1, #tabs, 1 do
|
Asa@0
|
221 tabs[i]:Hide()
|
Asa@0
|
222 end
|
Asa@0
|
223
|
Asa@0
|
224 --First pass, find the minimum number of rows needed to hold all tabs and the initial tab layout
|
Asa@0
|
225 local numtabs = #tablist
|
Asa@0
|
226 local numrows = 1
|
Asa@0
|
227 local usedwidth = 0
|
Asa@0
|
228
|
Asa@0
|
229 for i = 1, #tablist do
|
Asa@0
|
230 --If this is not the first tab of a row and there isn't room for it
|
Asa@0
|
231 if usedwidth ~= 0 and (width - usedwidth - widths[i]) < 0 then
|
Asa@0
|
232 rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
|
Asa@0
|
233 rowends[numrows] = i - 1
|
Asa@0
|
234 numrows = numrows + 1
|
Asa@0
|
235 usedwidth = 0
|
Asa@0
|
236 end
|
Asa@0
|
237 usedwidth = usedwidth + widths[i]
|
Asa@0
|
238 end
|
Asa@0
|
239 rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
|
Asa@0
|
240 rowends[numrows] = #tablist
|
Asa@0
|
241
|
Asa@0
|
242 --Fix for single tabs being left on the last row, move a tab from the row above if applicable
|
Asa@0
|
243 if numrows > 1 then
|
Asa@0
|
244 --if the last row has only one tab
|
Asa@0
|
245 if rowends[numrows-1] == numtabs-1 then
|
Asa@0
|
246 --if there are more than 2 tabs in the 2nd last row
|
Asa@0
|
247 if (numrows == 2 and rowends[numrows-1] > 2) or (rowends[numrows] - rowends[numrows-1] > 2) then
|
Asa@0
|
248 --move 1 tab from the second last row to the last, if there is enough space
|
Asa@0
|
249 if (rowwidths[numrows] + widths[numtabs-1]) <= width then
|
Asa@0
|
250 rowends[numrows-1] = rowends[numrows-1] - 1
|
Asa@0
|
251 rowwidths[numrows] = rowwidths[numrows] + widths[numtabs-1]
|
Asa@0
|
252 rowwidths[numrows-1] = rowwidths[numrows-1] - widths[numtabs-1]
|
Asa@0
|
253 end
|
Asa@0
|
254 end
|
Asa@0
|
255 end
|
Asa@0
|
256 end
|
Asa@0
|
257
|
Asa@0
|
258 --anchor the rows as defined and resize tabs to fill thier row
|
Asa@0
|
259 local starttab = 1
|
Asa@0
|
260 for row, endtab in ipairs(rowends) do
|
Asa@0
|
261 local first = true
|
Asa@0
|
262 for tabno = starttab, endtab do
|
Asa@0
|
263 local tab = tabs[tabno]
|
Asa@0
|
264 tab:ClearAllPoints()
|
Asa@0
|
265 if first then
|
Asa@0
|
266 tab:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 0, -(hastitle and 14 or 7)-(row-1)*20 )
|
Asa@0
|
267 first = false
|
Asa@0
|
268 else
|
Asa@0
|
269 tab:SetPoint("LEFT", tabs[tabno-1], "RIGHT", -10, 0)
|
Asa@0
|
270 end
|
Asa@0
|
271 end
|
Asa@0
|
272
|
Asa@0
|
273 -- equal padding for each tab to fill the available width,
|
Asa@0
|
274 -- if the used space is above 75% already
|
Asa@0
|
275 local padding = 0
|
Asa@0
|
276 if not (numrows == 1 and rowwidths[1] < width*0.75) then
|
Asa@0
|
277 padding = (width - rowwidths[row]) / (endtab - starttab+1)
|
Asa@0
|
278 end
|
Asa@0
|
279
|
Asa@0
|
280 for i = starttab, endtab do
|
Asa@0
|
281 PanelTemplates_TabResize(tabs[i], padding + 4, nil, width)
|
Asa@0
|
282 end
|
Asa@0
|
283 starttab = endtab + 1
|
Asa@0
|
284 end
|
Asa@0
|
285
|
Asa@0
|
286 self.borderoffset = (hastitle and 17 or 10)+((numrows)*20)
|
Asa@0
|
287 self.border:SetPoint("TOPLEFT",self.frame,"TOPLEFT",1,-self.borderoffset)
|
Asa@0
|
288 end
|
Asa@0
|
289
|
Asa@0
|
290 local function BuildTabsOnUpdate(this)
|
Asa@0
|
291 BuildTabs(this.obj)
|
Asa@0
|
292 this:SetScript("OnUpdate", nil)
|
Asa@0
|
293 end
|
Asa@0
|
294
|
Asa@0
|
295 local function OnWidthSet(self, width)
|
Asa@0
|
296 local content = self.content
|
Asa@0
|
297 local contentwidth = width - 60
|
Asa@0
|
298 if contentwidth < 0 then
|
Asa@0
|
299 contentwidth = 0
|
Asa@0
|
300 end
|
Asa@0
|
301 content:SetWidth(contentwidth)
|
Asa@0
|
302 content.width = contentwidth
|
Asa@0
|
303 BuildTabs(self)
|
Asa@0
|
304 self.frame:SetScript("OnUpdate", BuildTabsOnUpdate)
|
Asa@0
|
305 end
|
Asa@0
|
306
|
Asa@0
|
307
|
Asa@0
|
308 local function OnHeightSet(self, height)
|
Asa@0
|
309 local content = self.content
|
Asa@0
|
310 local contentheight = height - (self.borderoffset + 23)
|
Asa@0
|
311 if contentheight < 0 then
|
Asa@0
|
312 contentheight = 0
|
Asa@0
|
313 end
|
Asa@0
|
314 content:SetHeight(contentheight)
|
Asa@0
|
315 content.height = contentheight
|
Asa@0
|
316 end
|
Asa@0
|
317
|
Asa@0
|
318 local function LayoutFinished(self, width, height)
|
Asa@0
|
319 if self.noAutoHeight then return end
|
Asa@0
|
320 self:SetHeight((height or 0) + (self.borderoffset + 23))
|
Asa@0
|
321 end
|
Asa@0
|
322
|
Asa@0
|
323 local function Constructor()
|
Asa@0
|
324 local frame = CreateFrame("Frame",nil,UIParent)
|
Asa@0
|
325 local self = {}
|
Asa@0
|
326 self.type = Type
|
Asa@0
|
327
|
Asa@0
|
328 self.num = AceGUI:GetNextWidgetNum(Type)
|
Asa@0
|
329
|
Asa@0
|
330 self.localstatus = {}
|
Asa@0
|
331
|
Asa@0
|
332 self.OnRelease = OnRelease
|
Asa@0
|
333 self.OnAcquire = OnAcquire
|
Asa@0
|
334 self.SetTitle = SetTitle
|
Asa@0
|
335 self.CreateTab = CreateTab
|
Asa@0
|
336 self.SelectTab = SelectTab
|
Asa@0
|
337 self.BuildTabs = BuildTabs
|
Asa@0
|
338 self.SetStatusTable = SetStatusTable
|
Asa@0
|
339 self.SetTabs = SetTabs
|
Asa@0
|
340 self.LayoutFinished = LayoutFinished
|
Asa@0
|
341 self.frame = frame
|
Asa@0
|
342
|
Asa@0
|
343 self.OnWidthSet = OnWidthSet
|
Asa@0
|
344 self.OnHeightSet = OnHeightSet
|
Asa@0
|
345
|
Asa@0
|
346 frame.obj = self
|
Asa@0
|
347
|
Asa@0
|
348 frame:SetHeight(100)
|
Asa@0
|
349 frame:SetWidth(100)
|
Asa@0
|
350 frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
Asa@0
|
351
|
Asa@0
|
352 self.alignoffset = 18
|
Asa@0
|
353
|
Asa@0
|
354 local titletext = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
|
Asa@0
|
355 titletext:SetPoint("TOPLEFT",frame,"TOPLEFT",14,0)
|
Asa@0
|
356 titletext:SetPoint("TOPRIGHT",frame,"TOPRIGHT",-14,0)
|
Asa@0
|
357 titletext:SetJustifyH("LEFT")
|
Asa@0
|
358 titletext:SetHeight(18)
|
Asa@0
|
359 titletext:SetText("")
|
Asa@0
|
360
|
Asa@0
|
361 self.titletext = titletext
|
Asa@0
|
362
|
Asa@0
|
363 local border = CreateFrame("Frame",nil,frame)
|
Asa@0
|
364 self.border = border
|
Asa@0
|
365 self.borderoffset = 27
|
Asa@0
|
366 border:SetPoint("TOPLEFT",frame,"TOPLEFT",1,-27)
|
Asa@0
|
367 border:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-1,3)
|
Asa@0
|
368
|
Asa@0
|
369 border:SetBackdrop(PaneBackdrop)
|
Asa@0
|
370 border:SetBackdropColor(0.1,0.1,0.1,0.5)
|
Asa@0
|
371 border:SetBackdropBorderColor(0.4,0.4,0.4)
|
Asa@0
|
372
|
Asa@0
|
373 self.tabs = {}
|
Asa@0
|
374
|
Asa@0
|
375 --Container Support
|
Asa@0
|
376 local content = CreateFrame("Frame",nil,border)
|
Asa@0
|
377 self.content = content
|
Asa@0
|
378 content.obj = self
|
Asa@0
|
379 content:SetPoint("TOPLEFT",border,"TOPLEFT",10,-7)
|
Asa@0
|
380 content:SetPoint("BOTTOMRIGHT",border,"BOTTOMRIGHT",-10,7)
|
Asa@0
|
381
|
Asa@0
|
382 AceGUI:RegisterAsContainer(self)
|
Asa@0
|
383 return self
|
Asa@0
|
384 end
|
Asa@0
|
385
|
Asa@0
|
386 AceGUI:RegisterWidgetType(Type,Constructor,Version)
|
Asa@0
|
387 end
|