diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ReAction_Bar.lua	Fri Mar 07 22:19:03 2008 +0000
@@ -0,0 +1,380 @@
+--[[
+  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
+