diff ReAction.lua @ 257:920d17851a93 stable

Merge 1.1 beta 4 to stable
author Flick
date Tue, 12 Apr 2011 16:06:31 -0700
parents 47818b3938c9
children 9e708a155ab9
line wrap: on
line diff
--- a/ReAction.lua	Thu Nov 18 13:11:08 2010 -0800
+++ b/ReAction.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -3,59 +3,120 @@
 local pairs = pairs
 local type = type
 local geterrorhandler = geterrorhandler
-local LKB = LibStub("LibKeyBound-1.0")
 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
+-- make a deep copy of a table
+local 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
 
+-- traverse a table tree by key list and fetch the result or first nil
+local function tfetch(t, ...)
+  for i = 1, select('#', ...) do
+    t = t and t[select(i, ...)]
+  end
+  return t
+end
+
+-- traverse a table tree by key list and build tree as necessary
+local function tbuild(t, ...)
+  for i = 1, select('#', ...) do
+    local key = select(i, ...)
+    if not t[key] then t[key] = { } end
+    t = t[key]
+  end
+  return t
+end
+
+-- return a new array of keys of table 't', sorted by comparing 
+-- sub-fields (obtained via tfetch) of the table values
+local function fieldsort( t, ... )
+  local r = { }
+  for k in pairs(t) do
+    table.insert(r,k)
+  end
+  local path = { ... }
+  table.sort(r, function(lhs, rhs)
+     local olhs = tfetch(t[lhs], unpack(path)) or 0
+     local orhs = tfetch(t[rhs], unpack(path)) or 0
+     return olhs < orhs
+    end)
+  return r
+end
+
+-- store in the addon table
+addonTable.tcopy = tcopy
+addonTable.tfetch = tfetch
+addonTable.tbuild = tbuild
+addonTable.fieldsort = fieldsort
+
 ------ Core ------
 local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction",
   "AceEvent-3.0"
 )
 addonTable.ReAction = ReAction
-ReAction.version = "1.1"
+ReAction.version = GetAddOnMetadata("ReAction","Version")
 ReAction.L = L
 ReAction.LKB = LKB
 
 
+ReAction.barTypes = { }
+
 ------ Handlers ------
 function ReAction:OnInitialize()
   self.db = LibStub("AceDB-3.0"):New("ReAction_DB", 
-    { 
-      profile = {
-        bars = { },
-        defaultBar = { },
-      }
-    },
+    self.defaultProfile,
     true -- use global 'Default' (locale-specific)
   )
 
+  self:UpgradeProfile()
+
   self.bars = { }
-  self.defaultBarConfig = { }
+
+  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:RegisterEvent("UPDATE_SHAPESHIFT_FORMS")
+
   self:InitializeOptions()
 end
 
 function ReAction:OnEnable()
   self:InitializeBars()
+  self:UPDATE_SHAPESHIFT_FORMS() -- it doesn't fire on a /reloadui
 end
 
 function ReAction:OnDisable()
@@ -71,6 +132,16 @@
   end
 end
 
+function ReAction:UPDATE_SHAPESHIFT_FORMS()
+  -- Re-parse the rules table according to the new form list.
+  -- This happens both at initial login (after PLAYER_ENTERING_WORLD)
+  -- as well as when gaining new abilities. 
+  self.Bar:InitRuleFormats()
+  for _, bar in self:IterateBars() do
+    bar:ApplyStates()
+  end
+end
+
 function ReAction:LIBKEYBOUND_ENABLED( evt )
   self:SetKeybindMode(true)
 end
@@ -79,6 +150,24 @@
   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 ------
 
@@ -110,31 +199,26 @@
 function ReAction:CreateBar(name, config, ...)
   local profile = self.db.profile
 
-  if name then
-    if self.bars[name] then
-      self:UserError(format(L["ReAction: name '%s' already in use"],name))
-      return nil
-    end
-  else
-    local prefix = L["Bar "]
-    local i = 1
-    repeat
-      name = prefix..i
-      i = i + 1
-    until self.bars[name] == nil
+  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
-    config = self.defaultBarConfig[config]
-    if not config then
-      error(("ReAction:CreateBar() - unknown bar type '%s'"):format(tostring(select(1,...))))
+    class = self.barTypes[config]
+    if not class then
+      error(("ReAction:CreateBar() - unknown bar type '%s'"):format(config))
     end
-    config = tcopy(config)
-    config.btnRows    = select(1,...) or config.btnRows    or 1
-    config.btnColumns = select(2,...) or config.btnColumns or 12
-    config.btnWidth   = select(3,...) or config.btnWidth   or 36
-    config.btnHeight  = select(3,...) or config.btnHeight  or 36
-    config.spacing    = select(4,...) or config.spacing    or 3
+    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"
@@ -142,11 +226,16 @@
     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
-  config = config or profile.bars[name] or tcopy(profile.defaultBar)
 
   profile.bars[name] = config
-  local bar = self.Bar:New( name, config )  -- ReAction.Bar defined in Bar.lua
+  local bar = self.Bar:New( name, config, class )  -- ReAction.Bar defined in Bar.lua
   self.bars[name] = bar
   self.callbacks:Fire("OnCreateBar", bar, name)
   if self.configMode then
@@ -165,24 +254,18 @@
   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
+    -- re-anchor 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
@@ -226,35 +309,57 @@
 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
 
-function ReAction:RegisterBarType( name, config, isDefaultChoice )
-  self.defaultBarConfig[name] = config
-  if isDefaultChoice then
-    self.defaultBarConfigChoice = name
+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
-  self:RefreshEditor()
 end
 
-function ReAction:UnregisterBarType( name )
-  self.defaultBarConfig[name] = nil
-  if self.defaultBarConfigChoice == name then
-    self.defaultBarConfigChoice = nil
+function ReAction:ManageBlizzardBars()
+  for _, f in pairs(blizzFrames) do
+    ManageBlizzFrame(f, self.db.profile.options.hideBlizzardBars)
   end
-  self:RefreshEditor()
+  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
 end
 
 function ReAction:IterateBarTypes()
-  return pairs(self.defaultBarConfig)
+  return pairs(self.barTypes)
 end
 
-function ReAction:GetBarTypeConfig(name)
-  if name then
-    return self.defaultBarConfig[name]
+function ReAction:GetDefaultBarConfig(barType)
+  if barType and self.barTypes[barType] then
+    return self.barTypes[barType]:GetDefaultBarConfig()
   end
 end
 
@@ -267,7 +372,7 @@
 end
 
 function ReAction:GetDefaultBarType()
-  return self.defaultBarConfigChoice
+  return self.defaultBarType
 end
 
 function ReAction:SetConfigMode( mode )
@@ -302,3 +407,18 @@
 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
+