diff LibKraken/LibKraken.lua @ 59:d8bb2629fea8

LKT - organized addon templates a little - centralized ticker
author Nenue
date Sat, 27 Aug 2016 10:31:48 -0400
parents 9eebce04e69b
children 256585077cdd
line wrap: on
line diff
--- a/LibKraken/LibKraken.lua	Mon Aug 22 09:24:33 2016 -0400
+++ b/LibKraken/LibKraken.lua	Sat Aug 27 10:31:48 2016 -0400
@@ -41,54 +41,39 @@
 
 --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 max, unpack, tinsert, tremove = max, unpack, tinsert, tremove
+local ipairs, pairs, xpcall = ipairs, pairs, xpcall
+local type, assert = type, assert
+local IsLoggedIn = IsLoggedIn
 local db
 
+local print = DEVIAN_WORKSPACE and function(...) _G.print('LKT', ...) end or function() end
+local noFunc = function() end
 
 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 libInitialized = false
 local registeredHandles = {}
+local initialized = {}
+local enabled = {}
 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()
+local debuggers = {}
+local pending = {}
+
+
+local Embed = function (target, template)
+  for k,v in pairs(template) do
+    if not target[k] then
+      target[k] = template[k]
     end
   end
 end
 
-LibKTError = function(msg)
+local LibKT_Error = function(msg)
   local dstack = debugstack(2)
   :gsub("Interface\\AddOns\\",'')
   :gsub("<(.-)>", function(a) return '|cFF00FFFF<'.. a ..'>|r' end)
@@ -101,226 +86,81 @@
   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
+local LibKT_OnLoad = function(self)
+  --- /rl
+  -- ReloadUI shortcut
+  SLASH_RL1 = "/rl"
+  SlashCmdList.RL = function ()
+    ReloadUI()
+  end
+  libInitialized = true
+end
 
-  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
+local LibKT_OnEvent = function(self, event, arg1)
+  print(event, arg1)
+  if (event == 'ADDON_LOADED' and arg1 ~= 'Blizzard_DebugTools') or event == 'PLAYER_LOGIN' then
+    if not libInitialized then
+      LibKT_OnLoad(self)
     end
 
-  end
-  --if nodebug then
-    processing = false
-    return
-  --else
-  --  KT.UpdateEventStatus(addon, event, ...)
-  --  processing = false
-  --end
 
-end
+      -- run any init blocks left in the queue
+    for i, addon in  ipairs(KT.initStack) do
+      if not initialized[addon] then
+        print('|cFF0088FF'..tostring(addon)..'|r:init()')
+        if addon.init then
+          xpcall(addon.init, LibKT_Error)
+        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
+        if addon.event then
+          addon:SetScript('OnEvent', addon.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()
+        initialized[addon] = true
+      end
 
-        if addon.logfirst then
-          if not addon.firstEvent then
-            addon.firstEvent = event
-            addon.logfirst:SetText('|cFF00FF88first|r\n' .. logtext)
-          end
+      if #addon.modules >= 1 then
+        for i, module in ipairs(addon.modules) do
+          if not initialized[module] then
+            print(i .. ' |cFF0088FF'..tostring(addon)..'|r.|cFF00FFFF'..tostring(module)..'|r:init()')
+            if module.init then
+              xpcall(module.init, LibKT_Error)
+            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)
+            if module.event then
+              module:SetScript('OnEvent', module.event)
+            end
+            initialized[module] = true
           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)
+    if IsLoggedIn() then
+
+      for i, addon in  ipairs(KT.initStack) do
+        print('|cFF88FF00'..tostring(addon)..'|r')
+        if initialized[addon] then
+          if not enabled[addon] then
+            print('|cFF88FF00'..tostring(addon)..'|r:variables()')
+            if addon.variables then
+              xpcall(addon.variables, LibKT_Error)
+            end
+            enabled[addon] = true
+          end
+
+          if addon.modules and enabled[addon] then
+            for i, module in ipairs(addon.modules) do
+              print(i .. ' |cFF88FF00'..tostring(module)..'|r')
+              if not enabled[module] then
+                if module.variables then
+                  print(i..' |cFF88FF00'..tostring(addon)..'|r.|cFF00FFFF'.. tostring(module)..'|r:variables()')
+                  xpcall(module.variables, LibKT_Error)
+                end
+                enabled[module] = true
+              end
             end
           end
         end
@@ -329,96 +169,99 @@
   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
+--- GUI bits
+local defaultGUIAddon = {}
+do
+  local GetButtonTemplate = function(name, parent, template, onClick)
+    if _G[name] then
+      return _G[name]
+    end
 
---- Button generators
-
-local GetButtonTemplate = function(name, parent, template, onClick)
-  if _G[name] then
-    return _G[name]
+    local button = CreateFrame('Button', name, parent, template)
+    button:RegisterForClicks('AnyUp')
+    button:SetScript('OnClick', onClick)
+    return button
   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
 
-local SetButtonAnchor = function(self, collector, anchor, growth)
-  if self:GetID() == 0 then
-    self:SetID(#collector)
-    print('registered TabButton #', self:GetID())
+    if self:GetID() == 1 then
+      self:SetPoint(unpack(anchor))
+    else
+      growth[2] = collector[self:GetID()-1]
+      self:SetPoint(unpack(growth))
+    end
   end
 
-  if self:GetID() == 1 then
-    self:SetPoint(unpack(anchor))
-  else
-    growth[2] = collector[self:GetID()-1]
-    self:SetPoint(unpack(growth))
+  defaultGUIAddon.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
+
+  defaultGUIAddon.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
+
+  defaultGUIAddon.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
 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)
+local defaultAddon = {}
+do
+  defaultAddon.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
 
-  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()
+  defaultAddon.tick = function()
 
     if #tickerQueue == 0 then
       ticker:Cancel()
@@ -431,18 +274,169 @@
     end
   end
 
-  KT.wrap = function(f)
+  defaultAddon.next = function(f)
     if not ticker then
       --print('create ticker')
-      ticker = C_Timer.NewTicker(.001, KT.tick)
+      ticker = C_Timer.NewTicker(.001, defaultAddon.tick)
     end
     tinsert(tickerQueue, f)
 
     return #tickerQueue
+  end
+
+
+--- default OnEvent
+
+  local processing = false
+  local isHandled = false
+  local nodebug = false
+  defaultAddon.event = function (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, ...)
+    elseif 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
+
+    if addon.modules then
+      for i, module in ipairs(addon.modules) do
+        --print(i, module, event)
+        if module.event then
+          module.event(module, event, ...)
+        elseif 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
+    end
+    --if nodebug then
+    processing = false
+    return
+    --else
+    --  KT.UpdateEventStatus(addon, event, ...)
+    --  processing = false
+    --end
 
   end
+  defaultAddon.wrap = function(addon, module, name)
+    local moduleName = name or tostring(module)
+    print(addon, module)
+    print('|cFF0088FF'..tostring(addon)..'|r:wrap(|cFF00FFFF'.. moduleName .. '|r|cFFFFFF00)|r')
+
+    addon.modules = addon.modules or {}
+    tinsert(addon.modules, module)
+
+
+    if (module.DEVIAN_PNAME and DEVIAN_PNAME == module.DEVIAN_PNAME) or ((not module.DEVIAN_PNAME) and DEVIAN_WORKSPACE) then
+      debuggers[module] = function(...) _G.print(moduleName, ...) end
+    else
+      debuggers[module] = noFunc
+    end
+    return debuggers[module]
+  end
+
+  defaultAddon.GetName = function(self) return tostring(self) end
+end
+
+--- Frame registration
+KT.register = function(addon, arg, noGUI)
+  --print('register(', addon, arg, ')')
+  local name, handler
+  if type(addon) == 'string' and type(arg) == 'table' then
+    name = addon
+    -- 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
+      handler = arg
+    end
+  else
+    handler = addon
+    assert(type(handler) == 'table', 'Usage: KT.register(name, table) or KT.register(table, plugin)')
+  end
+
+
+  local printName
+  local isModule
+
+  local scriptName = debugstack(2,1,0):match(".+\\(%S+)%.lua")
+  if registeredHandles[handler] then
+    -- addon is already register; treat second argument as plugin target
+    isModule = true
+    if type(arg) == 'table' then
+      local mt = getmetatable(arg)
+      setmetatable(arg, {__index = mt.__index, __tostring = function() return scriptName end})
+      local debugger = handler:wrap(arg)
+      return handler, debugger
+    else
+      print(' + "|cFF00FFFF'..scriptName..'|r"')
+    end
+  else
+    -- new addon
+    --local scriptName = debugstack(2,1,0):match(".+\\(%S+)%.lua")
+    local mt = getmetatable(handler)
+    local nmt = {__index = mt.__index, __tostring = function() return scriptName end }
+    handler = setmetatable(handler, nmt)
+    Embed(handler, defaultAddon)
+    name = tostring(handler)
+    registeredHandles[handler] = name
+    if handler.SetScript then
+      handler:SetScript('OnEvent', handler.event)
+    end
+    handler.unhandled = 0
+    handler.missed = 0
+    handler.handled = 0
+    handler.firstEvent = false
+    handler.modules = {}
+    tinsert(KT.initStack, handler)
+
+    if not noGUI then
+      handler.UIPanelAnchor = {'TOPLEFT', handler, 'TOPLEFT', 12, -12 }
+      handler.UIPanelGrowth = {'TOPLEFT', 'TOPRIGHT', 14, 0}
+      Embed(handler, defaultGUIAddon)
+    end
+
+    print('|cFF0088FF'..tostring(addon)..'|r')
+  end
+
+  local debugFunc = noFunc
+  --@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
+  --@end-debug@
+  return handler, debugFunc
 end
 
 KT.handler:RegisterEvent('ADDON_LOADED')
 KT.handler:RegisterEvent('PLAYER_LOGIN')
-KT.handler:SetScript('OnEvent', onEvent)
\ No newline at end of file
+KT.handler:SetScript('OnEvent', LibKT_OnEvent)
\ No newline at end of file