view ReAction_Bar.lua @ 25:bf997ea151ca

yet another attempt to add missing files
author Flick <flickerstreak@gmail.com>
date Fri, 07 Mar 2008 22:19:03 +0000
parents
children f1e838841ce1
line wrap: on
line source
--[[
  ReAction bar module.

  This is the heart of ReAction, the bar management module. Many of its
  functions turn around and iterate all modules registered to the ReAction
  parent core.

  Also defined in this file is the Bar class implementation, which can be
  used by other modules to manipulate the action bars. Many of the module
  iterated calls pass a bar or list of bars as an argument.

  Module methods called by the Bar module:
    module:ApplyToBar(bar)
    module:RemoveFromBar(bar)
    module:RefreshBar(bar)
    module:ApplyConfigMode(mode,listOfBars)
    module:GetBarNameModifier(bar)
    module:EraseBarConfig(barName)


  useful Bar object API (partial list):
    f     = bar:GetFrame()      -- f is derived from SecureStateDriver
            bar:RefreshLayout()
    w,h   = bar:GetSize()
    r,c,s = bar:GetButtonGrid() -- #rows, #columns, inter-button spacing
    name  = bar:GetName()
            bar:PlaceButton(frame, idx, baseSizeX, baseSizeY) -- idx is 1-based

--]]

-- local imports
local ReAction = ReAction
local L = ReAction.L
local _G = _G
local AceOO = AceLibrary("AceOO-2.0")
local CreateFrame = CreateFrame
local geterrorhandler = geterrorhandler
local pcall = pcall
local print = ReAction.print

-- update ReAction revision if this file is newer
local revision = tonumber(("$Revision: 1 $"):match("%d+"))
if revision > ReAction.revision then
  Reaction.revision = revision
end

local moduleID = "Bar"

--
-- Bar module declaration
--
local module = ReAction:NewModule( moduleID )

--
-- Bar class declaration
--
local BarClass = AceOO.Class()
local Bar = BarClass.prototype
module.BarClass = BarClass


--
-- Bar module implementation
--
function module:OnInitialize()
  self.db = ReAction:AcquireDBNamespace(moduleID)
  ReAction:RegisterDefaults(moduleID,"profile", 
    { 
      bars = { },
      defaultBar = { }
    }
  )
  self.bars = {}
end

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

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

function module:OnProfileEnable()
  self:InitializeBars()
end

function module:OnProfileDisable()
  self:TearDownBars()
end

function module:InitializeBars()
  if not(self.inited) then
    for name, config in pairs(self.db.profile.bars) do
      if config then
        self:CreateBar(name, config)
      end
    end
    self:CallMethodOnAllBars("ApplyAnchor") -- re-anchor in the case of oddball ordering
    self.inited = true
  end
end

function module:TearDownBars()
  for name, bar in pairs(self.bars) do
    if bar then
      self.bars[name] = self:DeleteBar(bar)
    end
  end
  self.inited = false
end

-- Gets config from existing DB name or default if not supplied
-- Saves to DB if name not known
function module:CreateBar(name, config)
  local profile = self.db.profile
  if not name then
    i = 1
    repeat
      name = L["Bar "]..i
      i = i + 1
    until self.bars[name] == nil
  end
  config = config or profile.bars[name] or deepCopy(profile.defaultBar)
  if not profile.bars[name] then
    profile.bars[name] = config
  end
  local bar = self.BarClass:new( name, config )
  ReAction:CallMethodOnAllModules("ApplyToBar", bar)
  self.bars[name] = bar
  return bar
end


local SelectBar
do
  SelectBar = function(x)
    local bar, name
    if type(x) == "string" then
      name = x
      bar = module:GetBar(name)
    elseif AceOO.inherits(x,BarClass) then
      bar = x
      for k,v in pairs(module.bars) do
        if v == bar then
          name = k
        end
      end
    else
      error("bad argument to SelectBar")
    end
    return bar, name
  end
end

-- Takes either a bar name string or a bar object.
-- Does NOT destroy the DB entry, this function is only used for 
-- enable/disable and profile switching. To remove a bar permanently,
-- use EraseBar() instead.
function module:DeleteBar(x)
  local bar, name = SelectBar(x)
  if name and bar then
    self.bars[name] = nil
    ReAction:CallMethodOnAllModules("RemoveFromBar", bar)
    bar:Destroy()
  end
end

function module:EraseBar(x)
  local bar, name = SelectBar(x)
  if name and bar then
    self:DeleteBar(bar)
    self.db.profile.bars[name] = nil
    ReAction:CallMethodOnAllModules("EraseBarConfig", name)
  end
end

function module:GetBar(name)
  return self.bars[name]
end

function module:RenameBar(x, newname)
  local bar, name = SelectBar(x)
  if bar and name and newname then
    if self.bars[newname] then
      error(L["ReAction: name already in use"])
    end
    self.bars[newname] = self.bars[name]
    self.bars[name] = nil
    bar:SetName(newname)
    local cfg = self.db.profile.bars
    cfg[newname], cfg[name] = cfg[name], nil
  end
end

function module:CallMethodOnAllBars(method,...)
  local m
  if type(method) == "function" then
    m = method
  elseif type(method) ~= "string" then
    error("Invalid method passed to ReAction_Bar:CallMethodOnAllBars()")
  end
  for _, bar in pairs(self.bars) do
    if bar then
      local m = m or bar[method]
      if m then
        local success,err = pcall(m,bar,...)
        if not success then
          geterrorhandler()(err)
        end
      end
    end
  end
end



function module:GetBarMenuOptions(bar)
  if not(bar.modMenuOpts[moduleID]) then
    bar.modMenuOpts[moduleID] = {
      delete = {
        type = "execute",
        name = L["Delete Bar"],
        desc = L["Remove the bar from the current profile"],
        func = function() self:EraseBar(bar) end,
        order = 1
      },
    }
  end
  return bar.modMenuOpts[moduleID]
end

function module:GetBarConfigOptions(bar, cfgModule)
  if not(bar.modConfigOpts[moduleID]) then
    bar.modConfigOpts[moduleID] = {
      delete = {
        type = "execute",
        name = L["Delete Bar"],
        desc = L["Remove the bar from the current profile"],
        func = function() self:EraseBar(bar); cfgModule:RefreshConfig() end
      },
      rename = {
        type = "text",
        name = L["Rename Bar"],
        desc = L["Set a name for the bar"],
        get  = "GetName",
        set  = function(name) self:RenameBar(bar,name); cfgModule:RefreshConfig() end
      }
    }
  end
  return bar.modConfigOpts[moduleID]
end



--
-- Bar class implementation
--
function Bar:init( name, config )
  BarClass.super.prototype.init(self)
  self.name, self.config = name, config

  if type(config) ~= "table" then
    error("ReAction:Bar: config table required")
  end

  local f = CreateFrame("Frame",nil,config.parent or UIParent,"SecureStateDriverTemplate")
  f:SetFrameStrata("MEDIUM")
  config.width = config.width or 400
  config.height = config.height or 80
  f:SetWidth(config.width)
  f:SetWidth(config.height)

  self.frame = f
  self:RefreshLayout()
  self:ApplyAnchor()
  f:Show()
end

function Bar:Destroy()
  local f = self.frame
  f:UnregisterAllEvents()
  f:Hide()
  f:SetParent(UIParent)
  f:ClearAllPoints()
  self.labelString = nil
  self.controlFrame = nil
  self.frame = nil
  self.config = nil
end

function Bar:RefreshLayout()
  ReAction:CallMethodOnAllModules("RefreshBar", self)
end

function Bar:ApplyAnchor()
  local f, config = self.frame, self.config
  f:SetWidth(config.width)
  f:SetHeight(config.height)
  local anchor = config.anchor
  if anchor then
    local anchorTo
    if config.anchorTo then
      anchorTo = module:GetBar(config.anchorTo) or _G[config.anchorTo]
    end
    f:SetPoint(anchor, anchorTo, config.relativePoint, config.x or 0, config.y or 0)
  else
    f:SetPoint("CENTER")
  end
end

function Bar:GetFrame()
  return self.frame
end

function Bar:GetSize()
  return self.frame:GetWidth() or 200, self.frame:GetHeight() or 200
end

function Bar:SetSize(w,h)
  self.config.width = w
  self.config.height = h
end

function Bar:GetButtonSize()
  local w = self.config.btnWidth or 32
  local h = self.config.btnHeight or 32
  -- TODO: get from modules?
  return w,h
end

function Bar:SetButtonSize(w,h)
  if w > 0 and h > 0 then
    self.config.btnWidth = w
    self.config.btnHeight = h
  end
end

function Bar:GetButtonGrid()
  local cfg = self.config
  local r = cfg.btnRows or 1
  local c = cfg.btnColumns or 1
  local s = cfg.spacing or 4
  return r,c,s
end

function Bar:SetButtonGrid(r,c,s)
  if r > 0 and c > 0 and s > 0 then
    local cfg = self.config
    cfg.btnRows = r
    cfg.btnColumns = c
    cfg.spacing = s
  end
end

-- This should only be called from module:RenameBar(), otherwise
-- the bar's internal name and the module's list of bars by name
-- can get out of sync.
function Bar:SetName( name )
  name = name or ""
  self.name = name
end

function Bar:GetName()
  return self.name
end

function Bar:PlaceButton(f, idx, baseW, baseH)
  local r, c, s = self:GetButtonGrid()
  local bh, bw = self:GetButtonSize()
  local row, col = floor((idx-1)/c), mod((idx-1),c) -- zero-based
  local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s
  local scale = bw/baseW

  f:ClearAllPoints()
  f:SetPoint("TOPLEFT",x/scale,-y/scale)
  f:SetScale(scale)
--  f:Show()
end