view Init.lua @ 28:c33c17dd97e7

file renames
author Nenue
date Wed, 13 Apr 2016 20:19:37 -0400
parents 66b927b46776
children e84d645c8ab8
line wrap: on
line source
--- Modulizer framework
-- OnInitialize
-- OnUpdate
-- OnEnable     -- run when GetSpecialization() returns true

local ADDON, A = ...
Veneer = Veneer or CreateFrame('Frame', 'Veneer', UIParent)
local B = Veneer
local wipe, min, max, random, tinsert, tremove = table.wipe, math.min, math.max, math.random, table.insert, table.remove
local pairs, ipairs, select, unpack, _G = pairs, ipairs, select, unpack, _G
local type, tostring, format = type, tostring, string.format
A.frame = B

--- Cache tables
local initOnced
local modules = {}
local queuedModules = {}
local checkForConfig = {}
local moduleStack = {
}

--- Various region categories
B.displays = {}
B.configLayers = {}
B.configLayersRef = {}

--@debug@
--- Generates a print handler pointing to a static channel signature
-- @usage func = B.print(sig)
-- @param sig channel name or number
local printfuncs = {}
B.print = function(pref, ...)
  if Devian and Devian.InWorkspace() then
      printfuncs[pref] = printfuncs[pref] or function(...) print(pref,  ...) end

    return printfuncs[pref]
  else
   return function () end
  end
end

local rgb = {}
local getcolor = function()
  local n, p = 0, 4
  for i = 1, 3 do
    rgb[i] = min(random(n,p) * 64, 255)
    if rgb[i] == 255 then
      p = 4
    elseif rgb[i] > 0 then
      n = 2
    end
  end
  return unpack(rgb)
end

local color = {}
local fprints = {}
B.fprint = function()
  if not (Devian and Devian.InWorkspace()) then
    return function() end
  end


  local sig = debugstack(2,1)
  if fprints[sig] then
    return fprints[sig]
  end

  local func = sig:match("%`(%a+)%'")
  if not func then
    func = sig:match("<(.-)>")
  end
  func = func:gsub('(%l+)(%u)', function(a, b) return a:sub(0,2) .. b  end, 1)
  func = func:gsub('^.+%\\', '')
  if not func then
    func = 'noname'
  end

  local r, g, b = getcolor()
  color[sig] = color[sig] or format('|cFF%02X%02X%02X%s|r', r, g, b, func)

  --print(color[func] .. ' ( ' .. table.concat(args, ', ')..' )' )
  func = B.print(func)
  fprints[sig] = func
  return func
end

--@end-debug@
--[=[@non-debug@
B.print = function() end
--@end-non-debug@]=]

-- for the Mikk script
-- GLOBALS: NUM_LE_RAID_BUFF_TYPES
-- GLOBALS: BUFF_FLASH_TIME_ON, BUFF_FLASH_TIME_OFF, BUFF_MIN_ALPHA, BUFF_WARNING_TIME, BUFF_DURATION_WARNING_TIME
-- GLOBALS: BUFFS_PER_ROW, BUFF_MAX_DISPLAY, BUFF_ACTUAL_DISPLAY, DEBUFF_MAX_DISPLAY, DEBUFF_ACTUAL_DISPLAY, BUFF_ROW_SPACING
-- GLOBALS: CONSOLIDATED_BUFFS_PER_ROW, CONSOLIDATED_BUFF_ROW_HEIGHT, NUM_TEMP_ENCHANT_FRAMES
-- GLOBALS: BUFF_BUTTON_HEIGHT, BUFF_FRAME_BASE_EXTENT, BUFF_HORIZ_SPACING

local print = B.print('Bfl')

--- Template for making perpendicular traversals of the displays structure; also makes sure the table is there
B.Abstract = function(dest, key, table)
  if table then
    for _, v in pairs(dest) do
      v[key] = {}
    end
  end
  B[key] = setmetatable({}, {
    __index = function(t, k)
      return dest[k][key]
    end,
    __newindex = function(_, k, v)
      print('abstract write ('..key..'):', k)
      dest[k][key] = v
    end,
    __tostring = function() return 'Abstract:'..key..'' end
  })


  return B[key]
end


--- localize for speed
local layers, refs, displays = B.configLayers, B.configLayersRef, B.displays

local ModulesCall = function(func, flag)

  local n = 0
  for i = 1, #moduleStack do
    print('calling level '..i)
    local stackset = moduleStack[i]

    for name, module in pairs(stackset) do
      n = n + 1


      if module[func] then
        -- nil = pass
        if not flag or module.Conf[flag] then
          if (flag) then
            print('  check', flag, '=', module.Conf[flag])
          end

          print(' ',n..'  '..name..'.'..func..'()')
          module[func](module, module.Conf)
        end

      end
    end
  end
end


local Enable = function()
end

--- The things that happen repeatedly
local Init = function ()
end


--- Things that happen immediately upon entering world
local InitOnce = function()
  print('entering world first time')
  local defaults = B.ConfDefaults
  print('|cFFFFFF00Veneer|r')
  if not VeneerData then
    VeneerData = {}
    for k,v in pairs(defaults) do


      VeneerData[k] = v
    end
    print('Veneer defaults being used.')
  end

  B.Conf = setmetatable(VeneerData, {__index = function(_, k) return defaults[k] end})



  -- suffix tables
  for name, display in pairs(displays) do
    display.conf = setmetatable({}, {
      __index = function(_, k)
        --print('config check '.. name .. k)
        return B.Conf[name .. k] or B.Conf['BuffButton' .. k]
      end,
      __newindex = function(_, k , v)
        B.Conf[name..k] = v
      end,
    })
  end

  -- To ensure that modules are run in controlled order, walk the dependency list; if the dep shows up
  -- in the loaded manifest, remove the value. If the dep list isn't empty, move that module to the next
  -- layer.
  local loaded = {}
  local stackLevels = #moduleStack
  local i = 1
  moduleStack[1] = modules
  repeat
    print('setting init level '.. i)
    local queue = moduleStack[i]
    for name, module in pairs(queue) do

      if queuedModules[name] and #queuedModules[name] > 0 then
        local p = #queuedModules[name]
        for j = 1, p do
          local dep = queuedModules[name][j]

          if loaded[dep] then
            print( '    ' .. dep .. ' OK')
            queuedModules[name][j] = nil
            for k = j, p do
              print('   shift ' .. (k+1)  .. ' ('..tostring(queuedModules[name][k+1])..') to ' .. k ..'')
              queuedModules[name][k] = queuedModules[name][k+1]
            end
          end
        end

        if #queuedModules[name] == 0 then
          queuedModules[name] = nil
          print('  |cFF00FFFF'.. name ..'|r deps OK')
          loaded[name] = true
        else

          print('  |cFFFF8800' .. name ..'|r pending')
          local next = i+1
          if not  moduleStack[next] then
            moduleStack[next] = {}
          end
          stackLevels = next
          moduleStack[next][name] = module
          queue[name] = nil
        end

      else
        print('  |cFF00FF00'.. name ..'|r no deps')
        loaded[name] = true
      end
   end
    i = i + 1
  until i > stackLevels


  for level, batch in ipairs(moduleStack) do
    print('config level', level)
    for name, module in pairs(batch) do
      if not VeneerData[name] then
        VeneerData[name] = {}
      end

      if module.defaults then
        print('setting defaults for module', name)
        --[===[@non-debug@
        if not VeneerData[name] then
        --@end-non-debug@]===]
          VeneerData[name] = {}
        --[===[@non-debug@
        end
        --@end-non-debug@]===]
        for k,v in pairs(module.defaults) do
          VeneerData[name][k] = v
        end
        module.Conf = VeneerData[name]
      end

      if VeneerData[name].enabled == nil then
        VeneerData[name].enabled = true
      end

    end
  end


  if #checkForConfig >= 1 then
    local queuedFrame = tremove(checkForConfig)
    while queuedFrame do
      B.SetConfigLayers(queuedFrame)
      B.InitXMLFrame(queuedFrame)
      queuedFrame = tremove(checkForConfig)
    end
  end
  -- remove from existing
end

--- Fires an update to all modules
local lastUpdate
function B.UpdateAll(...)
  lastUpdate = GetTime()
  ModulesCall('OnUpdate')
end

B:RegisterEvent('PLAYER_ENTERING_WORLD')
B:SetScript('OnEvent', function(self, event)
  if event == 'PLAYER_ENTERING_WORLD' then
    if not initOnced then
      InitOnce()
      ModulesCall('OnInitialize')
      initOnced = true
      C_Timer.After(1, function()
        if GetSpecialization() then
          print(GetSpecialization(), 'enabling')

          ModulesCall('OnEnable', 'enabled')
          B:SetScript('OnUpdate', nil)
        end
      end)
    end
  end

  B.UpdateAll()

  if event == 'PLAYER_ENTERING_WORLD' then
    B.UpdateConfigLayers()
  end

end)

--- Modulizer method
--
function B:RegisterModule (name, module, ...)
  if modules[name] then
    print('pulling modules[|cFFFF8800'.. tostring(name) ..'|r]')
    return modules[name]
  end

  print('new module |cFF00BBFF'.. tostring(name) ..'|r')
  if module then
    if modules[name] then
      error("Module table for '"..tostring(name).."' already exists.")
    end
  else
    module = CreateFrame('Frame', 'Veneer' .. tostring(name) .. 'Handler', B, 'VeneerHandlerTemplate')
  end
  modules[name] = module
  B[name] = module
  if select('#', ...) >= 1 then
    local numDeps = select('#', ...)
    print('  '..numDeps..' deps detected')
    for i = 1, numDeps do
      local dep = select(i, ...)
        -- means that init/enable funcs are ordered to run after deps do their things
      queuedModules[name] = queuedModules[name]  or {}
      tinsert(queuedModules[name], dep)
      print('  needs '..dep)
    end
  end
  return module
end


B.SetConfigLayers =  function(frame)
  local print = B.fprint()
  if not frame.config then
    --print(frame:GetName(), 'has no config layers')
    return
  end
  --print('Registering config layers from', frame:GetName())

  for i, subframe in ipairs(frame.config) do
    -- make sure there are no duplicates
    if not refs[subframe] then
      local key = #layers+1
      layers[key] = subframe
      refs[subframe] = key
    end
    --print(' ', i, subframe:GetName())
  end
end

B.RemoveConfigLayers = function(frame)

  local print = B.fprint()
  print('|cFFFF0000RemoveConfigLayers', frame:GetName())
  for i, subframe in pairs(layers) do
    if subframe:GetParent() == frame then
      print('|cFFFF8800  ', subframe:GetParent():GetName(), '|cFFFFFF00', subframe:GetName())
      layers[i]:Hide()
      layers[i] = nil
      refs[subframe] = nil
    end
  end
end

B.UpdateConfigLayers = function()
  local print = B.fprint()
  local func = B.Conf.GuidesMode and 'Show' or 'Hide'
  local numAnchors = 0
  for name, display in pairs(displays) do
    numAnchors = numAnchors + 1
    display.anchor:EnableMouse(B.Conf.GuidesMode)
    if B.Conf.GuidesMode then
      display.anchor:SetScript('OnUpdate', display.anchor.OnUpdate)
    else
      display.anchor:SetScript('OnUpdate', nil)

      for i, anchorButton in ipairs(display.anchor.anchorButton) do
        anchorButton:Hide()
      end

    end
    print(B.Conf.ConfigMode)
    display.anchor:EnableMouse(B.Conf.ConfigMode)
  end
  for id, region in pairs(layers) do
    print(id, region:GetName(), func)
    region[func](region)
  end

  print('['..func..'] updated', #layers, 'regions,', numAnchors, 'frames')
end

local XMLFrame_SetEnabled = function(self, value)
  local name = self:GetName()


  if not B.Conf[name] then
    B.Conf[name] = {
      enabled = true
    }
  end

  print()
  local enabled
  if value == nil then
    if B.Conf[name].enabled == nil then
      print('toggle based on visibility')
      enabled = (not self:IsVisible()) and true or false
    else
      print('toggle a config value =', B.Conf[name].enabled)
      enabled = B.Conf[name].enabled
    end

    enabled = (enabled ~= true) and true or false
  else
      print('use argument value', value)
      enabled = value
  end

  print('arg =', value, 'conf =', B.Conf[name].enabled, 'result=', enabled)

  B.Conf[name].enabled = enabled

  local stateFunc = enabled and 'Show' or 'Hide'
  local eventFunc = enabled and 'OnToggle' or 'OnToggle'
  for i, region in pairs(self.toggled) do
    region[stateFunc](region)
  end
  if self.OnToggle then
    self:OnToggle(B.Conf[name].enabled)
  end
  if B.Conf[name].enabled then
    if self.OnEnable then
      self:OnEnable()
    end
  else
    if self.OnDisable then
      self:OnDisable()
    end
  end


end
--- Generic handlers for keeping track of XML-defined frames
B.OnLoad = function(self)
  tinsert(checkForConfig, self)
  self.SetEnabled = XMLFrame_SetEnabled
end

B.InitXMLFrame = function(self)
  local name = self:GetName()
  print('|cFF00FF00hello from '.. name)

  if self.drag then
    self:RegisterForDrag('LeftButton')
  else
    self:EnableMouse(false)
  end

  if not B.Conf[name] then
    B.Conf[name] = {
      enabled = true,
    }
  end
  local c = B.Conf[name]

  if c.position then
    print('restoring frame position', unpack(c.position))
    self:ClearAllPoints()
    local anchorTo, relativePoint, x, y = unpack(c.position)
    self:SetPoint(anchorTo, UIParent, relativePoint, x, y)
  else
    local a, _, b, c, d = self:GetPoint(1)
    print('seeding default position', a, b, c, d)
    c.position = {a, b, c, d}
  end
  local state = c.enabled
  self:SetEnabled(state)
end

B.OnDragStart = function(self)
  self.xA = self:GetLeft()
  self.yA = self:GetBottom()
  self.anchorTo, self.relativeTo, self.relativePoint, self.x, self.y = self:GetPoint(1)
  print('acquire anchor', self:GetPoint(1))
  print(self:GetName(), 'start moving ('..self.x..', '..self.y..')')
  self:StartMoving()
end

B.OnDragStop = function(self)
  local name = self:GetName()
  print(name, 'stop moving ('..self:GetLeft()..', '..self:GetBottom()..')')
  local xB = self:GetLeft() - self.xA
  local yB = self:GetBottom() - self.yA
  print('storing anchor point', self.anchorTo, self.relativePoint, self.x + xB, self.y + yB)

  self:StopMovingOrSizing()
  B.Conf[name].position = {self.anchorTo, self.relativePoint, self.x + xB, self.y + yB}
  B.InitXMLFrame(self)
end