view Veneer.lua @ 84:16b300d96724

rewritten using mixin attributes
author Nenue
date Tue, 18 Oct 2016 13:07:21 -0400
parents bb6b532c5d2f
children 27db212af783
line wrap: on
line source
-- Veneer
-- Base framework for making things draggable.




SLASH_VENEER1 = "/veneer"
SLASH_VENEER2 = "/vn"

SlashCmdList.VENEER = function(cmd)
end
VeneerCore = {
  Frames = {},
  ConfigLayers = {},
  FrameClusters = {},
  parserDepth = 0,
  pendingCalls = {},
}
VeneerHandlerMixin = {
  Reanchor = nop
}
local print = DEVIAN_WORKSPACE and function(...) print('Veneer', ...) end or nop
local wipe = table.wipe

local defaults = {
  enableAll = true,
  enableModule = {
    BuffFrame = true,
  },
  BuffFrame = {
    width = 48,
    height = 48,
  }
}

local configMode
local anonID = 0
local tostring = tostring
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 anchor_coefficients = {
  ['TOP'] = function(x, y) return x, y end,
  ['BOTTOM'] = function(x, y) return x,y end,
  ['LEFT'] = function(x, y) return x,y end,
  ['RIGHT'] = function(x,y) return x,y end,
}

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

  DEFAULT_CHAT_FRAME:AddMessage(txt)
end

function VeneerCore:OnLoad()
  print('|cFFFFFF00Veneer!|r')
  self:RegisterEvent('ADDON_LOADED')
  self:RegisterEvent('PLAYER_LOGIN')

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

function VeneerCore:OnEvent(event, ...)
  if event == 'ADDON_LOADED' or event == 'PLAYER_LOGIN' then
    if IsLoggedIn() and not self.intialized then
      self.intialized = true
      self:Setup()
    end
  end
end

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


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

function VeneerCore:Setup ()
  if (not VeneerData) or (not VeneerData.version) then
    VeneerData = defaults
  end
  self.data = VeneerData


  self:ExecuteOnClusters(nil, 'Setup')
end

function VeneerCore:AddHandler(handler, ...)
  print('*** Adding handler:', handler.moduleName or handler:GetName())
  local clusterTable = self.FrameClusters
  for i = 1, select('#', ...) do
    local anchor = select(i, ...)
    clusterTable[anchor] = clusterTable[anchor] or {}
    clusterTable = clusterTable[anchor]
    print('    cluster layer', i, anchor)
  end
  for k,v in pairs(VeneerHandlerMixin) do
    if not handler[k] then
      handler[k] = v
    end
  end
  tinsert(clusterTable, handler)
  handler:Reanchor()
end

function VeneerCore:ExecuteOnClusters(layer, method)
  self.parserDepth = self.parserDepth + 1
  layer = layer or self.FrameClusters
  if not layer then
    if self.parserDepth >= 1 then
      tinsert(self.pendingCalls, method)
      print('delaying walk for', method)
      return
    end
    print('|cFF00FFFFVeneer|r:'..method..'('..tostring(layer)..')')
  else
    print(' L'..self.parserDepth)
  end
  for anchor, cluster in pairs(layer) do
    for index, frame in ipairs(cluster) do
      print('  '..anchor..'.'..index..' = '..frame:GetName())
      if frame[method] then
        print('  '..frame:GetName()..':'..method..'(...)')
        frame[method](frame)
      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

function VeneerCore:Update()
  self:ExecuteOnClusters(nil, 'Update')
end

local VeneerButton_OnDragStart = function(self)
  self.startingLeft = self:GetLeft()
  self.startingBottom = self:GetBottom()
  self.anchors = self.anchors or {}
  table.wipe(self.anchors)

  local frame = self:GetParent()
  local n = frame:GetNumPoints()
  for i = 1, n do
    local anchor, parent, relative, x, y = frame:GetPoint(i)
    self.anchors[i] = {
      anchor = anchor,
      parent = parent,
      relative = relative,
      x = x,
      y = y
    }
  end

  print(self:GetName(), 'start moving', self.startingLeft, self.startingBottom)
  self:StartMoving()
end

local VeneerButton_OnDragStop =  function(self)
  self:StopMovingOrSizing()
  if self.OnDragStop then
    self.OnDragStop(self)
  else
    local frame = self:GetParent()
    local dx = self:GetLeft() - self.startingLeft
    local dy = self:GetBottom() - self.startingBottom

    frame:ClearAllPoints()
    for i, point in ipairs(self.anchors) do
      frame:SetPoint(point.anchor, point.parent, point.relative, point.x + dx, point.y + dy)
      print('adjusting anchor', point.anchor, point.parent, point.relative, point.x + dx, point.y + dy)
    end
  end
end

local Veneer_FixMovers = function()
  for frame, veneer in pairs(veneers) do
    if veneer:IsMoving() then
      VeneerButton_OnDragStop(veneer)
    end
  end
end

local VeneerButton_Update = function(self)
  if configMode then
    self:SetScript('OnDragStart', VeneerButton_OnDragStart)
    self:SetScript('OnDragStop', VeneerButton_OnDragStop)
    self:SetMovable(true)
    self:EnableMouse(true)
    self:RegisterForDrag('LeftButton')

    self.bg:SetColorTexture(0,1,0,0.5)
    for i, region in ipairs(self.configLayers) do
      region:Show()
    end
    self:Show()
  else

    self:SetScript('OnDragStart', self.StartMoving)
    self:SetScript('OnDragStop', self.StopMovingOrSizing)
    self:SetMovable(false)
    self:EnableMouse(false)

    self.bg:SetColorTexture(0,1,0,0)
    for i, region in ipairs(self.configLayers) do
      region:Hide()
    end
    if self.isHidden then
      self:Hide()
    end

  end
end

local ToggleVeneerConfig = function()
  if configMode then
    configMode = false
    Veneer:print('Config mode off.')
  else
    configMode = true
    Veneer:print('Config mode on.')
  end

  for frame, veneer in pairs(veneers) do
    VeneerButton_Update(veneer)
  end
end

local VeneerButton_OnShow = function(self)
  VeneerButton_Update(self)
end

function VeneerCore:Acquire (frame, template)
  if not frame then
    print('|cFFFF4400Unable to acquire frame...|r')
    return
  end
  local veneer = self.Frames[frame]
  if not veneer then
    local name = type(frame) == 'table' and GetTableName(frame) or GetAnonymousName()
    veneer = CreateFrame('Frame', name, frame, template or 'VeneerTemplate')
    print('+veneer', name)

    veneer:SetAllPoints(frame)
    veneer:SetParent(frame)
    veneer.label:SetText(name)
    veneer.bg:SetColorTexture(0,0,0,0)
    veneer:Hide()
    veneer:EnableMouse(false)

    veneer:SetScript('OnShow', VeneerButton_OnShow)

    -- find current X/Y
    veneer.currentLeft = frame:GetLeft()
    veneer.currentTop = frame:GetTop()
    self.Frames[frame] = veneer
  end

  return veneer
end

local mixin_probe = {
  'ArtifactFrame',
  'ArtifactFrameUnderlay',
}