Mercurial > wow > skeletonkey
view LibKraken/LibKraken.lua @ 57:9eebce04e69b
- Prevent bind settings from being updated in combat.
- Close the UI during combat.
- Resolve conflicting keybinds and inform the user of any results.
- Resolve conflicts for talents, but only when they are active.
author | Nenue |
---|---|
date | Mon, 22 Aug 2016 09:24:02 -0400 |
parents | ae012c9d8dc5 |
children | d8bb2629fea8 |
line wrap: on
line source
--[[ -- 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 debugFunc = emptyFunc --@debug@ local debugID = isModule and name or handler 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) --@end-debug@ 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)