view Veneer.lua @ 138:6e2f20230190 tip

- 8.1 TOC - disabled Currency and WorldState modules for lack of use - BoD progress link buttons for group finder
author Nenue
date Fri, 22 Feb 2019 17:34:58 -0500
parents 414e37af1b1b
children
line wrap: on
line source
-- Veneer Custom Interface Framework
-- 1. vn OnLoad
-- 2. OnEvent where IsLoggedIn() == true
-- 3. Setup() where (not self.initialized)
-- 4. Update()
-- 5. Reanchor()
local ADDON, addon = ...
local VENEER_VERSION = 703
local LE_FREE_FRAMES_GROUP = 1
local type, strrep, ipairs, tinsert, tostring, select = type, string.rep, ipairs, tinsert, tostring, select
local pairs, tremove = pairs, tremove
local print = DEVIAN_WORKSPACE and function(...) _G.print('Veneer', ...) end or nop
local eprint = DEVIAN_WORKSPACE and function(...) _G.print('VeneerEvent', ...) end or nop
local wipe = table.wipe
VeneerCore = {}
local Veneer = VeneerCore


SLASH_VENEER1 = "/veneer"
SLASH_VENEER2 = "/vn"
SlashCmdList.VENEER = function(cmd)
  _G.Veneer:print(addon.ConfigMode)
  if addon.ConfigMode == true then
    addon.ConfigMode = false
  else
    addon.ConfigMode = true
  end
  _G.Veneer:UpdateConfigLayers()
end

addon.L = setmetatable({}, {
  __index = function(k) return k end
})

Veneer.modules = {}
Veneer.Frames = {}
Veneer.ConfigLayers = {}
Veneer.FrameClusters = {
    [LE_FREE_FRAMES_GROUP] = {}
  }
Veneer.parserDepth = 0
Veneer.pendingCalls = {}
Veneer.AddOnCheck = {}

local defaults = {
  enableAll = true,
  ConfigMode = true
}

local configMode
local anonID = 0
local IsFrameHandle = IsFrameHandle
local GetAnonymousName = function(key)
  if not key then
    anonID = anonID + 1
    key = anonID
  end
  return 'VN' .. key
end
local GetTableName = function(table)
  return (IsFrameHandle(table) and table:GetName()) or tostring(table)
end

local OFFSET_PARALLELS = {
  TOP = {'LEFT', 'RIGHT', 'SetHeight'},
  BOTTOM = {'LEFT', 'RIGHT', 'SetHeight'},
  LEFT = {'TOP', 'BOTTOM', 'SetWidth'},
  RIGHT = {'TOP', 'BOTTOM', 'SetWidth'},
}
local ANCHOR_OFFSET_POINT = {
  TOP = 'BOTTOM',
  TOPLEFT = 'BOTTOMRIGHT',
  TOPRIGHT = 'BOTTOMLEFT',
  LEFT = 'RIGHT',
  RIGHT = 'LEFT',
  CENTER = 'CENTER',
  BOTTOM = 'TOP',
  BOTTOMRIGHT = 'TOPLEFT',
  BOTTOMLEFT = 'TOPRIGHT',
}
local ANCHOR_INSET_DELTA = {
  TOP = {0, -1},
  TOPLEFT = {1, -1},
  TOPRIGHT = {-1,-1},
  LEFT = {1, 0},
  BOTTOMLEFT = {1, 1},
  BOTTOM = {0, 1},
  BOTTOMRIGHT = {-1, 1},
  RIGHT = {-1, 0},
  CENTER = {0, 0},
}

function Veneer:print(...)
  local txt = '|cFFFFFF00Veneer|r:'
  for i = 1, select('#', ...) do
    txt = txt .. ' '.. tostring(select(i, ...))
  end

  DEFAULT_CHAT_FRAME:AddMessage(txt)
end

function Veneer:OnLoad()
  print('|cFFFFFF00Veneer!|r')
  self:RegisterEvent('ADDON_LOADED')
  self:RegisterEvent('PLAYER_LOGIN')
  --self:RegisterEvent('PLAYER_REGEN_ENABLED')
  --self:RegisterEvent('PLAYER_REGEN_DISABLED')

  self.DEVIAN_PNAME = 'Veneer'
  self:RegisterForDrag('LeftButton')


end

local select, IsAddOnLoaded, IsLoggedIn = select, IsAddOnLoaded, IsLoggedIn

function Veneer:OnEvent(event, ...)
  local print = eprint
  print('|cFFFF0088OnEvent()|r',event, ...)
  if (event == 'PLAYER_LOGIN') or (event == 'ADDON_LOADED') then
    print(IsLoggedIn(), self.initialized)
    if IsLoggedIn() and not self.intialized then
      self:Setup()
      self.intialized = true
      print('popping init sequence', self.intialized)
    end


    if self.intialized then
      local addon  = ...
      if self.AddOnCheck[addon] then
        print('  - setting up '..addon..' dependent modules:')
        local keepChecking = false
        for index, handler in ipairs(self.AddOnCheck[addon]) do
          print('  -', handler:GetName(), (not handler.initialized) and (handler.addonFrame and not _G[handler.addonFrame]))
          if not handler.initialized then
            print('  '..handler:GetName()..':Setup()')
            handler:Setup()
            handler.initialized = true
          end
        end
        if not keepChecking then
          self.AddOnCheck[addon] = nil
        end
      end
    end
  elseif event == 'PLAYER_REGEN_ENABLED' then
    for _, module in pairs(self.modules) do
      if module:IsShown() and module.hideCombat then
        module:Hide()
      end
    end

  elseif event == 'PLAYER_REGEN_DISABLED' then
    for _, module in pairs(self.modules) do
      if module:IsShown() and module.hideCombat then
        module:Show()
      end
    end
  end
end

function Veneer:OnDragStart()
  self:StartMoving()
end

function Veneer:OnDragStop()
  self:StopMovingOrSizing()
end

local VeneerModule_Setup = function(frame)
  if not frame.initialized then
    local doSetup = (not frame.addonTrigger) or select(2, IsAddOnLoaded(frame.addonTrigger))
    print('  '..frame:GetName()..'.doSetup =', doSetup)
    if doSetup then
      frame:Setup()
      frame.initialized = true
    else
      frame:RegisterEvent('ADDON_LOADED')
    end

  end
end

function Veneer:Setup ()
  print('|cFFFF0088Setup()|r')
  if (not VeneerData) then
    print('|cFF00FFFFresetting defaults|r')
    VeneerData = defaults
    VeneerData.version = VENEER_VERSION
  end
  self.data = VeneerData
  self:ExecuteOnClusters(nil, VeneerModule_Setup)

  addon.ConfigMode = VeneerData.ConfigMode
  print('|cFF00FF88configMode =', addon.ConfigMode)
  self:UpdateConfigLayers()
  self:Reanchor()
  self:Update()
end

function Veneer:UpdateConfigLayers()
  if VeneerData then
    VeneerData.ConfigMode = addon.ConfigMode
  end

  self:print('Config mode '..(addon.ConfigMode and '|cFF00FF00ON|r' or '|cFFFF0000OFF|r')..'. ', tostring(addon.ConfigMode))
  self:ExecuteOnClusters(nil, function(frame)
    if frame.UpdateConfigLayers then
      frame:UpdateConfigLayers(addon.ConfigMode)
    end


    if type(frame.ConfigLayer) == 'table' then
      for index, region in ipairs(frame.ConfigLayer) do
        print('setting', frame:GetName() .. '['.. index..']', 'to', addon.ConfigMode)

        region:SetShown(addon.ConfigMode)
      end
    end

    self.ConfigLayers[frame] = frame:IsShown()
    if addon.ConfigMode then
      print(frame:GetName(), self.ConfigLayers[frame])
      frame:SetShown(addon.ConfigMode)
    else
      frame:SetShown(self.ConfigLayers[frame])
    end
  end)
end


function Veneer:GetClusterFromArgs (...)
  return primaryAnchor, clusterTable, insertPosition
end

-- args: frame object, list of anchor groups, true for forced top, number for priority layer
local mixins = {}
function Veneer:AddHandler(handler, ...)
  print('|cFFFFFF00'..handler:GetName()..':|r', handler.moduleName, ...)

  wipe(mixins)
  for k,v in pairs(VeneerHandlerMixin) do
    if not handler[k] then
      tinsert(mixins, k)
      handler[k] = v
    end
  end
  if #mixins >= 1 then
    print('* Mixins:|cFF00FF88', table.concat(mixins, ', '))
  end

  self.modules[handler] = handler

  if not handler.anchorFrame then

    local clusterAnchor = handler.anchorGroup or handler.anchorPoint or 'CENTER'
    local clusterPriority = handler.anchorPriority
    print('panel group =', clusterAnchor)

    self.FrameClusters[clusterAnchor] = self.FrameClusters[clusterAnchor] or {}
    local clusterTable = self.FrameClusters[clusterAnchor]
    local clusterIndex

    if clusterPriority then
      for i = 1, #clusterTable do

        if clusterTable[i].anchorPriority and (clusterTable[i].anchorPriority > clusterPriority) then
          clusterIndex = i
          print('|cFF00BB00insert position:', clusterPriority, clusterIndex)
          break
        else
          print('pass', clusterTable[i])
          clusterIndex = i+1
        end
      end
    else
      print('|cFF00BB00inserting at front')
      clusterIndex = #clusterTable + 1
    end

    if not clusterIndex then
      clusterIndex = #clusterTable + 1
    end


    tinsert(clusterTable, clusterIndex, handler)
    print(' cluster', clusterAnchor, clusterTable, 'priority', clusterPriority, 'position', clusterIndex)

    handler.anchorCluster = clusterTable
    handler.anchorIndex = clusterIndex
  else
    local clusterTable = self.FrameClusters[LE_FREE_FRAMES_GROUP]
    handler.anchorCluster = clusterTable
    handler.anchorIndex = #clusterTable+1
    tinsert(clusterTable, handler.anchorIndex, handler)
    print(' free frame')
  end

  if handler.addonTrigger and not IsAddOnLoaded(handler.addonTrigger) then
    print('|cFFFF4400  -- dependency:', handler.addonTrigger)
    self.AddOnCheck[handler.addonTrigger] = self.AddOnCheck[handler.addonTrigger] or {}
    tinsert(self.AddOnCheck[handler.addonTrigger], handler)
  end


  if self.initialized then
    print('  -- initialization check')
    if handler.Setup then
      local doInit = (not handler.initialized)
      if handler.addonTrigger and not IsAddOnLoaded(handler.addonTrigger) then
        doInit = false
      end
      -- room to add other checks

      if doInit then
        handler:Setup()
        handler.initialized = true
        self:InternalReanchor(handler)
      end
    end
  end
end

function Veneer:Reanchor()
  --self:ExecuteOnClusters(nil, 'Reanchor')
  self:EvaluateAnchors()
end

function Veneer:Update()
  self:ExecuteOnClusters(nil, function(frame)
    if frame.initialized and frame.Update then
      frame:Update()
    end
  end)
  self:Reanchor()
end

-- updates anchor relations to and from the target handler
function Veneer:GetAnchor(...)

end


-- Recursives updates frame group anchors
function Veneer:EvaluateAnchors(parent)
  parent = parent or self
  local print = eprint
  print('|cFF88FF00DynamicReanchor()')
  for clusterPoint, cluster in pairs(parent.FrameClusters) do
    print(clusterPoint)
    if clusterPoint ~= LE_FREE_FRAMES_GROUP then
      local lastFrame
      for index, frame in ipairs(cluster) do
        print('  |cFF00FF00'..index, frame:GetName(), frame:IsShown(), (lastFrame and ('|cFFFFFF00'..lastFrame:GetName()..'|r') or '|cFF00FFFFUIParent'))
        if frame:IsShown() then

          if frame.anchorFrame then
            print(frame.anchorPoint)
            frame:SetPoint(frame.anchorPoint, frame.anchorFrame, frame.anchorFrom, frame.anchorX, frame.anchorY)
            print('anchored to', frame.anchorFrame,frame:GetTop(), frame:GetRight())
          else
            local anchorPoint = frame.anchorPoint or clusterPoint
            local anchorFrom = frame.anchorFrom or ANCHOR_OFFSET_POINT[clusterPoint]
            frame:ClearAllPoints()
            if lastFrame then
              frame:SetPoint(anchorPoint, lastFrame, anchorFrom, 0, 0)

              print('  fixing to', lastFrame, anchorPoint, anchorFrom, frame:GetTop(), frame:GetRight())
            else
              frame:SetPoint(anchorPoint, UIParent, clusterPoint, frame.anchorX, frame.anchorY)
              print('NEW', clusterPoint, anchorPoint, anchorFrom, frame.anchorX, frame.anchorY)
            end
            lastFrame = frame
          end

        end

      end
    end

  end
end

Veneer.DynamicReanchor = Veneer.EvaluateAnchors

-- Evaluates the current visibility state and re-anchors adjacent blocks accordingly
function Veneer:InternalReanchor(handler, printFunc)
  local print = eprint
  print('|cFF00FFFFVeneer:InternalReanchor('..handler:GetName()..')')
  if handler.anchorFrame then
    handler:SetPoint(handler.anchorPoint, handler.anchorFrame, handler.anchorFrom, handler.anchorX, handler.anchorY)
    return
  end


  local anchorPoint = handler.anchorPath or handler.anchorPoint
  local anchorParent, anchorTo = UIParent, anchorPoint
  local subPoint, subTo
  local nextFrame
  for index, frame in ipairs(handler.anchorCluster) do
    print('  |cFF00FF00'..index, frame:GetName(), frame:IsVisible())
    if frame:IsShown() then
      if frame ~= handler then
        anchorParent = frame
        anchorTo = ANCHOR_OFFSET_POINT[anchorPoint]

      else
        nextFrame = handler.anchorCluster[index+1]
        if nextFrame then

          subPoint = nextFrame.anchorPath or nextFrame.anchorPoint
          subTo = ANCHOR_OFFSET_POINT[subPoint]
          nextFrame:ClearAllPoints()
          nextFrame:SetPoint(subPoint, handler, subTo, 0, 0)
          print(' -- pushing '..nextFrame:GetName()..' down the anchor chain', subPoint, subTo)
        end
        break
      end
    end
  end

  if handler:IsShown() then
    handler:SetPoint(anchorPoint, anchorParent, anchorTo, 0, 0)
  else
    if anchorParent and nextFrame then
      nextFrame:SetPoint(subPoint, handler, subTo, 0, 0)
    end
  end


  print(handler.anchorPoint, anchorParent, anchorTo)
  if printFunc then
    printFunc('|cFF88FF00'..handler:GetName()..':SetPoint(', handler.anchorPoint, anchorParent, anchorTo)
  end
end

function Veneer:SlideBlock(frame, ...)
  local print = eprint
  local aX, aY = frame:GetLeft(), frame:GetTop()

  frame:SetPoint('TOPLEFT', frame, 'BOTTOMLEFT', aX, aY)
  frame.animation = frame.animation or {}
  frame.animation.startX = aX
  frame.animation.startY = aY

  local targetPoint, targetParent, targetAnchor, offsetX, offsetY = ...
  frame.BlockSlide:SetScript('OnFinished', function()
    frame:SetPoint(targetPoint, targetParent, targetAnchor, offsetX, offsetY)
    VeneerAnimationMixin.OnFinished(frame)
  end)

end

-- execute a function on all clusters in display order
function Veneer:ExecuteOnClusters(layer, method)
  local print = eprint
  self.parserDepth = self.parserDepth + 1
  if not layer then
    if self.parserDepth > 1 then
      tinsert(self.pendingCalls, method)
      print('delaying walk for', method)
      return
    end
    print('|cFF00FF00ExecuteOnClusters|r('..tostring(layer)..', '..tostring(method)..')')
  else
    print(' Level '..self.parserDepth)
  end

  layer = layer or self.FrameClusters
  for anchor, cluster in pairs(layer) do
    for index, frame in ipairs(cluster) do
      print(' '..anchor..'.'..index..' = '..frame:GetName())
      if type(method) == 'function' then
        method(frame, true)
      elseif frame[method] then
        print('  |cFF00FF00'..frame:GetName())
        frame[method](frame, true)
      end
    end
    if cluster.FrameClusters then
      self:ExecuteOnClusters(cluster.FrameClusters, method)
    end
  end
  self.parserDepth = self.parserDepth - 1

  if (self.parserDepth == 0) and (#self.pendingCalls >= 1) then
    local delayedMethod = tremove(self.pendingCalls, 1)
    print('starting delayed walk for', delayedMethod)
    self:ExecuteOnClusters(nil, delayedMethod)
  end
end



-- Takes frame handle and assigns a block to it
function Veneer:Acquire (frame, template)
  local print = eprint
  if not frame then
    print('|cFFFF4400Unable to acquire frame...|r')
    return
  end
  local veneer = self.Frames[frame]
  if not veneer then
    local name = GetAnonymousName()
    veneer = CreateFrame('Frame', name, frame, template)
    print(self:GetName()..':Acquire()', frame:GetName(), template)

    veneer:SetAllPoints(frame)
    veneer:SetParent(frame)
    veneer.label:SetText(name)
    veneer.bg:SetColorTexture(0,0,0,0)
    veneer:Hide()
    veneer:EnableMouse(false)
    -- find current X/Y
    veneer.currentLeft = frame:GetLeft()
    veneer.currentTop = frame:GetTop()
    self.Frames[frame] = veneer
  end
  return veneer
end