Mercurial > wow > skeletonkey
comparison LibKraken/LibKraken.lua @ 37:ae012c9d8dc5
more logjam cleanup
author | Nenue |
---|---|
date | Tue, 16 Aug 2016 10:28:37 -0400 |
parents | |
children | 9eebce04e69b |
comparison
equal
deleted
inserted
replaced
36:1e1fc3204bfc | 37:ae012c9d8dc5 |
---|---|
1 --[[ | |
2 -- KrakynTools | |
3 -- AddOn prototyping library. | |
4 -- | |
5 --- Bundles an object into the handler queue, returning the core object, and handlers for debug output and co-routine. | |
6 -- Addon name is determined in order of: (string first arg, second arg :GetName(), invoking filename). | |
7 -- Once an addon name/object is registered, subsequent calls will return a debugger that reports the file or plugin name. | |
8 -- @usage addon, print, wrap = KT.register(name, table) or KT.register(addon) or KT.register(addon, plugin) | |
9 -- @param name - name of addon, as found in global varargs | |
10 -- @param table - addon table from global varargs | |
11 -- | |
12 -- @param frame - frame object used by addon | |
13 -- @param plugin - string name of plugin or an object table to check for lib handlers | |
14 -- | |
15 -- Handlers: | |
16 -- :init() run immediately after KT sets itself up | |
17 -- :profile("Name-TruncatedRealm") called the first time SavedVars data becomes available | |
18 -- :variables() called upon variables being available | |
19 -- :event(event, ...) replaces the event callback | |
20 -- :ui() called by /ui when activating | |
21 -- | |
22 -- Embedded: | |
23 -- NOTES: | |
24 -- * `name' is passed as is into CreateFrame, so using nil produce an anonymous frame | |
25 -- * `coord' is a 4 or 8 size table unpacked into Texture:SetTexCoords() | |
26 -- | |
27 -- tab = frame:tab(name, tooltip, texture, coord) | |
28 -- produces a serial button that changes display tabs | |
29 -- | |
30 -- button = frame:button(name, text, tooltip, onClick) | |
31 -- produces a button with OnClick script | |
32 -- | |
33 -- uibutton = frame:uibutton(name, text, tooltip, onClick, texture, coord) | |
34 -- produces a header button with desired onClick | |
35 -- | |
36 -- | |
37 ]]-- | |
38 | |
39 local LIBKT_MAJOR, LIBKT_MINOR = "LibKraken", 2 | |
40 local KT = LibStub:NewLibrary(LIBKT_MAJOR, LIBKT_MINOR) | |
41 | |
42 --GLOBALS: KTErrorFrame, LibKTError, SlashCmdList, SLASH_RL1, SLASH_UI1 | |
43 local CreateFrame, debugstack, tostring, select = CreateFrame, debugstack, tostring, select | |
44 local max, unpack, tinsert = max, unpack, tinsert | |
45 local ipairs, xpcall, next, safecall = ipairs, xpcall, next, safecall | |
46 local UI_TOGGLE = false | |
47 local db | |
48 | |
49 | |
50 KT.handler = CreateFrame('Frame', 'LibKTHostFrame', UIParent) | |
51 KT.addons = {} | |
52 KT.initStack = {} | |
53 KT.varsStack = {} | |
54 local print = DEVIAN_WORKSPACE and function(...) _G.print('LKT', ...) end or function() end | |
55 local registeredHandles = {} | |
56 local handlers = {} | |
57 | |
58 | |
59 --- /rl | |
60 -- ReloadUI shortcut | |
61 SLASH_RL1 = "/rl" | |
62 SlashCmdList.RL = function () | |
63 ReloadUI() | |
64 end | |
65 | |
66 --- /ui | |
67 -- Run any addon:ui() methods | |
68 SLASH_UI1 = "/ui" | |
69 SlashCmdList.UI = function () | |
70 if UI_TOGGLE then | |
71 UI_TOGGLE = false | |
72 else | |
73 UI_TOGGLE = true | |
74 end | |
75 for i, frame in pairs(KT.frames) do | |
76 if UI_TOGGLE then | |
77 if frame.close then | |
78 frame.close() | |
79 else | |
80 frame:Hide() | |
81 end | |
82 else | |
83 if frame.ui then | |
84 frame.ui() | |
85 end | |
86 frame:Show() | |
87 end | |
88 end | |
89 end | |
90 | |
91 LibKTError = function(msg) | |
92 local dstack = debugstack(2) | |
93 :gsub("Interface\\AddOns\\",'') | |
94 :gsub("<(.-)>", function(a) return '|cFF00FFFF<'.. a ..'>|r' end) | |
95 | |
96 | |
97 | |
98 KTErrorFrame.errmsg:SetText(msg) | |
99 KTErrorFrame.debugstack:SetText(dstack) | |
100 KTErrorFrame:SetHeight(KTErrorFrame.debugstack:GetStringHeight() + KTErrorFrame.errmsg:GetStringHeight() + 12) | |
101 KTErrorFrame:Show() | |
102 end | |
103 | |
104 local debuggers = {} | |
105 local pending = {} | |
106 local processing = false | |
107 local isHandled = false | |
108 local nodebug = false | |
109 function KT.OnEvent (addon, event, ...) | |
110 if processing then | |
111 local args = {...} | |
112 C_Timer.After(0, function() KT.OnEvent(addon, event, unpack(args)) end) | |
113 return | |
114 else | |
115 | |
116 end | |
117 --- reset state | |
118 processing = true | |
119 isHandled = false | |
120 nodebug = false | |
121 | |
122 | |
123 if addon.event then | |
124 nodebug = addon.event(addon, event, ...) | |
125 end | |
126 | |
127 if addon[event] then | |
128 nodebug = addon[event](addon, event, ...) or nodebug | |
129 addon.missed = 0 | |
130 addon.handled = addon.handled + 1 | |
131 isHandled = true | |
132 else | |
133 addon.firstEvent = false | |
134 addon.unhandled = addon.unhandled + 1 | |
135 addon.missed = addon.missed + 1 | |
136 end | |
137 | |
138 for i, module in ipairs(addon.modules) do | |
139 --print(i, module) | |
140 if module[event] then | |
141 nodebug = module[event](addon, event, ...) or nodebug | |
142 addon.missed = 0 | |
143 addon.handled = addon.handled + 1 | |
144 isHandled = true | |
145 else | |
146 addon.firstEvent = false | |
147 addon.unhandled = addon.unhandled + 1 | |
148 addon.missed = addon.missed + 1 | |
149 end | |
150 | |
151 end | |
152 --if nodebug then | |
153 processing = false | |
154 return | |
155 --else | |
156 -- KT.UpdateEventStatus(addon, event, ...) | |
157 -- processing = false | |
158 --end | |
159 | |
160 end | |
161 | |
162 KT.UpdateEventStatus = function(addon, event, ...) | |
163 if (addon.DEVIAN_PNAME and addon.DEVIAN_PNAME == DEVIAN_PNAME) or ((not addon.DEVIAN_PNAME) and DEVIAN_WORKSPACE) then | |
164 print(addon:GetName(), event, ...) | |
165 end | |
166 | |
167 -- debug outputs | |
168 if addon.status then | |
169 addon.status:SetText(event .. '\n|cFF00FF00' .. addon.handled .. '|r |cFFFF8800' .. addon.missed .. '|r |cFFFF4400' .. addon.unhandled .. '|r') | |
170 if isHandled then | |
171 addon.status:SetTextColor(0,1,0) | |
172 if addon.log then | |
173 local logtext = event | |
174 for i = 1, select('#',...) do | |
175 logtext = logtext .. '\n' .. i .. ':' .. tostring(select(i,...)) | |
176 end | |
177 addon.log:SetText('|cFFFFFF00last|r\n' .. logtext) | |
178 local newWidth = addon.log:GetStringWidth() | |
179 | |
180 if addon.logfirst then | |
181 if not addon.firstEvent then | |
182 addon.firstEvent = event | |
183 addon.logfirst:SetText('|cFF00FF88first|r\n' .. logtext) | |
184 end | |
185 | |
186 newWidth = newWidth + addon.logfirst:GetStringWidth() | |
187 end | |
188 if addon.logdiff then | |
189 if not event ~= addon.firstEvent then | |
190 addon.firstEvent = event | |
191 addon.logdiff:SetText('|cFF0088FFdiff|r\n' .. logtext) | |
192 end | |
193 newWidth = newWidth + addon.logdiff:GetStringWidth() | |
194 end | |
195 --addon:SetWidth(newWidth) | |
196 end | |
197 else | |
198 addon.status:SetTextColor(1,0,0) | |
199 end | |
200 end | |
201 end | |
202 | |
203 KT.map = function(addon, addonTable) | |
204 setmetatable(addonTable, { | |
205 __index = function(_,k) | |
206 return addon[k] | |
207 end, | |
208 __newindex = function(_, k, v) | |
209 addon[k] = v | |
210 end | |
211 }) | |
212 end | |
213 | |
214 local emptyFunc = function() end | |
215 | |
216 KT.register = function(addon, arg, noGUI) | |
217 | |
218 local name, handler | |
219 if type(addon) == 'string' and type(arg) == 'table' then | |
220 -- it's a string, i.e. file vararg was passed | |
221 if _G[addon] then | |
222 -- check if it's the name of a frame and use that | |
223 handler = _G[addon] | |
224 else | |
225 -- re-arrange | |
226 name = addon | |
227 handler = arg | |
228 end | |
229 else | |
230 handler = addon | |
231 assert(type(handler) == 'table', 'Unable to parse ('..tostring(type(addon))..', '..tostring(type(arg))..')') | |
232 end | |
233 | |
234 | |
235 local loadedName | |
236 local printName | |
237 local isModule | |
238 | |
239 -- if exists, then second argument is probably a module name | |
240 if registeredHandles[handler] then | |
241 if type(arg) == 'table' then | |
242 tinsert(handler.modules, arg) | |
243 else | |
244 name = arg or debugstack(2,1,0):match(".+\\(%S+)%.lua") | |
245 end | |
246 isModule = true | |
247 | |
248 if not name then | |
249 name = debugstack(2,1,0):match(".+\\(%S+)%.lua") | |
250 end | |
251 local handlerName = handler:GetName() | |
252 loadedName = '|cFF00FF88'.. tostring(handlerName) .. '|r:|cFFFFFF00'.. tostring(name) | |
253 else | |
254 if handler.GetName then | |
255 name = handler:GetName() | |
256 elseif not name then | |
257 name = debugstack(2,1,0):match(".+\\(%S+)%.lua") | |
258 end | |
259 | |
260 loadedName = '|cFF00FFFF'.. tostring(name) .. '|r' | |
261 | |
262 registeredHandles[handler] = name | |
263 if handler.SetScript then | |
264 handler:SetScript('OnEvent', KT.OnEvent) | |
265 end | |
266 handler.unhandled = 0 | |
267 handler.missed = 0 | |
268 handler.handled = 0 | |
269 handler.firstEvent = false | |
270 handler.modules = {} | |
271 tinsert(KT.initStack, handler) | |
272 tinsert(KT.varsStack, handler) | |
273 | |
274 if handler.GetName and (not noGUI) then | |
275 handler.UIPanelAnchor = {'TOPLEFT', handler, 'TOPLEFT', 12, -12 } | |
276 handler.UIPanelGrowth = {'TOPLEFT', 'TOPRIGHT', 14, 0} | |
277 handler.button = KT.button | |
278 handler.uibutton = KT.uibutton | |
279 handler.tab = KT.tab | |
280 handler.print = KT.print | |
281 end | |
282 end | |
283 | |
284 local debugID = isModule and name or handler | |
285 local debugFunc = emptyFunc | |
286 if (handler.DEVIAN_PNAME and DEVIAN_PNAME == handler.DEVIAN_PNAME) or ((not handler.DEVIAN_PNAME) and DEVIAN_WORKSPACE) then | |
287 debuggers[debugID] = debuggers[debugID] or function(...) _G.print(name, ...) end | |
288 debugFunc = debuggers[debugID] | |
289 end | |
290 | |
291 print(loadedName) | |
292 | |
293 return handler, debugFunc, KT.wrap | |
294 end | |
295 | |
296 | |
297 | |
298 local onEvent = function(self, event, arg1) | |
299 if (event == 'ADDON_LOADED' and arg1 ~= 'Blizzard_DebugTools') or event == 'PLAYER_LOGIN' then | |
300 -- run any init blocks left in the queue | |
301 while #KT.initStack >= 1 do | |
302 local addon = tremove(KT.initStack, 1) | |
303 print('KT', addon:GetName(), 'init') | |
304 if addon.init then | |
305 xpcall(addon.init, LibKTError) | |
306 for i, module in ipairs(addon.modules) do | |
307 if module.init then | |
308 xpcall(module.init, LibKTError) | |
309 end | |
310 end | |
311 end | |
312 end | |
313 | |
314 -- run any variables blocks if player variables are ready | |
315 if IsLoggedIn() and #KT.varsStack >= 1 then | |
316 while #KT.varsStack >= 1 do | |
317 local addon = tremove(KT.varsStack, 1) | |
318 print(addon:GetName()) | |
319 if addon.variables then | |
320 xpcall(addon.variables, LibKTError) | |
321 for i, module in ipairs(addon.modules) do | |
322 if module.variables then | |
323 xpcall(module.variables, LibKTError) | |
324 end | |
325 end | |
326 end | |
327 end | |
328 end | |
329 end | |
330 end | |
331 | |
332 KT.print = function(module, ...) | |
333 local msg = '|cFF00FFFF'..module:GetName()..'|r:' | |
334 for i = 1, select('#', ...) do | |
335 msg = msg .. ' ' .. tostring(select(i, ...)) | |
336 end | |
337 DEFAULT_CHAT_FRAME:AddMessage(msg) | |
338 end | |
339 | |
340 --- Button generators | |
341 | |
342 local GetButtonTemplate = function(name, parent, template, onClick) | |
343 if _G[name] then | |
344 return _G[name] | |
345 end | |
346 | |
347 local button = CreateFrame('Button', name, parent, template) | |
348 button:RegisterForClicks('AnyUp') | |
349 button:SetScript('OnClick', onClick) | |
350 return button | |
351 end | |
352 | |
353 local SetButtonAnchor = function(self, collector, anchor, growth) | |
354 if self:GetID() == 0 then | |
355 self:SetID(#collector) | |
356 print('registered TabButton #', self:GetID()) | |
357 end | |
358 | |
359 if self:GetID() == 1 then | |
360 self:SetPoint(unpack(anchor)) | |
361 else | |
362 growth[2] = collector[self:GetID()-1] | |
363 self:SetPoint(unpack(growth)) | |
364 end | |
365 end | |
366 | |
367 KT.tab = function(self, name, tooltip, texture, coords) | |
368 local button = GetButtonTemplate(name, self, 'KTTabButton', self.SelectTab) | |
369 button.icon:SetTexture(texture) | |
370 button.tooltip = tooltip | |
371 button:SetSize(unpack(self.tabSize)) | |
372 if coords then | |
373 button.icon:SetTexCoord(unpack(coords)) | |
374 end | |
375 SetButtonAnchor(button, self.tabButtons, self.tabAnchor, self.tabGrowth) | |
376 return button | |
377 end | |
378 | |
379 KT.button = function(self, name, text, tooltip, onClick) | |
380 local button = GetButtonTemplate(name, self, 'KTButton', onClick) | |
381 | |
382 button.tooltip = tooltip | |
383 button:SetText(text) | |
384 button:SetWidth(max(button:GetWidth(), button:GetFontString():GetStringWidth() + 12)) | |
385 | |
386 SetButtonAnchor(button, self.controls, self.controlsAnchor, self.controlsGrowth) | |
387 return button | |
388 end | |
389 | |
390 KT.uibutton = function(self, name, text, tooltip, onClick, texture, coords) | |
391 local button = GetButtonTemplate(name, self, 'KTUIPanelButton', onClick) | |
392 | |
393 button.tooltip = tooltip | |
394 button:SetText(text) | |
395 | |
396 if self.UIPanelIcon then | |
397 local w, h, anchor, x, y = unpack(self.UIPanelIcon) | |
398 button.icon:SetTexture(texture) | |
399 button.icon:SetSize(w, h) | |
400 button.icon:ClearAllPoints() | |
401 button.icon:SetPoint(anchor, button, anchor, x, y) | |
402 end | |
403 | |
404 if not self.UIPanelSize then | |
405 button:SetWidth(button:GetFontString():GetStringWidth() + button.icon:GetWidth()/1.5) | |
406 else | |
407 button:SetSize(unpack(self.UIPanelSize)) | |
408 end | |
409 if coords then | |
410 button.icon:SetTexCoord(unpack(coords)) | |
411 end | |
412 SetButtonAnchor(button, self.UIPanels, self.UIPanelAnchor, self.UIPanelGrowth) | |
413 return button | |
414 end | |
415 | |
416 --- Co-routine Handler kajigger | |
417 do | |
418 local tickerQueue = {} | |
419 local ticker | |
420 local instant = false | |
421 KT.tick = function() | |
422 | |
423 if #tickerQueue == 0 then | |
424 ticker:Cancel() | |
425 ticker = nil | |
426 end | |
427 local func = tremove(tickerQueue, 1) | |
428 if func then | |
429 --print('#', #tickerQueue) | |
430 func() | |
431 end | |
432 end | |
433 | |
434 KT.wrap = function(f) | |
435 if not ticker then | |
436 --print('create ticker') | |
437 ticker = C_Timer.NewTicker(.001, KT.tick) | |
438 end | |
439 tinsert(tickerQueue, f) | |
440 | |
441 return #tickerQueue | |
442 | |
443 end | |
444 end | |
445 | |
446 KT.handler:RegisterEvent('ADDON_LOADED') | |
447 KT.handler:RegisterEvent('PLAYER_LOGIN') | |
448 KT.handler:SetScript('OnEvent', onEvent) |