comparison LibKraken/LibKraken-1.0.lua @ 5:9ac29fe77455

- dynamic profession spell mapping - dynamic talent spell mapping - protection of dynamic slots that aren't in use - plugin abstractors for accessing state data - a lot of fixes related to the 7.0.3 API
author Nenue
date Tue, 26 Jul 2016 19:29:44 -0400
parents
children a2fc77fa4c73
comparison
equal deleted inserted replaced
4:a30285f8191e 5:9ac29fe77455
1 --[[
2 -- KrakynTools
3 -- AddOn prototyping library.
4 --
5 -- Implements
6 -- KT.register(frame) to hook the following (all optional):
7 -- frame:init() run immediately after KT sets itself up
8 -- frame:profile("Name-TruncatedRealm") called the first time SavedVars data becomes available
9 -- frame:variables() called upon variables being available
10 -- frame:event(event, ...) replaces the event callback
11 -- frame:ui() called by /ui when activating
12 --
13 -- frame:tab(name, tooltip, texture, coord)
14 -- produces a serial button that changes display tabs
15 --
16 -- frame:button(name, text, tooltip, onClick)
17 -- produces a button with OnClick script
18 --
19 -- frame:uibutton(name, text, tooltip, onClick, texture, coord)
20 -- produces a header button with desired onClick
21 --
22 ]]--
23
24 local LIBKT_MAJOR, LIBKT_MINOR = "LibKraken", 1
25 local KT = LibStub:NewLibrary(LIBKT_MAJOR, LIBKT_MINOR)
26
27 --GLOBALS: LibKT, KrakTool, KTErrorFrame, LibKTError, SlashCmdList, SLASH_RL1, SLASH_UI1
28 local CreateFrame, debugstack, tostring, select = CreateFrame, debugstack, tostring, select
29 local print, max, unpack, tinsert = print, max, unpack, tinsert
30 local ipairs, xpcall, next, safecall = ipairs, xpcall, next, safecall
31 local UI_TOGGLE = false
32 local db
33
34
35 KT.handler = CreateFrame('Frame', 'LibKTHostFrame', UIParent)
36 KT.addons = {}
37 KT.initStack = {}
38 KT.varsStack = {}
39 local print = DEVIAN_WORKSPACE and function(...) print('LKT', ...) end or function() end
40 local registeredHandles = {}
41
42 --- /rl
43 -- ReloadUI shortcut
44 SLASH_RL1 = "/rl"
45 SlashCmdList.RL = function ()
46 ReloadUI()
47 end
48
49 --- /kv addon ...
50 -- Dumps table values from "addon", using the arguments as index values.
51 -- Numerics are converted, and names that end with "()" will be called as such
52 SLASH_KV1 = "/kv"
53 SlashCmdList.KV = function (editbox, input)
54
55 end
56
57
58 --- /ui
59 -- Run any addon:ui() methods
60 SLASH_UI1 = "/ui"
61 SlashCmdList.UI = function ()
62 if UI_TOGGLE then
63 UI_TOGGLE = false
64 else
65 UI_TOGGLE = true
66 end
67 for i, frame in pairs(KT.frames) do
68 if UI_TOGGLE then
69 if frame.close then
70 frame.close()
71 else
72 frame:Hide()
73 end
74 else
75 if frame.ui then
76 frame.ui()
77 end
78 frame:Show()
79 end
80 end
81 end
82
83 LibKTError = function(msg)
84 local dstack = debugstack(2)
85 :gsub("Interface\\AddOns\\",'')
86 :gsub("<(.-)>", function(a) return '|cFF00FFFF<'.. a ..'>|r' end)
87
88
89
90 KTErrorFrame.errmsg:SetText(msg)
91 KTErrorFrame.debugstack:SetText(dstack)
92 KTErrorFrame:SetHeight(KTErrorFrame.debugstack:GetStringHeight() + KTErrorFrame.errmsg:GetStringHeight() + 12)
93 KTErrorFrame:Show()
94 end
95
96
97 local pending = {}
98 local processing = false
99 local isHandled = false
100 local nodebug = false
101 function KT.OnEvent (addon, event, ...)
102 if processing then
103 local args = {...}
104 C_Timer.After(0, function() KT.OnEvent(addon, event, unpack(args)) end)
105 return
106 else
107
108 end
109 --- reset state
110 processing = true
111 isHandled = false
112 nodebug = false
113
114
115 if addon.event then
116 nodebug = addon.event(addon, event, ...)
117 end
118
119 if addon[event] then
120 nodebug = addon[event](addon, event, ...) or nodebug
121 addon.missed = 0
122 addon.handled = addon.handled + 1
123 isHandled = true
124 else
125 addon.firstEvent = false
126 addon.unhandled = addon.unhandled + 1
127 addon.missed = addon.missed + 1
128 end
129
130 for i, module in ipairs(addon.modules) do
131 --print(i, module)
132 if module[event] then
133 nodebug = module[event](addon, event, ...) or nodebug
134 addon.missed = 0
135 addon.handled = addon.handled + 1
136 isHandled = true
137 else
138 addon.firstEvent = false
139 addon.unhandled = addon.unhandled + 1
140 addon.missed = addon.missed + 1
141 end
142
143 end
144 if nodebug then
145 processing = false
146 return
147 else
148 KT.UpdateEventStatus(addon, event, ...)
149 processing = false
150 end
151
152 end
153
154 KT.UpdateEventStatus = function(addon, event, ...)
155 print(addon:GetName(), event, ...)
156
157 -- debug outputs
158 if addon.status then
159 addon.status:SetText(event .. '\n|cFF00FF00' .. addon.handled .. '|r |cFFFF8800' .. addon.missed .. '|r |cFFFF4400' .. addon.unhandled .. '|r')
160 if isHandled then
161 addon.status:SetTextColor(0,1,0)
162 if addon.log then
163 local logtext = event
164 for i = 1, select('#',...) do
165 logtext = logtext .. '\n' .. i .. ':' .. tostring(select(i,...))
166 end
167 addon.log:SetText('|cFFFFFF00last|r\n' .. logtext)
168 local newWidth = addon.log:GetStringWidth()
169
170 if addon.logfirst then
171 if not addon.firstEvent then
172 addon.firstEvent = event
173 addon.logfirst:SetText('|cFF00FF88first|r\n' .. logtext)
174 end
175
176 newWidth = newWidth + addon.logfirst:GetStringWidth()
177 end
178 if addon.logdiff then
179 if not event ~= addon.firstEvent then
180 addon.firstEvent = event
181 addon.logdiff:SetText('|cFF0088FFdiff|r\n' .. logtext)
182 end
183 newWidth = newWidth + addon.logdiff:GetStringWidth()
184 end
185 --addon:SetWidth(newWidth)
186 end
187 else
188 addon.status:SetTextColor(1,0,0)
189 end
190 end
191 end
192
193 KT.register = function(addon, name, noGUI)
194 if registeredHandles[addon] then
195 name = name or debugstack(2,1,0):gsub("\\n.+", ""):gsub("^Interface\\AddOns\\", ""):gsub("%s+$", "")
196 else
197 if not name then
198 assert(type(addon) == 'table', 'Need a valid table.')
199 if addon.GetName then
200 name = addon:GetName()
201 else
202 name = debugstack(2,1,0):gsub("\\n.+", ""):gsub("^Interface\\AddOns\\", ""):gsub("%s+$", "")
203 end
204 assert(type(name) == 'string', 'Unable to resolve a valid stub name.')
205 end
206 -- if calling again, assume name is a file handle
207
208 registeredHandles[addon] = name
209 KT.addons[name] = addon
210 if addon.SetScript then
211 addon:SetScript('OnEvent', KT.OnEvent)
212 end
213 addon.unhandled = 0
214 addon.missed = 0
215 addon.handled = 0
216 addon.firstEvent = false
217 addon.modules = {}
218 tinsert(KT.initStack, addon)
219 tinsert(KT.varsStack, addon)
220
221 if addon.GetName and (not noGUI) then
222 addon.UIPanelAnchor = {'TOPLEFT', addon, 'TOPLEFT', 12, -12 }
223 addon.UIPanelGrowth = {'TOPLEFT', 'TOPRIGHT', 14, 0}
224 addon.button = KT.button
225 addon.uibutton = KT.uibutton
226 addon.tab = KT.tab
227 addon.print = KT.print
228 end
229 end
230
231 return addon, (DEVIAN_WORKSPACE and function(...) _G.print(name, ...) end or function() end)
232 end
233
234
235
236 local onEvent = function(self, event, arg1)
237 if (event == 'ADDON_LOADED' and arg1 ~= 'Blizzard_DebugTools') or event == 'PLAYER_LOGIN' then
238 -- run any init blocks left in the queue
239 while #KT.initStack >= 1 do
240 local addon = tremove(KT.initStack, 1)
241 print('KT', addon:GetName(), 'init')
242 if addon.init then
243 xpcall(addon.init, LibKTError)
244 for i, module in ipairs(addon.modules) do
245 if module.init then
246 xpcall(module.init, LibKTError)
247 end
248 end
249 end
250 end
251
252 -- run any variables blocks if player variables are ready
253 if IsLoggedIn() and #KT.varsStack >= 1 then
254 while #KT.varsStack >= 1 do
255 local addon = tremove(KT.varsStack, 1)
256 print(addon:GetName())
257 if addon.variables then
258 xpcall(addon.variables, LibKTError)
259 for i, module in ipairs(addon.modules) do
260 if module.variables then
261 xpcall(module.variables, LibKTError)
262 end
263 end
264 end
265 end
266 end
267 end
268 end
269
270 KT.print = function(module, ...)
271 local msg = '|cFF00FFFF'..module:GetName()..'|r:'
272 for i = 1, select('#', ...) do
273 msg = msg .. ' ' .. tostring(select(i, ...))
274 end
275 DEFAULT_CHAT_FRAME:AddMessage(msg)
276 end
277
278 --- Button generators
279
280 local GetButtonTemplate = function(name, parent, template, onClick)
281 if _G[name] then
282 return _G[name]
283 end
284
285 local button = CreateFrame('Button', name, parent, template)
286 button:RegisterForClicks('AnyUp')
287 button:SetScript('OnClick', onClick)
288 return button
289 end
290
291 local SetButtonAnchor = function(self, collector, anchor, growth)
292 if self:GetID() == 0 then
293 self:SetID(#collector)
294 print('registered TabButton #', self:GetID())
295 end
296
297 if self:GetID() == 1 then
298 self:SetPoint(unpack(anchor))
299 else
300 growth[2] = collector[self:GetID()-1]
301 self:SetPoint(unpack(growth))
302 end
303 end
304
305 KT.tab = function(self, name, tooltip, texture, coords)
306 local button = GetButtonTemplate(name, self, 'KTTabButton', self.SelectTab)
307 button.icon:SetTexture(texture)
308 button.tooltip = tooltip
309 button:SetSize(unpack(self.tabSize))
310 if coords then
311 button.icon:SetTexCoord(unpack(coords))
312 end
313 SetButtonAnchor(button, self.tabButtons, self.tabAnchor, self.tabGrowth)
314 return button
315 end
316
317 KT.button = function(self, name, text, tooltip, onClick)
318 local button = GetButtonTemplate(name, self, 'KTButton', onClick)
319
320 button.tooltip = tooltip
321 button:SetText(text)
322 button:SetWidth(max(button:GetWidth(), button:GetFontString():GetStringWidth() + 12))
323
324 SetButtonAnchor(button, self.controls, self.controlsAnchor, self.controlsGrowth)
325 return button
326 end
327
328 KT.uibutton = function(self, name, text, tooltip, onClick, texture, coords)
329 local button = GetButtonTemplate(name, self, 'KTUIPanelButton', onClick)
330
331 button.tooltip = tooltip
332 button:SetText(text)
333
334 if self.UIPanelIcon then
335 local w, h, anchor, x, y = unpack(self.UIPanelIcon)
336 button.icon:SetTexture(texture)
337 button.icon:SetSize(w, h)
338 button.icon:ClearAllPoints()
339 button.icon:SetPoint(anchor, button, anchor, x, y)
340 end
341
342 if not self.UIPanelSize then
343 button:SetWidth(button:GetFontString():GetStringWidth() + button.icon:GetWidth()/1.5)
344 else
345 button:SetSize(unpack(self.UIPanelSize))
346 end
347 if coords then
348 button.icon:SetTexCoord(unpack(coords))
349 end
350 SetButtonAnchor(button, self.UIPanels, self.UIPanelAnchor, self.UIPanelGrowth)
351 return button
352 end
353
354
355 KT.handler:RegisterEvent('ADDON_LOADED')
356 KT.handler:RegisterEvent('PLAYER_LOGIN')
357 KT.handler:SetScript('OnEvent', onEvent)