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)