view ReAction.lua @ 231:158c9299185b

Fix button type config lookup
author Flick
date Tue, 22 Mar 2011 11:35:04 -0700
parents 98114c158e62
children 0e20f65375d5
line wrap: on
line source
local addonName, addonTable = ...
local pcall = pcall
local pairs = pairs
local type = type
local geterrorhandler = geterrorhandler
local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
local LKB = LibStub("LibKeyBound-1.0",true)
if not LKB then
  LoadAddOn("LibKeyBound-1.0")
  LKB = LibStub("LibKeyBound-1.0")
end

------ Utility ------
local tcopy
do
  function tcopy(x)
    if type(x) ~= "table" then
      return x
    end
    local r = {}
    for k,v in pairs(x) do
      r[k] = tcopy(v)
    end
    return r
  end
end

------ Core ------
local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction",
  "AceEvent-3.0"
)
addonTable.ReAction = ReAction
ReAction.version = "1.1"
ReAction.L = L
ReAction.LKB = LKB


ReAction.barTypes = { }

------ Handlers ------
function ReAction:OnInitialize()
  self.db = LibStub("AceDB-3.0"):New("ReAction_DB", 
    self.defaultProfile,
    true -- use global 'Default' (locale-specific)
  )

  self:UpgradeProfile()

  self.bars = { }

  self.LBF = LibStub("LibButtonFacade",true)
  if self.LBF then
    self.LBF:RegisterSkinCallback("ReAction", self.OnSkinChanged, self)
  end

  -- It's fairly normal to use the Blizzard vehicle bar, and to have
  -- your regular buttons in the same location. If you do this, and don't
  -- bother to hide your buttons, they'll obscure some parts of the vehicle bar.
  VehicleMenuBar:SetFrameLevel(VehicleMenuBar:GetFrameLevel()+3)

  self.callbacks = LibStub("CallbackHandler-1.0"):New(self)
  
  LKB.RegisterCallback(self,"LIBKEYBOUND_ENABLED")
  LKB.RegisterCallback(self,"LIBKEYBOUND_DISABLED")
  LKB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED")

  -- see Profile.lua for these callback implementations
  self.db.RegisterCallback(self,"OnProfileChanged")
  self.db.RegisterCallback(self,"OnProfileCopied","OnProfileChanged")
  self.db.RegisterCallback(self,"OnNewProfile")
  self.db.RegisterCallback(self,"OnProfileReset", "OnNewProfile")

  self:RegisterEvent("PLAYER_REGEN_DISABLED")

  self:InitializeOptions()
end

function ReAction:OnEnable()
  self:InitializeBars()
end

function ReAction:OnDisable()
  self:TearDownBars()
end

function ReAction:PLAYER_REGEN_DISABLED()
  if self.configMode == true then
    self:UserError(L["ReAction config mode disabled during combat."])
    self:SetConfigMode(false)
    self:SetKeybindMode(false)
    self:CloseEditor()
  end
end

function ReAction:LIBKEYBOUND_ENABLED( evt )
  self:SetKeybindMode(true)
end

function ReAction:LIBKEYBOUND_DISABLED( evt )
  return self:SetKeybindMode(false)
end

function ReAction:OnSkinChanged( skinID, gloss, backdrop, group, button, colors )
  if group == nil then
    -- don't store global
  else
    -- 'group' is the bar-name
    local bar = self:GetBar(group)
    if bar then
      local c = bar:GetConfig().ButtonFacade
      if c then
        c.skinID   = skinID
        c.gloss    = gloss
        c.backdrop = backdrop
        c.colors   = colors
      end  
    end
  end
end


------ Methods ------

function ReAction:UserError(msg)
  UIErrorsFrame:AddMessage(msg)
end

function ReAction:GetBar(arg)
  if type(arg) == "string" then
    return self.bars[arg], arg
  elseif type(arg) == "table" then -- reverse lookup
    for name, bar in pairs(self.bars) do
      if arg == bar then
        return bar, name
      end
    end
  else
    error("ReAction:GetBar() requires either a name or a bar table arg")
  end
end

function ReAction:IterateBars()
  return pairs(self.bars)
end

-- usage:
--  (1) ReAction:CreateBar(name, [cfgTable])
--  (2) ReAction:CreateBar(name, "barType", [nRows], [nCols], [btnSize], [btnSpacing])
function ReAction:CreateBar(name, config, ...)
  local profile = self.db.profile

  name = tostring(name)
  if not name or name == "" then
    error("ReAction:CreateBar() - bar name string required")
  elseif self.bars[name] then
    self:UserError(format(L["ReAction: name '%s' already in use"],name))
    return nil
  end

  local class
  if type(config) == "string" then
    class = self.barTypes[config]
    if not class then
      error(("ReAction:CreateBar() - unknown bar type '%s'"):format(config))
    end
    config = tcopy(class:GetDefaultBarConfig())
    config.btnRows    = select(1,...) or config.btnRows
    config.btnColumns = select(2,...) or config.btnColumns
    config.btnWidth   = select(3,...) or config.btnWidth
    config.btnHeight  = select(3,...) or config.btnHeight
    config.spacing    = select(4,...) or config.spacing
    config.width      = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1
    config.height     = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1
    config.anchor     = config.anchor or "UIParent"
    config.point      = config.point or "BOTTOM"
    config.relpoint   = config.relpoint or "BOTTOM"
    config.y          = config.y or 200
    config.x          = config.x or 0
  else
    config = config or profile.bars[name] or { }
    if not config or not config.type or not self.barTypes[config.type] then
      error(("ReAction: Unable to construct/fetch config table for bar '%s'"):format(name))
    end
    class = self.barTypes[config.type]
  end

  profile.bars[name] = config
  local bar = self.Bar:New( name, config )  -- ReAction.Bar defined in Bar.lua
  self.bars[name] = bar
  self.callbacks:Fire("OnCreateBar", bar, name)
  if self.configMode then
    bar:ShowControls(true)
  end

  return bar
end

function ReAction:DestroyBar(x)
  local bar, name = self:GetBar(x)
  if bar and name then
    self.bars[name] = nil
    self.callbacks:Fire("OnDestroyBar", bar, name)
    bar:Destroy()
  end
end

function ReAction:RefreshBar(x)
  local bar, name = self:GetBar(x)
  if bar and name then
    self.callbacks:Fire("OnRefreshBar", bar, name)
  end
end

function ReAction:InitializeBars()
  if not self.barsInitialized then
    self:ManageBlizzardBars()

    for name, config in pairs(self.db.profile.bars) do
      if config then
        self:CreateBar(name, config)
      end
    end
    -- re-anchor and refresh in case anchor order does not match init order
    for name, bar in pairs(self.bars) do
      bar:ApplyAnchor()
      self.callbacks:Fire("OnRefreshBar", bar, name)
    end
    self.barsInitialized = true
  end
end

function ReAction:TearDownBars()
  for name, bar in pairs(self.bars) do
    if bar then
      self.bars[name] = self:DestroyBar(bar)
    end
  end
  self.barsInitialized = false
end

function ReAction:RebuildAll()
  self:TearDownBars()
  self:InitializeBars()
end

function ReAction:RenameBar(x, newname)
  local bar, name = self:GetBar(x)
  if type(newname) ~= "string" then
    error("ReAction:RenameBar() - second argument must be a string")
  end
  if bar and name and #newname > 0 then
    if newname == name then
      return
    end
    if self.bars[newname] then
      self:UserError(format(L["ReAction: name '%s' already in use"],newname))
    else
      self.bars[newname], self.bars[name] = self.bars[name], nil
      bar:SetName(newname or "")
      local cfg = self.db.profile.bars
      cfg[newname], cfg[name] = cfg[name], nil
      self.callbacks:Fire("OnRenameBar", bar, name, newname)
    end
  end
end

function ReAction:EraseBar(x)
  local bar, name = self:GetBar(x)
  if bar and name then
    self.callbacks:Fire("OnEraseBar", bar, name)
    self:DestroyBar(bar)
    self.db.profile.bars[name] = nil
  end
end

local blizzFrames = {
  MainMenuBar,
  MultiBarLeft,
  MultiBarRight,
  MultiBarBottomLeft,
  MultiBarBottomRight,
}

local hideFrame = CreateFrame("Frame")
hideFrame:Hide()
local hiddenParents = { }
local function ManageBlizzFrame(f, hide)
  if hide and not hiddenParents[f] then
    hiddenParents[f] = f:GetParent()
    f:SetParent(hideFrame)
  elseif not hide and hiddenParents[f] then
    f:SetParent(hiddenParents[f])
    hiddenParents[f] = nil
    if f:IsShown() then 
      f:Show() -- refresh
    end
  end
end

function ReAction:ManageBlizzardBars()
  for _, f in pairs(blizzFrames) do
    ManageBlizzFrame(f, self.db.profile.options.hideBlizzardBars)
  end
  ManageBlizzFrame(VehicleMenuBar, self.db.profile.options.hideBlizzardVehicleBar)
end

function ReAction:RegisterBarType( class, isDefault )
  local name = class:GetButtonTypeID()
  self.barTypes[name] = class
  if isDefault then
    self.defaultBarType = name
  end
  self:RefreshEditor()
end

function ReAction:IterateBarTypes()
  return pairs(self.barTypes)
end

function ReAction:GetDefaultBarConfig(barType)
  if barType and self.barTypes[barType] then
    return self.barTypes[barType]:GetDefaultBarConfig()
  end
end

function ReAction:GetBarTypeOptions( fill )
  fill = fill or { }
  for k in self:IterateBarTypes() do
    fill[k] = k
  end
  return fill
end

function ReAction:GetDefaultBarType()
  return self.defaultBarType
end

function ReAction:SetConfigMode( mode )
  if mode ~= self.configMode then
    if mode then
      self:SetKeybindMode(false)
    end
    self.configMode = mode
    self.callbacks:Fire("OnConfigModeChanged", mode)
  end
end

function ReAction:GetConfigMode()
  return self.configMode
end

function ReAction:SetKeybindMode( mode )
  if mode ~= self.kbMode then
    if mode then
      self:SetConfigMode(false)
      LKB:Activate()
    else
      LKB:Deactivate()
    end
    for _, bar in self:IterateBars() do
      bar:SetKeybindMode(mode)
    end
    self.kbMode = LKB:IsShown() or false
  end
end

function ReAction:GetKeybindMode( mode )
  return self.kbMode
end


-- ConfigMode support
CONFIGMODE_CALLBACKS = CONFIGMODE_CALLBACKS or {}

function CONFIGMODE_CALLBACKS.ReAction( action, mode )
  if action == "ON" then
    ReAction:SetConfigMode(true)
  elseif action == "OFF" then
    ReAction:SetConfigMode(false)
  elseif action == "LISTMODES" then
    -- no modes
  end
end