diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LibKraken/LibKraken-1.0.lua	Tue Jul 26 19:29:44 2016 -0400
@@ -0,0 +1,357 @@
+--[[
+-- KrakynTools
+-- AddOn prototyping library.
+--
+-- Implements
+--  KT.register(frame) to hook the following (all optional):
+--    frame:init()                            run immediately after KT sets itself up
+--    frame:profile("Name-TruncatedRealm")    called the first time SavedVars data becomes available
+--    frame:variables()                       called upon variables being available
+--    frame:event(event, ...)                 replaces the event callback
+--    frame:ui()                              called by /ui when activating
+--
+--    frame:tab(name, tooltip, texture, coord)
+--      produces a serial button that changes display tabs
+--
+--    frame:button(name, text, tooltip, onClick)
+--      produces a button with OnClick script
+--
+--    frame:uibutton(name, text, tooltip, onClick, texture, coord)
+--      produces a header button with desired onClick
+--
+]]--
+
+local LIBKT_MAJOR, LIBKT_MINOR = "LibKraken", 1
+local KT = LibStub:NewLibrary(LIBKT_MAJOR, LIBKT_MINOR)
+
+--GLOBALS: LibKT, KrakTool, KTErrorFrame, LibKTError, SlashCmdList, SLASH_RL1, SLASH_UI1
+local CreateFrame, debugstack, tostring, select = CreateFrame, debugstack, tostring, select
+local print, max, unpack, tinsert = print, 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(...) print('LKT', ...) end or function() end
+local registeredHandles = {}
+
+--- /rl
+-- ReloadUI shortcut
+SLASH_RL1 = "/rl"
+SlashCmdList.RL = function ()
+  ReloadUI()
+end
+
+--- /kv addon ...
+-- Dumps table values from "addon", using the arguments as index values.
+-- Numerics are converted, and names that end with "()" will be called as such
+SLASH_KV1 = "/kv"
+SlashCmdList.KV = function (editbox, input)
+
+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 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, ...)
+  print(addon:GetName(), event, ...)
+
+  -- 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.register = function(addon, name, noGUI)
+  if registeredHandles[addon] then
+    name = name or debugstack(2,1,0):gsub("\\n.+", ""):gsub("^Interface\\AddOns\\", ""):gsub("%s+$", "")
+  else
+    if not name then
+      assert(type(addon) == 'table', 'Need a valid table.')
+      if addon.GetName then
+        name = addon:GetName()
+      else
+        name = debugstack(2,1,0):gsub("\\n.+", ""):gsub("^Interface\\AddOns\\", ""):gsub("%s+$", "")
+      end
+      assert(type(name) == 'string', 'Unable to resolve a valid stub name.')
+    end
+    -- if calling again, assume name is a file handle
+
+    registeredHandles[addon] = name
+    KT.addons[name] = addon
+    if addon.SetScript then
+      addon:SetScript('OnEvent', KT.OnEvent)
+    end
+    addon.unhandled = 0
+    addon.missed = 0
+    addon.handled = 0
+    addon.firstEvent = false
+    addon.modules = {}
+    tinsert(KT.initStack, addon)
+    tinsert(KT.varsStack, addon)
+
+    if addon.GetName and (not noGUI) then
+      addon.UIPanelAnchor = {'TOPLEFT', addon, 'TOPLEFT', 12, -12 }
+      addon.UIPanelGrowth = {'TOPLEFT', 'TOPRIGHT', 14, 0}
+      addon.button = KT.button
+      addon.uibutton = KT.uibutton
+      addon.tab = KT.tab
+      addon.print = KT.print
+    end
+  end
+
+  return addon, (DEVIAN_WORKSPACE and function(...) _G.print(name, ...) end or function() end)
+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
+
+
+KT.handler:RegisterEvent('ADDON_LOADED')
+KT.handler:RegisterEvent('PLAYER_LOGIN')
+KT.handler:SetScript('OnEvent', onEvent)
\ No newline at end of file