Mercurial > wow > skeletonkey
changeset 37:ae012c9d8dc5
more logjam cleanup
author | Nenue |
---|---|
date | Tue, 16 Aug 2016 10:28:37 -0400 |
parents | 1e1fc3204bfc |
children | 93e2a51b3a52 |
files | LibKraken/LibKraken.lua |
diffstat | 1 files changed, 448 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LibKraken/LibKraken.lua Tue Aug 16 10:28:37 2016 -0400 @@ -0,0 +1,448 @@ +--[[ +-- KrakynTools +-- AddOn prototyping library. +-- +--- Bundles an object into the handler queue, returning the core object, and handlers for debug output and co-routine. +-- Addon name is determined in order of: (string first arg, second arg :GetName(), invoking filename). +-- Once an addon name/object is registered, subsequent calls will return a debugger that reports the file or plugin name. +-- @usage addon, print, wrap = KT.register(name, table) or KT.register(addon) or KT.register(addon, plugin) +-- @param name - name of addon, as found in global varargs +-- @param table - addon table from global varargs +-- +-- @param frame - frame object used by addon +-- @param plugin - string name of plugin or an object table to check for lib handlers +-- +-- Handlers: +-- :init() run immediately after KT sets itself up +-- :profile("Name-TruncatedRealm") called the first time SavedVars data becomes available +-- :variables() called upon variables being available +-- :event(event, ...) replaces the event callback +-- :ui() called by /ui when activating +-- +-- Embedded: +-- NOTES: +-- * `name' is passed as is into CreateFrame, so using nil produce an anonymous frame +-- * `coord' is a 4 or 8 size table unpacked into Texture:SetTexCoords() +-- +-- tab = frame:tab(name, tooltip, texture, coord) +-- produces a serial button that changes display tabs +-- +-- button = frame:button(name, text, tooltip, onClick) +-- produces a button with OnClick script +-- +-- uibutton = frame:uibutton(name, text, tooltip, onClick, texture, coord) +-- produces a header button with desired onClick +-- +-- +]]-- + +local LIBKT_MAJOR, LIBKT_MINOR = "LibKraken", 2 +local KT = LibStub:NewLibrary(LIBKT_MAJOR, LIBKT_MINOR) + +--GLOBALS: KTErrorFrame, LibKTError, SlashCmdList, SLASH_RL1, SLASH_UI1 +local CreateFrame, debugstack, tostring, select = CreateFrame, debugstack, tostring, select +local max, unpack, tinsert = max, unpack, tinsert +local ipairs, xpcall, next, safecall = ipairs, xpcall, next, safecall +local UI_TOGGLE = false +local db + + +KT.handler = CreateFrame('Frame', 'LibKTHostFrame', UIParent) +KT.addons = {} +KT.initStack = {} +KT.varsStack = {} +local print = DEVIAN_WORKSPACE and function(...) _G.print('LKT', ...) end or function() end +local registeredHandles = {} +local handlers = {} + + +--- /rl +-- ReloadUI shortcut +SLASH_RL1 = "/rl" +SlashCmdList.RL = function () + ReloadUI() +end + +--- /ui +-- Run any addon:ui() methods +SLASH_UI1 = "/ui" +SlashCmdList.UI = function () + if UI_TOGGLE then + UI_TOGGLE = false + else + UI_TOGGLE = true + end + for i, frame in pairs(KT.frames) do + if UI_TOGGLE then + if frame.close then + frame.close() + else + frame:Hide() + end + else + if frame.ui then + frame.ui() + end + frame:Show() + end + end +end + +LibKTError = function(msg) + local dstack = debugstack(2) + :gsub("Interface\\AddOns\\",'') + :gsub("<(.-)>", function(a) return '|cFF00FFFF<'.. a ..'>|r' end) + + + + KTErrorFrame.errmsg:SetText(msg) + KTErrorFrame.debugstack:SetText(dstack) + KTErrorFrame:SetHeight(KTErrorFrame.debugstack:GetStringHeight() + KTErrorFrame.errmsg:GetStringHeight() + 12) + KTErrorFrame:Show() +end + +local debuggers = {} +local pending = {} +local processing = false +local isHandled = false +local nodebug = false +function KT.OnEvent (addon, event, ...) + if processing then + local args = {...} + C_Timer.After(0, function() KT.OnEvent(addon, event, unpack(args)) end) + return + else + + end + --- reset state + processing = true + isHandled = false + nodebug = false + + + if addon.event then + nodebug = addon.event(addon, event, ...) + end + + if addon[event] then + nodebug = addon[event](addon, event, ...) or nodebug + addon.missed = 0 + addon.handled = addon.handled + 1 + isHandled = true + else + addon.firstEvent = false + addon.unhandled = addon.unhandled + 1 + addon.missed = addon.missed + 1 + end + + for i, module in ipairs(addon.modules) do + --print(i, module) + if module[event] then + nodebug = module[event](addon, event, ...) or nodebug + addon.missed = 0 + addon.handled = addon.handled + 1 + isHandled = true + else + addon.firstEvent = false + addon.unhandled = addon.unhandled + 1 + addon.missed = addon.missed + 1 + end + + end + --if nodebug then + processing = false + return + --else + -- KT.UpdateEventStatus(addon, event, ...) + -- processing = false + --end + +end + +KT.UpdateEventStatus = function(addon, event, ...) + if (addon.DEVIAN_PNAME and addon.DEVIAN_PNAME == DEVIAN_PNAME) or ((not addon.DEVIAN_PNAME) and DEVIAN_WORKSPACE) then + print(addon:GetName(), event, ...) + end + + -- debug outputs + if addon.status then + addon.status:SetText(event .. '\n|cFF00FF00' .. addon.handled .. '|r |cFFFF8800' .. addon.missed .. '|r |cFFFF4400' .. addon.unhandled .. '|r') + if isHandled then + addon.status:SetTextColor(0,1,0) + if addon.log then + local logtext = event + for i = 1, select('#',...) do + logtext = logtext .. '\n' .. i .. ':' .. tostring(select(i,...)) + end + addon.log:SetText('|cFFFFFF00last|r\n' .. logtext) + local newWidth = addon.log:GetStringWidth() + + if addon.logfirst then + if not addon.firstEvent then + addon.firstEvent = event + addon.logfirst:SetText('|cFF00FF88first|r\n' .. logtext) + end + + newWidth = newWidth + addon.logfirst:GetStringWidth() + end + if addon.logdiff then + if not event ~= addon.firstEvent then + addon.firstEvent = event + addon.logdiff:SetText('|cFF0088FFdiff|r\n' .. logtext) + end + newWidth = newWidth + addon.logdiff:GetStringWidth() + end + --addon:SetWidth(newWidth) + end + else + addon.status:SetTextColor(1,0,0) + end + end +end + +KT.map = function(addon, addonTable) + setmetatable(addonTable, { + __index = function(_,k) + return addon[k] + end, + __newindex = function(_, k, v) + addon[k] = v + end + }) +end + +local emptyFunc = function() end + +KT.register = function(addon, arg, noGUI) + + local name, handler + if type(addon) == 'string' and type(arg) == 'table' then + -- it's a string, i.e. file vararg was passed + if _G[addon] then + -- check if it's the name of a frame and use that + handler = _G[addon] + else + -- re-arrange + name = addon + handler = arg + end + else + handler = addon + assert(type(handler) == 'table', 'Unable to parse ('..tostring(type(addon))..', '..tostring(type(arg))..')') + end + + + local loadedName + local printName + local isModule + + -- if exists, then second argument is probably a module name + if registeredHandles[handler] then + if type(arg) == 'table' then + tinsert(handler.modules, arg) + else + name = arg or debugstack(2,1,0):match(".+\\(%S+)%.lua") + end + isModule = true + + if not name then + name = debugstack(2,1,0):match(".+\\(%S+)%.lua") + end + local handlerName = handler:GetName() + loadedName = '|cFF00FF88'.. tostring(handlerName) .. '|r:|cFFFFFF00'.. tostring(name) + else + if handler.GetName then + name = handler:GetName() + elseif not name then + name = debugstack(2,1,0):match(".+\\(%S+)%.lua") + end + + loadedName = '|cFF00FFFF'.. tostring(name) .. '|r' + + registeredHandles[handler] = name + if handler.SetScript then + handler:SetScript('OnEvent', KT.OnEvent) + end + handler.unhandled = 0 + handler.missed = 0 + handler.handled = 0 + handler.firstEvent = false + handler.modules = {} + tinsert(KT.initStack, handler) + tinsert(KT.varsStack, handler) + + if handler.GetName and (not noGUI) then + handler.UIPanelAnchor = {'TOPLEFT', handler, 'TOPLEFT', 12, -12 } + handler.UIPanelGrowth = {'TOPLEFT', 'TOPRIGHT', 14, 0} + handler.button = KT.button + handler.uibutton = KT.uibutton + handler.tab = KT.tab + handler.print = KT.print + end + end + + local debugID = isModule and name or handler + local debugFunc = emptyFunc + if (handler.DEVIAN_PNAME and DEVIAN_PNAME == handler.DEVIAN_PNAME) or ((not handler.DEVIAN_PNAME) and DEVIAN_WORKSPACE) then + debuggers[debugID] = debuggers[debugID] or function(...) _G.print(name, ...) end + debugFunc = debuggers[debugID] + end + + print(loadedName) + + return handler, debugFunc, KT.wrap +end + + + +local onEvent = function(self, event, arg1) + if (event == 'ADDON_LOADED' and arg1 ~= 'Blizzard_DebugTools') or event == 'PLAYER_LOGIN' then + -- run any init blocks left in the queue + while #KT.initStack >= 1 do + local addon = tremove(KT.initStack, 1) + print('KT', addon:GetName(), 'init') + if addon.init then + xpcall(addon.init, LibKTError) + for i, module in ipairs(addon.modules) do + if module.init then + xpcall(module.init, LibKTError) + end + end + end + end + + -- run any variables blocks if player variables are ready + if IsLoggedIn() and #KT.varsStack >= 1 then + while #KT.varsStack >= 1 do + local addon = tremove(KT.varsStack, 1) + print(addon:GetName()) + if addon.variables then + xpcall(addon.variables, LibKTError) + for i, module in ipairs(addon.modules) do + if module.variables then + xpcall(module.variables, LibKTError) + end + end + end + end + end + end +end + +KT.print = function(module, ...) + local msg = '|cFF00FFFF'..module:GetName()..'|r:' + for i = 1, select('#', ...) do + msg = msg .. ' ' .. tostring(select(i, ...)) + end + DEFAULT_CHAT_FRAME:AddMessage(msg) +end + +--- Button generators + +local GetButtonTemplate = function(name, parent, template, onClick) + if _G[name] then + return _G[name] + end + + local button = CreateFrame('Button', name, parent, template) + button:RegisterForClicks('AnyUp') + button:SetScript('OnClick', onClick) + return button +end + +local SetButtonAnchor = function(self, collector, anchor, growth) + if self:GetID() == 0 then + self:SetID(#collector) + print('registered TabButton #', self:GetID()) + end + + if self:GetID() == 1 then + self:SetPoint(unpack(anchor)) + else + growth[2] = collector[self:GetID()-1] + self:SetPoint(unpack(growth)) + end +end + +KT.tab = function(self, name, tooltip, texture, coords) + local button = GetButtonTemplate(name, self, 'KTTabButton', self.SelectTab) + button.icon:SetTexture(texture) + button.tooltip = tooltip + button:SetSize(unpack(self.tabSize)) + if coords then + button.icon:SetTexCoord(unpack(coords)) + end + SetButtonAnchor(button, self.tabButtons, self.tabAnchor, self.tabGrowth) + return button +end + +KT.button = function(self, name, text, tooltip, onClick) + local button = GetButtonTemplate(name, self, 'KTButton', onClick) + + button.tooltip = tooltip + button:SetText(text) + button:SetWidth(max(button:GetWidth(), button:GetFontString():GetStringWidth() + 12)) + + SetButtonAnchor(button, self.controls, self.controlsAnchor, self.controlsGrowth) + return button +end + +KT.uibutton = function(self, name, text, tooltip, onClick, texture, coords) + local button = GetButtonTemplate(name, self, 'KTUIPanelButton', onClick) + + button.tooltip = tooltip + button:SetText(text) + + if self.UIPanelIcon then + local w, h, anchor, x, y = unpack(self.UIPanelIcon) + button.icon:SetTexture(texture) + button.icon:SetSize(w, h) + button.icon:ClearAllPoints() + button.icon:SetPoint(anchor, button, anchor, x, y) + end + + if not self.UIPanelSize then + button:SetWidth(button:GetFontString():GetStringWidth() + button.icon:GetWidth()/1.5) + else + button:SetSize(unpack(self.UIPanelSize)) + end + if coords then + button.icon:SetTexCoord(unpack(coords)) + end + SetButtonAnchor(button, self.UIPanels, self.UIPanelAnchor, self.UIPanelGrowth) + return button +end + +--- Co-routine Handler kajigger +do + local tickerQueue = {} + local ticker + local instant = false + KT.tick = function() + + if #tickerQueue == 0 then + ticker:Cancel() + ticker = nil + end + local func = tremove(tickerQueue, 1) + if func then + --print('#', #tickerQueue) + func() + end + end + + KT.wrap = function(f) + if not ticker then + --print('create ticker') + ticker = C_Timer.NewTicker(.001, KT.tick) + end + tinsert(tickerQueue, f) + + return #tickerQueue + + end +end + +KT.handler:RegisterEvent('ADDON_LOADED') +KT.handler:RegisterEvent('PLAYER_LOGIN') +KT.handler:SetScript('OnEvent', onEvent) \ No newline at end of file