changeset 257:920d17851a93 stable

Merge 1.1 beta 4 to stable
author Flick
date Tue, 12 Apr 2011 16:06:31 -0700
parents b2b105747466 (current diff) 586447595262 (diff)
children a7d2efb6ffc9
files .hgtags classes/ActionButton.lua classes/BagButton.lua classes/Bar.lua classes/Button.lua classes/MultiCastButton.lua classes/Overlay.lua classes/PetActionButton.lua classes/StanceButton.lua classes/VehicleExitButton.lua classes/classes.xml modules/Action.lua modules/Bag.lua modules/HideBlizzard.lua modules/LBF.lua modules/ModuleTemplate.lua modules/PetAction.lua modules/Stance.lua modules/State.lua modules/Totem.lua modules/VehicleExit.lua modules/modules.xml
diffstat 39 files changed, 6534 insertions(+), 7213 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu Nov 18 13:11:08 2010 -0800
+++ b/.hgtags	Tue Apr 12 16:06:31 2011 -0700
@@ -1,3 +1,4 @@
 2c05008464e5cf809251d40c8f88ad87fa3ac554 1.1 Beta 1
 9945a783d8b29e6e81eb8d42823d56dc84759d15 1.1 Beta 2
 3e451836ce6dfa758794c27a4b3a2a1f12595e83 1.1 Beta 3
+47818b3938c912c19018419cb5738d4013107167 1.1 beta 4
--- a/.pkgmeta	Thu Nov 18 13:11:08 2010 -0800
+++ b/.pkgmeta	Tue Apr 12 16:06:31 2011 -0700
@@ -4,10 +4,6 @@
   - libdatabroker-1-1
   - buttonfacade
 
-optional-dependencies:
-  - ace3
-  - libkeybound-1-0
-
 externals:
   lib/AceAddon-3.0:
     url: svn://svn.wowace.com/wow/ace3/mainline/trunk/AceAddon-3.0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ActionButton.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,806 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local IsUsableAction = IsUsableAction
+local IsEquippedAction = IsEquippedAction
+local IsConsumableAction = IsConsumableAction
+local IsStackableAction = IsStackableAction
+local GetActionText = GetActionText
+local GetCVar = GetCVar
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+local IsCurrentAction = IsCurrentAction
+local IsAutoRepeatAction = IsAutoRepeatAction
+local IsUsableAction = IsUsableAction
+local IsAttackAction = IsAttackAction
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local GetActionCooldown = GetActionCooldown
+local GetActionTexture = GetActionTexture
+local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
+local TOOLTIP_UPDATE_TIME = TOOLTIP_UPDATE_TIME
+local IsActionInRange = IsActionInRange
+local InCombatLockdown = InCombatLockdown
+local HasAction = HasAction
+
+--
+-- Secure snippets
+-- These are run within the context of the bar's sandbox, as the
+-- buttons themselves do not have their own sandbox.
+--
+local _onstate_mc = -- function(self, stateid, newstate)
+[[
+  local oldMcVehicleState = mcVehicleState
+  mcVehicleState = newstate
+  control:ChildUpdate()
+  if oldMcVehicleState == "vehicle" or mcVehicleState == "vehicle" then
+    control:ChildUpdate("vehicle")
+  end
+]]
+
+local _childupdate = -- function(self, snippetid, message)
+[[
+  local action = nil
+  if (doVehicle and mcVehicleState == "vehicle") or
+     (doMindControl and mcVehicleState == "mc") then
+    local idx = self:GetAttribute("bar-idx")
+    local maxN = (doVehicle and mcVehicleState == "vehicle") and 7 or 12
+    if idx and idx <= maxN then
+      action = 120 + idx
+    else
+      action = 0
+    end
+  elseif state and settings[state] and settings[state].page then
+    action = self:GetAttribute("action-"..settings[state].page) 
+  end
+  if action == nil then
+    action = self:GetAttribute("default-action")
+  end
+
+  self:SetAttribute("action",action)
+
+  if not self:GetAttribute("showgrid") then
+    local tempShow = self:GetAttribute("showgrid-temp")
+    local evtShow = self:GetAttribute("showgrid-event")
+    if tempShow then tempShow = (tempShow > 0) end
+    if evtShow then evtShow = (evtShow > 0) end
+
+    if tempShow or evtShow or HasAction(action) then
+      self:Show()
+    else
+      self:Hide()
+    end
+  end
+]]
+
+local _childupdate_vehicleExit =  -- function(self, snippetid, message)
+[[
+  local show = (mcVehicleState == "vehicle")
+  if show and doVehicle then
+    self:SetAttribute("type","macro")
+    self:Show()
+  else
+    self:SetAttribute("type","action")
+  end
+  control:CallMethod("ShowVehicleExit",show)
+]]
+
+local _childupdate_showgrid = -- function(self, snippetid, message)
+[[
+  showgrid_event = message
+  self:SetAttribute("showgrid-event",message)
+  if not self:GetAttribute("showgrid") then
+    local count = message + (self:GetAttribute("showgrid-temp") or 0)
+    if count <= 0 then
+      local action = self:GetAttribute("action")
+        -- note that HasAction is not updated on the target of a drag until after ACTIONBAR_HIDEGRID
+        -- so, we set a flag for this button in pre-click/receive-drag and check for it here
+      if HasAction(action) or self:GetAttribute("showgrid-clicked") then
+        if not self:IsShown() then
+          self:Show()
+        end
+        self:SetAttribute("showgrid-clicked",false)
+      else 
+        if self:IsShown() then
+          self:Hide()
+        end
+      end
+    else
+      self:Show()
+    end
+  end
+]]
+
+local _onDragStart = -- function(self, button, kind, value, ...)
+[[
+  if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
+    return kind, value, ...
+  else
+    return "action", self:GetAttribute("action")
+  end
+]]
+
+local _onReceiveDrag = -- function(self, button, kind, value, ...)
+[[
+  if kind ~= "spell" and kind ~= "item" and kind ~= "macro" and kind ~= "flyout" then
+    return kind, value, ...
+  else
+    if showgrid_event and showgrid_event > 0 then
+      self:SetAttribute("showgrid-clicked",true)
+    end
+    return "action", self:GetAttribute("action")
+  end
+]]
+
+local _onClick = -- function(self, button, down)
+[[
+  if showgrid_event and showgrid_event > 0 then
+    self:SetAttribute("showgrid-clicked",true)
+  end
+  return button
+]]
+
+--
+-- private
+--
+local eventList = {
+  "PLAYER_ENTERING_WORLD",
+  "ACTIONBAR_PAGE_CHANGED",
+  "ACTIONBAR_SLOT_CHANGED",
+  "UPDATE_BINDINGS",
+  "ACTIONBAR_UPDATE_STATE",
+  "ACTIONBAR_UPDATE_USABLE",
+  "ACTIONBAR_UPDATE_COOLDOWN",
+  "UNIT_INVENTORY_CHANGED",
+  "LEARNED_SPELL_IN_TAB",
+  "UPDATE_INVENTORY_ALERTS",
+  "PLAYER_TARGET_CHANGED",
+  "TRADE_SKILL_SHOW",
+  "TRADE_SKILL_CLOSE",
+  "PLAYER_ENTER_COMBAT",
+  "PLAYER_LEAVE_COMBAT",
+  "START_AUTOREPEAT_SPELL",
+  "STOP_AUTOREPEAT_SPELL",
+  "UNIT_ENTERED_VEHICLE",
+  "UNIT_EXITED_VEHICLE",
+  "COMPANION_UPDATE",
+}
+
+--
+-- Action Button class
+--
+local buttonTypeID = "Action"
+local Super = ReAction.Button
+local Action = setmetatable( 
+  { 
+    defaultBarConfig = { 
+      type = buttonTypeID,
+      btnWidth = 36,
+      btnHeight = 36,
+      btnRows = 1,
+      btnColumns = 12,
+      spacing = 3,
+      buttons = { },
+    },
+
+    barType = L["Action Bar"],
+    buttonTypeID = buttonTypeID
+  },
+  { __index = Super } )
+
+ReAction.Button.Action = Action
+ReAction:RegisterBarType(Action, true)
+
+function Action:New( config, bar, idx, idHint )
+  local name = format("ReAction_%s_Action_%d",bar:GetName(),idx)
+ 
+  self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+  self.barConfig = bar:GetConfig()
+
+  local f = self:GetFrame()
+  local barFrame = bar:GetFrame()
+
+  self.rangeTimer = TOOLTIP_UPDATE_TIME
+
+  -- set up the base action ID
+  self:SetActionIDPool("action",120)
+  config.actionID = self:AcquireActionID(config.actionID, idHint)
+  self.nPages = 1
+
+  -- attribute setup
+  f:SetAttribute("type","action")
+  f:SetAttribute("checkselfcast", true)
+  f:SetAttribute("checkfocuscast", true)
+  f:SetAttribute("action", config.actionID)
+  f:SetAttribute("default-action", config.actionID)
+  f:SetAttribute("bar-idx",idx)
+  f:SetAttribute("showgrid-temp",0)
+  f:SetAttribute("showgrid-event",0)
+  f:SetAttribute("showgrid",not self:GetBarConfig().hideEmpty)
+
+  -- non secure scripts
+  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+  f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
+  f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
+  f:SetScript("OnUpdate", function(frame, elapsed) self:OnUpdate(elapsed) end)
+  f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
+  f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)
+
+  -- event registration
+  f:EnableMouse(true)
+  f:RegisterForDrag("LeftButton", "RightButton")
+  f:RegisterForClicks("AnyUp")
+  for _, evt in pairs(eventList) do
+    f:RegisterEvent(evt)
+  end
+
+  f.action = config.actionID -- need this to support silly ActionButton_UpdateFlyout. Should not taint anything anymore.
+
+  -- secure handlers
+  f:SetAttribute("_childupdate", _childupdate)
+  f:SetAttribute("_childupdate-showgrid",_childupdate_showgrid)
+  barFrame:WrapScript(f, "OnDragStart", _onDragStart)
+  barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
+  barFrame:WrapScript(f, "OnClick", _onClick)
+
+  -- attach to skinner
+  bar:SkinButton(self)
+
+  -- initial display
+  if ReAction:GetConfigMode() then
+    self:ShowGridTemp(true)
+  end
+
+  self:Refresh()
+
+  return self
+end
+
+function Action:Destroy()
+  local f = self:GetFrame()
+  local c = self:GetConfig()
+
+  f:SetAttribute("_childupdate-vehicle",nil)
+  f:SetAttribute("action",c.actionID) -- so that Super.Destroy releases the right one
+
+  if c.pageactions and #c.pageactions > 1 then
+    for i = 2, #c.pageactions do 
+      self:ReleaseActionID(c.pageactions[i])
+      self:ReleaseActionID(id)
+    end
+  end
+  
+  Super.Destroy(self)
+end
+
+function Action:GetBarConfig()
+  -- this is the per-bar Action module config structure,
+  -- not the config structure of the bar itself
+  return self.barConfig
+end
+
+function Action:Refresh()
+  Super.Refresh(self)
+  self:RefreshPages()
+  self:InstallVehicle()
+  self:ShowGrid(not self:GetBarConfig().hideEmpty)
+  self:UpdateAction()
+end
+
+function Action:InstallVehicle()
+  local f = self:GetFrame()
+  if self.idx == 7 and self:GetBarConfig().vehicle then
+    if not self.vehicleInstalled then
+      self.vehicleInstalled = true
+      -- install vehicle-exit button on 7th button (only)
+      f:SetAttribute("_childupdate-vehicle", _childupdate_vehicleExit)
+      f:SetAttribute("macrotext","/run VehicleExit()")
+      self:GetBar():GetFrame().ShowVehicleExit = function(bar,show)
+        self:ShowVehicleExit(show)
+      end
+    end
+    -- setscale blows away tex coords
+    self:UpdateIcon()
+  elseif self.vehicleInstalled then
+    self.vehicleInstalled = false
+    f:SetAttribute("_childupdate-vehicle",nil)
+    f:SetAttribute("macrotext",nil)
+  end
+end
+
+function Action:ShowGrid( show )
+  if not InCombatLockdown() then
+    self.frame:SetAttribute("showgrid", show)
+    self:UpdateShowGrid()
+  end
+end
+
+function Action:ShowGridTemp( show )
+  -- This function only modifies the show-grid when out
+  -- of combat, and is ignored by the secure handler. Use 
+  -- it for configuration modes.
+  if not InCombatLockdown() then
+    local count = self.showGridTempCount or 0
+    if show then
+      count = count + 1
+    else
+      count = count - 1
+    end
+    if count < 0 then count = 0 end
+    self.showGridTempCount = count
+    self:GetFrame():SetAttribute("showgrid-temp",count)
+    self:UpdateShowGrid()
+  end
+end
+
+function Action:UpdateAll()
+  self:UpdateActionIDLabel(ReAction:GetConfigMode())
+  self:UpdateHotkey()
+  self:UpdateShowGrid()
+  self:UpdateIcon()
+  self:UpdateBorder()
+  self:UpdateMacroText()
+  self:UpdateCount()
+  self:UpdateTooltip()
+  self:UpdateCheckedState()
+  self:UpdateUsable()
+  self:UpdateCooldown()
+  self:UpdateFlash()
+end
+
+function Action:UpdateAction()
+  local action = self:GetActionID()
+  if action ~= self.actionID then
+    self.actionID = action
+    self:UpdateAll()
+  end
+end
+
+function Action:UpdateShowGrid()
+  if not InCombatLockdown() then
+    local f = self:GetFrame()
+    local count = (f:GetAttribute("showgrid-event") or 0) +
+                  (self.showGridTempCount or 0) +
+                  (f:GetAttribute("showgrid") and 1 or 0)
+
+    if count <= 0 and not HasAction(self.actionID) then
+      if f:IsShown() then
+        f:Hide()
+      end
+    elseif not f:IsShown() then
+      f:Show()
+    end
+  end
+end
+
+function Action:UpdateIcon()
+  local texture, tLeft, tRight, tTop, tBottom = self:GetIconTexture()
+  local icon = self.frames.icon
+  local hotkey = self.frames.hotkey
+  local f = self:GetFrame()
+  
+  if self.vehicleExitMode then
+    texture = "Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up"
+    icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
+    icon:SetVertexColor(1,1,1)
+  else
+    icon:SetTexCoord(0,1,0,1)
+  end
+
+  if texture then
+    icon:SetTexture(texture)
+    if tLeft then
+      icon:SetTexCoord(tLeft,tRight,tTop,tBottom)
+    end
+    icon:Show()
+    self.rangeTimer = -1
+    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
+  else
+    icon:Hide()
+    self.frames.cooldown:Hide()
+    self.rangeTimer = nil
+    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
+  end
+end
+
+function Action:GetIconTexture()
+  return GetActionTexture(self.actionID)
+end
+
+function Action:UpdateBorder()
+  local action = self.actionID
+  if ReAction:GetKeybindMode() then
+    self:UpdateKeybindModeDisplay(true)
+  elseif IsEquippedAction(action) then
+    self.frames.border:SetVertexColor(0, 1.0, 0, 0.35)
+    self.frames.border:Show()
+  else
+    self.frames.border:Hide()
+  end
+end
+
+function Action:UpdateMacroText()
+  local action = self.actionID
+  if not IsConsumableAction(action) and not IsStackableAction(action) then
+    self.frames.name:SetText(GetActionText(action))
+  else
+    self.frames.name:SetText("")
+  end
+end
+
+function Action:UpdateCount()
+  local action = self.actionID
+  if IsConsumableAction(action) or IsStackableAction(action) then
+    self.frames.count:SetText(GetActionCount(action))
+  else
+    self.frames.count:SetText("")
+  end
+end
+
+function Action:UpdateTooltip()
+  local f = self:GetFrame()
+  if GameTooltip:GetOwner() == f then
+    self:SetTooltip()
+  end
+end
+
+function Action:SetTooltip()
+  local f = self:GetFrame()
+  if GetCVar("UberTooltips") == "1" then
+    GameTooltip_SetDefaultAnchor(GameTooltip, f)
+  else
+    GameTooltip:SetOwner(f,"ANCHOR_RIGHT")
+  end
+  GameTooltip:SetAction(self.actionID)
+end
+
+function Action:UpdateCheckedState()
+  local action = self.actionID
+  if IsCurrentAction(action) or IsAutoRepeatAction(action) then
+    self:GetFrame():SetChecked(1)
+  else
+    self:GetFrame():SetChecked(0)
+  end
+end
+
+function Action:UpdateUsable()
+  local isUsable, notEnoughMana = self:GetUsable()
+  local noRange = self:GetInRange()
+
+  isUsable = self.vehicleExitMode or (isUsable and not noRange)
+
+  if isUsable then
+    if self.usableStatus ~= "usable" then
+      self.frames.icon:SetVertexColor(1.0, 1.0, 1.0)
+      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
+      self.usableStatus = "usable"
+    end
+  elseif noRange then
+    if self.usableStatus ~= "norange" then
+      self.frames.icon:SetVertexColor(1.0,0.1,0.1)
+      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
+      self.usableStatus = "norange"
+    end
+  elseif notEnoughMana then
+    if self.usableStatus ~= "oom" then
+      self.frames.icon:SetVertexColor(0.5, 0.5, 1.0)
+      self.frames.normalTexture:SetVertexColor(0.5, 0.5, 1.0)
+      self.usableStatus = "oom"
+    end
+  else
+    if self.usableStatus ~= "unusable" then
+      self.frames.icon:SetVertexColor(0.4, 0.4, 0.4)
+      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
+      self.usableStatus = "unusable"
+    end
+  end
+end
+
+function Action:GetUsable()
+  return IsUsableAction(self.actionID)
+end
+
+function Action:GetInRange()
+  return IsActionInRange(self.actionID) == 0
+end
+
+function Action:UpdateCooldown()
+  CooldownFrame_SetTimer(self.frames.cooldown, self:GetCooldown())
+end
+
+function Action:GetCooldown()
+  return GetActionCooldown(self.actionID)
+end
+
+function Action:UpdateFlash()
+  local action = self.actionID
+  self:SetFlash( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) )
+end
+
+function Action:SetFlash(flash)
+  if self.flashing ~= flash then
+    self.flashing = flash
+    self.flashtime = 0
+    if not flash then
+      self.frames.flash:Hide()
+    end
+    self:UpdateCheckedState()
+  end
+end
+
+function Action:RunFlash(elapsed)
+  if self.flashing then
+    local flashtime = self.flashtime - elapsed
+    self.flashtime = flashtime
+    if flashtime <= 0 then
+      local overtime = -flashtime
+      if overtime >= ATTACK_BUTTON_FLASH_TIME then
+        overtime = 0
+      end
+      flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
+      local flash = self.frames.flash
+      if flash:IsShown() then
+        flash:Hide()
+      else
+        flash:Show()
+      end
+    end
+  end
+end
+
+function Action:RunRangeFinder(elapsed)
+  local rangeTimer = self.rangeTimer
+  if rangeTimer then
+    rangeTimer = rangeTimer - elapsed
+    self.rangeTimer = rangeTimer
+    if rangeTimer <= 0 then
+      self:UpdateUsable()
+      self.rangeTimer = TOOLTIP_UPDATE_TIME
+    end
+  end
+end
+
+function Action:GetActionID(page)
+  if page == nil then
+    -- get the effective ID
+    return self:GetFrame():GetAttribute("action")
+  else
+    if page == 1 then
+      return self.config.actionID
+    else
+      return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
+    end
+  end
+end
+
+function Action:SetActionID( id, page )
+  id = tonumber(id)
+  page = tonumber(page)
+  if id == nil or id < 1 or id > 120 then
+    ReAction:UserError(L["Action ID range is 1-120"])
+    return
+  end
+  if page and page ~= 1 then
+    if not self.config.pageactions then
+      self.config.pageactions = { }
+    end
+    self:ReleaseActionID(self.config.pageactions[page])
+    self.config.pageactions[page] = id
+    self:AcquireActionID(self.config.pageactions[page])
+    self.frame:SetAttribute("action-page"..page,id)
+  else
+    self:ReleaseActionID(self.config.actionID)
+    self.config.actionID = id
+    self:AcquireActionID(self.config.actionID)
+    self.frame:SetAttribute("action",id)
+    self.frame:SetAttribute("default-action",id)
+    if self.config.pageactions then
+      self.config.pageactions[1] = id
+      self.frame:SetAttribute("action-page1",id)
+    end
+  end
+end
+
+function Action:RefreshPages( force )
+  local nPages = self:GetBarConfig().nPages
+  if nPages and (nPages ~= self.nPages or force) then
+    local f = self:GetFrame()
+    local c = self.config.pageactions
+    if nPages > 1 and not c then
+      c = { }
+      self.config.pageactions = c
+    end
+    for i = 1, nPages do
+      if i > 1 then
+        c[i] = self:AcquireActionID(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
+      else
+        c[i] = self.config.actionID  -- page 1 is the same as the base actionID
+      end
+      f:SetAttribute("action-page"..i,c[i])
+    end
+    for i = nPages+1, #c do
+      self:ReleaseActionID(c[i])
+      c[i] = nil
+      f:SetAttribute("action-page"..i,nil)
+    end
+    self.nPages = nPages
+  end
+end
+
+function Action:SetupBar( bar )
+  Super.SetupBar(self,bar)
+
+  local f = bar:GetFrame()
+  local config = bar:GetConfig()
+  f:SetAttribute("mindcontrol",config.mindcontrol)
+  f:SetAttribute("vehicle",config.vehicle)
+  f:Execute(
+    [[
+    doMindControl = self:GetAttribute("mindcontrol")
+    doVehicle = self:GetAttribute("vehicle")
+    control:ChildUpdate()
+    ]])
+
+  f:SetAttribute("_onstate-mc", _onstate_mc)
+  RegisterStateDriver(f, "mc", "[vehicleui] vehicle; [bonusbar:5] mc; none")
+
+  f:SetAttribute("lockbuttons",config.lockButtons)
+  f:SetAttribute("lockbuttonscombat",config.lockButtonsCombat)
+  f:Execute(
+    [[
+      lockButtons = self:GetAttribute("lockbuttons")
+      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
+    ]])
+end
+
+
+function Action:SetButtonLock( bar, lock, lockCombat )
+  local f = bar:GetFrame()
+  f:SetAttribute("lockbuttons",lock)
+  f:SetAttribute("lockbuttonscombat",lockCombat)
+  f:Execute(
+    [[
+      lockButtons = self:GetAttribute("lockbuttons")
+      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
+    ]])
+end
+
+
+function Action:ShowVehicleExit(show)
+  self.vehicleExitMode = show and self:GetBarConfig().vehicle
+  self:UpdateIcon()
+end
+
+function Action:OnEnter( )
+  self:SetTooltip()
+end
+
+function Action:OnLeave( )
+  GameTooltip:Hide()
+end
+
+function Action:OnAttributeChanged( attr, value )
+  if attr ~= "statehidden" then
+    self:UpdateAction()
+  end
+  local f = self:GetFrame()
+  f.action = f:GetAttribute("action") -- support ActionButton_UpdateFlyout
+end
+
+function Action:PostClick( )
+  self:UpdateCheckedState()
+end
+
+function Action:OnUpdate( elapsed )
+  self:RunFlash(elapsed)
+  self:RunRangeFinder(elapsed)
+end
+
+function Action:OnDragStart()
+  self:UpdateCheckedState()
+  self:UpdateFlash()
+end
+
+function Action:OnReceiveDrag()
+  self:UpdateCheckedState()
+  self:UpdateFlash()
+end
+
+function Action:OnEvent(event, ...)
+  if self[event] then
+    self[event](self, event, ...)
+  end
+end
+
+function Action:ACTIONBAR_SLOT_CHANGED(event, action)
+  if action == 0 or action == self.actionID then
+    self:UpdateAll()
+  end
+end
+
+function Action:PLAYER_ENTERING_WORLD()
+  self:UpdateAction()
+end
+
+function Action:ACTIONBAR_PAGE_CHANGED()
+  self:UpdateAction()
+end
+
+function Action:UPDATE_BONUS_ACTIONBAR()
+  self:UpdateAction()
+end
+
+function Action:UPDATE_BINDINGS()
+  self:UpdateHotkey()
+end
+
+function Action:PLAYER_TARGET_CHANGED()
+  self.rangeTimer = -1
+end
+
+function Action:ACTIONBAR_UPDATE_STATE()
+  self:UpdateCheckedState()
+end
+
+function Action:TRADE_SKILL_SHOW()
+  self:UpdateCheckedState()
+end
+Action.TRADE_SKILL_CLOSE = Action.TRADE_SKILL_CLOSE
+
+function Action:UNIT_ENTERED_VEHICLE(event,unit)
+  if unit == "player" then
+    self:UpdateCheckedState()
+  end
+end
+Action.UNIT_EXITED_VEHICLE = Action.UNIT_ENTERED_VEHICLE
+
+function Action:COMPANION_UPDATE(event,unit)
+  if unit == "mount" then
+    self:UpdateCheckedState()
+  end
+end
+
+function Action:ACTIONBAR_UPDATE_USABLE()
+  self:UpdateUsable()
+end
+
+function Action:ACTIONBAR_UPDATE_COOLDOWN()
+  self:UpdateCooldown()
+end
+
+function Action:PLAYER_ENTER_COMBAT()
+  if IsAttackAction(self.actionID) then
+    self:SetFlash(true)
+  end
+end
+
+function Action:PLAYER_LEAVE_COMBAT()
+  if IsAttackAction(self.actionID) then
+    self:SetFlash(false)
+  end
+end
+
+function Action:START_AUTOREPEAT_SPELL()
+  if IsAutoRepeatAction(self.actionID) then
+    self:SetFlash(true)
+  end
+end
+
+function Action:STOP_AUTOREPEAT_SPELL()
+  if not IsAttackAction(self.actionID) then
+    self:SetFlash(false)
+  end
+end
+
+function Action:UNIT_INVENTORY_CHANGED(unit)
+  if unit == "player" then
+    self:UpdateTooltip()
+  end
+end
+
+function Action:LEARNED_SPELL_IN_TAB()
+  self:UpdateTooltip()
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BagButton.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,499 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local GetCVar = GetCVar
+local ContainerIDToInventoryID = ContainerIDToInventoryID
+local NUM_CONTAINER_FRAMES = NUM_CONTAINER_FRAMES
+local IsModifiedClick = IsModifiedClick
+local CursorHasItem = CursorHasItem
+local GetInventoryItemTexture = GetInventoryItemTexture
+local GetInventorySlotInfo = GetInventorySlotInfo
+local PickupBagFromSlot = PickupBagFromSlot
+local CursorCanGoInSlot = CursorCanGoInSlot
+
+-- class declarations
+local buttonTypeID = "Bag"
+local weak     = { __mode = "k" }
+local Super    = ReAction.Button
+local BagBase  = setmetatable( 
+  { 
+    defaultBarConfig = { 
+      type = buttonTypeID,
+      btnWidth = 30,
+      btnHeight = 30,
+      btnRows = 1,
+      btnColumns = 6,
+      spacing = 4,
+      buttons = { }
+    },
+
+    barType = L["Bag Bar"],
+    buttonTypeID = buttonTypeID,
+
+    allButtons = setmetatable( { }, weak )
+  },
+  { __index = Super } )
+
+local Bag      = setmetatable( { }, { __index = BagBase } )
+local Backpack = setmetatable( { }, { __index = BagBase } )
+local Keyring  = setmetatable( { }, { __index = BagBase } )
+
+ReAction.Button.Bag = BagBase
+ReAction:RegisterBarType(BagBase)
+
+--
+-- Bag Button base class
+--
+
+function BagBase:New( btnCfg, bar, idx, idHint )
+  local name = format("ReAction_%s_Bag_%d",bar:GetName(),idx)
+
+  -- use a variable private leaf implementation class
+  -- unlike traditional OO programming, we can initialize the leaf
+  -- class before initializing its parent
+  local class = Bag
+  if idx == 1 then
+    class = Backpack
+  elseif idx == 6 then
+    class = Keyring
+  end
+  self = class:New(name, btnCfg, bar, idx)
+
+  local f = self:GetFrame()
+  local config = self:GetConfig()
+
+  -- set up the bag ID pool
+  self:SetActionIDPool("bag",6)
+  config.bagID = self:AcquireActionID(config.bagID, idHint, true)
+
+  -- non secure scripts
+  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+  f:SetScript("OnReceiveDrag", function(frame, ...) self:OnReceiveDrag(...) end)
+  f:SetScript("OnClick", function(frame, ...) self:OnClick(...) end)
+
+  -- secure handlers
+  -- (none)
+
+  -- event registration
+  f:EnableMouse(true)
+  f:RegisterForClicks("LeftButtonUp","RightButtonUp")
+  f:RegisterEvent("UPDATE_BINDINGS")
+
+  -- frame setup
+  f:SetID(self:GetBagID())
+
+  if not f.hotkey then
+    local h = f:CreateFontString(name.."HotKey","ARTWORK","NumberFontNormalSmallGray")
+    h:SetWidth(30)
+    h:SetHeight(10)
+    h:SetJustifyH("RIGHT")
+    h:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2)
+    h:Show()
+    f.hotkey = h
+  end
+
+  if not _G[name.."ItemAnim"] then
+    local anim = CreateFrame("Model",name.."ItemAnim",f,"ItemAnimTemplate")
+    anim:SetPoint("BOTTOMRIGHT",f,"BOTTOMRIGHT",-10,0)
+    anim:Hide()
+  end
+
+  if not f.border then
+    local b = f:CreateTexture(name.."Border","OVERLAY")
+    b:SetAllPoints()
+    b:SetWidth(f:GetWidth()*(62/36))
+    b:SetHeight(f:GetHeight()*(62/36))
+    b:SetTexture("Interface\\Buttons\UI-ActionButton-Border")
+    b:SetBlendMode("ADD")
+    b:Hide()
+    f.border = b
+  end
+
+  self.frames.count:SetDrawLayer("ARTWORK")
+
+  self.frames.hotkey = f.hotkey
+  self.frames.border = _G[name.."Border"]
+  self.frames.icon = _G[name.."IconTexture"]
+  self.frames.anim = _G[name.."ItemAnim"]
+
+  -- initial display
+  if ReAction:GetConfigMode() then
+    self:GetFrame():Show()
+  end
+
+  self:Refresh()
+
+  BagBase.allButtons[self] = true
+
+  return self
+end
+
+function BagBase:Destroy()
+  BagBase.allButtons[self] = nil
+  Super.Destroy(self)
+end
+
+
+function BagBase:GetActionID()
+  return self.config.bagID
+end
+
+function BagBase:GetBagID()
+  return self:GetActionID() - 1
+end
+
+function BagBase:Refresh()
+  Super.Refresh(self)
+  self:UpdateHotkey()
+  self:Update()
+end
+
+function BagBase:Update()
+  self:UpdateChecked()
+end
+
+function BagBase:UpdateChecked(force)
+  if force == nil then
+    for i=1, NUM_CONTAINER_FRAMES do
+      local c = _G["ContainerFrame"..i]
+      if c:GetID() == self:GetBagID() and c:IsShown() then
+        self:GetFrame():SetChecked(1)
+        return
+      end
+    end
+    self:GetFrame():SetChecked(0)
+  end
+  self:GetFrame():SetChecked(force)
+end
+
+function BagBase:OnEvent(evt, ...)
+  if self[evt] then
+    self[evt](self, ...)
+  end
+end
+
+function BagBase:OnEnter()
+  self:SetTooltip()
+end
+
+function BagBase:OnLeave()
+  GameTooltip:Hide()
+end
+
+function BagBase:UPDATE_BINDINGS()
+  self:UpdateHotkey()
+end
+
+function BagBase:IterateAllButtons()
+  return pairs(self.allButtons)
+end
+
+
+--
+-- Bag Button class
+--
+function Bag:New(name, cfg, bar, idx)
+  self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
+
+  local f = self:GetFrame()
+
+  f:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight")
+
+  f:RegisterEvent("CURSOR_UPDATE")
+  f:RegisterEvent("BAG_UPDATE")
+  f:RegisterEvent("BAG_CLOSED")
+  f:SetScript("OnDragStart", function(frame, ...) self:OnDragStart(...) end)
+  f:RegisterForDrag("LeftButton")
+
+  -- attach to skinner
+  bar:SkinButton(self,
+    {
+      Icon = _G[name.."IconTexture"]
+    }
+  )
+
+  return self
+end
+
+function Bag:GetInventorySlot()
+  return ContainerIDToInventoryID(self:GetBagID())
+end
+
+function Bag:GetInventorySlotName()
+  return "Bag"..(self:GetBagID()-1).."Slot"
+end
+
+function Bag:SetTooltip()
+  GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_LEFT")
+  if not GameTooltip:SetInventoryItem("player", self:GetInventorySlot()) then
+    GameTooltip:SetText(EQUIP_CONTAINER, 1.0, 1.0, 1.0)
+  end
+end
+
+function Bag:Update()
+	local texture = GetInventoryItemTexture("player", self:GetInventorySlot())
+	if texture then
+    self.frames.icon:SetTexture(texture)
+    self.frames.icon:Show()
+    self:GetFrame():SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
+	else
+    local _, bgTex = GetInventorySlotInfo(self:GetInventorySlotName())
+    self.frames.icon:SetTexture(bgTex)
+    self:GetFrame():SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
+	end
+  self:UpdateChecked()
+end
+
+function Bag:OnClick()
+  if IsModifiedClick("OPENALLBAGS") then
+    OpenAllBags()
+  else
+    if not PutItemInBag(self:GetInventorySlot()) then
+      ToggleBag(self:GetBagID())
+    end
+  end
+  self:UpdateChecked()
+end
+
+function Bag:OnReceiveDrag()
+  if CursorHasItem() then
+    PutItemInBag(self:GetInventorySlot())
+  end
+end
+
+function Bag:OnDragStart()
+  PickupBagFromSlot(self:GetInventorySlot())
+  self:Update()
+end
+
+function Bag:BAG_UPDATE(bag)
+  if bag == self:GetBagID() then
+    self:Update()
+  end
+end
+
+function Bag:CURSOR_UPDATE()
+  if CursorCanGoInSlot(self:GetInventorySlot()) then
+    self:GetFrame():LockHighlight()
+  else
+    self:GetFrame():UnlockHighlight()
+  end
+end
+
+function Bag:BAG_CLOSED(bag)
+  if bag == self:GetBagID() then
+    self:Update()
+  end
+end
+
+
+--
+-- Backpack Button class
+--
+function Backpack:New(name, cfg, bar, idx)
+  self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
+
+  local f = self:GetFrame()
+  local icon = _G[name.."IconTexture"]
+  icon:SetTexture("Interface\\Buttons\\Button-Backpack-Up")
+  icon:Show()
+  f:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight")
+  f:RegisterEvent("PLAYER_ENTERING_WORLD");
+  f:RegisterEvent("CVAR_UPDATE");
+  f:SetScript("OnShow", function(frame, ...) self:OnShow(...) end)
+
+  -- attach to skinner
+  bar:SkinButton(self,
+    {
+      Icon = _G[name.."IconTexture"]
+    }
+  )
+
+  return self
+end
+
+function Backpack:Update()
+  self:UpdateFreeSlots()
+  self:UpdateChecked()
+end
+
+function Backpack:UpdateFreeSlots()
+  if GetCVar("displayFreeBagSlots") == "1" then
+    local total = 0
+    for i = BACKPACK_CONTAINER, NUM_BAG_SLOTS do
+      local free, family = GetContainerNumFreeSlots(i)
+      if family == 0 then
+        total = total + free
+      end
+    end
+
+    self.freeSlots = total
+    self.frames.count:SetText(format("(%s)", self.freeSlots))
+    self.frames.count:Show()
+  elseif self.frames.count:IsShown() then
+    self.frames.count:Hide()
+  end
+end
+
+function Backpack:SetTooltip()
+  GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_LEFT")
+  GameTooltip:SetText(BACKPACK_TOOLTIP, 1.0, 1.0, 1.0)
+  GameTooltip:AddLine(string.format(NUM_FREE_SLOTS, (self.freeSlots or 0)))
+  GameTooltip:Show();
+end
+
+function Backpack:OnShow()
+  self:UpdateFreeSlots()
+end
+
+function Backpack:OnClick()
+  if IsModifiedClick("OPENALLBAGS") then
+    OpenAllBags()
+  else
+    if not PutItemInBackpack() then
+      ToggleBackpack()
+    end
+  end
+  self:UpdateChecked()
+end
+
+function Backpack:OnReceiveDrag()
+  if CursorHasItem() then
+    PutItemInBackpack()
+  end
+end
+
+function Backpack:PLAYER_ENTERING_WORLD()
+  self:CVAR_UPDATE("DISPLAY_FREE_BAG_SLOTS", GetCVar("displayFreeBagSlots"))
+end
+
+function Backpack:CVAR_UPDATE( cvar, value )
+  if cvar == "DISPLAY_FREE_BAG_SLOTS" then
+    if value == "1" then
+      self:GetFrame():RegisterEvent("BAG_UPDATE")
+    else
+      self:GetFrame():UnregisterEvent("BAG_UPDATE")
+    end
+    self:UpdateFreeSlots()
+  end
+end
+
+function Backpack:BAG_UPDATE(bag)
+  if bag >= BACKPACK_CONTAINER and bag <= NUM_BAG_SLOTS then
+    self:UpdateFreeSlots()
+  end
+end
+
+
+--
+-- Keyring Button class
+--
+function Keyring:New(name, cfg, bar, idx)
+  self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
+
+  local f = self:GetFrame()
+
+  f:SetWidth(18)
+  f:SetHeight(39)
+
+  local tex = f:GetNormalTexture()
+  tex:ClearAllPoints()
+  tex:SetAllPoints()
+  
+  f:SetNormalTexture("Interface\\Buttons\\UI-Button-KeyRing")
+  f:SetHighlightTexture("Interface\\Buttons\\UI-Button-KeyRing-Highlight")
+  f:SetPushedTexture("Interface\\Buttons\\UI-Button-KeyRing-Down")
+  f:GetNormalTexture():SetTexCoord(0,0.5625,0,0.609375)
+  f:GetHighlightTexture():SetTexCoord(0,0.5625,0,0.609375)
+  f:GetPushedTexture():SetTexCoord(0,0.5625,0,0.609375)
+
+  if not HasKey() then
+    f:Hide()
+  end
+
+  -- DO NOT attach to skinner
+
+  return self
+end
+
+function Keyring:GetBagID()
+  return KEYRING_CONTAINER
+end
+
+function Keyring:Refresh()
+  local f = self:GetFrame()
+  self.bar:PlaceButton( self, f:GetHeight(), f:GetHeight() ) -- use height x height since it's an odd size
+  self:UpdateHotkey()
+  self:Update()
+end
+
+function Keyring:SetTooltip()
+  GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_RIGHT");
+  GameTooltip:SetText(KEYRING, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+  GameTooltip:AddLine();
+end
+
+function Keyring:OnReceiveDrag()
+  if CursorHasItem() then
+    PutKeyInKeyRing()
+  end
+end
+
+function Keyring:OnClick()
+  if CursorHasItem() then
+    PutKeyInKeyRing()
+  else
+    ToggleKeyRing()
+  end
+  self:UpdateChecked()
+end
+
+function Keyring:ShowGridTemp(show)
+  if not HasKey() then
+    if show then 
+      self:GetFrame():Show()
+    else
+      self:GetFrame():Hide()
+    end
+  end
+end
+
+
+
+-- hook some functions to propagate to our bag buttons
+hooksecurefunc("Disable_BagButtons", 
+  function()
+    for b in BagBase:IterateAllButtons() do
+      local f = b:GetFrame()
+      f:Disable()
+      SetDesaturation(b.frames.icon,1)
+    end
+  end)
+
+hooksecurefunc("Enable_BagButtons",
+  function()
+    for b in BagBase:IterateAllButtons() do
+      local f = b:GetFrame()
+      f:Enable()
+      SetDesaturation(b.frames.icon,nil)
+    end
+  end)
+
+hooksecurefunc("ContainerFrame_OnHide",
+  function()
+    for b in BagBase:IterateAllButtons() do
+      b:Update()
+    end
+  end)
+
+hooksecurefunc("ContainerFrame_OnShow",
+  function()
+    for b in BagBase:IterateAllButtons() do
+      b:Update()
+    end
+  end)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Bar.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,854 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local LKB = ReAction.LKB
+local _G = _G
+local CreateFrame = CreateFrame
+local floor = math.floor
+local fmod = math.fmod
+local format = string.format
+local tfetch = addonTable.tfetch
+local tbuild = addonTable.tbuild
+local fieldsort = addonTable.fieldsort
+
+local LSG = LibStub("ReAction-LibShowActionGrid-1.0")
+
+---- Secure snippets ----
+local _reaction_init = 
+[[
+  anchorKeys = newtable("point","relPoint","x","y")
+
+  state = nil
+  set_state = nil
+  state_override = nil
+  unit_exists = nil
+
+  showAll = false
+  hidden = false
+
+  defaultAlpha = 1.0
+  defaultScale = 1.0
+  defaultAnchor = newtable()
+
+  activeStates = newtable()
+  settings = newtable()
+  extensions = newtable()
+]]
+
+local _reaction_refresh = 
+[[
+  local oldState = state
+  state = state_override or set_state or state
+
+  local hide = nil
+  if state then
+    local settings = settings[state]
+    if settings then
+      -- show/hide
+      hide = settings.hide
+      -- re-anchor
+      local old_anchor = activeStates.anchor
+      activeStates.anchor = settings.anchorEnable and state
+      if old_anchor ~= activeStates.anchor or not set_state then
+        if activeStates.anchor then
+          if settings.anchorPoint then
+            self:ClearAllPoints()
+            local f = self:GetAttribute("frameref-anchor-"..state)
+            if f then
+              self:SetPoint(settings.anchorPoint, f, settings.anchorRelPoint, settings.anchorX, settings.anchorY)
+            end
+          end
+        elseif defaultAnchor.point then
+          self:ClearAllPoints()
+          self:SetPoint(defaultAnchor.point, defaultAnchor.frame, 
+                        defaultAnchor.relPoint, defaultAnchor.x, defaultAnchor.y)
+        end
+      end
+      -- re-scale
+      local old_scale = activeStates.scale
+      activeStates.scale = settings.enableScale and state
+      if old_scale ~= activeStates.scale or not set_state then
+        self:SetScale(activeStates.scale and settings.scale or defaultScale)
+      end
+      -- alpha
+      local old_alpha = activeStates.alpha
+      activeStates.alpha = settings.enableAlpha and state
+      if old_alpha ~= activeStates.alpha or not set_state then
+        self:SetAlpha(activeStates.alpha and settings.alpha or defaultAlpha)
+      end
+    end
+  end
+
+  -- hide if state or unit_exists says to
+  hide = not showAll and (hide or unithide)
+  if hide ~= hidden then
+    hidden = hide
+    if hide then
+      self:Hide()
+    else
+      self:Show()
+    end
+  end
+
+  for _, attr in pairs(extensions) do
+    control:RunAttribute(attr)
+  end
+  
+  control:ChildUpdate()
+
+  if showAll then
+    control:CallMethod("UpdateHiddenLabel", state and settings[state] and settings[state].hide)
+  end
+
+  if oldState ~= state then
+    control:CallMethod("StateRefresh", state)
+  end
+]]
+
+local _onstate_reaction = -- function( self, stateid, newstate )
+[[
+  set_state = newstate
+]] .. _reaction_refresh
+
+local _onstate_showgrid = -- function( self, stateid, newstate )
+[[
+  control:ChildUpdate(stateid,newstate)
+  control:CallMethod("UpdateShowGrid")
+]]
+
+local _onstate_unitexists = -- function( self, stateid, newstate )
+[[
+  unithide = not newstate or newstate == "hide"
+]] .. _reaction_refresh
+
+local _onclick =  -- function( self, button, down )
+[[
+  if state_override == button then
+    state_override = nil -- toggle
+  else
+    state_override = button
+  end
+]] .. _reaction_refresh
+
+-- For reference
+-- the option field names must match the field names of the options table, below
+local stateProperties = { 
+  hide = true,
+  --keybindState = true, TODO: broken
+  anchorEnable = true,
+  anchorFrame = true,
+  anchorPoint = true,
+  anchorRelPoint = true,
+  anchorX = true,
+  anchorY = true,
+  enableScale = true,
+  scale = true,
+  enableAlpha = true,
+  alpha = true,
+}
+
+
+
+---- Bar class ----
+local Bar   = { }
+local frameList = { }
+
+ReAction.Bar = Bar -- export to ReAction
+
+function Bar:New( name, config, buttonClass )
+  if type(config) ~= "table" then
+    error("ReAction.Bar: config table required")
+  end
+
+  -- create new self
+  self = setmetatable( 
+    { 
+      config      = config,
+      name        = name,
+      buttons     = { },
+      buttonClass = buttonClass,
+      width       = config.width or 480,
+      height      = config.height or 40,
+    }, 
+    {__index = self} )
+  
+  -- The frame type is 'Button' in order to have an OnClick handler. However, the frame itself is
+  -- not mouse-clickable by the user.
+  local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent
+  name = name and "ReAction-"..name
+  local f = name and frameList[name]
+  if not f then
+    f = CreateFrame("Button", name, parent, "SecureHandlerStateTemplate, SecureHandlerClickTemplate")
+    if name then
+      frameList[name] = f
+    end
+  end
+  f:SetFrameStrata("MEDIUM")
+  f:SetWidth(self.width)
+  f:SetHeight(self.height)
+  f:SetAlpha(config.alpha or 1.0)
+  f:Show()
+  f:EnableMouse(false)
+  f:SetClampedToScreen(true)
+  LSG:AddFrame(f)
+
+  -- secure handlers
+  f:Execute(_reaction_init)
+  f:SetAttribute("_onstate-reaction",   _onstate_reaction)
+  f:SetAttribute("_onstate-showgrid",   _onstate_showgrid)
+  f:SetAttribute("_onstate-unitexists", _onstate_unitexists)
+  f:SetAttribute("_onclick",            _onclick)
+
+  -- secure handler CallMethod()s
+  f.UpdateShowGrid    = function() self:UpdateShowGrid() end
+  f.StateRefresh      = function() self:RefreshControls() end
+  f.UpdateHiddenLabel = function(f,hidden) self:SetLabelSubtext(hidden and L["Hidden"]) end
+
+  -- Override the default frame accessor to provide strict read-only access
+  function self:GetFrame()
+    return f
+  end
+
+  self:ApplyAnchor()
+  self:SetConfigMode(ReAction:GetConfigMode())
+  self:SetKeybindMode(ReAction:GetKeybindMode())
+
+  if ReAction.LBF then
+    local g = ReAction.LBF:Group(L["ReAction"], self.name)
+    self.config.ButtonFacade = self.config.ButtonFacade or {
+      skinID = "Blizzard",
+      backdrop = true,
+      gloss = 0,
+      colors = {},
+    }
+    local c = self.config.ButtonFacade
+    g:Skin(c.skinID, c.gloss, c.backdrop, c.colors)
+    self.LBFGroup = g
+  end
+
+  ReAction.RegisterCallback(self, "OnConfigModeChanged")
+
+  buttonClass:SetupBar(self)
+  self:ApplyStates()
+
+  return self
+end
+
+function Bar:Destroy()
+  local f = self:GetFrame()
+  self:CleanupStates()
+  for idx, b in self:IterateButtons() do
+    b:Destroy()
+  end
+  f:UnregisterAllEvents()
+  self:ShowControls(false)
+  ReAction.UnregisterAllCallbacks(self)
+  LKB.UnregisterAllCallbacks(self)
+  if self.LBFGroup then
+    self.LBFGroup:Delete(true)
+  end
+  LSG:RemoveFrame(f)
+  f:SetParent(UIParent)
+  f:ClearAllPoints()
+  f:Hide()
+end
+
+--
+-- Events
+--
+
+function Bar:OnConfigModeChanged(event, mode)
+  self:SetConfigMode(mode)
+end
+
+--
+-- Accessors
+--
+
+function Bar:GetName()
+  return self.name
+end
+
+-- only ReAction:RenameBar() should call this function. Calling from any other
+-- context will desync the bar list in the ReAction class.
+function Bar:SetName(name)
+  if self.LBFGroup then
+    -- LBF doesn't offer a method of renaming a group, so delete and remake the group.
+    local c = self.config.ButtonFacade
+    local g = ReAction.LBF:Group(L["ReAction"], name)
+    for idx, b in self:IterateButtons() do
+      self.LBFGroup:RemoveButton(b:GetFrame(), true)
+      g:AddButton(b:GetFrame())
+    end
+    self.LBFGroup:Delete(true)
+    self.LBFGroup = g
+    self.LBFGroup:Skin(c.skinID, c.gloss, c.backdrop, c.colors)
+  end
+  self.name = name
+  if self.overlay then
+    self.overlay:SetLabel(self.name)
+  end
+end
+
+function Bar:GetFrame()
+  -- this method is included for documentation purposes. It is overridden
+  -- for each object in the :New() method.
+  error("Invalid Bar object: used without initialization")
+end
+
+function Bar:GetButton(idx)
+  return self.buttons[idx]
+end
+
+function Bar:GetButtonClass()
+  return self.buttonClass
+end
+
+function Bar:GetConfig()
+  return self.config
+end
+
+function Bar:GetAnchor()
+  local c = self.config
+  return (c.point or "CENTER"), 
+         (c.anchor or self:GetFrame():GetParent():GetName()), 
+         (c.relpoint or c.point or "CENTER"), 
+         (c.x or 0), 
+         (c.y or 0)
+end
+
+function Bar:SetAnchor(point, frame, relativePoint, x, y)
+  local c = self.config
+  c.point = point or c.point
+  c.anchor = frame or c.anchor
+  c.relpoint = relativePoint or c.relpoint
+  c.x = x or c.x
+  c.y = y or c.y
+  self:ApplyAnchor()
+end
+
+function Bar:GetSize()
+  local f = self:GetFrame()
+  return f:GetWidth(), f:GetHeight()
+end
+
+function Bar:SetSize(w,h)
+  local f = self:GetFrame()
+  self.config.width = w
+  self.config.height = h
+  f:SetWidth(w)
+  f:SetHeight(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:GetNumButtons()
+  local r,c = self:GetButtonGrid()
+  return r*c
+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
+  self.buttonClass:SetupBar(self)
+end
+
+function Bar:GetAlpha()
+  return self.config.alpha or 1.0
+end
+
+function Bar:SetAlpha(value)
+  self.config.alpha = value
+  self:GetFrame():SetAlpha(value or 1.0)
+  self:UpdateDefaultStateAlpha()
+end
+
+function Bar:IterateButtons()
+  -- iterator returns idx, button, but does NOT iterate in index order
+  return pairs(self.buttons)
+end
+
+--
+-- Methods
+--
+
+function Bar:SetConfigMode(mode)
+  self:SetSecureData("showAll",mode)
+  self:ShowControls(mode)
+  for idx, b in self:IterateButtons() do
+    b:ShowGridTemp(mode)
+    b:UpdateActionIDLabel(mode)
+  end
+end
+
+function Bar:SetKeybindMode(mode)
+  self:SetSecureData("showAll",mode)
+  for idx, b in self:IterateButtons() do
+    b:SetKeybindMode(mode)
+  end
+end
+
+function Bar:ApplyAnchor()
+  local f = self:GetFrame()
+  local c = self.config
+  local p = c.point
+
+  f:SetWidth(c.width)
+  f:SetHeight(c.height)
+  f:ClearAllPoints()
+  
+  if p then
+    local a = f:GetParent()
+    if c.anchor then
+      local bar = ReAction:GetBar(c.anchor)
+      if bar then
+        a = bar:GetFrame()
+      else
+        a = _G[c.anchor]
+      end
+    end
+    local fr = a or f:GetParent()
+    f:SetPoint(p, a or f:GetParent(), c.relpoint, c.x or 0, c.y or 0)
+  else
+    f:SetPoint("CENTER")
+  end
+
+  self:UpdateDefaultStateAnchor()
+end
+
+function Bar:ClipNButtons( n )
+  local cfg = self.config
+  local r = cfg.btnRows or 1
+  local c = cfg.btnColumns or 1
+
+  cfg.btnRows = ceil(n/c)
+  cfg.btnColumns = min(n,c)
+end
+
+function Bar:AddButton(idx, button)
+  local f = self:GetFrame()
+
+  self.buttons[idx] = button
+
+  -- Store a properly wrapped reference to the child frame as an attribute 
+  -- (accessible via "frameref-btn#")
+  f:SetFrameRef(format("btn%d",idx), button:GetFrame())
+
+  -- button constructors are responsible for calling SkinButton
+end
+
+function Bar:RemoveButton(button)
+  local idx = button:GetIndex()
+  if idx then
+    self:GetFrame():SetAttribute(format("frameref-btn%d",idx),nil)
+    self.buttons[idx] = nil
+  end
+  if self.LBFGroup then
+    self.LBFGroup:RemoveButton(button:GetFrame(),true)
+  end
+end
+
+function Bar:PlaceButton(button, baseW, baseH)
+  local idx = button:GetIndex()
+  if idx then 
+    local r, c, s = self:GetButtonGrid()
+    local bh, bw = self:GetButtonSize()
+    local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based
+    local x, y = col*bw + (col+0.5)*s, -(row*bh + (row+0.5)*s)
+    local scale = bw/baseW
+    local b = button:GetFrame()
+
+    b:ClearAllPoints()
+    b:SetPoint("TOPLEFT",x/scale,y/scale)
+    b:SetScale(scale)
+  end
+end
+
+function Bar:SkinButton( button, data )
+  if self.LBFGroup then
+    self.LBFGroup:AddButton(button:GetFrame(), data)
+  end
+end
+
+function Bar:UpdateShowGrid()
+  for idx, button in self:IterateButtons() do
+    button:UpdateShowGrid()
+  end
+end
+
+function Bar:ShowControls(show)
+  if show then
+    if not self.overlay then
+      self.overlay = Bar.Overlay:New(self) -- see Overlay.lua
+    end
+    self.overlay:Show()
+    self:RefreshSecureState()
+  elseif self.overlay then
+    self.overlay:Hide()
+  end
+end
+
+function Bar:RefreshControls()
+  if self.overlay and self.overlay:IsShown() then
+    self.overlay:RefreshControls()
+  end
+end
+
+function Bar:SetLabelSubtext(text)
+  if self.overlay then 
+    self.overlay:SetLabelSubtext(text) 
+  end
+end
+
+--
+-- Secure state functions
+--
+
+function Bar:GetSecureState()
+  local env = GetManagedEnvironment(self:GetFrame())
+  return env and env.state
+end
+
+function Bar:GetStateProperty(state, propname)
+  return tfetch(self:GetConfig(), "states", state, propname)
+end
+
+function Bar:SetStateProperty(state, propname, value)
+  local s = tbuild(self:GetConfig(), "states", state)
+  s[propname] = value
+  self:SetSecureStateData(state, propname, value)
+end
+
+function Bar:ApplyStates()
+  local states = tfetch(self:GetConfig(), "states")
+  if states then
+    self:SetStateDriver(states)
+  end
+end
+
+function Bar:CleanupStates()
+  self:SetStateDriver(nil)
+end
+
+function Bar:RefreshSecureState()
+  self:GetFrame():Execute(_reaction_refresh)
+end
+
+-- usage: SetSecureData(globalname, [tblkey1, tblkey2, ...], value)
+function Bar:SetSecureData( ... )
+  local n = select('#',...)
+  if n < 2 then
+    error("ReAction.Bar:SetSecureData() requires at least 2 arguments")
+  end
+  local f = self:GetFrame()
+  f:SetAttribute("data-depth",n-1)
+  f:SetAttribute("data-value",select(n,...))
+  for i = 1, n-1 do
+    local key = select(i,...)
+    if key == nil then
+      error("ReAction.Bar:SetSecureData() - nil table key in argument list (#"..i..")")
+    end
+    f:SetAttribute("data-key-"..i, key)
+  end
+  f:Execute(
+    [[
+      local n = self:GetAttribute("data-depth")
+      if n > 0 then
+        local value = self:GetAttribute("data-value")
+        local t = _G
+        for i = 1, n do
+          local key = self:GetAttribute("data-key-"..i)
+          if not key then return end
+          if not t[key] then
+            t[key] = newtable()
+          end
+          if i == n then
+            t[key] = value
+          else
+            t = t[key]
+          end
+        end
+      end
+    ]])
+  self:RefreshSecureState()
+end
+
+function Bar:SetSecureStateData( state, key, value )
+  self:SetSecureData("settings",state,key,value)
+end
+
+-- sets a snippet to be run as an extension to _onstate-reaction
+function Bar:SetSecureStateExtension( id, snippet )
+  if id == nil then
+    error("ReAction.Bar:SetSecureStateExtension() requires an id")
+  end
+  local f = self:GetFrame()
+  f:SetAttribute("input-secure-ext-id",id)
+  f:SetAttribute("secure-ext-"..id,snippet)
+  f:Execute(
+    [[
+      local id = self:GetAttribute("input-secure-ext-id")
+      if id then
+        extensions[id] = self:GetAttribute("secure-ext-"..id) or nil
+      end
+    ]])
+  self:RefreshSecureState()
+end
+
+function Bar:SetFrameRef( name, refFrame )
+  if refFrame then
+    local _, explicit = refFrame:IsProtected()
+    if not explicit then
+      refFrame = nil
+    end
+  end
+  if refFrame then
+    self:GetFrame():SetFrameRef(name,refFrame)
+  else
+    self:GetFrame():SetAttribute("frameref-"..name,nil)
+  end
+end
+
+function Bar:SetStateDriver( states )
+  if states then
+    for state, props in pairs(states) do
+      self:SetSecureStateData(state, "active_", true) -- make sure there's a 'settings' field for this state
+      for propname, value in pairs(props) do
+        if propname == "anchorFrame" then
+          self:SetFrameRef("anchor-"..state, _G[value])
+        elseif propname == "rule" then
+          -- do nothing
+        else
+          self:SetSecureStateData(state, propname, value)
+        end
+      end
+    end
+  end
+  local rule = states and self:BuildStateRule(states)
+  if rule then
+    RegisterStateDriver(self:GetFrame(),"reaction",rule)
+  elseif self.statedriver then
+    UnregisterStateDriver(self:GetFrame(),"reaction")
+  end
+  self.statedriver = rule
+  self:BuildStateKeybinds(states)
+  self:RefreshSecureState()
+end
+
+-- pass unit=nil to set up the unit elsewhere, if you want something more complex
+function Bar:RegisterUnitWatch( unit, enable )
+  local f = self:GetFrame()
+  if unit then
+    f:SetAttribute("unit",unit)
+  end
+  if enable then
+    if not self.unitwatch then
+      RegisterUnitWatch(self:GetFrame(),true)
+    end
+  elseif self.unitwatch then
+    UnregisterUnitWatch(self:GetFrame())
+  end
+  self.unitwatch = enable
+  self:RefreshSecureState()
+end
+
+function Bar:SetStateKeybind( key, state )
+  local f = self:GetFrame()
+  local binds = self.statebinds
+  if not binds then
+    binds = { }
+    self.statebinds = binds
+  end
+
+  -- clear the old binding, if any
+  if binds[state] then
+    SetOverrideBinding(f, false, binds[state], nil)
+  end
+
+  if key then
+    SetOverrideBindingClick(f, false, key, f:GetName(), state) -- state name is virtual mouse button
+  end
+  binds[state] = key
+end
+
+function Bar:GetStateKeybind( state )
+  if self.statebinds and state then
+    return self.statebinds[state]
+  end
+end
+
+function Bar:UpdateDefaultStateAnchor()
+  local point, frame, relPoint, x, y = self:GetAnchor()
+  local f = self:GetFrame()
+  f:SetAttribute("defaultAnchor-point",point)
+  f:SetAttribute("defaultAnchor-relPoint",relPoint)
+  f:SetAttribute("defaultAnchor-x",x)
+  f:SetAttribute("defaultAnchor-y",y)
+  self:SetFrameRef("defaultAnchor",_G[frame or "UIParent"])
+  f:Execute([[
+    for _, k in pairs(anchorKeys) do
+      defaultAnchor[k] = self:GetAttribute("defaultAnchor-"..k)
+    end
+    defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor")
+  ]])
+end
+
+function Bar:UpdateDefaultStateAlpha()
+  local f = self:GetFrame()
+  f:SetAttribute("defaultAlpha",self:GetAlpha())
+  f:Execute([[
+    defaultAlpha = self:GetAttribute("defaultAlpha")
+  ]])
+end
+
+---- secure state driver rules ----
+
+local playerClass = select(2, UnitClass("player"))
+local function ClassFilter(...)
+  for i = 1, select('#',...) do
+    if playerClass == select(i,...) then
+      return false
+    end
+  end
+  return true
+end
+
+local ruleformats = { 
+  stealth       = { format = "stealth",        filter = ClassFilter("ROGUE","DRUID") },
+  nostealth     = { format = "nostealth",      filter = ClassFilter("ROGUE","DRUID") },
+  shadowdance   = { format = "bonusbar:2",     filter = ClassFilter("ROGUE") },
+  shadowform    = { format = "form:1",         filter = ClassFilter("PRIEST") },
+  noshadowform  = { format = "noform",         filter = ClassFilter("PRIEST") },
+  battle        = { format = "stance:1",       filter = ClassFilter("WARRIOR") },
+  defensive     = { format = "stance:2",       filter = ClassFilter("WARRIOR") },
+  berserker     = { format = "stance:3",       filter = ClassFilter("WARRIOR") },
+  caster        = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") },
+  bear          = { format = "form:1",         filter = ClassFilter("DRUID") },
+  cat           = { format = "form:3",         filter = ClassFilter("DRUID") },
+  tree          = { format = "form:5",         filter = ClassFilter("DRUID") },
+  moonkin       = { format = "form:5",         filter = ClassFilter("DRUID") },
+  demon         = { format = "form:2",         filter = ClassFilter("WARLOCK") },
+  nodemon       = { format = "noform",         filter = ClassFilter("WARLOCK") },
+  pet           = { format = "pet" },
+  nopet         = { format = "nopet" },
+  harm          = { format = "@target,harm" },
+  help          = { format = "@target,help" },
+  notarget      = { format = "@target,noexists" },
+  focusharm     = { format = "@focus,harm" },
+  focushelp     = { format = "@focus,help" },
+  nofocus       = { format = "@focus,noexists" },
+  raid          = { format = "group:raid" },
+  party         = { format = "group:party" },
+  solo          = { format = "nogroup" },
+  combat        = { format = "combat" },
+  nocombat      = { format = "nocombat" },
+  possess       = { format = "@vehicle,noexists,bonusbar:5" },
+  vehicle       = { format = "@vehicle,exists,bonusbar:5" },
+}
+
+function Bar.InitRuleFormats()
+  local forms = { }
+  for i = 1, GetNumShapeshiftForms() do
+    local _, name = GetShapeshiftFormInfo(i)
+    forms[name] = i;
+  end
+    -- use 9 if not found since 9 is never a valid stance/form
+  local defensive = forms[GetSpellInfo(71)] or 9
+  local berserker = forms[GetSpellInfo(2458)] or 9
+  local bear      = forms[GetSpellInfo(5487)] or 9
+  local aquatic   = forms[GetSpellInfo(1066)] or 9
+  local cat       = forms[GetSpellInfo(768)] or 9
+  local travel    = forms[GetSpellInfo(783)] or 9
+  local tree      = forms[GetSpellInfo(33891)] or 9
+  local moonkin   = forms[GetSpellInfo(24858)] or 9
+  local flight    = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9
+
+  ruleformats.defensive.format = "stance:"..defensive
+  ruleformats.berserker.format = "stance:"..berserker
+  ruleformats.caster.format    = format("form:0/%d/%d/%d", aquatic, travel, flight)
+  ruleformats.bear.format      = "form:"..bear
+  ruleformats.cat.format       = "form:"..cat
+  ruleformats.tree.format      = "form:"..tree
+  ruleformats.moonkin.format   = "form:"..moonkin
+end
+
+function Bar:BuildStateRule(states)
+  -- states is a table :
+  --   states[statename].rule = {
+  --     order = #,
+  --     type = "default"/"custom"/"any"/"all",
+  --     values = { ... }, -- keys of ruleformats[]
+  --     custom = "...",
+  --   }
+  local rules = { }
+  local default
+
+  for idx, state in ipairs(fieldsort(states, "rule", "order")) do
+    local c = states[state].rule
+    local type = c.type
+    if type == "default" then
+      default = default or state
+    elseif type == "custom" then
+      if c.custom then
+        -- strip out all spaces from the custom rule
+        table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state))
+      end
+    elseif type == "any" or type == "all" then
+      if c.values then
+        local clauses = { }
+        for key, value in pairs(c.values) do
+          if ruleformats[key] and not ruleformats[key].filter then
+            table.insert(clauses, ruleformats[key].format)
+          end
+        end
+        if #clauses > 0 then
+          local sep = (type == "any") and "][" or ","
+          table.insert(rules, format("[%s] %s", table.concat(clauses,sep), state))
+        end
+      end
+    end
+  end
+  -- make sure that the default, if any, is last
+  if default then
+    table.insert(rules, default)
+  end
+  return table.concat(rules,";")
+end
+
+function Bar:BuildStateKeybinds( states )
+  if states then
+    for name, state in pairs(states) do
+      local rule = tfetch(state, "rule")
+      if rule and rule.type == "keybind" then
+        self:SetStateKeybind(rule.keybind, name)
+      else
+        self:SetStateKeybind(nil, name) -- this clears an existing keybind
+      end
+    end
+  end
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Button.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,359 @@
+--[[
+  ReAction Button base class
+--]]
+
+-- local imports
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local LKB = ReAction.LKB
+local _G = _G
+local CreateFrame = CreateFrame
+local GetBindingKey = GetBindingKey
+local format = string.format
+
+-- private
+local trash = CreateFrame("Frame")
+local frameList = { }
+local idPools = { }
+
+local function kb_onEnter( frame )
+  LKB:Set(frame)
+end
+
+-- Button class
+local buttonTypeID = "Button"
+local Button = { 
+  defaultBarConfig = {
+    type = buttonTypeID,
+    btnWidth = 36,
+    btnHeight = 36,
+    btnRows = 1,
+    btnColumns = 12,
+    spacing = 3
+  },
+  barType = L["Button Bar"]
+} 
+
+ReAction.Button = Button -- export to ReAction
+
+function Button:New( name, config, bar, idx, inherits, buttonType )
+  buttonType = buttonType or "CheckButton"
+
+  -- create new self
+  self = setmetatable( 
+    { 
+      bar = bar,
+      idx = idx,
+      config = config,
+      name = name,
+    }, 
+    { __index = self } )
+
+  -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
+  -- existing globals. Can't set to nil in the global because it's then tainted.
+  -- Caller is responsible for ensuring global uniqueness of names.
+  local f = name and frameList[name]
+  if f then
+    f:SetParent(bar:GetFrame())
+  else
+    f = CreateFrame(buttonType, name, bar:GetFrame(), inherits)
+    if name then
+      frameList[name] = f
+    end
+  end
+
+  self.frame = f
+
+  local frames = { }
+  self.frames = frames
+  frames.icon          = _G[name.."Icon"]
+  frames.flash         = _G[name.."Flash"]
+  frames.hotkey        = _G[name.."HotKey"]
+  frames.count         = _G[name.."Count"]
+  frames.name          = _G[name.."Name"]
+  frames.border        = _G[name.."Border"]
+  frames.cooldown      = _G[name.."Cooldown"]
+  frames.normalTexture = _G[name.."NormalTexture"]
+
+  if config then
+    config.name = name
+  end
+
+  -- install LibKeyBound handlers onto frame
+  function f:GetActionName()
+    return format("%s:%s", bar:GetName(), idx)
+  end
+
+  local clickBinding = format("CLICK %s:LeftButton", name)
+  function f:GetHotkey()
+    return LKB:ToShortKey(GetBindingKey(clickBinding))
+  end
+
+  return self
+end
+
+function Button:Destroy()
+  local f = self:GetFrame()
+  f:UnregisterAllEvents()
+  self:ReleaseActionID(self:GetActionID())
+  if f then
+    f:Hide()
+    f:SetParent(trash)
+    f:ClearAllPoints()
+  end
+end
+
+function Button:GetBar()
+  return self.bar
+end
+
+function Button:GetFrame()
+  return self.frame
+end
+
+function Button:GetIndex()
+  return self.idx
+end
+
+function Button:GetName()
+  return self.name
+end
+
+function Button:GetDefaultBarConfig()
+  return self.defaultBarConfig
+end
+
+function Button:GetBarType()
+  return self.barType
+end
+
+function Button:GetButtonTypeID()
+  return self.buttonTypeID
+end
+
+function Button:GetConfig()
+  return self.config
+end
+
+function Button:GetActionID()
+  -- derived classes should override this
+  return nil
+end
+
+function Button:SetActionIDPool( poolID, maxID )
+  self.actionPoolID = poolID
+  self.actionMaxID = maxID
+end
+
+function Button:SetupBar( bar )
+  local config = bar:GetConfig()
+  if not config.buttons then
+    config.buttons = { }
+  end
+  local btnCfg = config.buttons
+
+  local r, c = bar:GetButtonGrid()
+  local n = r*c
+  local cfgN = n
+
+  local hint = nil
+  local i = 1
+  repeat
+    local b = bar:GetButton(i)
+    if b then
+      if i > n then
+        bar:RemoveButton(b)
+        b:Destroy()
+        if i > cfgN then
+          btnCfg[i] = nil
+        end
+      else
+        b:Refresh()
+        hint = b:GetActionID()
+      end
+    elseif i <= n then
+      local cfg = btnCfg[i] or { }
+      local success, r = pcall(self.New, self, cfg, bar, i, hint)  -- note call semantics for derived class constructors
+      if success and r then
+        b = r
+        bar:AddButton(i,b)
+        btnCfg[i] = cfg
+        b:Refresh()
+        hint = b:GetActionID()
+      else
+        n = i - 1
+        if not success then
+          bar:ClipNButtons(n)
+          cfgN = n
+          geterrorhandler()(r)
+        end
+      end
+    end
+    i = i + 1
+  until b == nil
+end
+
+function Button:AcquireActionID( id, hint, unique )
+  local poolID = self.actionPoolID
+  local maxID = self.actionMaxID
+  if not poolID or not maxID then
+    error("AcquireActionID: must setup pool first with SetActionIDPool")
+  end
+  local pool = idPools[poolID]
+  if not pool then
+    pool = { nWraps = 0, useCount = { } }
+    for i = 1, maxID do
+      pool.useCount[i] = 0
+    end
+    idPools[poolID] = pool
+  end
+  local useCount = pool.useCount
+  if id == nil then
+    repeat
+      local nWraps = pool.nWraps or 0
+      if hint and (useCount[hint] == nil or useCount[hint] == nWraps) then
+        id = hint
+      else
+        local start = hint or 1
+        for i = start, maxID do
+          if useCount[i] == nil or useCount[i] == nWraps then
+            id = i
+            break
+          end
+        end
+        if not id then
+          for i = 1, start do
+            if useCount[i] == nil or useCount[i] == nWraps then
+              id = i
+              break
+            end
+          end
+        end
+      end
+      if id == nil then
+        if unique then
+          return nil
+        end
+        pool.nWraps = nWraps + 1
+      end
+    until id ~= nil
+  end
+  useCount[id] = (useCount[id] or 0) + 1
+  return id
+end
+
+function Button:ReleaseActionID( id )
+  local poolID = self.actionPoolID
+  if not poolID  then
+    error("ReleaseActionID: must setup pool first with SetActionIDPool")
+  end
+  local pool = idPools[poolID]
+  if pool and id and pool.useCount[id] then
+    pool.useCount[id] = pool.useCount[id] - 1
+    pool.nWraps = min(pool.useCount[id], pool.nWraps)
+  end
+end
+
+function Button:Refresh()
+  local f = self:GetFrame()
+  self.bar:PlaceButton( self, f:GetWidth(), f:GetHeight() )
+end
+
+function Button:SetKeybindMode( mode )
+  local f = self.frame
+  if mode then
+    self.oldOnEnter = f:GetScript("OnEnter")
+    f:SetScript("OnEnter", kb_onEnter)
+  elseif self.oldOnEnter then
+    f:SetScript("OnEnter", self.oldOnEnter)
+    self.oldOnEnter = nil
+  end
+  self:ShowGridTemp(mode)
+  self:UpdateKeybindModeDisplay( mode )
+end
+
+function Button:UpdateKeybindModeDisplay( mode )
+  local border = self.frames.border or _G[format("%sBorder",tostring(self:GetName()))]
+  if border then
+    if mode then
+      border:SetVertexColor(LKB:GetColorKeyBoundMode())
+      border:Show()
+    else
+      border:Hide()
+    end
+  end
+end
+
+function Button:UpdateHotkey( hotkey )
+  hotkey = hotkey or self.frames.hotkey
+  if not hotkey then
+    hotkey = _G[self:GetName().."HotKey"]
+    self.frames.hotkey = hotkey
+  end
+  if hotkey then
+    local txt = self.frame:GetHotkey()
+    hotkey:SetText( txt )
+    if txt == nil or txt == "" then
+      hotkey:Hide()
+    else
+      hotkey:Show()
+    end
+  end
+end
+
+function Button:GetActionIDLabel( create )
+  local f = self:GetFrame()
+  if not f.actionIDLabel and create then
+    local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
+    label:SetAllPoints()
+    label:SetJustifyH("CENTER")
+    label:SetShadowColor(0,0,0,1)
+    label:SetShadowOffset(2,-2)
+    f.actionIDLabel = label -- store the label with the frame for recycling
+  end
+  return f.actionIDLabel
+end
+
+function Button:UpdateActionIDLabel( show )
+  local label = self:GetActionIDLabel( show )
+  if label then
+    if show then
+      local id = self:GetActionID()
+      if id then
+        label:SetText(tostring(id))
+        label:Show()
+        return
+      end
+    end
+    label:Hide()
+  end
+end
+
+function Button:SetNormalVertexColor( r, g, b, a )
+  if ReAction.LBF then
+    ReAction.LBF:SetNormalVertexColor(self:GetFrame(), r, g, b, a)
+  else
+    self:GetFrame():GetNormalTexture():SetVertexColor(r,g,b,a)
+  end
+end
+
+function Button:GetNormalVertexColor()
+  if ReAction.LBF then
+    return ReAction.LBF:GetNormalVertexColor(self:GetFrame())
+  else
+    return self:GetFrame():GetNormalTexture():GetVertexColor()
+  end
+end
+
+function Button:UpdateShowGrid()
+ -- does nothing by default
+end
+
+function Button:ShowGridTemp(show)
+  -- does nothing by default
+end
+
+function Button:ShowGrid(show)
+  -- does nothing by default
+end
--- a/Editor.lua	Thu Nov 18 13:11:08 2010 -0800
+++ b/Editor.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -3,12 +3,17 @@
 local L = ReAction.L
 local _G = _G
 local wipe = wipe
+local format = string.format
+local InCombatLockdown = InCombatLockdown
+local tfetch = addonTable.tfetch
+local tbuild = addonTable.tbuild
 
 local AceConfigReg = LibStub("AceConfigRegistry-3.0")
 local AceConfigDialog = LibStub("AceConfigDialog-3.0")
 
 
 local pointTable = {
+  NONE        = " ",
   CENTER      = L["Center"], 
   LEFT        = L["Left"],
   RIGHT       = L["Right"],
@@ -20,7 +25,9 @@
   BOTTOMRIGHT = L["Bottom Right"],
 }
 
-local Editor = { }
+local Editor = { 
+  buttonHandlers = { }
+}
 
 function Editor:New()
   -- create new self
@@ -90,12 +97,12 @@
             name = L["Button Type"],
             get  = function() return self.tmp.barType or ReAction:GetDefaultBarType() or "" end,
             set  = function(info, val) 
-                     local c = ReAction:GetBarTypeConfig(val)
+                     local c = ReAction:GetDefaultBarConfig(val)
                      self.tmp.barType = val 
-                     self.tmp.barSize = c.defaultButtonSize or self.tmp.barSize
-                     self.tmp.barRows = c.defaultBarRows or self.tmp.barRows
-                     self.tmp.barCols = c.defaultBarCols or self.tmp.barCols
-                     self.tmp.barSpacing = c.defaultBarSpacing or self.tmp.barSpacing
+                     self.tmp.barSize = c.btnWidth or self.tmp.barSize
+                     self.tmp.barRows = c.btnRows or self.tmp.barRows
+                     self.tmp.barCols = c.btnColumns or self.tmp.barCols
+                     self.tmp.barSpacing = c.spacing or self.tmp.barSpacing
                    end,
             values = "GetBarTypes",
             order = 3,
@@ -173,12 +180,9 @@
 
   ReAction.RegisterCallback(self,"OnCreateBar")
   ReAction.RegisterCallback(self,"OnDestroyBar")
-  ReAction.RegisterCallback(self,"OnEraseBar")
   ReAction.RegisterCallback(self,"OnRenameBar")
 
-  for name, bar in ReAction:IterateBars() do
-    self:CreateBarTree(bar)
-  end
+  self:RefreshBarOptions()
 
   return self
 end
@@ -203,160 +207,170 @@
   AceConfigReg:NotifyChange(self.configID)
 end
 
-function Editor:CreateBarTree(bar)
+function Editor:UpdateBarOptions(bar)
   local name = bar:GetName()
-  -- AceConfig doesn't allow spaces, etc, in arg key names, and they must be
-  -- unique strings. So generate a unique key (it can be whatever) for the bar
+  local key  = self.barOptMap[name]
   local args = self.options.args
-  local key
-  local i = 1
-  repeat
-    key = ("bar%s"):format(i)
-    i = i+1
-  until args[key] == nil
-  self.barOptMap[name] = key
-  args[key] = { 
-    type = "group",
-    name = name,
-    childGroups = "tab",
-    order = i+100,
-    args = {
-      general = {
-        type = "group",
-        name = L["General"],
-        order = 1,
-        args = {
-          name = {
-            type = "input",
-            name = L["Rename Bar"],
-            get  = function() return bar:GetName() end,
-            set  = function(info, value) return ReAction:RenameBar(bar, value) end,
-            order = 1,
-          },
-          delete = {
-            type = "execute",
-            name = L["Delete Bar"],
-            desc = function() return bar:GetName() end,
-            confirm = true,
-            func = function() ReAction:EraseBar(bar) end,
-            order = 2
-          },
-          anchor = {
-            type = "group",
-            name = L["Anchor"],
-            inline = true,
-            args = {
-              frame = {
-                type = "input",
-                name = L["Frame"],
-                desc = L["The frame that the bar is anchored to"],
-                get  = function() local _, f = bar:GetAnchor(); return f end,
-                set  = function(info, val) bar:SetAnchor(nil,val) end,
-                validate = function(info, name) 
-                    if name then
-                      local f = ReAction:GetBar(name)
-                      if f then
-                        return true
-                      else
-                        f = _G[name]
-                        if f and type(f) == "table" and f.IsObjectType and f:IsObjectType("Frame") then
-                          local _, explicit = f:IsProtected()
-                          return explicit
+
+  if not key then
+    -- AceConfig doesn't allow spaces, etc, in arg key names, and they must be
+    -- unique strings. So generate a unique key (it can be whatever) for the bar
+    local i = 1
+    repeat
+      key = ("bar%s"):format(i)
+      i = i+1
+    until args[key] == nil
+    self.barOptMap[name] = key
+
+    args[key] = { 
+      type = "group",
+      name = name,
+      childGroups = "tab",
+      order = i+100,
+      args = {
+        general = {
+          type = "group",
+          name = L["General"],
+          order = 1,
+          args = {
+            name = {
+              type = "input",
+              name = L["Rename Bar"],
+              get  = function() return bar:GetName() end,
+              set  = function(info, value) return ReAction:RenameBar(bar, value) end,
+              order = 1,
+            },
+            delete = {
+              type = "execute",
+              name = L["Delete Bar"],
+              desc = function() return bar:GetName() end,
+              confirm = true,
+              func = function() ReAction:EraseBar(bar) end,
+              order = 2
+            },
+            anchor = {
+              type = "group",
+              name = L["Anchor"],
+              inline = true,
+              args = {
+                frame = {
+                  type = "input",
+                  name = L["Frame"],
+                  desc = L["The frame that the bar is anchored to"],
+                  get  = function() local _, f = bar:GetAnchor(); return f end,
+                  set  = function(info, val) bar:SetAnchor(nil,val) end,
+                  validate = function(info, name) 
+                      if name then
+                        local f = ReAction:GetBar(name)
+                        if f then
+                          return true
+                        else
+                          f = _G[name]
+                          if f and type(f) == "table" and f.IsObjectType and f:IsObjectType("Frame") then
+                            local _, explicit = f:IsProtected()
+                            return explicit
+                          end
                         end
                       end
-                    end
-                    return false
-                  end,
-                width = "double",
-                order = 1
+                      return false
+                    end,
+                  width = "double",
+                  order = 1
+                },
+                point = {
+                  type = "select",
+                  name = L["Point"],
+                  desc = L["Anchor point on the bar frame"],
+                  style = "dropdown",
+                  get  = function() return bar:GetAnchor() end,
+                  set  = function(info, val) bar:SetAnchor(val) end,
+                  values = pointTable,
+                  order = 2,
+                },
+                relativePoint = {
+                  type = "select",
+                  name = L["Relative Point"],
+                  desc = L["Anchor point on the target frame"],
+                  style = "dropdown",
+                  get  = function() local p,f,r = bar:GetAnchor(); return r end,
+                  set  = function(info, val) bar:SetAnchor(nil,nil,val) end,
+                  values = pointTable,
+                  order = 3,
+                },
+                x = {
+                  type = "input",
+                  pattern = "\-?%d+",
+                  name = L["X offset"],
+                  get = function() local p,f,r,x = bar:GetAnchor(); return ("%d"):format(x) end,
+                  set = function(info,val) bar:SetAnchor(nil,nil,nil,val) end,
+                  order = 4
+                },
+                y = {
+                  type = "input",
+                  pattern = "\-?%d+",
+                  name = L["Y offset"],
+                  get = function() local p,f,r,x,y = bar:GetAnchor(); return ("%d"):format(y) end,
+                  set = function(info,val) bar:SetAnchor(nil,nil,nil,nil,val) end,
+                  order = 5
+                },
               },
-              point = {
-                type = "select",
-                name = L["Point"],
-                desc = L["Anchor point on the bar frame"],
-                style = "dropdown",
-                get  = function() return bar:GetAnchor() end,
-                set  = function(info, val) bar:SetAnchor(val) end,
-                values = pointTable,
-                order = 2,
-              },
-              relativePoint = {
-                type = "select",
-                name = L["Relative Point"],
-                desc = L["Anchor point on the target frame"],
-                style = "dropdown",
-                get  = function() local p,f,r = bar:GetAnchor(); return r end,
-                set  = function(info, val) bar:SetAnchor(nil,nil,val) end,
-                values = pointTable,
-                order = 3,
-              },
-              x = {
-                type = "input",
-                pattern = "\-?%d+",
-                name = L["X offset"],
-                get = function() local p,f,r,x = bar:GetAnchor(); return ("%d"):format(x) end,
-                set = function(info,val) bar:SetAnchor(nil,nil,nil,val) end,
-                order = 4
-              },
-              y = {
-                type = "input",
-                pattern = "\-?%d+",
-                name = L["Y offset"],
-                get = function() local p,f,r,x,y = bar:GetAnchor(); return ("%d"):format(y) end,
-                set = function(info,val) bar:SetAnchor(nil,nil,nil,nil,val) end,
-                order = 5
-              },
+              order = 3
             },
-            order = 3
-          },
-          alpha = {
-            type = "range",
-            name = L["Transparency"],
-            get  = function() return bar:GetAlpha() end,
-            set  = function(info, val) bar:SetAlpha(val) end,
-            min = 0, 
-            max = 1,
-            isPercent = true,
-            step = 0.01,
-            bigStep = 0.05,
-            order = 4,
+            alpha = {
+              type = "range",
+              name = L["Transparency"],
+              get  = function() return bar:GetAlpha() end,
+              set  = function(info, val) bar:SetAlpha(val) end,
+              min = 0, 
+              max = 1,
+              isPercent = true,
+              step = 0.01,
+              bigStep = 0.05,
+              order = 4,
+            },
           },
         },
-      },
+        buttonOpts = self:CreateButtonOptions(bar),
+        stateOpts  = self:CreateStateOptions(bar)
+      }
     }
-  }
-  self:RefreshBarOptions()
+  end
+
+end
+
+function Editor:CreateButtonOptions(bar)
+  local buttonClass = bar:GetButtonClass()
+  local classID = buttonClass:GetButtonTypeID()
+  local handler = self.buttonHandlers[classID]
+
+  if handler then
+    local h = handler:New(bar)
+    return h:GetOptions()
+  end
 end
 
 function Editor:RefreshBarOptions()
   for name, key in pairs(self.barOptMap) do
-    local bar = ReAction:GetBar(name)
-    if bar and key and self.options.args[key] then
-      self.options.args[key].plugins = self:GenerateBarOptionsTable(bar)
+    if not ReAction:GetBar(name) then
+      self.barOptMap[name] = nil
+      self.options.args[key] = nil
     end
   end
-  AceConfigReg:NotifyChange(self.configID)
+  for name, bar in ReAction:IterateBars() do
+    self:UpdateBarOptions(bar)
+  end
+  self:Refresh()
 end
 
 function Editor:OnCreateBar(evt, bar)
-  if not self.tmp.creating then
-    -- a bit of hack to work around OnCreateBar event handler ordering
-    self:CreateBarTree(bar)
-  end
+  self:UpdateBarOptions(bar)
+  self:Refresh()
 end
 
 function Editor:OnDestroyBar(evt, bar, name)
   local key = self.barOptMap[name]
   if key then
-    self.options.args[key] = nil
-  end
-  self:Refresh()
-end
-
-function Editor:OnEraseBar(evt, name)
-  local key = self.barOptMap[name]
-  self.barOptMap[name] = nil
-  if key then
+    self.barOptMap[name] = nil
     self.options.args[key] = nil
     self:Refresh()
   end
@@ -364,8 +378,8 @@
 
 function Editor:OnRenameBar(evt, bar, oldname, newname)
   local key = self.barOptMap[oldname]
-  self.barOptMap[oldname], self.barOptMap[newname] = nil, key
   if key then
+    self.barOptMap[oldname], self.barOptMap[newname] = nil, key
     self.options.args[key].name = newname
     self:Refresh()
   end
@@ -379,42 +393,1300 @@
 
 function Editor:CreateBar()
   if self.tmp.barName and self.tmp.barName ~= "" then
-    self.tmp.creating = true
     local bar = ReAction:CreateBar(self.tmp.barName, self.tmp.barType or ReAction:GetDefaultBarType(), self.tmp.barRows, self.tmp.barCols, self.tmp.barSize, self.tmp.barSpacing)
     if bar then
-      self:CreateBarTree(bar)
       AceConfigDialog:SelectGroup(self.configID, self.barOptMap[self.tmp.barName])
       self.tmp.barName = nil
     end
-    self.tmp.creating = false
   end
 end
 
-function Editor:GenerateBarOptionsTable( bar )
-  local opts = { }
-  if not ReAction.barOptionGenerators then
-    return
+-------------------------------
+---- Action button handler ----
+-------------------------------
+
+do
+  local ActionHandler = {
+    buttonClass = ReAction.Button.Action,
+    options = {
+      hideEmpty = {
+        name = L["Hide Empty Buttons"],
+        order = 1,
+        type = "toggle",
+        width = "double",
+        get  = "GetHideEmpty",
+        set  = "SetHideEmpty",
+      },
+      lockButtons = {
+        name = L["Lock Buttons"],
+        desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"],
+        order = 2,
+        type = "toggle",
+        get = "GetLockButtons",
+        set = "SetLockButtons",
+      },
+      lockOnlyCombat = {
+        name = L["Only in Combat"],
+        desc = L["Only lock the buttons when in combat"],
+        order = 3,
+        type = "toggle",
+        disabled = "LockButtonsCombatDisabled",
+        get = "GetLockButtonsCombat",
+        set = "SetLockButtonsCombat",
+      },
+      pages = {
+        name  = L["# Pages"],
+        desc  = L["Use the Dynamic State tab to specify page transitions"],
+        order = 4,
+        type  = "range",
+        min   = 1,
+        max   = 10,
+        step  = 1,
+        get   = "GetNumPages",
+        set   = "SetNumPages",
+      },
+      mindcontrol = {
+        name = L["Mind Control Support"],
+        desc = L["When possessing a target (e.g. via Mind Control), map the first 12 buttons of this bar to the possessed target's actions."],
+        order = 5,
+        type = "toggle",
+        width = "double",
+        set = "SetMindControl",
+        get = "GetMindControl",
+      },
+      vehicle = {
+        name = L["Vehicle Support"],
+        desc = L["When on a vehicle, map the first 6 buttons of this bar to the vehicle actions. The vehicle-exit button is mapped to the 7th button. Pitch controls are not supported."],
+        order = 6,
+        type = "toggle",
+        width = "double",
+        get = "GetVehicle",
+        set = "SetVehicle",
+      },
+      actions = {
+        name   = L["Edit Action IDs"],
+        order  = 7,
+        type   = "group",
+        inline = true,
+        args   = {
+          method = {
+            name   = L["Assign"],
+            order  = 1,
+            type   = "select",
+            width  = "double",
+            values = { [0] = L["Choose Method..."],
+                       [1] = L["Individually"],
+                       [2] = L["All at Once"], },
+            get    = "GetActionEditMethod",
+            set    = "SetActionEditMethod",
+          },
+          rowSelect = {
+            name   = L["Row"],
+            desc   = L["Rows are numbered top to bottom"],
+            order  = 2,
+            type   = "select",
+            width  = "half",
+            hidden = "IsButtonSelectHidden",
+            values = "GetRowList",
+            get    = "GetSelectedRow",
+            set    = "SetSelectedRow",
+          },
+          colSelect = {
+            name   = L["Col"],
+            desc   = L["Columns are numbered left to right"],
+            order  = 3,
+            type   = "select",
+            width  = "half",
+            hidden = "IsButtonSelectHidden",
+            values = "GetColumnList",
+            get    = "GetSelectedColumn",
+            set    = "SetSelectedColumn",
+          },
+          pageSelect = {
+            name   = L["Page"],
+            order  = 4,
+            type   = "select",
+            width  = "half",
+            hidden = "IsPageSelectHidden",
+            values = "GetPageList",
+            get    = "GetSelectedPage",
+            set    = "SetSelectedPage",
+          },
+          single = {
+            name   = L["Action ID"],
+            usage  = L["Specify ID 1-120"],
+            order  = 5,
+            type   = "input",
+            width  = "half",
+            hidden = "IsButtonSelectHidden",
+            get    = "GetActionID",
+            set    = "SetActionID",
+            validate = "ValidateActionID",
+          },
+          multi = {
+            name   = L["ID List"],
+            usage  = L["Specify a comma-separated list of IDs for each button in the bar (in order). Separate multiple pages with semicolons (;)"],
+            order  = 6,
+            type   = "input",
+            multiline = true,
+            width  = "double",
+            hidden = "IsMultiIDHidden",
+            get    = "GetMultiID",
+            set    = "SetMultiID",
+            validate = "ValidateMultiID",
+          },
+        },
+      },
+    }
+  }
+
+  Editor.buttonHandlers[ActionHandler.buttonClass:GetButtonTypeID()] = ActionHandler
+
+  local meta = { __index = ActionHandler }
+
+  function ActionHandler:New( bar )
+    return setmetatable(
+      {
+        bar = bar,
+        config = bar:GetConfig(),
+      }, 
+      meta)
   end
 
-  for module, func in pairs(ReAction.barOptionGenerators) do
-    local success, r
-    if type(func) == "string" then
-      success, r = pcall(module[func], module, bar)
-    else
-      success, r = pcall(func, bar)
-    end
-    if success then
-      if r then
-        opts[module:GetName()] = { [module:GetName()] = r }
+  function ActionHandler:Refresh()
+    self.buttonClass:SetupBar(self.bar)
+  end
+
+  function ActionHandler:UpdateButtonLock()
+    self.buttonClass:SetButtonLock(self.bar, self.config.lockButtons, self.config.lockButtonsCombat)
+  end
+
+  function ActionHandler:GetLastButton()
+    return self.bar:GetButton(self.bar:GetNumButtons())
+  end
+
+    -- options handlers
+  function ActionHandler:GetOptions()
+    return {
+      type = "group",
+      name = L["Action Buttons"],
+      handler = self,
+      order = 2,
+      args = self.options
+    }
+  end
+
+  function ActionHandler:SetHideEmpty(info, value)
+    if value ~= self.config.hideEmpty then
+      self.config.hideEmpty = value
+      for _, b in self.bar:IterateButtons() do
+        b:ShowGrid(not value)
       end
-    else
-      geterrorhandler()(r)
     end
   end
-  return opts
+
+  function ActionHandler:GetHideEmpty()
+    return self.config.hideEmpty
+  end
+
+  function ActionHandler:GetLockButtons()
+    return self.config.lockButtons
+  end
+
+  function ActionHandler:SetLockButtons(info, value)
+    self.config.lockButtons = value
+    self:UpdateButtonLock()
+  end
+
+  function ActionHandler:GetLockButtonsCombat()
+    return self.config.lockButtonsCombat
+  end
+
+  function ActionHandler:SetLockButtonsCombat(info, value)
+    self.config.lockButtonsCombat = value
+    self:UpdateButtonLock()
+  end
+
+  function ActionHandler:LockButtonsCombatDisabled()
+    return not self.config.lockButtons
+  end
+
+  function ActionHandler:GetNumPages()
+    return self.config.nPages
+  end
+
+  function ActionHandler:SetNumPages(info, value)
+    self.config.nPages = value
+    self:Refresh()
+  end
+
+  function ActionHandler:GetMindControl()
+    return self.config.mindcontrol
+  end
+
+  function ActionHandler:SetMindControl(info, value)
+    self.config.mindcontrol = value
+    self:Refresh()
+  end
+
+  function ActionHandler:GetVehicle()
+    return self.config.vehicle
+  end
+
+  function ActionHandler:SetVehicle(info, value)
+    self.config.vehicle = value
+    self:Refresh()
+  end
+
+  function ActionHandler:GetActionEditMethod()
+    return self.editMethod or 0
+  end
+
+  function ActionHandler:SetActionEditMethod(info, value)
+    self.editMethod = value
+  end
+
+  function ActionHandler:IsButtonSelectHidden()
+    return self.editMethod ~= 1
+  end
+
+  function ActionHandler:GetRowList()
+    local r,c = self.bar:GetButtonGrid()
+    if self.rowList == nil or #self.rowList ~= r then
+      local list = { }
+      for i = 1, r do
+        table.insert(list,i)
+      end
+      self.rowList = list
+    end
+    return self.rowList
+  end
+
+  function ActionHandler:GetSelectedRow()
+    local r, c = self.bar:GetButtonGrid()
+    local row = self.selectedRow or 1
+    if row > r then
+      row = 1
+    end
+    self.selectedRow = row
+    return row
+  end
+
+  function ActionHandler:SetSelectedRow(info, value)
+    self.selectedRow = value
+  end
+
+  function ActionHandler:GetColumnList()
+    local r,c = self.bar:GetButtonGrid()
+    if self.columnList == nil or #self.columnList ~= c then
+      local list = { }
+      for i = 1, c do
+        table.insert(list,i)
+      end
+      self.columnList = list
+    end
+    return self.columnList
+  end
+
+  function ActionHandler:GetSelectedColumn()
+    local r, c = self.bar:GetButtonGrid()
+    local col = self.selectedColumn or 1
+    if col > c then
+      col = 1
+    end
+    self.selectedColumn = col
+    return col
+  end
+
+  function ActionHandler:SetSelectedColumn(info, value)
+    self.selectedColumn = value
+  end
+
+  function ActionHandler:IsPageSelectHidden()
+    return self.editMethod ~= 1 or (self.config.nPages or 1) < 2
+  end
+
+  function ActionHandler:GetPageList()
+    local n = self.config.nPages or 1
+    if self.pageList == nil or #self.pageList ~= n then
+      local p = { }
+      for i = 1, n do
+        table.insert(p,i)
+      end
+      self.pageList = p
+    end
+    return self.pageList
+  end
+
+  function ActionHandler:GetSelectedPage()
+    local p = self.selectedPage or 1
+    if p > (self.config.nPages or 1) then
+      p = 1
+    end
+    self.selectedPage = p
+    return p
+  end
+
+  function ActionHandler:SetSelectedPage(info, value)
+    self.selectedPage = value
+  end
+
+  function ActionHandler:GetActionID()
+    local row = self.selectedRow or 1
+    local col = self.selectedColumn or 1
+    local r, c = self.bar:GetButtonGrid()
+    local n = (row-1) * c + col
+    local btn = self.bar:GetButton(n)
+    if btn then
+      return tostring(btn:GetActionID(self.selectedPage or 1))
+    end
+  end
+
+  function ActionHandler:SetActionID(info, value)
+    local row = self.selectedRow or 1
+    local col = self.selectedColumn or 1
+    local r, c = self.bar:GetButtonGrid()
+    local n = (row-1) * c + col
+    local btn = self.bar:GetButton(n)
+    if btn then
+      btn:SetActionID(tonumber(value), self.selectedPage or 1)
+    end
+  end
+
+  function ActionHandler:ValidateActionID(info, value)
+    value = tonumber(value)
+    if value == nil or value < 1 or value > 120 then
+      return L["Specify ID 1-120"]
+    end
+    return true
+  end
+
+  function ActionHandler:IsMultiIDHidden()
+    return self.editMethod ~= 2
+  end
+
+  function ActionHandler:GetMultiID()
+    local p = { }
+    for i = 1, self.config.nPages or 1 do
+      local b = { }
+      for _, btn in self.bar:IterateButtons() do
+        table.insert(b, btn:GetActionID(i))
+      end
+      table.insert(p, table.concat(b,","))
+    end
+    return table.concat(p,";\n")
+  end
+
+
+  local function ParseMultiID(nBtns, nPages, s)
+    if s:match("[^%d%s,;]") then
+      return nil
+    end
+    local p = { }
+    for list in s:gmatch("[^;]+") do
+      local pattern = ("^%s?$"):format(("%s*(%d+)%s*,"):rep(nBtns))
+      local ids = { list:match(pattern) }
+      if #ids ~= nBtns then
+        return nil
+      end
+      table.insert(p,ids)
+    end
+    if #p ~= nPages then
+      return nil
+    end
+    return p
+  end
+
+  function ActionHandler:SetMultiID(info, value)
+    local p = ParseMultiID(self.bar:GetNumButtons(), self.config.nPages or 1, value)
+    for page, b in ipairs(p) do
+      for button, id in ipairs(b) do
+        self.bar:GetButton(button):SetActionID(id, page)
+      end
+    end
+  end
+
+  function ActionHandler:ValidateMultiID(info, value)
+    local bad = L["Invalid action ID list string"]
+    if value == nil or ParseMultiID(self.bar:GetNumButtons(), self.config.nPages or 1, value) == nil then
+      return bad
+    end
+    return true
+  end
 end
 
 
+----------------------------------
+---- PetAction button handler ----
+----------------------------------
+
+do
+  local PetHandler = { 
+    buttonClass = ReAction.Button.PetAction,
+  }
+
+  Editor.buttonHandlers[PetHandler.buttonClass:GetButtonTypeID()] = PetHandler
+
+  local meta = { __index = PetHandler }
+
+  function PetHandler:New(bar)
+    return setmetatable(
+      {
+        bar = bar,
+        config = bar.config
+      }, meta)
+  end
+
+  function PetHandler:GetLockButtons()
+    return self.config.lockButtons
+  end
+
+  function PetHandler:SetLockButtons(info, value)
+    self.config.lockButtons = value
+    self.buttonClass:UpdateButtonLock(self.bar)
+  end
+
+  function PetHandler:GetLockButtonsCombat()
+    return self.config.lockButtonsCombat
+  end
+
+  function PetHandler:SetLockButtonsCombat(info, value)
+    self.config.lockButtonsCombat = value
+    self.buttonClass:UpdateButtonLock(self.bar)
+  end
+
+  function PetHandler:LockButtonsCombatDisabled()
+    return not self.config.lockButtons
+  end
+
+  function PetHandler:GetOptions()
+    return {
+      type = "group",
+      name = L["Pet Buttons"],
+      handler = self,
+      order = 2,
+      args = {
+        lockButtons = {
+          name = L["Lock Buttons"],
+          desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"],
+          order = 2,
+          type = "toggle",
+          get = "GetLockButtons",
+          set = "SetLockButtons",
+        },
+        lockOnlyCombat = {
+          name = L["Only in Combat"],
+          desc = L["Only lock the buttons when in combat"],
+          order = 3,
+          type = "toggle",
+          disabled = "LockButtonsCombatDisabled",
+          get = "GetLockButtonsCombat",
+          set = "SetLockButtonsCombat",
+        },
+      }
+    }
+  end
+end
+
+
+-------------------------------------
+---- Vehicle Exit button handler ----
+-------------------------------------
+
+do
+  local VExitHandler = { 
+    buttonClass = ReAction.Button.VehicleExit,
+  }
+
+  Editor.buttonHandlers[VExitHandler.buttonClass:GetButtonTypeID()] = VExitHandler
+
+  local meta = { __index = VExitHandler }
+
+  function VExitHandler:New(bar)
+    return setmetatable(
+      {
+        bar = bar,
+      }, meta)
+  end
+
+  function VExitHandler:GetConfig()
+    return self.bar:GetConfig()
+  end
+
+  function VExitHandler:GetPassengerOnly()
+    return not self:GetConfig().withControls
+  end
+
+  function VExitHandler:SetPassengerOnly(info, value)
+    self:GetConfig().withControls = not value
+    self.buttonClass:UpdateRegistration(self.bar)
+  end
+
+
+  function VExitHandler:GetOptions()
+    return {
+      type = "group",
+      name = L["Exit Vehicle"],
+      handler = self,
+      args = {
+        passengerOnly = {
+          name = L["Show only when passenger"],
+          desc = L["Only show the button when riding as a passenger in a vehicle (no vehicle controls)"],
+          order = 2,
+          width = "double",
+          type = "toggle",
+          get = "GetPassengerOnly",
+          set = "SetPassengerOnly",
+        },
+      }
+    }
+  end
+end
+
+
+------------------------------
+--- Dynamic State options ----
+------------------------------
+do
+  local ApplyStates   = ReAction.Bar.ApplyStates
+  local CleanupStates = ReAction.Bar.CleanupStates
+  local SetProperty   = ReAction.Bar.SetStateProperty
+  local GetProperty   = ReAction.Bar.GetStateProperty
+
+  -- pre-sorted by the order they should appear in
+  local rules = {
+    --  rule       fields
+    { "stance",  { {battle = L["Battle Stance"]}, {defensive = L["Defensive Stance"]}, {berserker = L["Berserker Stance"]} } },
+    { "form",    { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {tree = L["Tree of Life"]}, {moonkin = L["Moonkin Form"]} } },
+    { "stealth", { {stealth = L["Stealth"]}, {nostealth = L["No Stealth"]}, {shadowdance = L["Shadow Dance"]} } },
+    { "shadow",  { {shadowform = L["Shadowform"]}, {noshadowform = L["No Shadowform"]} } },
+    { "demon",   { {demon = L["Demon Form"]}, {nodemon = L["No Demon Form"]} } },
+    { "pet",     { {pet = L["With Pet"]}, {nopet = L["Without Pet"]} } },
+    { "target",  { {harm = L["Hostile Target"]}, {help = L["Friendly Target"]}, {notarget = L["No Target"]} } },
+    { "focus",   { {focusharm = L["Hostile Focus"]}, {focushelp = L["Friendly Focus"]}, {nofocus = L["No Focus"]} } },
+    { "possess", { {possess = L["Mind Control"]} } },
+    { "vehicle", { {vehicle = L["In a Vehicle"]} } },
+    { "group",   { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } },
+    { "combat",  { {combat = L["In Combat"]}, {nocombat = L["Out of Combat"]} } },
+  }
+
+  local ruleSelect = { }
+  local ruleMap    = { }
+  local optionMap  = setmetatable({},{__mode="k"})
+
+
+  -- unpack rules table into ruleSelect and ruleMap
+  for _, c in ipairs(rules) do
+    local rule, fields = unpack(c)
+    for _, field in ipairs(fields) do
+      local key, label = next(field)
+      table.insert(ruleSelect, label)
+      table.insert(ruleMap, key)
+    end
+  end
+
+  local stateOptions = {
+    ordering = {
+      name = L["Info"],
+      order = 1,
+      type = "group",
+      args = {
+        delete = {
+          name = L["Delete this State"],
+          order = -1,
+          type = "execute",
+          func = "DeleteState",
+        },
+        rename = {
+          name = L["Name"],
+          order = 1,
+          type = "input",
+          get  = "GetName",
+          set  = "SetStateName",
+          pattern = "^%w*$",
+          usage = L["State names must be alphanumeric without spaces"],
+        },
+        ordering = {
+          name = L["Evaluation Order"],
+          desc = L["State transitions are evaluated in the order listed:\nMove a state up or down to change the order"],
+          order = 2,
+          type = "group",
+          inline = true,
+          args = {
+            up = {
+              name  = L["Up"],
+              order = 1,
+              type  = "execute",
+              width = "half",
+              func  = "MoveStateUp",
+            },
+            down = {
+              name  = L["Down"],
+              order = 2,
+              type  = "execute",
+              width = "half",
+              func  = "MoveStateDown",
+            }
+          }
+        }
+      }
+    },
+    properties = {
+      name = L["Properties"],
+      order = 2,
+      type = "group",
+      args = { 
+        desc = {
+          name = L["Set the properties for the bar when in this state"],
+          order = 1,
+          type = "description"
+        },
+        page = {
+          name     = L["Show Page #"],
+          order    = 11,
+          type     = "select",
+          width    = "half",
+          disabled = "IsPageDisabled",
+          hidden   = "IsPageHidden",
+          values   = "GetPageValues",
+          set      = "SetProp",
+          get      = "GetPage",
+        },
+        hide = {
+          name = L["Hide Bar"],
+          order = 90,
+          type = "toggle",
+          set  = "SetProp",
+          get  = "GetProp",
+        },
+        --[[ BROKEN
+        keybindState = {
+          name  = L["Override Keybinds"],
+          desc  = L["Set this state to maintain its own set of keybinds which override the defaults when active"],
+          order = 91,
+          type  = "toggle",
+          set   = "SetProp",
+          get   = "GetProp",
+        }, ]]
+        position = {
+          name  = L["Position"],
+          order = 92,
+          type  = "group",
+          inline = true,
+          args = {
+            anchorEnable = {
+              name  = L["Reposition"],
+              order = 1,
+              type  = "toggle",
+              set   = "SetProp",
+              get   = "GetProp",
+            },
+            anchorFrame = {
+              name   = L["Anchor Frame"],
+              order  = 2,
+              type   = "select",
+              values = "GetAnchorFrames",
+              set    = "SetAnchorFrame",
+              get    = "GetAnchorFrame",
+              disabled = "GetAnchorDisabled",
+              hidden = "GetAnchorDisabled",
+            },
+            anchorPoint = {
+              name  = L["Point"],
+              order = 3,
+              type  = "select",
+              values = pointTable,
+              set   = "SetAnchorPointProp",
+              get   = "GetAnchorPointProp",
+              disabled = "GetAnchorDisabled",
+              hidden = "GetAnchorDisabled",
+            },
+            anchorRelPoint = {
+              name  = L["Relative Point"],
+              order = 4,
+              type  = "select",
+              values = pointTable,
+              set   = "SetAnchorPointProp",
+              get   = "GetAnchorPointProp",
+              disabled = "GetAnchorDisabled",
+              hidden = "GetAnchorDisabled",
+            },
+            anchorX = {
+              name  = L["X Offset"],
+              order = 5,
+              type  = "range",
+              min   = -100,
+              max   = 100,
+              step  = 1,
+              set   = "SetProp",
+              get   = "GetProp",
+              disabled = "GetAnchorDisabled",
+              hidden = "GetAnchorDisabled",
+            },
+            anchorY = {
+              name  = L["Y Offset"],
+              order = 6,
+              type  = "range",
+              min   = -100,
+              max   = 100,
+              step  = 1,
+              set   = "SetProp",
+              get   = "GetProp",
+              disabled = "GetAnchorDisabled",
+              hidden = "GetAnchorDisabled",
+            },
+          },
+        },
+        scale = {
+          name  = L["Scale"],
+          order = 93,
+          type  = "group",
+          inline = true,
+          args = {
+            enableScale = {
+              name  = L["Set New Scale"],
+              order = 1,
+              type  = "toggle",
+              set   = "SetProp",
+              get   = "GetProp",
+            },
+            scale = {
+              name  = L["Scale"],
+              order = 2,
+              type  = "range",
+              min   = 0.25,
+              max   = 2.5,
+              step  = 0.05,
+              isPercent = true,
+              set   = "SetProp",
+              get   = "GetScale",
+              disabled = "GetScaleDisabled",
+              hidden = "GetScaleDisabled",
+            },
+          },
+        },
+        alpha = {
+          name  = L["Transparency"],
+          order = 94,
+          type  = "group",
+          inline = true,
+          args = {
+            enableAlpha = {
+              name  = L["Set Transparency"],
+              order = 1,
+              type  = "toggle",
+              set   = "SetProp",
+              get   = "GetProp",
+            },
+            alpha = {
+              name  = L["Transparency"],
+              order = 2,
+              type  = "range",
+              min   = 0,
+              max   = 1,
+              step  = 0.01,
+              bigStep = 0.05,
+              isPercent = true,
+              set   = "SetProp",
+              get   = "GetAlpha",
+              disabled = "GetAlphaDisabled",
+              hidden = "GetAlphaDisabled",
+            },
+          },
+        },
+      },
+      plugins = { }
+    },
+    rules = {
+      name   = L["Rule"],
+      order  = 3,
+      type   = "group",
+      args   = {
+        mode = {
+          name   = L["Select this state"],
+          order  = 2,
+          type   = "select",
+          style  = "radio",
+          values = { 
+            default = L["by default"], 
+            any = L["when ANY of these"], 
+            all = L["when ALL of these"], 
+            custom = L["via custom rule"],
+            keybind = L["via keybinding"],
+          },
+          set    = "SetType",
+          get    = "GetType",
+        },
+        clear = {
+          name     = L["Clear All"],
+          order    = 3,
+          type     = "execute",
+          hidden   = "GetClearAllDisabled",
+          disabled = "GetClearAllDisabled",
+          func     = "ClearAllConditions",
+        },
+        inputs = {
+          name     = L["Conditions"],
+          order    = 4,
+          type     = "multiselect",
+          hidden   = "GetConditionsDisabled",
+          disabled = "GetConditionsDisabled",
+          values   = ruleSelect,
+          set      = "SetCondition",
+          get      = "GetCondition",
+        },
+        custom = {
+          name = L["Custom Rule"],
+          order = 5,
+          type = "input",
+          multiline = true,
+          hidden = "GetCustomDisabled",
+          disabled = "GetCustomDisabled",
+          desc = L["Syntax like macro rules: see preset rules for examples"],
+          set  = "SetCustomRule",
+          get  = "GetCustomRule",
+          validate = "ValidateCustomRule",
+        },
+        keybind = {
+          name = L["Keybinding"],
+          order = 6,
+          inline = true,
+          hidden = "GetKeybindDisabled",
+          disabled = "GetKeybindDisabled",
+          type = "group",
+          args = {
+            desc = {
+              name = L["Invoking a state keybind toggles an override of all other transition rules."],
+              order = 1,
+              type = "description",
+            },
+            keybind = {
+              name = L["State Hotkey"],
+              desc = L["Define an override toggle keybind"],
+              order = 2,
+              type = "keybinding",
+              set  = "SetKeybind",
+              get  = "GetKeybind",
+            },
+          },
+        },
+      },
+    },
+  }
+
+  local StateHandler = { }
+  local meta         = { __index = StateHandler }
+
+  function StateHandler:New( bar, opts )
+    local self = setmetatable(
+      { 
+        bar = bar 
+      }, 
+      meta )
+
+    function self:GetName()
+      return opts.name
+    end
+
+    function self:SetName(name)
+      opts.name = name
+    end
+
+    function self:GetOrder()
+      return opts.order
+    end
+
+    -- get reference to states table: even if the bar
+    -- name changes the states table ref won't
+    self.states = tbuild(bar:GetConfig(), "states")
+    self.state  = tbuild(self.states, opts.name)
+
+    opts.order = self:GetRuleField("order")
+    if opts.order == nil then
+      -- add after the highest
+      opts.order = 100
+      for _, state in pairs(self.states) do
+        local x = tonumber(tfetch(state, "rule", "order"))
+        if x and x >= opts.order then
+          opts.order = x + 1
+        end
+      end
+      self:SetRuleField("order",opts.order)
+    end
+
+    return self
+  end
+
+  -- helper methods
+
+  function StateHandler:SetRuleField( key, value, ... )
+    tbuild(self.state, "rule", ...)[key] = value
+  end
+
+  function StateHandler:GetRuleField( ... )
+    return tfetch(self.state, "rule", ...)
+  end
+
+  function StateHandler:FixAll( setkey )
+    -- if multiple selections in the same group are chosen when 'all' is selected,
+    -- keep only one of them. If changing the mode, the first in the fields list will 
+    -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set,
+    -- it will be retained.
+    local notified = false
+    if self:GetRuleField("type") == "all" then
+      for _, c in ipairs(rules) do
+        local rule, fields = unpack(c)
+        local once = false
+        if setkey then
+          for idx, field in ipairs(fields) do
+            if next(field) == setkey then
+              once = true
+            end
+          end
+        end
+        for idx, field in ipairs(fields) do
+          local key = next(field)
+          if self:GetRuleField("values",key) then
+            if once and key ~= setkey then
+              self:SetRuleField(key,false,"values")
+              if not setkey and not notified then
+                ReAction:UserError(L["Warning: one or more incompatible rules were turned off"])
+                notified = true
+              end
+            end
+            once = true
+          end
+        end
+      end
+    end
+  end
+
+  function StateHandler:GetNeighbors()
+    local before, after
+    for k, v in pairs(self.states) do
+      local o = tonumber(tfetch(v, "rule", "order"))
+      if o and k ~= self:GetName() then
+        local obefore = tfetch(self.states,before,"rule","order")
+        local oafter  = tfetch(self.states,after,"rule","order")
+        if o < self:GetOrder() and (not obefore or obefore < o) then
+          before = k
+        end
+        if o > self:GetOrder() and (not oafter or oafter > o) then
+          after = k
+        end
+      end
+    end
+    return before, after
+  end
+
+  function StateHandler:SwapOrder( a, b )
+    -- do options table
+    local args = optionMap[self.bar].args
+    args[a].order, args[b].order = args[b].order, args[a].order
+    -- do profile
+    a = tbuild(self.states, a, "rule")
+    b = tbuild(self.states, b, "rule")
+    a.order, b.order = b.order, a.order
+  end
+
+  -- handler methods 
+
+  function StateHandler:GetProp( info )
+    -- gets property of the same name as the options arg
+    return GetProperty(self.bar, self:GetName(), info[#info])
+  end
+
+  function StateHandler:SetProp( info, value )
+    -- sets property of the same name as the options arg
+    SetProperty(self.bar, self:GetName(), info[#info], value)
+  end
+
+  function StateHandler:DeleteState()
+    if self.states[self:GetName()] then
+      self.states[self:GetName()] = nil
+      ApplyStates(self.bar)
+    end
+    optionMap[self.bar].args[self:GetName()] = nil
+  end
+
+  function StateHandler:SetStateName(info, value)
+    -- check for existing state name
+    if self.states[value] then
+      ReAction:UserError(format(L["State named '%s' already exists"],value))
+      return
+    end
+    local args = optionMap[self.bar].args
+    local name = self:GetName()
+    self.states[value], args[value], self.states[name], args[name] = self.states[name], args[name], nil, nil
+    self:SetName(value)
+    ApplyStates(self.bar)
+    ReAction:ShowEditor(self.bar, moduleID, value)
+    end
+
+  function StateHandler:MoveStateUp()
+    local before, after = self:GetNeighbors()
+    if before then
+      self:SwapOrder(before, self:GetName())
+      ApplyStates(self.bar)
+    end
+  end
+
+  function StateHandler:MoveStateDown()
+    local before, after = self:GetNeighbors()
+    if after then
+      self:SwapOrder(self:GetName(), after)
+      ApplyStates(self.bar)
+    end
+  end
+
+  function StateHandler:GetAnchorDisabled()
+    return not GetProperty(self.bar, self:GetName(), "anchorEnable")
+  end
+
+  function StateHandler:IsPageDisabled()
+    local n = self.bar:GetConfig().nPages or 1
+    return not (n > 1)
+  end
+
+  function StateHandler:IsPageHidden()
+    return not self.bar:GetConfig().nPages
+  end
+
+  function StateHandler:GetPageValues()
+    if not self._pagevalues then
+      self._pagevalues = { }
+    end
+    local n = self.bar:GetConfig().nPages
+      -- cache the results
+    if self._npages ~= n then
+      self._npages = n
+      wipe(self._pagevalues)
+      for i = 1, n do
+        self._pagevalues["page"..i] = i
+      end
+    end
+    return self._pagevalues
+  end
+
+  function StateHandler:GetPage(info)
+    return self:GetProp(info) or 1
+  end
+
+  function StateHandler:GetAnchorFrames(info)
+    self._anchorframes = self._anchorframes or { }
+    table.wipe(self._anchorframes)
+
+    table.insert(self._anchorframes, "UIParent")
+    for name, bar in ReAction:IterateBars() do
+      table.insert(self._anchorframes, bar:GetFrame():GetName())
+    end
+    return self._anchorframes
+  end
+
+  function StateHandler:GetAnchorFrame(info)
+    local value = self:GetProp(info)
+    for k,v in pairs(self._anchorframes) do
+      if v == value then
+        return k
+      end
+    end
+  end
+
+  function StateHandler:SetAnchorFrame(info, value)
+    local f = _G[self._anchorframes[value]]
+    if f then
+      self.bar:SetFrameRef("anchor-"..self:GetName(), f)
+      self:SetProp(info, f:GetName())
+    end
+  end
+
+  function StateHandler:SetAnchorPointProp(info, value)
+    self:SetProp(info, value ~= "NONE" and value or nil)
+  end
+
+  function StateHandler:GetAnchorPointProp(info)
+    return self:GetProp(info) or "NONE"
+  end
+
+  function StateHandler:GetScale(info)
+    return self:GetProp(info) or 1.0
+  end
+
+  function StateHandler:GetScaleDisabled()
+    return not GetProperty(self.bar, self:GetName(), "enableScale")
+  end
+
+  function StateHandler:GetAlpha(info)
+    return self:GetProp(info) or 1.0
+  end
+
+  function StateHandler:GetAlphaDisabled()
+    return not GetProperty(self.bar, self:GetName(), "enableAlpha")
+  end
+
+  function StateHandler:SetType(info, value)
+    self:SetRuleField("type", value)
+    self:FixAll()
+    ApplyStates(self.bar)
+  end
+
+  function StateHandler:GetType()
+    return self:GetRuleField("type")
+  end
+
+  function StateHandler:GetClearAllDisabled()
+    local t = self:GetRuleField("type")
+    return not( t == "any" or t == "all" or t == "custom")
+  end
+
+  function StateHandler:ClearAllConditions()
+    local t = self:GetRuleField("type")
+    if t == "custom" then
+      self:SetRuleField("custom","")
+    elseif t == "any" or t == "all" then
+      self:SetRuleField("values", {})
+    end
+    ApplyStates(self.bar)
+  end
+
+  function StateHandler:GetConditionsDisabled()
+    local t = self:GetRuleField("type")
+    return not( t == "any" or t == "all")
+  end
+
+  function StateHandler:SetCondition(info, key, value)
+    self:SetRuleField(ruleMap[key], value or nil, "values")
+    if value then
+      self:FixAll(ruleMap[key])
+    end
+    ApplyStates(self.bar)
+  end
+
+  function StateHandler:GetCondition(info, key)
+    return self:GetRuleField("values", ruleMap[key]) or false
+  end
+
+  function StateHandler:GetCustomDisabled()
+    return self:GetRuleField("type") ~= "custom"
+  end
+
+  function StateHandler:SetCustomRule(info, value)
+    self:SetRuleField("custom",value)
+    ApplyStates(self.bar)
+  end
+
+  function StateHandler:GetCustomRule()
+    return self:GetRuleField("custom") or ""
+  end
+
+  function StateHandler:ValidateCustomRule(info, value)
+    local s = value:gsub("%s","") -- remove all spaces
+    -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler
+    repeat
+      if s == "" then
+        return true
+      end
+      local c, r = s:match("(%b[])(.*)")
+      if c == nil and s and #s > 0 then
+        return format(L["Invalid custom rule '%s': each clause must appear within [brackets]"],value or "")
+      end
+      s = r
+    until c == nil
+    return true
+  end
+
+  function StateHandler:GetKeybindDisabled()
+    return self:GetRuleField("type") ~= "keybind"
+  end
+
+  function StateHandler:GetKeybind()
+    return self:GetRuleField("keybind")
+  end
+
+  function StateHandler:SetKeybind(info, value)
+    if value and #value == 0 then
+      value = nil
+    end
+    self:SetRuleField("keybind",value)
+    ApplyStates(self.bar)
+  end
+
+  local function CreateStateOptions(bar, name)
+    local opts = { 
+      type = "group",
+      name = name,
+      childGroups = "tab",
+      args = stateOptions
+    }
+
+    opts.handler = StateHandler:New(bar,opts)
+
+    return opts
+  end
+
+  function Editor:CreateStateOptions(bar)
+    local private = { }
+    local states = tbuild(bar:GetConfig(), "states")
+    local options = {
+      name = L["Dynamic State"],
+      type = "group",
+      order = -1,
+      childGroups = "tree",
+      disabled = InCombatLockdown,
+      args = {
+        __desc__ = {
+          name = L["States are evaluated in the order they are listed"],
+          order = 1,
+          type = "description",
+        },
+        __new__ = {
+          name = L["New State..."],
+          order = 2,
+          type = "group",
+          args = {
+            name = {
+              name = L["State Name"],
+              desc = L["Set a name for the new state"],
+              order = 1,
+              type = "input",
+              get = function() return private.newstatename or "" end,
+              set = function(info,value) private.newstatename = value end,
+              pattern = "^%w*$",
+              usage = L["State names must be alphanumeric without spaces"],
+            },
+            create = {
+              name = L["Create State"],
+              order = 2,
+              type = "execute",
+              func = function ()
+                  local name = private.newstatename
+                  if states[name] then
+                    ReAction:UserError(format(L["State named '%s' already exists"],name))
+                  else
+                    -- TODO: select default state options and pass as final argument
+                    states[name] = { }
+                    optionMap[bar].args[name] = CreateStateOptions(bar,name)
+                    ReAction:ShowEditor(bar, moduleID, name)
+                    private.newstatename = ""
+                  end
+                end,
+              disabled = function()
+                  local name = private.newstatename or ""
+                  return #name == 0 or name:find("%W")
+                end,
+            }
+          }
+        }
+      }
+    }
+    for name, config in pairs(states) do
+      options.args[name] = CreateStateOptions(bar,name)
+    end
+    optionMap[bar] = options
+    return options
+  end
+end
+
 
 ---- Export to ReAction ----
 function ReAction:ShowEditor(bar, ...)
@@ -439,22 +1711,3 @@
   end
 end
 
-function ReAction:RegisterBarOptionGenerator( module, func )
-  if not module or type(module) ~= "table" then -- doesn't need to be a proper module, strictly
-    error("ReAction:RegisterBarOptionGenerator() : Invalid module")
-  end
-  if type(func) == "string" then
-    if not module[func] then
-      error(("ReAction:RegisterBarOptionGenerator() : Invalid method '%s'"):format(func))
-    end
-  elseif func and type(func) ~= "function" then
-    error("ReAction:RegisterBarOptionGenerator() : Invalid function")
-  end
-  self.barOptionGenerators = self.barOptionGenerators or { }
-  self.barOptionGenerators[module] = func
-
-  if self.editor then
-    self.editor:RefreshBarOptions()
-  end
-end
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MultiCastButton.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,779 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local unpack = unpack
+local GetCVar = GetCVar
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local InCombatLockdown = InCombatLockdown
+local IsUsableSpell = IsUsableSpell
+local IsUsableAction = IsUsableAction
+local IsSpellKnown = IsSpellKnown
+local IsSpellInRange = IsSpellInRange
+local IsActionInRange = IsActionInRange
+local GetSpellInfo = GetSpellInfo
+local GetSpellCooldown = GetSpellCooldown
+local GetActionCooldown = GetActionCooldown
+local GetSpellTexture = GetSpellTexture
+local GetActionTexture = GetActionTexture
+local GetMultiCastTotemSpells = GetMultiCastTotemSpells
+
+--[[
+  Blizzard Constants:
+    - NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4
+    - NUM_MULTI_CAST_PAGES = 3
+    - SHAMAN_TOTEM_PRIORITIES = { } -- sets the order of the totems
+    - TOTEM_MULTI_CAST_SUMMON_SPELLS = { } -- list of summon spellIDs
+    - TOTEM_MULTI_CAST_RECALL_SPELLS = { } -- list of recall spellIDs
+
+  Blizzard Events:
+    - UPDATE_MULTI_CAST_ACTIONBAR
+
+  Blizzard APIs:
+    - GetMultiCastBarOffset() : returns 6
+
+    - SetMultiCastSpell(actionID, spellID) (protected) OR
+         SetAttribute("type","multispell")
+         SetAttribute("action",actionID)
+         SetAttribute("spell",spellID)
+
+         note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(),
+               so that's action ID 132-144.
+
+    - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot)
+        returns spellIDs for all known totems that fit that slot. This function is available in
+        the secure environment.
+
+  Blizzard textures:
+    All the textures for the multicast bar (arrows, empty-slot icons, etc) are part of a single
+    texture: each texture uses SetTexCoord() to display only a slice of the textures. I suppose
+    this is to slightly optimize texture load performance, but it makes the UI code more clumsy.
+
+    Each totem button and arrow has a colored border indicating its elemental type.
+
+    TODO: 
+      - make whether to show the colored border configurable (looks really bad with ButtonFacade:Zoomed)
+      - apply ButtonFacade to the flyout buttons? Or at least zoom the textures slightly?
+      - use a multiplier with SetTexCoord on totem bar texture?
+
+  Design Notes:
+    - Only the header has a secure context. All other frames execute in its context.
+
+    - Each button is either type "spell" (summon/recall) or type "action" (totem action IDs are 
+      GetBonusBarOffset()=6, 132-144) with 3 pages of 4 buttons. The paging is controlled by
+      the summon flyout, which is also paged with the summon spells (the recall button is not paged)
+    
+    - A spell list is updated in the secure context at setup time (TODO: redo setup when learning new 
+      spells) with the list of spells known for each slot.
+    
+    - Each button (except recall) has an arrow button which appears on mouseover and when clicked
+      opens the flyout via a wrapped OnClick handler. When the flyout is open, the arrow does not
+      appear.
+    
+    - A single flyout with N+1 (1 slot is to select no totem for the set) flyout-buttons is a child
+      of the bar. Each time the flyout panel is opened, the individual  buttons grab their corresponding
+      spell/type from the list, according to the slot which opened the flyout. Each button either sets
+      the current page (summon) or sets a multispell to an actionID via type="multispell". None of them
+      actually cast any spells (though, I suppose we could modify this so that e.g. configurable 
+      right-click casts the spell). The flyout also has a close button which closes the flyout: the
+      flyout-open code positions the close button anchored to the last button in the flyout (which 
+      changes dynamically because each slot has a different number of items in the list).
+
+    - Multicast sets are not stances, there's no need (or ability) to handle swapping sets if one of 
+      the summon spells is cast from elsewhere.
+
+    - The default UI has Call of the Elements always selected on UI load. This module remembers the last
+      selected one and restores it.
+
+
+]]--
+
+
+--
+-- Secure snippets
+--
+
+-- bar
+local _bar_init = -- function(self)
+[[
+  -- set up some globals in the secure environment
+  flyout               = self:GetFrameRef("flyout")
+  flyoutSlot           = nil
+  summonSlot           = self:GetAttribute("summonSlot")
+  recallSlot           = self:GetAttribute("recallSlot")
+  baseActionID         = self:GetAttribute("baseActionID")
+  slotsPerPage         = self:GetAttribute("slotsPerPage")
+  currentPage          = currentPage or self:GetAttribute("lastSummon") or 1
+
+  totemIDsBySlot = newtable()
+  for i = 1, slotsPerPage do
+    totemIDsBySlot[i] = self:GetAttribute("TOTEM_PRIORITY_"..i)
+  end
+
+  -- these are set up in bar:SetupBar()
+  flyoutChildren = flyoutChildren or newtable()
+  summonSpells = summonSpells or newtable()
+]]
+
+local _onstate_multispellpage = -- function(self, stateid, newstate)
+[[
+  currentPage = tonumber(newstate)
+  control:CallMethod("UpdateLastSummon",currentPage)
+  control:ChildUpdate()
+]]
+
+
+-- buttons
+local _childupdate = -- function(self, snippetid, message)
+[[
+  local t = self:GetAttribute("type")
+  self:SetAttribute(t, self:GetAttribute(t.."-page"..currentPage))
+]]
+
+local _onEnter = -- function(self)
+  -- for whatever reason, RegisterAutoHide is unreliable
+  -- unless you re-anchor the frame prior to calling it.
+  -- Even then, it's still not terribly reliable.
+[[
+  local slot = self:GetAttribute("bar-idx")
+  local arrow = owner:GetFrameRef("arrow-"..slot)
+  if arrow and not arrow:IsShown() and not (flyout:IsVisible() and flyoutSlot == slot) then
+    arrow:ClearAllPoints()
+    arrow:SetPoint("BOTTOM",self,"TOP",0,0)
+    arrow:Show()
+    arrow:RegisterAutoHide(0)
+    arrow:AddToAutoHide(self)
+  end
+]]
+
+
+-- flyout arrow
+local _arrow_openFlyout = -- function(self)
+[[
+  local slot = self:GetAttribute("bar-idx")
+  local totemID = totemIDsBySlot[slot - (summonSlot or 0)]
+  if totemID == 0 then
+    totemID = "summon"
+  end
+
+  local lastButton, lastPage
+  for page, b in ipairs(flyoutChildren) do
+    b:Hide()
+    b:SetAttribute("totemSlot",totemID)
+    if slot == summonSlot then
+      local spellID = self:GetParent():GetAttribute("spell-page"..page)
+      if spellID then
+        b:SetAttribute("type","changePage")
+        b:SetAttribute("spell",spellID)
+        b:Show()
+        lastButton = b
+        lastPage = page
+      end
+    else
+      local spell = select(page, 0, GetMultiCastTotemSpells(totemID) )
+      if spell then
+        b:SetAttribute("type","multispell")
+        b:SetAttribute("action", baseActionID + (currentPage - 1)*slotsPerPage + totemID)
+        b:SetAttribute("spell", spell)
+        b:Show()
+        lastButton = b
+        lastPage = page
+      end
+    end
+  end
+
+  local close = owner:GetFrameRef("close")
+  if lastButton and close then
+    close:ClearAllPoints()
+    close:SetPoint("BOTTOM",lastButton,"TOP",0,0) -- TODO: better anchoring
+    close:Show()
+    control:CallMethod("UpdateFlyoutTextures",totemID)
+  end
+
+  flyout:ClearAllPoints()
+  flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0)  -- TODO: better anchoring
+  if lastPage then
+    flyout:SetHeight(lastPage * 27 + (close and close:GetHeight() or 0))
+  end
+  flyout:Show()
+  flyout:RegisterAutoHide(1) -- TODO: configurable
+  flyout:AddToAutoHide(owner)
+  flyoutSlot = slot
+  self:Hide()
+]]
+
+local _closeFlyout = -- function(self)
+[[
+  flyout:Hide()
+]]
+
+
+-- flyout child buttons
+local _flyout_child_preClick = -- function(self, button, down)
+[[
+  local button = button
+  if self:GetAttribute("type") == "changePage" then
+    owner:SetAttribute("state-multispellpage",self:GetAttribute("index"))
+    self:GetParent():Hide()
+    return false
+  else
+    return nil, "close"
+  end
+]]
+
+local _flyout_child_postClick = -- function(self, message, button, down)
+[[
+  if message == "close" then
+    self:GetParent():Hide() -- hide flyout after selecting
+  end
+]]
+
+
+--
+-- The Blizzard totem bar textures are all actually one big texture,
+-- with texcoord offsets. Shamelessly stolen from FrameXML/MultiCastActionBarFrame.lua
+--
+local TOTEM_TEXTURE = "Interface\\Buttons\\UI-TotemBar"
+local FLYOUT_UP_BUTTON_HL_TCOORDS   = { 72/128,  92/128, 88/256,  98/256 }
+local FLYOUT_DOWN_BUTTON_HL_TCOORDS = { 72/128,  92/128, 69/256,  79/256 }
+
+local SLOT_EMPTY_TCOORDS = {
+  [EARTH_TOTEM_SLOT] = {  66/128,  96/128,   3/256,  33/256 },
+	[FIRE_TOTEM_SLOT]  = {  67/128,  97/128, 100/256, 130/256 },
+	[WATER_TOTEM_SLOT] = {  39/128,  69/128, 209/256, 239/256 },
+	[AIR_TOTEM_SLOT]   = {  66/128,  96/128,  36/256,  66/256 },
+}
+
+local SLOT_OVERLAY_TCOORDS = {
+	[EARTH_TOTEM_SLOT] = {   1/128,  35/128, 172/256, 206/256 },
+	[FIRE_TOTEM_SLOT]  = {  36/128,  70/128, 172/256, 206/256 },
+	[WATER_TOTEM_SLOT] = {   1/128,  35/128, 207/256, 240/256 },
+	[AIR_TOTEM_SLOT]   = {  36/128,  70/128, 137/256, 171/256 },
+}
+
+local FLYOUT_UP_BUTTON_TCOORDS = {
+	["summon"]         = {  99/128, 127/128,  84/256, 102/256 },
+	[EARTH_TOTEM_SLOT] = {  99/128, 127/128, 160/256, 178/256 },
+	[FIRE_TOTEM_SLOT]  = {  99/128, 127/128, 122/256, 140/256 },
+	[WATER_TOTEM_SLOT] = {  99/128, 127/128, 199/256, 217/256 },
+	[AIR_TOTEM_SLOT]   = {  99/128, 127/128, 237/256, 255/256 },
+}
+
+local FLYOUT_DOWN_BUTTON_TCOORDS = {
+	["summon"]         = {  99/128, 127/128,  65/256,  83/256 },
+	[EARTH_TOTEM_SLOT] = {  99/128, 127/128, 141/256, 159/256 },
+	[FIRE_TOTEM_SLOT]  = {  99/128, 127/128, 103/256, 121/256 },
+	[WATER_TOTEM_SLOT] = {  99/128, 127/128, 180/256, 198/256 },
+	[AIR_TOTEM_SLOT]   = {  99/128, 127/128, 218/256, 236/256 },
+}
+
+local FLYOUT_TOP_TCOORDS = {
+	["summon"]         = {  33/128,  65/128,   1/256,  23/256 },
+	[EARTH_TOTEM_SLOT] = {   0/128,  32/128,  46/256,  68/256 },
+	[FIRE_TOTEM_SLOT]  = {  33/128,  65/128,  46/256,  68/256 },
+	[WATER_TOTEM_SLOT] = {   0/128,  32/128,   1/256,  23/256 },
+	[AIR_TOTEM_SLOT]   = {   0/128,  32/128,  91/256, 113/256 },
+}
+
+local FLYOUT_MIDDLE_TCOORDS = {
+	["summon"]         = {  33/128,  65/128,  23/256,  43/256 },
+	[EARTH_TOTEM_SLOT] = {   0/128,  32/128,  68/256,  88/256 },
+	[FIRE_TOTEM_SLOT]  = {  33/128,  65/128,  68/256,  88/256 },
+	[WATER_TOTEM_SLOT] = {   0/128,  32/128,  23/256,  43/256 },
+	[AIR_TOTEM_SLOT]   = {   0/128,  32/128, 113/256, 133/256 },
+}
+
+local eventList = { 
+  "ACTIONBAR_SLOT_CHANGED",
+  "ACTIONBAR_UPDATE_STATE",
+  "ACTIONBAR_UPDATE_USABLE",
+  "ACTIONBAR_UPDATE_COOLDOWN",
+  "UPDATE_BINDINGS",
+  "UPDATE_MULTI_CAST_ACTIONBAR",
+}
+
+--
+-- MultiCast Button class
+-- Inherits implementation methods from Action button class, but circumvents the constructor
+-- and redefines/removes some methods.
+--
+local buttonTypeID = "Totem"
+local Super = ReAction.Button
+local Action = ReAction.Button.Action
+local MultiCast = setmetatable( 
+  { 
+    defaultBarConfig = { 
+      type = buttonTypeID,
+      btnWidth = 36,
+      btnHeight = 36,
+      btnRows = 1,
+      btnColumns = 6,
+      spacing = 3,
+      buttons = { }
+    },
+
+    barType = L["Totem Bar"], 
+    buttonTypeID = buttonTypeID
+  },
+  { __index = Action } )
+
+ReAction.Button.MultiCast = MultiCast
+ReAction:RegisterBarType(MultiCast)
+
+function MultiCast:New( btnConfig, bar, idx )
+  local maxIndex = bar.nTotemSlots or 0
+  if bar.summonSlot then
+    maxIndex = maxIndex + 1
+  end
+  if bar.recallSlot then
+    maxIndex = maxIndex + 1
+  end
+
+  if not bar.hasMulticast or idx > maxIndex then
+    return false
+  end
+
+  if idx < 1 then
+    error("invalid index")
+  end
+
+  local name = format("ReAction_%s_Totem_%d",bar:GetName(),idx)
+ 
+  self = Super.New(self, name, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+
+  local barFrame = bar:GetFrame()
+  local f = self:GetFrame()
+
+  -- attributes
+  local page = (idx == bar.recallSlot) and 1 or bar:GetConfig().lastSummon or 1
+  if idx == bar.recallSlot or idx == bar.summonSlot then
+    f:SetAttribute("type","spell")
+    local spells = (idx == bar.summonSlot) and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS
+    f:SetAttribute("spell",spells[page])
+    for i, spell in ipairs(spells) do 
+      if spell and IsSpellKnown(spell) then
+        f:SetAttribute("spell-page"..i, spell)
+      end
+    end
+  else
+    local offset = bar.summonSlot and 1 or 0
+    local slot = SHAMAN_TOTEM_PRIORITIES[idx - offset]
+    local baseAction = barFrame:GetAttribute("baseActionID") + slot
+    self.totemSlot = slot
+    f:SetAttribute("type","action")
+    f:SetAttribute("action", baseAction + (page - 1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
+    for i = 1, NUM_MULTI_CAST_PAGES do
+      f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
+    end
+    if not f.overlayTex then
+      local tx = f:CreateTexture("OVERLAY")
+      tx:SetTexture(TOTEM_TEXTURE)
+      tx:SetTexCoord(unpack(SLOT_OVERLAY_TCOORDS[self.totemSlot]))
+      tx:SetWidth(34)
+      tx:SetHeight(34)
+      tx:SetPoint("CENTER")
+      tx:Show()
+      f.overlayTex = tx
+    end
+  end
+  f:SetAttribute("bar-idx",idx)
+
+  -- non secure scripts
+  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+  f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
+  f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
+
+  -- secure handlers
+  if idx ~= bar.recallSlot then
+    f:SetAttribute("_childupdate",_childupdate)
+  end
+  barFrame:WrapScript(f, "OnEnter", _onEnter)
+
+  -- event registration
+  f:EnableMouse(true)
+  f:RegisterForClicks("AnyUp")
+  for _, evt in pairs(eventList) do
+    f:RegisterEvent(evt)
+  end
+
+  -- Set up a proxy for the icon texture for use with ButtonFacade
+  local SetTexCoordRaw = self.frames.icon.SetTexCoord
+  self.frames.icon.SetTexCoord = function( tx, ... )
+    if self:GetIconTexture() == TOTEM_TEXTURE then
+      SetTexCoordRaw(tx,select(2,self:GetIconTexture()))
+    else
+      SetTexCoordRaw(tx,...)
+    end
+  end
+
+  -- attach to skinner
+  bar:SkinButton(self)
+
+  f:Show()
+
+  -- open arrow and flyout background textures
+  if idx ~= bar.recallSlot then
+    local arrow = f._arrowFrame or CreateFrame("Button", nil, f, "SecureFrameTemplate")
+    f._arrowFrame = arrow
+    arrow:SetWidth(28)
+    arrow:SetHeight(18)
+    arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring
+    arrow:SetNormalTexture(TOTEM_TEXTURE)
+    local slot = self.totemSlot or "summon"
+    arrow:GetNormalTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_TCOORDS[slot]) )
+    arrow:SetHighlightTexture(TOTEM_TEXTURE)
+    arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) )
+    arrow:SetAttribute("bar-idx",idx)
+    arrow:Hide()
+    barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout)
+    barFrame:SetFrameRef("arrow-"..idx,arrow)
+  end
+
+  self:Refresh()
+
+  return self
+end
+
+function MultiCast:Destroy()
+  local barFrame = self.bar:GetFrame()
+  local f = self:GetFrame()
+  pcall( barFrame.UnwrapScript, barFrame, f, "OnEnter" ) -- ignore errors
+  if f._arrowFrame then
+    pcall( barFrame.UnwrapScript, barFrame, f._arrowFrame,"OnClick" ) -- ignore errors
+  end
+  Super.Destroy(self)
+end
+
+function MultiCast:Refresh()
+  Super.Refresh(self)
+  self:UpdateAction()
+end
+
+function MultiCast:ShowGrid( show )
+end
+
+function MultiCast:ShowGridTemp( show )
+end
+
+function MultiCast:AcquireActionID()
+end
+
+function MultiCast:ReleaseActionID()
+end
+
+function MultiCast:UpdateShowGrid()
+end
+
+function MultiCast:UpdateBorder()
+end
+
+function MultiCast:UpdateMacroText()
+end
+
+function MultiCast:UpdateCount()
+end
+
+function MultiCast:UpdateCheckedState()
+  local action = self:GetActionID()
+  if action and IsCurrentAction(action) then
+    self:GetFrame():SetChecked(1)
+  else
+    self:GetFrame():SetChecked(0)
+  end
+end
+
+function MultiCast:RefreshHasActionAttributes()
+end
+
+function MultiCast:UpdateFlash()
+end
+
+function MultiCast:GetIconTexture()
+  local tx
+  if self.spellID then
+    tx = GetSpellTexture(GetSpellInfo(self.spellID))
+  elseif self.actionID then
+    tx = GetActionTexture(self.actionID)
+  end
+  if tx then
+    return tx
+  else
+    return TOTEM_TEXTURE, unpack(SLOT_EMPTY_TCOORDS[self.totemSlot or 1])
+  end
+end
+
+function MultiCast:UpdateAction()
+  local action = self:GetActionID()
+  if action then
+    if action ~= self.actionID then
+      self.actionID = action
+      self:UpdateAll()
+    end
+  else
+    local spellID = self:GetSpellID()
+    if spellID ~= self.spellID then
+      self.spellID = spellID
+      self:UpdateAll()
+    end
+  end
+end
+
+function MultiCast:GetActionID(page)
+  return self:GetFrame():GetAttribute("action")
+end
+
+function MultiCast:GetSpellID(page)
+  return self:GetFrame():GetAttribute("spell")
+end
+
+function MultiCast:SetActionID( id  )
+  error("Can not set action ID of multicast buttons")
+end
+
+function MultiCast:SetTooltip()
+  local barFrame = self:GetFrame()
+  if GetCVar("UberTooltips") == "1" then
+    GameTooltip_SetDefaultAnchor(GameTooltip, barFrame)
+  else
+    GameTooltip:SetOwner(barFrame)
+  end
+  if self.spellID then
+    GameTooltip:SetSpellByID(self.spellID,false,true)
+  elseif self.actionID then
+    GameTooltip:SetAction(self.actionID)
+  end
+end
+
+function MultiCast:GetUsable()
+  if self.spellID then
+    return IsUsableSpell((GetSpellInfo(self.spellID)))
+  elseif self.actionID then
+    return IsUsableAction(self.actionID)
+  end
+end
+
+function MultiCast:GetInRange()
+  if self.spellID then
+    return IsSpellInRange((GetSpellInfo(self.spellID))) == 0
+  elseif self.actionID then
+    return IsActionInRange(self.actionID) == 0
+  end
+end
+
+function MultiCast:GetCooldown()
+  if self.spellID then
+    return GetSpellCooldown((GetSpellInfo(self.spellID)))
+  elseif self.actionID then
+    return GetActionCooldown(self.actionID)
+  else
+    return 0, 0, 0
+  end
+end
+
+function MultiCast:UPDATE_MULTI_CAST_ACTIONBAR()
+  self:UpdateAll()
+end
+
+
+--
+-- flyout setup
+--
+local function ShowFlyoutTooltip(frame)
+  if GetCVar("UberTooltips") == "1" then
+    GameTooltip_SetDefaultAnchor(GameTooltip, frame)
+  else
+    GameTooltip:SetOwner(frame)
+  end
+  local spell = frame:GetAttribute("spell")
+  if spell == nil or spell == 0 then
+    GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
+  else
+    GameTooltip:SetSpellByID(spell,false,true)
+  end
+end
+
+local function HideFlyoutTooltip()
+  GameTooltip:Hide()
+end
+
+local function UpdateFlyoutIcon(frame)
+  local spellID = frame:GetAttribute("spell")
+  if spellID == 0 or spellID == nil then
+    frame.icon:SetTexture(TOTEM_TEXTURE)
+    local slot = tonumber(frame:GetAttribute("totemSlot")) or 1
+    frame.icon:SetTexCoord( unpack(SLOT_EMPTY_TCOORDS[slot]) )
+  else
+    frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID)))
+    frame.icon:SetTexCoord(0,1,0,1)
+  end
+end
+
+function MultiCast:SetupBar( bar )
+  Super.SetupBar(self,bar)
+
+  local slot = 0
+  local nTotemSlots = 0
+  local summonSlot = nil
+  local recallSlot = nil
+
+  -- figure out the capabilities of the character
+	for i, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do 
+    if spell and IsSpellKnown(spell) then
+      slot = 1
+      summonSlot = 1
+    end
+	end
+
+  for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do
+		local totem = SHAMAN_TOTEM_PRIORITIES[i];
+		if GetTotemInfo(totem) and GetMultiCastTotemSpells(totem) then
+      nTotemSlots = nTotemSlots + 1
+      slot = slot + 1
+    end
+  end
+
+  slot = slot + 1
+	for i, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do 
+    if spell and IsSpellKnown(spell) then
+      recallSlot = slot
+    end
+	end
+
+  if nTotemSlots == 0 then
+    bar.hasMulticast = false -- no multicast capability
+    return
+  end
+
+  bar.hasMulticast = true
+  bar.summonSlot   = summonSlot
+  bar.recallSlot   = recallSlot
+  bar.nTotemSlots  = nTotemSlots
+
+
+  local f = bar:GetFrame()
+
+  -- init bar secure environment
+  f:SetAttribute("lastSummon", bar:GetConfig().lastSummon)
+  f:SetAttribute("summonSlot", summonSlot)
+  f:SetAttribute("recallSlot", recallSlot)
+  f:SetAttribute("slotsPerPage", NUM_MULTI_CAST_BUTTONS_PER_PAGE)
+  f:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS)
+  for i, p in ipairs(SHAMAN_TOTEM_PRIORITIES) do
+    f:SetAttribute("TOTEM_PRIORITY_"..i,p)
+  end
+  f:SetAttribute("_onstate-multispellpage", _onstate_multispellpage)
+
+  function f:UpdateLastSummon(value)
+    bar:GetConfig().lastSummon = value
+  end
+
+  -- create flyout container frame and close arrow
+  local flyout = bar._flyoutFrame
+  if not flyout then
+    flyout = CreateFrame("Frame", nil, f, "SecureFrameTemplate")
+    bar._flyoutFrame = flyout
+    f:SetFrameRef("flyout",flyout)
+    flyout.buttons = { }
+    flyout:Hide()
+    flyout:SetWidth(24)
+    flyout:SetHeight(1)
+    flyout:SetPoint("BOTTOM",f,"TOP",0,0)
+
+    local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate")
+    close:SetWidth(28)
+    close:SetHeight(18)
+    close:SetPoint("BOTTOM",flyout,"TOP")
+    close:SetNormalTexture(TOTEM_TEXTURE)
+    close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS["summon"]))
+    close:SetHighlightTexture(TOTEM_TEXTURE)
+    close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) )
+    f:SetFrameRef("close",close)
+    f:WrapScript(close, "OnClick", _closeFlyout)
+    close:Show()
+
+    local midTx = flyout:CreateTexture("BACKGROUND")
+    midTx:SetWidth(32)
+    midTx:SetHeight(20)
+    midTx:SetPoint("BOTTOM")
+    midTx:SetTexture(TOTEM_TEXTURE)
+    midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS["summon"]))
+    midTx:Show()
+
+    local topTx = flyout:CreateTexture("BACKGROUND")
+    topTx:SetWidth(32)
+    topTx:SetHeight(20)
+    topTx:SetTexture(TOTEM_TEXTURE)
+    midTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS["summon"]))
+    topTx:SetPoint("BOTTOM",midTx,"TOP",0,-10)
+    topTx:Show()
+
+    function flyout:UpdateTextures(slot)
+      slot = slot or "summon"
+      close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS[slot]))
+      midTx:ClearAllPoints()
+      midTx:SetPoint("BOTTOM")
+      midTx:SetPoint("TOP",close,"BOTTOM",0,0)
+      midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS[slot]))
+      topTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS[slot]))
+    end
+
+    -- create flyout buttons
+    for i = 1, 10 do -- maximum 9 spells + 1 empty slot
+      local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate")
+      b:SetWidth(24)
+      b:SetHeight(24)
+      local prev = flyout.buttons[i-1]
+      b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring
+      b.icon = b:CreateTexture("BACKGROUND")
+      b.icon:SetAllPoints()
+      b.icon:Show()
+      b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
+      b:GetHighlightTexture():SetBlendMode("ADD")
+      b:RegisterForClicks("AnyUp")
+      b:SetScript("OnShow",UpdateFlyoutIcon)
+      b:SetScript("OnEnter",ShowFlyoutTooltip)
+      b:SetScript("OnLeave",HideFlyoutTooltip)
+      b:SetAttribute("index",i)
+      f:SetAttribute("flyout-child-idx",i)
+      f:SetFrameRef("flyout-child",b)
+      f:Execute([[
+          flyoutChildren = flyoutChildren or newtable()
+          flyoutChildren[self:GetAttribute("flyout-child-idx")] = self:GetFrameRef("flyout-child")
+        ]])
+      f:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick)
+      b:Show()
+      flyout.buttons[i] = b
+    end
+  end
+
+  -- scale flyout frame
+  local scale = bar:GetButtonSize() / 36
+  flyout:SetScale(scale)
+
+  function f:UpdateFlyoutTextures(slot)
+    flyout:UpdateTextures(slot)
+  end
+
+  -- re-execute setup when new spells are loaded
+  if not f.events_registered then
+    f:RegisterEvent("UPDATE_MULTI_CAST_ACTIONBAR")
+    f:RegisterEvent("PLAYER_ENTERING_WORLD")
+      -- Bar.frame does not use OnEvent
+    f:SetScript("OnEvent", 
+      function()
+        if not InCombatLockdown() then
+          self:SetupBar(bar)
+        end
+      end)
+    f.events_registered = true
+  end
+
+
+  f:Execute(_bar_init)
+end
+
--- a/Options.lua	Thu Nov 18 13:11:08 2010 -0800
+++ b/Options.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -40,10 +40,9 @@
             type     = "toggle",
             name     = L["Hide Blizzard Action Bars"],
             desc     = L["Hide the default main bar and extra action bars"],
-            handler  = self:GetModule("HideBlizzard"),
-            get      = "IsHidden",
-            set      = "SetHidden",
-            disabled = "OptionDisabled",
+            get      = "OptionGetHideBlizzardBars",
+            set      = "OptionSetHideBlizzardBars",
+            disabled = InCombatLockdown,
             width    = "full",
             order    = 3,
           },
@@ -51,10 +50,9 @@
             type     = "toggle",
             name     = L["Hide Blizzard Vehicle Bar"],
             desc     = L["Hide the default vechicle action bar"],
-            handler  = self:GetModule("HideBlizzard"),
-            get      = "IsHidden",
-            set      = "SetHidden",
-            disabled = "OptionDisabled",
+            get      = "OptionGetHideBlizzardVehicleBar",
+            set      = "OptionSetHideBlizzardVehicleBar",
+            disabled = function() return InCombatLockdown() or ReAction:OptionGetHideBlizzardBars() == false end,
             width    = "full",
             order    = 4,
           },
@@ -101,10 +99,6 @@
 
   AceConfigDialog:AddToBlizOptions(configID, options.args.profiles.name, configID, "profiles")
 
-  self.db.RegisterCallback(self,"OnProfileChanged")
-  self.db.RegisterCallback(self,"OnProfileReset", "OnProfileChanged")
-  self.db.RegisterCallback(self,"OnProfileCopied","OnProfileChanged")
-
   SlashCmdList["REACTION"] = function(option)
     option = string.match(option or "", "^%s*(%S+)")
     if option == "config" or option == "options" then
@@ -139,6 +133,14 @@
     showAlert = true,
     whileDead = true,
   }
+
+  -- reroute blizzard action bar config to ReAction config window
+  InterfaceOptionsActionBarsPanel:HookScript("OnShow", 
+    function() 
+      if ReAction:OptionGetHideBlizzardBars() then
+        ReAction:ShowOptions()
+      end
+    end )
 end
 
 
@@ -147,14 +149,6 @@
 end
 
 
-function ReAction:OnProfileChanged()
-  self:RebuildAll()
-  if not self.db.global.skipKeybindWarning then
-    StaticPopup_Show("REACTION_KB_WARN")
-  end
-end
-
-
 function ReAction:OptionSetConfigMode(info, value)
   self:SetConfigMode(value) 
 end
@@ -181,6 +175,25 @@
 end
 
 
+function ReAction:OptionSetHideBlizzardBars( info, hide )
+  self.db.profile.options.hideBlizzardBars = hide
+  self:ManageBlizzardBars()
+end
+
+function ReAction:OptionGetHideBlizzardBars()
+  return self.db.profile.options.hideBlizzardBars
+end
+
+function ReAction:OptionSetHideBlizzardVehicleBar( info, hide )
+  self.db.profile.options.hideBlizzardVehicleBar = hide
+  self:ManageBlizzardBars()
+end
+
+function ReAction:OptionGetHideBlizzardVehicleBar()
+  return self.db.profile.options.hideBlizzardVehicleBar
+end
+
+
 -- export to LDB
 local LDB = LibStub:GetLibrary("LibDataBroker-1.1")
 if LDB then
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Overlay.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,754 @@
+local addonName, addonTable = ...
+local ReAction               = addonTable.ReAction
+local L                      = ReAction.L
+local LKB                    = ReAction.LKB
+local CreateFrame            = CreateFrame
+local InCombatLockdown       = InCombatLockdown
+local floor                  = math.floor
+local min                    = math.min
+local format                 = string.format
+local GameTooltip            = GameTooltip
+local Bar                    = ReAction.Bar
+local GetSize                = Bar.GetSize
+local SetSize                = Bar.SetSize
+local GetButtonSize          = Bar.GetButtonSize
+local GetButtonGrid          = Bar.GetButtonGrid
+local SetButtonSize          = Bar.SetButtonSize
+local SetButtonGrid          = Bar.SetButtonGrid
+local ApplyAnchor            = Bar.ApplyAnchor
+local GameTooltipTextRight1  = GameTooltipTextRight1
+local GameTooltipTextRight2  = GameTooltipTextRight2
+local GameTooltipTextRight3  = GameTooltipTextRight3
+
+--
+-- Wrap some of the bar manipulators to make them state-aware
+--
+local function SetAnchor( bar, point, frame, relPoint, x, y )
+  local state = bar:GetSecureState()
+  if state then
+    local anchorstate = bar:GetStateProperty(state, "anchorEnable")
+    if anchorstate then
+      bar:SetStateProperty(state, "anchorFrame", frame)
+      bar:SetStateProperty(state, "anchorPoint", point)
+      bar:SetStateProperty(state, "anchorRelPoint", relPoint)
+      bar:SetStateProperty(state, "anchorX", x or 0)
+      bar:SetStateProperty(state, "anchorY", y or 0)
+      bar:SetAnchor(bar:GetAnchor())
+      return
+    end
+  end
+  bar:SetAnchor(point, frame, relPoint, x, y)
+end
+
+local function GetStateScale( bar )
+  local state = bar:GetSecureState()
+  if state and bar:GetStateProperty(state, "enableScale") then
+    return bar:GetStateProperty(state, "scale")
+  end
+end
+
+local function SetStateScale( bar, scale )
+  local state = bar:GetSecureState()
+  if state and bar:GetStateProperty(state, "enableScale") then
+    bar:SetStateProperty(state, "scale", scale)
+  end
+end
+
+
+--
+-- Bar config overlay
+--
+
+local function GetNormalTextColor()
+  return 1.0, 1.0, 1.0, 1.0
+end
+
+local function GetAnchoredTextColor()
+  return 1.0, 1.0, 1.0, 1.0
+end
+
+local function GetNormalBgColor()
+  return 0.7, 0.7, 1.0, 0.3
+end
+
+local function GetAnchoredBgColor()
+  return 0.9, 0.2, 0.7, 0.3
+end
+
+local function StoreSize(bar)
+  local f = bar:GetFrame()
+  SetSize( bar, f:GetWidth(), f:GetHeight() )
+end
+
+local function StoreExtents(bar)
+  local f = bar:GetFrame()
+  local p, fr, rp, x, y = f:GetPoint(1)
+  fr = fr and fr:GetName() or "UIParent"
+  SetAnchor( bar, p, fr, rp, x, y )
+  SetSize( bar, f:GetWidth(), f:GetHeight() )
+end
+
+local function RecomputeButtonSize(bar)
+  local w, h = GetSize(bar)
+  local bw, bh = GetButtonSize(bar)
+  local r, c, s = GetButtonGrid(bar)
+
+  local scaleW = (floor(w/c) - s) / bw
+  local scaleH = (floor(h/r) - s) / bh
+  local scale = min(scaleW, scaleH)
+
+  SetButtonSize(bar, scale * bw, scale * bh, s)
+end
+
+local function ComputeBarScale(bar, overlay)
+  local w, h = overlay:GetWidth() - 8, overlay:GetHeight() - 8
+  local bw, bh = GetButtonSize(bar)
+  local r, c, s = GetButtonGrid(bar)
+
+  local scaleW = w / (c*(bw+s))
+  local scaleH = h / (r*(bh+s))
+  local scale = min(scaleW, scaleH)
+
+  if scale > 2.5 then
+    scale = 2.5
+  elseif scale < 0.25 then
+    scale = 0.25
+  end
+
+  return scale
+end
+
+local function RecomputeButtonSpacing(bar)
+  local w, h = GetSize(bar)
+  local bw, bh = GetButtonSize(bar)
+  local r, c, s = GetButtonGrid(bar)
+
+  SetButtonGrid(bar,r,c,min(floor(w/c) - bw, floor(h/r) - bh))
+end
+
+local function RecomputeGrid(bar)
+  local w, h = GetSize(bar)
+  local bw, bh = GetButtonSize(bar)
+  local r, c, s = GetButtonGrid(bar)
+
+  SetButtonGrid(bar, floor(h/(bh+s)), floor(w/(bw+s)), s)
+end
+
+local function ClampToButtons(bar)
+  local bw, bh = GetButtonSize(bar)
+  local r, c, s = GetButtonGrid(bar)
+  SetSize(bar, (bw+s)*c + 1, (bh+s)*r + 1)
+end
+
+local function HideGameTooltip()
+  GameTooltip:Hide()
+end
+
+local anchorInside  = { inside = true }
+local anchorOutside = { outside = true }
+local edges = { "BOTTOM", "TOP", "LEFT", "RIGHT" }
+local oppositeEdges = {
+  TOP = "BOTTOM",
+  BOTTOM = "TOP",
+  LEFT = "RIGHT",
+  RIGHT = "LEFT"
+}
+local pointsOnEdge = {
+  BOTTOM = { "BOTTOM", "BOTTOMLEFT",  "BOTTOMRIGHT",  },
+  TOP    = { "TOP",    "TOPLEFT",     "TOPRIGHT",     },
+  RIGHT  = { "RIGHT",  "BOTTOMRIGHT", "TOPRIGHT",     },
+  LEFT   = { "LEFT",   "BOTTOMLEFT",  "TOPLEFT",      },
+}
+local edgeSelector = {
+  BOTTOM = 1,  -- select x of x,y
+  TOP    = 1,  -- select x of x,y
+  LEFT   = 2,  -- select y of x,y
+  RIGHT  = 2,  -- select y of x,y  
+}
+local snapPoints = {
+  [anchorOutside] = {
+    BOTTOMLEFT  = {"BOTTOMRIGHT","TOPLEFT","TOPRIGHT"},
+    BOTTOM      = {"TOP"},
+    BOTTOMRIGHT = {"BOTTOMLEFT","TOPRIGHT","TOPLEFT"},
+    RIGHT       = {"LEFT"},
+    TOPRIGHT    = {"TOPLEFT","BOTTOMRIGHT","BOTTOMLEFT"},
+    TOP         = {"BOTTOM"},
+    TOPLEFT     = {"TOPRIGHT","BOTTOMLEFT","BOTTOMRIGHT"},
+    LEFT        = {"RIGHT"},
+    CENTER      = {"CENTER"}
+  },
+  [anchorInside] = {
+    BOTTOMLEFT  = {"BOTTOMLEFT"},
+    BOTTOM      = {"BOTTOM"},
+    BOTTOMRIGHT = {"BOTTOMRIGHT"},
+    RIGHT       = {"RIGHT"},
+    TOPRIGHT    = {"TOPRIGHT"},
+    TOP         = {"TOP"},
+    TOPLEFT     = {"TOPLEFT"},
+    LEFT        = {"LEFT"},
+    CENTER      = {"CENTER"}
+  }
+}
+local insidePointOffsetFuncs = {
+  BOTTOMLEFT  = function(x, y) return x, y end,
+  BOTTOM      = function(x, y) return 0, y end,
+  BOTTOMRIGHT = function(x, y) return -x, y end,
+  RIGHT       = function(x, y) return -x, 0 end,
+  TOPRIGHT    = function(x, y) return -x, -y end,
+  TOP         = function(x, y) return 0, -y end,
+  TOPLEFT     = function(x, y) return x, -y end,
+  LEFT        = function(x, y) return x, 0 end,
+  CENTER      = function(x, y) return x, y end,
+}
+local pointCoordFuncs = {
+  BOTTOMLEFT  = function(f) return f:GetLeft(),  f:GetBottom() end,
+  BOTTOM      = function(f) return nil,          f:GetBottom() end,
+  BOTTOMRIGHT = function(f) return f:GetRight(), f:GetBottom() end,
+  RIGHT       = function(f) return f:GetRight(), nil end,
+  TOPRIGHT    = function(f) return f:GetRight(), f:GetTop() end,
+  TOP         = function(f) return nil,          f:GetTop() end,
+  TOPLEFT     = function(f) return f:GetLeft(),  f:GetTop() end,
+  LEFT        = function(f) return f:GetLeft(),  nil end,
+  CENTER      = function(f) return f:GetCenter() end,
+}
+local edgeBoundsFuncs = {
+  BOTTOM = function(f) return f:GetLeft(), f:GetRight() end,
+  LEFT   = function(f) return f:GetBottom(), f:GetTop() end
+}
+edgeBoundsFuncs.TOP   = edgeBoundsFuncs.BOTTOM
+edgeBoundsFuncs.RIGHT = edgeBoundsFuncs.LEFT
+local cornerTexCoords = {
+              -- ULx, ULy, LLx, LLy, URx, URy, LRx, LRy
+  TOPLEFT     = { 1,   1,   1,   0,   0,   1,   0,   0 },
+  TOPRIGHT    = { 1,   0,   0,   0,   1,   1,   0,   1 },
+  BOTTOMLEFT  = { 0,   1,   1,   1,   0,   0,   1,   0 },
+  BOTTOMRIGHT = { 0,   0,   0,   1,   1,   0,   1,   1 },
+}
+
+-- Returns absolute coordinates x,y of the named point 'p' of frame 'f'
+local function GetPointCoords( f, p )
+  local x, y = pointCoordFuncs[p](f)
+  if not(x and y) then
+    local cx, cy = f:GetCenter()
+    x = x or cx
+    y = y or cy
+  end
+  return x, y
+end
+
+
+-- Returns true if frame 'f1' can be anchored to frame 'f2'
+local function CheckAnchorable( f1, f2 )
+  -- can't anchor a frame to itself or to nil
+  if f1 == f2 or f2 == nil then
+    return false
+  end
+  
+  -- can always anchor to UIParent
+  if f2 == UIParent then
+    return true
+  end
+  
+  -- also can't do circular anchoring of frames 
+  -- walk the anchor chain, which generally shouldn't be that expensive
+  -- (who nests draggables that deep anyway?)
+  for i = 1, f2:GetNumPoints() do
+    local _, f = f2:GetPoint(i)
+    if not f then f = f2:GetParent() end
+    return CheckAnchorable(f1,f)
+  end
+  
+  return true
+end
+
+-- Returns true if frames f1 and f2 specified edges overlap
+local function CheckEdgeOverlap( f1, f2, e )
+  local l1, u1 = edgeBoundsFuncs[e](f1)
+  local l2, u2 = edgeBoundsFuncs[e](f2)
+  return l1 <= l2 and l2 <= u1 or l2 <= l1 and l1 <= u2
+end
+
+-- Returns true if point p1 on frame f1 overlaps edge e2 on frame f2
+local function CheckPointEdgeOverlap( f1, p1, f2, e2 )
+  local l, u = edgeBoundsFuncs[e2](f2)
+  local x, y = GetPointCoords(f1,p1)
+  x = select(edgeSelector[e2], x, y)
+  return l <= x and x <= u
+end
+
+-- Returns the distance between corresponding edges. It is 
+-- assumed that the passed in edges e1 and e2 are the same or opposites
+local function GetEdgeDistance( f1, f2, e1, e2 )
+  local x1, y1 = pointCoordFuncs[e1](f1)
+  local x2, y2 = pointCoordFuncs[e2](f2)
+  return math.abs((x1 or y1) - (x2 or y2))
+end
+
+local globalSnapTargets = { [UIParent] = anchorInside }
+
+local function GetClosestFrameEdge(f1,f2,a)
+  local dist, edge, opp
+  if f2:IsVisible() and CheckAnchorable(f1,f2) then
+    for _, e in pairs(edges) do
+      local o = a.inside and e or oppositeEdges[e]
+      if CheckEdgeOverlap(f1,f2,e) then
+        local d = GetEdgeDistance(f1, f2, e, o)
+        if not dist or (d < dist) then
+          dist, edge, opp = d, e, o
+        end
+      end
+    end
+  end
+  return dist, edge, opp
+end
+
+local function GetClosestVisibleEdge( f )
+  local r, o, e1, e2
+  local a = anchorOutside
+  for _, b in ReAction:IterateBars() do
+    local d, e, opp = GetClosestFrameEdge(f,b:GetFrame(),a)
+    if d and (not r or d < r) then
+      r, o, e1, e2 = d, b:GetFrame(), e, opp
+    end
+  end
+  for f2, a2 in pairs(globalSnapTargets) do
+    local d, e, opp = GetClosestFrameEdge(f,f2,a2)
+    if d and (not r or d < r) then
+      r, o, e1, e2, a = d, f2, e, opp, a2
+    end
+  end
+  return o, e1, e2, a
+end
+
+local function GetClosestVisiblePoint(f1)
+  local f2, e1, e2, a = GetClosestVisibleEdge(f1)
+  if f2 then
+    local rsq, p, rp, x, y
+    -- iterate pointsOnEdge in order and use < to prefer edge centers to corners
+    for _, p1 in ipairs(pointsOnEdge[e1]) do
+      if CheckPointEdgeOverlap(f1,p1,f2,e2) then
+        for _, p2 in pairs(snapPoints[a][p1]) do
+          local x1, y1 = GetPointCoords(f1,p1)
+          local x2, y2 = GetPointCoords(f2,p2)
+          local dx = x1 - x2
+          local dy = y1 - y2
+          local rsq2 = dx*dx + dy*dy
+          if not rsq or rsq2 < rsq then
+            rsq, p, rp, x, y = rsq2, p1, p2, dx, dy
+          end
+        end
+      end
+    end
+    return f2, p, rp, x, y
+  end
+end
+
+local function GetClosestPointSnapped(f1, rx, ry, xOff, yOff)
+  local o, p, rp, x, y = GetClosestVisiblePoint(f1)
+  local s = false
+
+  local insideOffsetFunc = p and insidePointOffsetFuncs[p]
+  local coordFunc = p and pointCoordFuncs[p]
+  if not insideOffsetFunc or not coordFunc then
+    return
+  end
+  
+  local sx, sy = insideOffsetFunc(xOff or 0, yOff or 0)
+  local xx, yy = coordFunc(f1)
+  if xx and yy then
+    if math.abs(x) <= rx then
+      if math.abs(y) <= ry then
+        x = sx
+        y = sy
+        s = true
+      elseif CheckEdgeOverlap(f1,o,"LEFT") then
+        x = sx
+        s = true
+      end
+    elseif math.abs(y) <= ry and CheckEdgeOverlap(f1,o,"TOP") then
+      y = sy
+      s = true
+    end
+  elseif xx then
+    if math.abs(x) <= rx then
+      x = sx
+      s = true
+      if math.abs(y) <= ry then
+        y = sy
+      end
+    end
+  elseif yy then
+    if math.abs(y) <= ry then
+      y = sy
+      s = true
+      if math.abs(x) <= rx then
+        x = sx
+      end
+    end
+  end
+
+  -- correct for some Lua oddities with doubles
+  if x == -0 then x = 0 end
+  if y == -0 then y = 0 end
+  
+  if s then
+    return o, p, rp, math.floor(x), math.floor(y)
+  end
+end
+
+local function CreateSnapIndicator()
+  local si = CreateFrame("Frame",nil,UIParent)
+  si:SetFrameStrata("HIGH")
+  si:SetHeight(16)
+  si:SetWidth(16)
+  local tex = si:CreateTexture()
+  tex:SetAllPoints()
+  tex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock")
+  tex:SetBlendMode("ADD")
+  tex:SetDrawLayer("OVERLAY")
+  return si
+end
+
+local si1 = CreateSnapIndicator()
+local si2 = CreateSnapIndicator()
+
+local function DisplaySnapIndicator( f, rx, ry, xOff, yOff )
+  local o, p, rp, x, y, snap = GetClosestPointSnapped(f, rx, ry, xOff, yOff)
+  if o then
+    si1:ClearAllPoints()
+    si2:ClearAllPoints()
+    si1:SetPoint("CENTER", f, p, 0, 0)
+    local xx, yy = pointCoordFuncs[rp](o)
+    x = math.abs(x) <=rx and xx and 0 or x
+    y = math.abs(y) <=ry and yy and 0 or y
+    si2:SetPoint("CENTER", o, rp, x, y)
+    si1:Show()
+    si2:Show()
+  else
+    if si1:IsVisible() then
+      si1:Hide()
+      si2:Hide()
+    end
+  end
+  return o, p
+end
+
+local function HideSnapIndicator()
+  if si1:IsVisible() then
+    si1:Hide()
+    si2:Hide()
+  end
+end
+
+local function UpdateLabelString(overlay)
+  local label = overlay.labelString
+  if label then
+    local name = overlay.labelName
+    if name and overlay.labelSubtext then
+      name = format("%s (%s)", name, overlay.labelSubtext)
+    end
+    label:SetText(name or "")
+  end
+end
+
+local function CreateControls(bar)
+  local f = bar:GetFrame()
+
+  f:SetMovable(true)
+  f:SetResizable(true)
+
+  -- child of UIParent so that alpha and scale doesn't propagate to it
+  local overlay = CreateFrame("Button", nil, UIParent)
+  overlay:EnableMouse(true)
+  overlay:SetFrameLevel(10) -- set it above the buttons
+  overlay:SetPoint("TOPLEFT", f, "TOPLEFT", -4, 4)
+  overlay:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 4, -4)
+  overlay:SetBackdrop({
+    edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+    tile = true,
+    tileSize = 16,
+    edgeSize = 16,
+    insets = { left = 0, right = 0, top = 0, bottom = 0 },
+  })
+
+  -- textures
+  local bgTex = overlay:CreateTexture(nil,"BACKGROUND")
+  bgTex:SetTexture(0.7,0.7,1.0,0.2)
+  bgTex:SetPoint("TOPLEFT",4,-4)
+  bgTex:SetPoint("BOTTOMRIGHT",-4,4)
+  local hTex = overlay:CreateTexture(nil,"HIGHLIGHT")
+  hTex:SetTexture(0.7,0.7,1.0,0.2)
+  hTex:SetPoint("TOPLEFT",4,-4)
+  hTex:SetPoint("BOTTOMRIGHT",-4,4)
+  hTex:SetBlendMode("ADD")
+  local aTex = overlay:CreateTexture(nil,"ARTWORK")
+  aTex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock")
+  aTex:SetWidth(16)
+  aTex:SetHeight(16)
+  aTex:Hide()
+
+  -- label
+  local label = overlay:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
+  label:SetAllPoints()
+  label:SetJustifyH("CENTER")
+  label:SetShadowColor(0,0,0,1)
+  label:SetShadowOffset(3,-3)
+  label:SetTextColor(GetNormalTextColor())
+  label:SetText(bar:GetName())
+  label:Show()
+  overlay.labelString = label
+  overlay.labelName = bar:GetName()
+
+  local function UpdateAnchorDecoration()
+    local point, anchor, relPoint, x, y = f:GetPoint(1)
+    if point then
+      local ofsx, ofsy = insidePointOffsetFuncs[point](x,y)
+      if (anchor and anchor ~= UIParent) or (ofsx == 0 and ofsy == 0) then
+        bgTex:SetTexture( GetAnchoredBgColor() )
+        hTex:SetTexture( GetAnchoredBgColor() )
+        label:SetTextColor( GetAnchoredTextColor() )
+        aTex:ClearAllPoints()
+        aTex:SetPoint(point)
+        aTex:Show()
+        return
+      end
+    end
+    bgTex:SetTexture( GetNormalBgColor() )
+    hTex:SetTexture( GetNormalBgColor() )
+    label:SetTextColor( GetNormalTextColor() )
+    aTex:Hide()
+  end
+
+  local function StopResize()
+    f:StopMovingOrSizing()
+    f.isMoving = false
+    f:SetScript("OnUpdate",nil)
+    StoreSize(bar)
+    ClampToButtons(bar)
+    ReAction:RefreshEditor()
+  end
+
+  local function CornerUpdate()
+    local bw, bh = GetButtonSize(bar)
+    local r, c, s = GetButtonGrid(bar)
+    local ss = GetStateScale(bar)
+    if IsShiftKeyDown() then
+      if ss then
+        f:SetMinResize( ((s+bw)*c*0.25)/ss, ((s+bh)*r*0.25)/ss )
+        f:SetMaxResize( ((s+bw)*c*2.5 + 1)/ss, ((s+bh)*r*2.5 + 1)/ss )
+        scale = ComputeBarScale(bar, overlay)
+      else
+        f:SetMinResize( (s+12)*c+1, (s+12)*r+1 )
+        f:SetMaxResize( (s+128)*c+1, (s+128)*r+1 )
+        RecomputeButtonSize(bar)
+      end
+    elseif not ss and IsAltKeyDown() then
+      f:SetMinResize( bw*c, bh*r )
+      f:SetMaxResize( 2*bw*c, 2*bh*r )
+      RecomputeButtonSpacing(bar)
+    else
+      f:SetMinResize( bw+s+1, bh+s+1 )
+      f:SetMaxResize( 50*(bw+s)+1, 50*(bh+s)+1 )
+      RecomputeGrid(bar)
+    end
+    GameTooltipTextRight2:SetText(format("%d x %d",r,c))
+
+    local ss = GetStateScale(bar)
+    if ss then
+      GameTooltipTextRight4:SetText(format("%d%%", scale*100))
+    else
+      local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh)
+      GameTooltipTextRight3:SetText(size)
+      GameTooltipTextRight4:SetText(tostring(s))
+    end
+  end
+
+  -- corner drag handles
+  for _, point in pairs({"BOTTOMLEFT","TOPLEFT","BOTTOMRIGHT","TOPRIGHT"}) do
+    local corner = CreateFrame("Frame",nil,overlay)
+    corner:EnableMouse(true)
+    corner:SetWidth(16)
+    corner:SetHeight(16)
+    corner:SetPoint(point)
+
+    local tex = corner:CreateTexture(nil,"HIGHLIGHT")
+    tex:SetTexture("Interface\\AddOns\\ReAction\\img\\corner")
+    tex:SetTexCoord(unpack(cornerTexCoords[point]))
+    tex:SetBlendMode("ADD")
+    tex:SetAlpha(0.6)
+    tex:SetAllPoints()
+    
+    corner:SetScript("OnMouseDown",
+      function(_,btn)
+        f:SetScript("OnUpdate", CornerUpdate)
+        f:StartSizing(point)
+      end
+    )
+    corner:SetScript("OnMouseUp",
+      function()
+        local ss = GetStateScale(bar)
+        if ss then
+          SetStateScale(bar, ComputeBarScale(bar, overlay))
+        end
+        StopResize()
+      end)
+    corner:SetScript("OnEnter",
+      function()
+        local bw, bh = GetButtonSize(bar)
+        local r, c, s = bar:GetButtonGrid()
+        local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh)
+        local ss = GetStateScale(bar)
+        local state = bar:GetSecureState()
+        GameTooltip:SetOwner(f, "ANCHOR_"..point)
+        if ss then
+          GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
+        else
+          GameTooltip:AddLine(bar:GetName())
+        end
+        GameTooltip:AddDoubleLine(format("|cffcccccc%s|r %s",L["Drag"],L["to add/remove buttons:"]), format("%d x %d",r,c))
+        if ss then
+          GameTooltip:AddLine(L["State Scale Override"])
+          GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to change scale:"]), format("%d%%", bar:GetStateProperty(state,"scale")*100))
+        else
+          GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to resize buttons:"]), tostring(floor(size)))
+          GameTooltip:AddDoubleLine(format("|cff0033cc%s|r %s",L["Hold Alt"],  L["to change spacing:"]), tostring(floor(s)))
+        end
+        GameTooltip:Show()
+      end
+    )
+    corner:SetScript("OnLeave", 
+      function()
+        GameTooltip:Hide()
+        f:SetScript("OnUpdate",nil)
+      end
+    )
+  end
+
+  overlay:RegisterForDrag("LeftButton")
+  overlay:RegisterForClicks("RightButtonUp")
+  
+  overlay:SetScript("OnDragStart",
+    function()
+      f:StartMoving()
+      f.isMoving = true
+      local w,h = bar:GetButtonSize()
+      f:ClearAllPoints()
+      UpdateAnchorDecoration()
+      f:SetScript("OnUpdate", function()
+          if IsShiftKeyDown() then
+            local f, p = DisplaySnapIndicator(f,w,h)
+          else
+            HideSnapIndicator()
+          end
+        end)
+    end
+  )
+
+  local function UpdateDragTooltip()
+    GameTooltip:SetOwner(f, "ANCHOR_TOPRIGHT")
+    local ss = GetStateScale(bar)
+    local state = bar:GetSecureState()
+    if ss then
+      GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
+    else
+      GameTooltip:AddLine(bar:GetName())
+    end
+    GameTooltip:AddLine(format("|cffcccccc%s|r %s",L["Drag"],L["to move"]))
+    GameTooltip:AddLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to anchor to nearby frames"]))
+    GameTooltip:AddLine(format("|cff00cccc%s|r %s",L["Right-click"],L["for options..."]))
+    local point, frame, relpoint, x, y = bar:GetFrame():GetPoint(1)
+    if point then
+      local ofsx, ofsy = insidePointOffsetFuncs[point](x,y)
+      if (frame and frame ~= UIParent) or (ofsx == 0 and ofsy == 0) then
+        frame = frame or UIParent
+        GameTooltip:AddLine(format("%s <%s>",L["Currently anchored to"],frame:GetName()))
+      end
+    end
+    GameTooltip:Show()
+  end
+
+  overlay:SetScript("OnDragStop",
+    function()
+      f:StopMovingOrSizing()
+      f.isMoving = false
+      f:SetScript("OnUpdate",nil)
+
+      if IsShiftKeyDown() then
+        local w, h = bar:GetButtonSize()
+        local a, p, rp, x, y = GetClosestPointSnapped(f,w,h)
+        if a then
+          f:ClearAllPoints()
+          f:SetPoint(p,a,rp,x,y)
+        end
+        HideSnapIndicator()
+      end
+
+      StoreExtents(bar)
+      ReAction:RefreshEditor()
+      UpdateDragTooltip()
+      UpdateAnchorDecoration()
+    end
+  )
+
+  overlay:SetScript("OnEnter",
+    function()
+      UpdateDragTooltip()
+    end
+  )
+
+  overlay:SetScript("OnLeave", HideGameTooltip)
+
+  overlay:SetScript("OnClick",
+    function()
+      ReAction:ShowEditor(bar)
+    end
+  )
+
+  function overlay:RefreshControls()
+    UpdateAnchorDecoration()
+  end
+
+  overlay:SetScript("OnShow", overlay.RefreshControls)
+
+  if ReAction:GetKeybindMode() then
+    overlay:SetFrameLevel(1)
+  end
+
+  UpdateLabelString(overlay)
+  UpdateAnchorDecoration()
+
+  return overlay
+end
+
+
+-- export methods to the Bar prototype
+Bar.Overlay = { }
+function Bar.Overlay:New( bar )
+  return setmetatable( {frame = CreateControls(bar)}, {__index=self} )
+end
+
+function Bar.Overlay:SetLabel(name)
+  self.frame.labelName = name
+  UpdateLabelString(self.frame)
+end
+
+function Bar.Overlay:SetLabelSubtext(text)
+  self.frame.labelSubtext = text
+  UpdateLabelString(self.frame)
+end
+
+function Bar.Overlay:Show()
+  self.frame:Show()
+end
+
+function Bar.Overlay:Hide()
+  self.frame:Hide()
+end
+
+function Bar.Overlay:IsShown()
+  return self.frame:IsShown()
+end
+
+function Bar.Overlay:RefreshControls()
+  self.frame:RefreshControls()
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PetActionButton.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,324 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local GetCVar = GetCVar
+local InCombatLockdown = InCombatLockdown
+local GetPetActionInfo = GetPetActionInfo
+local GetPetActionSlotUsable = GetPetActionSlotUsable
+local GetPetActionCooldown = GetPetActionCooldown
+local AutoCastShine_AutoCastStart = AutoCastShine_AutoCastStart
+local AutoCastShine_AutoCastStop = AutoCastShine_AutoCastStop
+local SetDesaturation = SetDesaturation
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+
+--
+-- Secure snippets
+-- These are run within the context of the bar's sandbox, as the
+-- buttons themselves do not have their own sandbox.
+--
+local _onDragStart = -- function(self, button, kind, value, ...)
+[[
+  if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
+    return kind, value, ...
+  else
+    return "petaction", self:GetAttribute("action")
+  end
+]]
+
+local _onReceiveDrag = -- function(self, button, kind, value, ...)
+[[
+  if kind then -- pet spells on the cursor return nil from GetCursorInfo(), which is very strange
+    return kind, value, ...
+  end
+  return "petaction", self:GetAttribute("action")
+]]
+
+--
+-- private
+--
+local eventList = {
+"PLAYER_CONTROL_LOST",
+"PLAYER_CONTROL_GAINED",
+"PLAYER_FARSIGHT_FOCUS_CHANGED",
+"UNIT_PET",
+"UNIT_FLAGS",
+"UNIT_AURA",
+"PET_BAR_UPDATE",
+"PET_BAR_UPDATE_COOLDOWN",
+"PET_BAR_UPDATE_USABLE",
+"UPDATE_BINDINGS",
+}
+
+--
+-- Pet Action Button class
+--
+local buttonTypeID = "PetAction"
+local Super = ReAction.Button
+local Pet = setmetatable( 
+  { 
+    defaultBarConfig = { 
+      type = buttonTypeID,
+      btnWidth = 30,
+      btnHeight = 30,
+      btnRows = 1,
+      btnColumns = 10,
+      spacing = 8,
+      buttons = { }
+    },
+
+    barType = L["Pet Action Bar"], 
+    buttonTypeID = buttonTypeID
+  },
+  { __index = Super } )
+
+ReAction.Button.PetAction = Pet
+ReAction:RegisterBarType(Pet)
+
+function Pet:New( config, bar, idx, idHint )
+  local name = format("ReAction_%s_PetAction_%d",bar:GetName(),idx)
+ 
+  self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+
+  local f = self:GetFrame()
+  if not f.autoCastTexture then
+    -- store autocast stuff with the frame for recycling
+    local tex = f:CreateTexture(nil,"OVERLAY")
+    tex:SetTexture([[Interface\Buttons\UI-AutoCastableOverlay]])
+    tex:SetHeight(58)
+    tex:SetWidth(58)
+    tex:SetPoint("CENTER")
+    f.autoCastTexture = tex
+    f.autoCastShine = CreateFrame("Frame",name.."Shine",f,"AutoCastShineTemplate") -- create after autocast texture so it's on top
+    -- move the cooldown around
+    local cd = self.frames.cooldown
+    cd:ClearAllPoints()
+    cd:SetWidth(33)
+    cd:SetHeight(33)
+    cd:SetPoint("CENTER", f, "CENTER", -2, -1)
+    -- resize to 30x30
+    f:SetHeight(30)
+    f:SetWidth(30)
+    local nt = _G[name.."NormalTexture"]
+    nt:SetHeight(54)
+    nt:SetWidth(54)
+  end
+  local barFrame = bar:GetFrame()
+
+  -- set up the base action ID
+  self:SetActionIDPool("pet",10)
+  config.actionID = self:AcquireActionID(config.actionID, idHint, true)
+
+  -- attribute setup
+  -- There's no secure way to do PetAutoCastToggle by actionID, so use
+  -- a click-through proxy to the Blizzard pet buttons for right-click
+  -- Note that technically this doesn't do PetStopAttack() when 
+  -- IsPetAttackActive() is true: however that's only true when using
+  -- Eyes of the Beast and appears not to really do anything (at least
+  -- I can't find any difference)
+  f:SetAttribute("type","pet")
+  f:SetAttribute("type2","click")
+  f:SetAttribute("clickbutton2",_G["PetActionButton"..config.actionID])
+  f:SetAttribute("action",config.actionID)
+  f:SetAttribute("checkselfcast", true)
+  f:SetAttribute("checkfocuscast", true)
+
+  -- non secure scripts
+  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+  f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
+  f:SetScript("PreClick", function(frame) self:PreClick() end)
+  f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
+  f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)
+
+  -- secure handlers
+  barFrame:WrapScript(f, "OnDragStart", _onDragStart)
+  barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
+
+  -- event registration
+  f:EnableMouse(true)
+  f:RegisterForDrag("LeftButton", "RightButton")
+  f:RegisterForClicks("AnyUp")
+  for _, evt in pairs(eventList) do
+    f:RegisterEvent(evt)
+  end
+
+  -- attach to skinner
+  bar:SkinButton(self,
+   {
+     AutoCast = f.autoCastShine,
+     AutoCastable = f.autoCastTexture
+   })
+
+  self:Refresh()
+  f:Show()
+
+  return self
+end
+
+function Pet:SetupBar(bar)
+  Super.SetupBar(self,bar)
+
+  -- auto show/hide when pet exists
+  bar:RegisterUnitWatch("pet",true)
+
+  self:UpdateButtonLock(bar)
+end
+
+function Pet:UpdateButtonLock(bar)
+  local f = bar:GetFrame()
+  f:SetAttribute("lockbuttons",bar.config.lockButtons)
+  f:SetAttribute("lockbuttonscombat",bar.config.lockButtonsCombat)
+  f:Execute(
+    [[
+      lockButtons = self:GetAttribute("lockbuttons")
+      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
+    ]])
+end
+
+function Pet:Refresh()
+  Super.Refresh(self)
+  self:Update()
+  self:UpdateHotkey()
+end
+
+function Pet:GetActionID()
+  return self.config.actionID
+end
+
+function Pet:SetActionID(id)
+  if not InCombatLockdown() then
+    if id < 0 or id > 10 then
+      ReAction:UserError(L["Pet action ID range is 1-10"])
+      return
+    end
+    self.config.actionID = id
+    f:SetAttribute("clickbutton2",_G["PetActionButton"..id])
+    f:SetAttribute("action",id)
+    self:Update()
+    self:UpdateHotkey()
+  end
+end
+
+function Pet:Update()
+  local action = self.config.actionID
+  local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(action)
+  local f = self:GetFrame()
+  local icon = self.frames.icon
+
+  if isToken then
+    icon:SetTexture(_G[texture])
+    self.tooltipName = _G[name]
+  else
+    icon:SetTexture(texture)
+    self.tooltipName = name
+  end
+
+  self.isToken = isToken
+	self.tooltipSubtext = subtext
+  f:SetChecked( isActive and 1 or 0 )
+
+  if autoCastAllowed then
+    f.autoCastTexture:Show()
+  else
+    f.autoCastTexture:Hide()
+  end
+
+  if autoCastEnabled then
+    AutoCastShine_AutoCastStart(f.autoCastShine)
+  else
+    AutoCastShine_AutoCastStop(f.autoCastShine)
+  end
+
+  if texture then
+    if GetPetActionSlotUsable(action) then
+      SetDesaturation(icon,nil)
+    else
+      SetDesaturation(icon,1)
+    end
+    icon:Show()
+    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
+  else
+    icon:Hide()
+    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
+  end
+
+  self:UpdateCooldown()
+end
+
+function Pet:UpdateCooldown()
+  CooldownFrame_SetTimer(self.frames.cooldown, GetPetActionCooldown(self.config.actionID))
+end
+
+function Pet:SetTooltip()
+  if self.tooltipName then
+    local f = self:GetFrame()
+    local uber = GetCVar("UberTooltips")
+    if self.isToken or (uber == "0") then
+      if uber == "0" then
+        GameTooltip:SetOwner(f, "ANCHOR_RIGHT")
+      else
+        GameTooltip_SetDefaultAnchor(GameTooltip, f)
+      end
+      GameTooltip:SetText(self.tooltipName)
+      if self.tooltipSubtext then
+        GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5)
+      end
+      GameTooltip:Show()
+    else
+      GameTooltip_SetDefaultAnchor(GameTooltip, f)
+      GameTooltip:SetPetAction(self.config.actionID)
+    end
+  else
+    GameTooltip:Hide()
+  end
+end
+
+function Pet:OnEvent(event, unit)
+  if event =="PET_BAR_UPDATE_COOLDOWN" then
+    self:UpdateCooldown()
+  elseif event == "UPDATE_BINDINGS" then
+    self:UpdateHotkey()
+  elseif event == "UNIT_PET" then
+    if unit == "player" then
+      self:Update()
+    end
+  elseif event == "UNIT_FLAGS" or event == "UNIT_AURA" then
+    if unit == "pet" then
+      self:Update()
+    end
+  else
+    self:Update()
+  end
+end
+
+function Pet:OnEnter()
+  self:SetTooltip()
+end
+
+function Pet:OnLeave()
+  GameTooltip:Hide()
+end
+
+function Pet:OnAttributeChanged(attr,value)
+  self:Update()
+end
+
+function Pet:PreClick()
+  self:GetFrame():SetChecked(0)
+end
+
+function Pet:OnDragStart()
+  self:SetChecked(0)
+  self:Update()
+end
+
+function Pet:OnReceiveDrag()
+  self:SetChecked(0)
+  self:Update()
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Profile.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,157 @@
+local _, addonTable = ...
+local ReAction = addonTable.ReAction
+
+ReAction.PROFILEVERSION_LATEST = 2
+
+ReAction.defaultProfile = { 
+  profile = {
+    dbversion = nil,
+    bars = { },
+    options = { 
+      hideBlizzardBars = false,
+      hideBlizzardVehicleBar = false,
+    },
+  },
+  global = {
+    skipKeybindWarning = false,
+  }
+}
+
+function ReAction:UpgradeProfile()
+  local db = self.db
+
+  if not db.profile.dbversion then
+    -- upgrade from legacy db to v1
+
+    -- (1) remove unused defaultBars table (cleanup)
+    db.profile.defaultBars = nil
+
+    -- (2) HideBlizzard is no longer a module
+    local hb = db:GetNamespace("HideBlizzard",true) or db:RegisterNamespace("HideBlizzard")
+    if hb then
+      db.profile.options.hideBlizzardBars = hb.profile.hide
+      db.profile.options.hideBlizzardVehicleBar = hb.profile.hideVehicle
+      hb:ResetProfile()
+    end
+
+    -- (3) LBF is no longer a module
+    local bf = db:GetNamespace("ButtonFacade",true) or db:RegisterNamespace("ButtonFacade")
+    if bf then
+      for name, bar in pairs(db.profile.bars) do
+        bar.ButtonFacade = bf.profile[name] or bar.ButtonFacade
+      end
+      bf:ResetProfile()
+    end
+
+    -- (4) Action module uses the bar config directly
+    local action = db:GetNamespace("Action",true) or db:RegisterNamespace("Action")
+    if action then
+      for name, bar in pairs(db.profile.bars) do
+        local ac = action.profile.bars and action.profile.bars[name]
+        if ac then
+          for key, value in pairs(ac) do
+            bar[key] = value
+          end
+        end
+      end
+      action:ResetProfile()
+    end
+
+    -- (5) Bags module uses the bar config directly
+    local bag = db:GetNamespace("Bag",true) or db:RegisterNamespace("Bag")
+    if bag then
+      for name, bar in pairs(db.profile.bars) do
+        local bc = bag.profile.buttons and bag.profile.buttons[name]
+        if bc then
+          bar.buttons = bc
+        end
+      end
+      bag:ResetProfile()
+    end
+
+    -- (6) Pet module uses the bar config directly
+    local pet = db:GetNamespace("PetAction",true) or db:RegisterNamespace("PetAction")
+    if pet then
+      for name, bar in pairs(db.profile.bars) do
+        local pc = pet.profile.buttons and pet.profile.buttons[name]
+        if pc then
+          bar.buttons = pc
+        end
+      end
+      pet:ResetProfile()
+    end
+
+    -- (7) Stance module uses the bar config directly
+    local stance = db:GetNamespace("Stance",true) or db:RegisterNamespace("Stance")
+    if stance then
+      for name, bar in pairs(db.profile.bars) do
+        local sc = stance.profile.buttons and stance.profile.buttons[name]
+        if sc then
+          bar.buttons = sc
+        end
+      end
+      stance:ResetProfile()
+    end
+
+    -- (8) Totem module uses the bar config directly
+    local totem = db:GetNamespace("Totem",true) or db:RegisterNamespace("Totem")
+    if totem then
+      for name, bar in pairs(db.profile.bars) do
+        local tc = totem.profile.buttons and totem.profile.buttons[name]
+        if tc then 
+          bar.buttons = tc
+        end
+      end
+      totem:ResetProfile()
+    end
+
+    -- (9) Vehicle exit button uses the bar config directly
+    local vehicle = db:GetNamespace("VehicleExit",true) or db:RegisterNamespace("VehicleExit")
+    if vehicle then
+      for name, bar in pairs(db.profile.bars) do
+        local vc = vehicle.profile.buttons and vehicle.profile.buttons[name]
+        if vc then
+          bar.buttons = vc
+        end
+      end
+      vehicle:ResetProfile()
+    end
+
+    db.profile.dbversion = 1
+  end
+
+
+  if db.profile.dbversion < 2 then
+    -- upgrade from v1 to v2
+
+    -- (10) State module uses the bar config directly
+    local state = db:GetNamespace("State",true) or db:RegisterNamespace("State")
+    if state then
+      for name, bar in pairs(db.profile.bars) do
+        local sc = state.profile.bars and state.profile.bars[name] and state.profile.bars[name].states
+        if sc then
+          bar.states = sc
+        end
+      end
+      state:ResetProfile()
+    end
+
+    db.profile.dbversion = 2
+  end
+
+  db.profile.dbversion = self.PROFILEVERSION_LATEST
+end
+
+function ReAction:OnProfileChanged()
+  self:UpgradeProfile()
+  self:RebuildAll()
+  if not self.db.global.skipKeybindWarning then
+    StaticPopup_Show("REACTION_KB_WARN") -- see Options.lua
+  end
+end
+
+function ReAction:OnNewProfile()
+  self.db.profile.dbversion = ReAction.PROFILEVERSION_LATEST
+  self:OnProfileChanged()
+end
+
--- 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
+
--- a/ReAction.toc	Thu Nov 18 13:11:08 2010 -0800
+++ b/ReAction.toc	Tue Apr 12 16:06:31 2011 -0700
@@ -4,9 +4,8 @@
 ## DefaultState: enabled
 ## LoadOnDemand: 0
 ## Author: Flick
-## Version: 1.1
+## Version: 1.1 beta 4
 ## SavedVariables: ReAction_DB
-## OptionalDeps: Ace3, LibKeyBound-1.0
 ## X-Embeds: Ace3, LibKeyBound-1.0
 ## X-Category: Action Bars
 ## X-License: MIT
--- a/ReAction.xml	Thu Nov 18 13:11:08 2010 -0800
+++ b/ReAction.xml	Tue Apr 12 16:06:31 2011 -0700
@@ -6,10 +6,16 @@
   <Include file="locale\locale.xml"/>
 
   <Script file="ReAction.lua"/>
+  <Script file="Profile.lua"/>
+  <Script file="Bar.lua"/>
+  <Script file="Overlay.lua"/>
+  <Script file="Button.lua"/>
+  <Script file="ActionButton.lua"/>
+  <Script file="PetActionButton.lua"/>
+  <Script file="StanceButton.lua"/>
+  <Script file="BagButton.lua"/>
+  <Script file="VehicleExitButton.lua"/>
+  <Script file="MultiCastButton.lua"/>
   <Script file="Options.lua"/>
   <Script file="Editor.lua"/>
-
-  <Include file="classes\classes.xml"/>
-  <Include file="modules\modules.xml"/>
-
 </Ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/StanceButton.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,198 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local GetCVar = GetCVar
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local InCombatLockdown = InCombatLockdown
+local GetNumShapeshiftForms = GetNumShapeshiftForms
+local GetShapeshiftFormInfo = GetShapeshiftFormInfo
+local IsUsableSpell = IsUsableSpell
+local GetSpellInfo = GetSpellInfo
+
+--
+-- private
+--
+local playerClass = select(2,UnitClass("player"))
+
+local eventList = {
+  "PLAYER_REGEN_ENABLED",
+  "PLAYER_ENTERING_WORLD",
+  "UPDATE_SHAPESHIFT_FORM",
+  "UPDATE_SHAPESHIFT_FORMS",
+  "UPDATE_SHAPESHIFT_USABLE",
+  "UPDATE_SHAPESHIFT_COOLDOWN",
+  "UPDATE_BINDINGS",
+}
+
+--
+-- Stance Button class
+--
+local buttonTypeID = "Stance"
+local Super = ReAction.Button
+local Stance = setmetatable(
+  { 
+    defaultConfig = { 
+      type = buttonTypeID,
+      btnHeight = 36,
+      btnWidth = 36,
+      btnRows = 1,
+      btnColumns = 6,
+      spacing = 3
+    }, 
+
+    barType = L["Stance Bar"], 
+    buttonTypeID = buttonTypeID
+  },
+  { __index = Super } )
+
+ReAction.Button.Stance = Stance
+ReAction:RegisterBarType(Stance)
+
+function Stance:New( config, bar, idx, idHint )
+  local name = format("ReAction_%s_Stance_%d",bar:GetName(),idx)
+ 
+  self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+
+  local f = self:GetFrame()
+  local barFrame = bar:GetFrame()
+  local config = self:GetConfig()
+
+  -- set up the base stance ID
+  self:SetActionIDPool("stance",8)
+  config.stanceID = self:AcquireActionID(config.stanceID, idHint, true)
+
+  -- attribute setup
+  f:SetAttribute("type","spell")
+
+  -- non secure scripts
+  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+  f:SetScript("PreClick", function(frame, ...) self:PreClick(...) end)
+
+  -- secure handlers
+  -- (none)
+
+  -- event registration
+  f:EnableMouse(true)
+  f:RegisterForClicks("AnyUp")
+  for _, evt in pairs(eventList) do
+    f:RegisterEvent(evt)
+  end
+
+  -- attach to skinner
+  bar:SkinButton(self)
+
+  -- initial display
+  if ReAction:GetConfigMode() then
+    self:GetFrame():Show()
+  end
+
+  self:Refresh()
+
+  return self
+end
+
+function Stance:GetActionID()
+  return self.config.stanceID
+end
+
+function Stance:UpdateAction()
+  if InCombatLockdown() then
+    self.updatePending = true
+  else
+    self.updatePending = false
+    local idx = self:GetActionID()
+    local f = self:GetFrame()
+    if idx > GetNumShapeshiftForms() then
+      f:Hide()
+    else
+      f:SetAttribute("spell", select(2,GetShapeshiftFormInfo(idx)))
+      f:Show()
+      self:Update()
+    end
+  end
+end
+
+function Stance:Refresh()
+  Super.Refresh(self)
+  self:UpdateHotkey()
+  self:UpdateAction()
+end
+
+function Stance:Update()
+  local texture, _, isActive, isCastable = GetShapeshiftFormInfo(self:GetActionID())
+  
+  local icon = self.frames.icon
+  icon:SetTexture(texture)
+  self:GetFrame():SetChecked( isActive and 1 or 0 )
+  if isCastable then
+    self.frames.hotkey:Show()
+    icon:SetVertexColor(1.0, 1.0, 1.0)
+  else
+    icon:SetVertexColor(0.4, 0.4, 0.4)
+  end
+
+  self:UpdateCooldown()
+end
+
+function Stance:UpdateCooldown()
+  local start, duration, enabled = GetShapeshiftFormCooldown(self:GetActionID())
+  if start then
+    CooldownFrame_SetTimer(self.frames.cooldown, start, duration, enabled)
+  end
+end
+
+function Stance:SetTooltip()
+  if GetCVar("UberTooltips") == "1" then
+    GameTooltip_SetDefaultAnchor(GameTooltip, self:GetFrame())
+  else
+    GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_RIGHT")
+  end
+  GameTooltip:SetShapeshift(self:GetActionID())
+end
+
+function Stance:OnEnter()
+  self:SetTooltip()
+end
+
+function Stance:OnLeave()
+  GameTooltip:Hide()
+end
+
+function Stance:PreClick()
+  local f = self:GetFrame()
+  f:SetChecked( not f:GetChecked() )
+end
+
+function Stance:OnEvent(event, arg)
+  if event == "PLAYER_REGEN_ENABLED" then
+    if self.updatePending then
+      self:UpdateAction()
+    end
+  elseif event == "UPDATE_SHAPESHIFT_COOLDOWN" then
+    self:UpdateCooldown()
+  elseif event == "UPDATE_SHAPESHIFT_FORMS" then
+    self:UpdateAction()
+  elseif event == "UNIT_AURA" then
+    if arg == "player" then
+      self:Update()
+    end
+  elseif event == "UPDATE_BINDINGS" then
+    self:UpdateHotkey()
+  else
+    self:Update()
+  end
+end
+
+function Stance:ShowGridTemp(show)
+  if show then
+    self:GetFrame():Show()
+  else
+    self:UpdateAction()
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VehicleExitButton.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,108 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local format = string.format
+
+--
+-- VExitButton Button class
+--
+local buttonTypeID = "VehicleExit"
+local Super = ReAction.Button
+local VExitButton = setmetatable(
+  { 
+    defaultBarConfig = { 
+      type = buttonTypeID ,
+      btnWidth = 36,
+      btnHeight = 36,
+      btnRows = 1,
+      btnColumns = 1,
+      spacing = 3,
+      buttons = { }
+    },
+
+    barType = L["Exit Vehicle Floater"], 
+    buttonTypeID = buttonTypeID
+  }, 
+  { __index = Super } )
+
+ReAction.Button.VehicleExit = VExitButton
+ReAction:RegisterBarType(VExitButton)
+
+function VExitButton:New( config, bar, idx )
+  local name = format("ReAction_%s_VehicleExit_%d",bar:GetName(),idx)
+ 
+  self = Super.New(self, name, config, bar, idx, "SecureFrameTemplate, ActionButtonTemplate", "Button")
+
+  -- frame setup
+  local f = self:GetFrame()
+  self.frames.icon:SetTexture("Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up")
+  self.frames.icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
+
+  -- attribute setup
+  -- (none)
+
+  -- non secure scripts
+  f:SetScript("OnClick", VehicleExit)
+  f:SetScript("OnEnter", function(frame) GameTooltip_AddNewbieTip(frame, LEAVE_VEHICLE, 1.0, 1.0, 1.0, nil) end)
+  f:SetScript("OnLeave", GameTooltip_Hide)
+  f:SetScript("OnEvent", function(frame, evt, ...) self:OnEvent(evt,...) end)
+
+  -- event registration
+  f:EnableMouse(true)
+  f:RegisterForClicks("AnyUp")
+  f:RegisterEvent("UPDATE_BINDINGS")
+
+  -- attach to skinner
+  bar:SkinButton(self)
+
+  self:Refresh()
+  self:UpdateHotkey()
+
+  return self
+end
+
+function VExitButton:SetupBar(bar)
+  Super.SetupBar(self,bar)
+  self:UpdateRegistration(bar)
+end
+
+function VExitButton:GetActionID()
+  return 1
+end
+
+function VExitButton:Refresh()
+  Super.Refresh(self)
+  -- it seems that setscale kills the texcoord, have to refresh it
+  self.frames.icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375) 
+end
+
+function VExitButton:OnEvent(event, ...)
+  if self[event] then
+    self[event](self, event, ...)
+  end
+end
+
+function VExitButton:UPDATE_BINDINGS()
+  self:UpdateHotkey()
+end
+
+function VExitButton:UpdateRegistration(bar)
+  -- auto show/hide when on a vehicle
+  local config = bar:GetConfig()
+  local f = bar:GetFrame()
+  if config.withControls then
+    if bar.vehicleExitStateRegistered then
+      UnregisterStateDriver(f, "unitexists")
+      bar.vehicleExitStateRegistered = false
+    end
+    bar:RegisterUnitWatch("vehicle",true)
+  else
+    bar:RegisterUnitWatch("vehicle",false)
+    if not bar.vehicleExitStateRegistered then
+      f:SetAttribute("unit","vehicle")
+      RegisterStateDriver(f, "unitexists", "[target=vehicle,exists,novehicleui] show; hide") -- spoof onstate-unitexists
+      bar.vehicleExitStateRegistered = true
+    end
+  end
+end
+
--- a/classes/ActionButton.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,782 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local IsUsableAction = IsUsableAction
-local IsEquippedAction = IsEquippedAction
-local IsConsumableAction = IsConsumableAction
-local IsStackableAction = IsStackableAction
-local GetActionText = GetActionText
-local GetCVar = GetCVar
-local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
-local IsCurrentAction = IsCurrentAction
-local IsAutoRepeatAction = IsAutoRepeatAction
-local IsUsableAction = IsUsableAction
-local IsAttackAction = IsAttackAction
-local CooldownFrame_SetTimer = CooldownFrame_SetTimer
-local GetActionCooldown = GetActionCooldown
-local GetActionTexture = GetActionTexture
-local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
-local TOOLTIP_UPDATE_TIME = TOOLTIP_UPDATE_TIME
-local IsActionInRange = IsActionInRange
-local InCombatLockdown = InCombatLockdown
-local HasAction = HasAction
-
---
--- Secure snippets
--- These are run within the context of the bar's sandbox, as the
--- buttons themselves do not have their own sandbox.
---
-local _onstate_mc = -- function(self, stateid, newstate)
-[[
-  local oldMcVehicleState = mcVehicleState
-  mcVehicleState = newstate
-  control:ChildUpdate()
-  if oldMcVehicleState == "vehicle" or mcVehicleState == "vehicle" then
-    control:ChildUpdate("vehicle")
-  end
-]]
-
-local _childupdate = -- function(self, snippetid, message)
-[[
-  local action = nil
-  if (doVehicle and mcVehicleState == "vehicle") or
-     (doMindControl and mcVehicleState == "mc") then
-    local idx = self:GetAttribute("bar-idx")
-    local maxN = (doVehicle and mcVehicleState == "vehicle") and 7 or 12
-    if idx and idx <= maxN then
-      action = 120 + idx
-    else
-      action = 0
-    end
-  elseif state and settings[state] and settings[state].page then
-    action = self:GetAttribute("action-"..settings[state].page) 
-  end
-  if action == nil then
-    action = self:GetAttribute("default-action")
-  end
-
-  self:SetAttribute("action",action)
-
-  if not self:GetAttribute("showgrid") then
-    local tempShow = self:GetAttribute("showgrid-temp")
-    local evtShow = self:GetAttribute("showgrid-event")
-    if tempShow then tempShow = (tempShow > 0) end
-    if evtShow then evtShow = (evtShow > 0) end
-
-    if tempShow or evtShow or HasAction(action) then
-      self:Show()
-    else
-      self:Hide()
-    end
-  end
-]]
-
-local _childupdate_vehicleExit =  -- function(self, snippetid, message)
-[[
-  local show = (mcVehicleState == "vehicle")
-  if show and doVehicle then
-    self:SetAttribute("type","macro")
-    self:Show()
-  else
-    self:SetAttribute("type","action")
-  end
-  control:CallMethod("ShowVehicleExit",show)
-]]
-
-local _childupdate_showgrid = -- function(self, snippetid, message)
-[[
-  showgrid_event = message
-  self:SetAttribute("showgrid-event",message)
-  if not self:GetAttribute("showgrid") then
-    local count = message + (self:GetAttribute("showgrid-temp") or 0)
-    if count <= 0 then
-      local action = self:GetAttribute("action")
-        -- note that HasAction is not updated on the target of a drag until after ACTIONBAR_HIDEGRID
-        -- so, we set a flag for this button in pre-click/receive-drag and check for it here
-      if HasAction(action) or self:GetAttribute("showgrid-clicked") then
-        if not self:IsShown() then
-          self:Show()
-        end
-        self:SetAttribute("showgrid-clicked",false)
-      else 
-        if self:IsShown() then
-          self:Hide()
-        end
-      end
-    else
-      self:Show()
-    end
-  end
-]]
-
-local _onDragStart = -- function(self, button, kind, value, ...)
-[[
-  if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
-    return kind, value, ...
-  else
-    return "action", self:GetAttribute("action")
-  end
-]]
-
-local _onReceiveDrag = -- function(self, button, kind, value, ...)
-[[
-  if kind ~= "spell" and kind ~= "item" and kind ~= "macro" then
-    return kind, value, ...
-  else
-    if showgrid_event and showgrid_event > 0 then
-      self:SetAttribute("showgrid-clicked",true)
-    end
-    return "action", self:GetAttribute("action")
-  end
-]]
-
-local _onClick = -- function(self, button, down)
-[[
-  if showgrid_event and showgrid_event > 0 then
-    self:SetAttribute("showgrid-clicked",true)
-  end
-  return button
-]]
-
---
--- private
---
-local eventList = {
-  "PLAYER_ENTERING_WORLD",
-  "ACTIONBAR_PAGE_CHANGED",
-  "ACTIONBAR_SLOT_CHANGED",
-  "UPDATE_BINDINGS",
-  "ACTIONBAR_UPDATE_STATE",
-  "ACTIONBAR_UPDATE_USABLE",
-  "ACTIONBAR_UPDATE_COOLDOWN",
-  "UNIT_INVENTORY_CHANGED",
-  "LEARNED_SPELL_IN_TAB",
-  "UPDATE_INVENTORY_ALERTS",
-  "PLAYER_TARGET_CHANGED",
-  "TRADE_SKILL_SHOW",
-  "TRADE_SKILL_CLOSE",
-  "PLAYER_ENTER_COMBAT",
-  "PLAYER_LEAVE_COMBAT",
-  "START_AUTOREPEAT_SPELL",
-  "STOP_AUTOREPEAT_SPELL",
-  "UNIT_ENTERED_VEHICLE",
-  "UNIT_EXITED_VEHICLE",
-  "COMPANION_UPDATE",
-}
-
---
--- Action Button class
---
-local Super = ReAction.Button
-local Action = setmetatable( { }, { __index = Super } )
-ReAction.Button.Action = Action
-
-function Action:New( idx, barConfig, bar, idHint )
-  local name = format("ReAction_%s_Action_%d",bar:GetName(),idx)
- 
-  self = Super.New(self, name, barConfig.buttons[idx], bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
-  self.barConfig = barConfig
-
-  local f = self:GetFrame()
-  local barFrame = bar:GetFrame()
-  local config = self:GetConfig()
-
-  self.rangeTimer = TOOLTIP_UPDATE_TIME
-
-  -- set up the base action ID
-  self:SetActionIDPool("action",120)
-  config.actionID = self:AcquireActionID(config.actionID, idHint)
-  self.nPages = 1
-
-  -- attribute setup
-  f:SetAttribute("type","action")
-  f:SetAttribute("checkselfcast", true)
-  f:SetAttribute("checkfocuscast", true)
-  f:SetAttribute("action", config.actionID)
-  f:SetAttribute("default-action", config.actionID)
-  f:SetAttribute("bar-idx",idx)
-  f:SetAttribute("showgrid-temp",0)
-  f:SetAttribute("showgrid-event",0)
-  f:SetAttribute("showgrid",not self:GetBarConfig().hideEmpty)
-
-  -- non secure scripts
-  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
-  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
-  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
-  f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
-  f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
-  f:SetScript("OnUpdate", function(frame, elapsed) self:OnUpdate(elapsed) end)
-  f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
-  f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)
-
-  -- event registration
-  f:EnableMouse(true)
-  f:RegisterForDrag("LeftButton", "RightButton")
-  f:RegisterForClicks("AnyUp")
-  for _, evt in pairs(eventList) do
-    f:RegisterEvent(evt)
-  end
-
-  -- secure handlers
-  f:SetAttribute("_childupdate", _childupdate)
-  f:SetAttribute("_childupdate-showgrid",_childupdate_showgrid)
-  barFrame:WrapScript(f, "OnDragStart", _onDragStart)
-  barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
-  barFrame:WrapScript(f, "OnClick", _onClick)
-
-  -- attach to skinner
-  bar:SkinButton(self)
-
-  -- initial display
-  if ReAction:GetConfigMode() then
-    self:ShowGridTemp(true)
-  end
-
-  self:Refresh()
-
-  return self
-end
-
-function Action:Destroy()
-  local f = self:GetFrame()
-  local c = self:GetConfig()
-
-  f:SetAttribute("_childupdate-vehicle",nil)
-  f:SetAttribute("action",c.actionID) -- so that Super.Destroy releases the right one
-
-  if c.pageactions and #c.pageactions > 1 then
-    for i = 2, #c.pageactions do 
-      self:ReleaseActionID(c.pageactions[i])
-      self:ReleaseActionID(id)
-    end
-  end
-  
-  Super.Destroy(self)
-end
-
-function Action:GetBarConfig()
-  -- this is the per-bar Action module config structure,
-  -- not the config structure of the bar itself
-  return self.barConfig
-end
-
-function Action:Refresh()
-  Super.Refresh(self)
-  self:RefreshPages()
-  self:InstallVehicle()
-  self:ShowGrid(not self:GetBarConfig().hideEmpty)
-  self:UpdateAction()
-end
-
-function Action:InstallVehicle()
-  local f = self:GetFrame()
-  if self.idx == 7 and self:GetBarConfig().vehicle then
-    if not self.vehicleInstalled then
-      self.vehicleInstalled = true
-      -- install vehicle-exit button on 7th button (only)
-      f:SetAttribute("_childupdate-vehicle", _childupdate_vehicleExit)
-      f:SetAttribute("macrotext","/run VehicleExit()")
-      self:GetBar():GetFrame().ShowVehicleExit = function(bar,show)
-        self:ShowVehicleExit(show)
-      end
-    end
-    -- setscale blows away tex coords
-    self:UpdateIcon()
-  elseif self.vehicleInstalled then
-    self.vehicleInstalled = false
-    f:SetAttribute("_childupdate-vehicle",nil)
-    f:SetAttribute("macrotext",nil)
-  end
-end
-
-function Action:ShowGrid( show )
-  if not InCombatLockdown() then
-    self.frame:SetAttribute("showgrid", show)
-    self:UpdateShowGrid()
-  end
-end
-
-function Action:ShowGridTemp( show )
-  -- This function only modifies the show-grid when out
-  -- of combat, and is ignored by the secure handler. Use 
-  -- it for configuration modes.
-  if not InCombatLockdown() then
-    local count = self.showGridTempCount or 0
-    if show then
-      count = count + 1
-    else
-      count = count - 1
-    end
-    if count < 0 then count = 0 end
-    self.showGridTempCount = count
-    self:GetFrame():SetAttribute("showgrid-temp",count)
-    self:UpdateShowGrid()
-  end
-end
-
-function Action:UpdateAll()
-  self:UpdateActionIDLabel(ReAction:GetConfigMode())
-  self:UpdateHotkey()
-  self:UpdateShowGrid()
-  self:UpdateIcon()
-  self:UpdateBorder()
-  self:UpdateMacroText()
-  self:UpdateCount()
-  self:UpdateTooltip()
-  self:UpdateCheckedState()
-  self:UpdateUsable()
-  self:UpdateCooldown()
-  self:UpdateFlash()
-end
-
-function Action:UpdateAction()
-  local action = self:GetActionID()
-  if action ~= self.actionID then
-    self.actionID = action
-    self:UpdateAll()
-  end
-end
-
-function Action:UpdateShowGrid()
-  if not InCombatLockdown() then
-    local f = self:GetFrame()
-    local count = (f:GetAttribute("showgrid-event") or 0) +
-                  (self.showGridTempCount or 0) +
-                  (f:GetAttribute("showgrid") and 1 or 0)
-
-    if count <= 0 and not HasAction(self.actionID) then
-      if f:IsShown() then
-        f:Hide()
-      end
-    elseif not f:IsShown() then
-      f:Show()
-    end
-  end
-end
-
-function Action:UpdateIcon()
-  local texture, tLeft, tRight, tTop, tBottom = self:GetIconTexture()
-  local icon = self.frames.icon
-  local hotkey = self.frames.hotkey
-  local f = self:GetFrame()
-  
-  if self.vehicleExitMode then
-    texture = "Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up"
-    icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
-    icon:SetVertexColor(1,1,1)
-  else
-    icon:SetTexCoord(0,1,0,1)
-  end
-
-  if texture then
-    icon:SetTexture(texture)
-    if tLeft then
-      icon:SetTexCoord(tLeft,tRight,tTop,tBottom)
-    end
-    icon:Show()
-    self.rangeTimer = -1
-    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
-  else
-    icon:Hide()
-    self.frames.cooldown:Hide()
-    self.rangeTimer = nil
-    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
-  end
-end
-
-function Action:GetIconTexture()
-  return GetActionTexture(self.actionID)
-end
-
-function Action:UpdateBorder()
-  local action = self.actionID
-  if ReAction:GetKeybindMode() then
-    self:UpdateKeybindModeDisplay(true)
-  elseif IsEquippedAction(action) then
-    self.frames.border:SetVertexColor(0, 1.0, 0, 0.35)
-    self.frames.border:Show()
-  else
-    self.frames.border:Hide()
-  end
-end
-
-function Action:UpdateMacroText()
-  local action = self.actionID
-  if not IsConsumableAction(action) and not IsStackableAction(action) then
-    self.frames.name:SetText(GetActionText(action))
-  else
-    self.frames.name:SetText("")
-  end
-end
-
-function Action:UpdateCount()
-  local action = self.actionID
-  if IsConsumableAction(action) or IsStackableAction(action) then
-    self.frames.count:SetText(GetActionCount(action))
-  else
-    self.frames.count:SetText("")
-  end
-end
-
-function Action:UpdateTooltip()
-  local f = self:GetFrame()
-  if GameTooltip:GetOwner() == f then
-    self:SetTooltip()
-  end
-end
-
-function Action:SetTooltip()
-  local f = self:GetFrame()
-  if GetCVar("UberTooltips") == "1" then
-    GameTooltip_SetDefaultAnchor(GameTooltip, f)
-  else
-    GameTooltip:SetOwner(f,"ANCHOR_RIGHT")
-  end
-  GameTooltip:SetAction(self.actionID)
-end
-
-function Action:UpdateCheckedState()
-  local action = self.actionID
-  if IsCurrentAction(action) or IsAutoRepeatAction(action) then
-    self:GetFrame():SetChecked(1)
-  else
-    self:GetFrame():SetChecked(0)
-  end
-end
-
-function Action:UpdateUsable()
-  local isUsable, notEnoughMana = self:GetUsable()
-  local noRange = self:GetInRange()
-
-  isUsable = self.vehicleExitMode or (isUsable and not noRange)
-
-  if isUsable then
-    if self.usableStatus ~= "usable" then
-      self.frames.icon:SetVertexColor(1.0, 1.0, 1.0)
-      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
-      self.usableStatus = "usable"
-    end
-  elseif noRange then
-    if self.usableStatus ~= "norange" then
-      self.frames.icon:SetVertexColor(1.0,0.1,0.1)
-      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
-      self.usableStatus = "norange"
-    end
-  elseif notEnoughMana then
-    if self.usableStatus ~= "oom" then
-      self.frames.icon:SetVertexColor(0.5, 0.5, 1.0)
-      self.frames.normalTexture:SetVertexColor(0.5, 0.5, 1.0)
-      self.usableStatus = "oom"
-    end
-  else
-    if self.usableStatus ~= "unusable" then
-      self.frames.icon:SetVertexColor(0.4, 0.4, 0.4)
-      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
-      self.usableStatus = "unusable"
-    end
-  end
-end
-
-function Action:GetUsable()
-  return IsUsableAction(self.actionID)
-end
-
-function Action:GetInRange()
-  return IsActionInRange(self.actionID) == 0
-end
-
-function Action:UpdateCooldown()
-  CooldownFrame_SetTimer(self.frames.cooldown, self:GetCooldown())
-end
-
-function Action:GetCooldown()
-  return GetActionCooldown(self.actionID)
-end
-
-function Action:UpdateFlash()
-  local action = self.actionID
-  self:SetFlash( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) )
-end
-
-function Action:SetFlash(flash)
-  if self.flashing ~= flash then
-    self.flashing = flash
-    self.flashtime = 0
-    if not flash then
-      self.frames.flash:Hide()
-    end
-    self:UpdateCheckedState()
-  end
-end
-
-function Action:RunFlash(elapsed)
-  if self.flashing then
-    local flashtime = self.flashtime - elapsed
-    self.flashtime = flashtime
-    if flashtime <= 0 then
-      local overtime = -flashtime
-      if overtime >= ATTACK_BUTTON_FLASH_TIME then
-        overtime = 0
-      end
-      flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
-      local flash = self.frames.flash
-      if flash:IsShown() then
-        flash:Hide()
-      else
-        flash:Show()
-      end
-    end
-  end
-end
-
-function Action:RunRangeFinder(elapsed)
-  local rangeTimer = self.rangeTimer
-  if rangeTimer then
-    rangeTimer = rangeTimer - elapsed
-    self.rangeTimer = rangeTimer
-    if rangeTimer <= 0 then
-      self:UpdateUsable()
-      self.rangeTimer = TOOLTIP_UPDATE_TIME
-    end
-  end
-end
-
-function Action:GetActionID(page)
-  if page == nil then
-    -- get the effective ID
-    return self:GetFrame():GetAttribute("action")
-  else
-    if page == 1 then
-      return self.config.actionID
-    else
-      return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
-    end
-  end
-end
-
-function Action:SetActionID( id, page )
-  id = tonumber(id)
-  page = tonumber(page)
-  if id == nil or id < 1 or id > 120 then
-    ReAction:UserError(L["Action ID range is 1-120"])
-    return
-  end
-  if page and page ~= 1 then
-    if not self.config.pageactions then
-      self.config.pageactions = { }
-    end
-    self:ReleaseActionID(self.config.pageactions[page])
-    self.config.pageactions[page] = id
-    self:AcquireActionID(self.config.pageactions[page])
-    self.frame:SetAttribute("action-page"..page,id)
-  else
-    self:ReleaseActionID(self.config.actionID)
-    self.config.actionID = id
-    self:AcquireActionID(self.config.actionID)
-    self.frame:SetAttribute("action",id)
-    self.frame:SetAttribute("default-action",id)
-    if self.config.pageactions then
-      self.config.pageactions[1] = id
-      self.frame:SetAttribute("action-page1",id)
-    end
-  end
-end
-
-function Action:RefreshPages( force )
-  local nPages = self:GetBarConfig().nPages
-  if nPages and (nPages ~= self.nPages or force) then
-    local f = self:GetFrame()
-    local c = self.config.pageactions
-    if nPages > 1 and not c then
-      c = { }
-      self.config.pageactions = c
-    end
-    for i = 1, nPages do
-      if i > 1 then
-        c[i] = self:AcquireActionID(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
-      else
-        c[i] = self.config.actionID  -- page 1 is the same as the base actionID
-      end
-      f:SetAttribute("action-page"..i,c[i])
-    end
-    for i = nPages+1, #c do
-      self:ReleaseActionID(c[i])
-      c[i] = nil
-      f:SetAttribute("action-page"..i,nil)
-    end
-    self.nPages = nPages
-  end
-end
-
-function Action.SetupBarHeader( bar, config ) -- call this as a static method
-  local f = bar:GetFrame()
-  f:SetAttribute("mindcontrol",config.mindcontrol)
-  f:SetAttribute("vehicle",config.vehicle)
-  f:Execute(
-    [[
-    doMindControl = self:GetAttribute("mindcontrol")
-    doVehicle = self:GetAttribute("vehicle")
-    control:ChildUpdate()
-    ]])
-
-  f:SetAttribute("_onstate-mc", _onstate_mc)
-  RegisterStateDriver(f, "mc", "[vehicleui] vehicle; [bonusbar:5] mc; none")
-
-  f:SetAttribute("lockbuttons",config.lockButtons)
-  f:SetAttribute("lockbuttonscombat",config.lockButtonsCombat)
-  f:Execute(
-    [[
-      lockButtons = self:GetAttribute("lockbuttons")
-      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
-    ]])
-end
-
-
-function Action.SetButtonLock( bar, lock, lockCombat ) -- call this as a static method
-  local f = bar:GetFrame()
-  f:SetAttribute("lockbuttons",lock)
-  f:SetAttribute("lockbuttonscombat",lockCombat)
-  f:Execute(
-    [[
-      lockButtons = self:GetAttribute("lockbuttons")
-      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
-    ]])
-end
-
-
-function Action:ShowVehicleExit(show)
-  self.vehicleExitMode = show and self:GetBarConfig().vehicle
-  self:UpdateIcon()
-end
-
-function Action:OnEnter( )
-  self:SetTooltip()
-end
-
-function Action:OnLeave( )
-  GameTooltip:Hide()
-end
-
-function Action:OnAttributeChanged( attr, value )
-  if attr ~= "statehidden" then
-    self:UpdateAction()
-  end
-end
-
-function Action:PostClick( )
-  self:UpdateCheckedState()
-end
-
-function Action:OnUpdate( elapsed )
-  self:RunFlash(elapsed)
-  self:RunRangeFinder(elapsed)
-end
-
-function Action:OnDragStart()
-  self:UpdateCheckedState()
-  self:UpdateFlash()
-end
-
-function Action:OnReceiveDrag()
-  self:UpdateCheckedState()
-  self:UpdateFlash()
-end
-
-function Action:OnEvent(event, ...)
-  if self[event] then
-    self[event](self, event, ...)
-  end
-end
-
-function Action:ACTIONBAR_SLOT_CHANGED(event, action)
-  if action == 0 or action == self.actionID then
-    self:UpdateAll()
-  end
-end
-
-function Action:PLAYER_ENTERING_WORLD()
-  self:UpdateAction()
-end
-
-function Action:ACTIONBAR_PAGE_CHANGED()
-  self:UpdateAction()
-end
-
-function Action:UPDATE_BONUS_ACTIONBAR()
-  self:UpdateAction()
-end
-
-function Action:UPDATE_BINDINGS()
-  self:UpdateHotkey()
-end
-
-function Action:PLAYER_TARGET_CHANGED()
-  self.rangeTimer = -1
-end
-
-function Action:ACTIONBAR_UPDATE_STATE()
-  self:UpdateCheckedState()
-end
-
-function Action:TRADE_SKILL_SHOW()
-  self:UpdateCheckedState()
-end
-Action.TRADE_SKILL_CLOSE = Action.TRADE_SKILL_CLOSE
-
-function Action:UNIT_ENTERED_VEHICLE(event,unit)
-  if unit == "player" then
-    self:UpdateCheckedState()
-  end
-end
-Action.UNIT_EXITED_VEHICLE = Action.UNIT_ENTERED_VEHICLE
-
-function Action:COMPANION_UPDATE(event,unit)
-  if unit == "mount" then
-    self:UpdateCheckedState()
-  end
-end
-
-function Action:ACTIONBAR_UPDATE_USABLE()
-  self:UpdateUsable()
-end
-
-function Action:ACTIONBAR_UPDATE_COOLDOWN()
-  self:UpdateCooldown()
-end
-
-function Action:PLAYER_ENTER_COMBAT()
-  if IsAttackAction(self.actionID) then
-    self:SetFlash(true)
-  end
-end
-
-function Action:PLAYER_LEAVE_COMBAT()
-  if IsAttackAction(self.actionID) then
-    self:SetFlash(false)
-  end
-end
-
-function Action:START_AUTOREPEAT_SPELL()
-  if IsAutoRepeatAction(self.actionID) then
-    self:SetFlash(true)
-  end
-end
-
-function Action:STOP_AUTOREPEAT_SPELL()
-  if not IsAttackAction(self.actionID) then
-    self:SetFlash(false)
-  end
-end
-
-function Action:UNIT_INVENTORY_CHANGED(unit)
-  if unit == "player" then
-    self:UpdateTooltip()
-  end
-end
-
-function Action:LEARNED_SPELL_IN_TAB()
-  self:UpdateTooltip()
-end
--- a/classes/BagButton.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,439 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local GetCVar = GetCVar
-local ContainerIDToInventoryID = ContainerIDToInventoryID
-local NUM_CONTAINER_FRAMES = NUM_CONTAINER_FRAMES
-local IsModifiedClick = IsModifiedClick
-local CursorHasItem = CursorHasItem
-local GetInventoryItemTexture = GetInventoryItemTexture
-local GetInventorySlotInfo = GetInventorySlotInfo
-local PickupBagFromSlot = PickupBagFromSlot
-local CursorCanGoInSlot = CursorCanGoInSlot
-
--- class declarations
-local Super    = ReAction.Button
-local BagBase  = setmetatable( { }, { __index = Super } )
-local Bag      = setmetatable( { }, { __index = BagBase } )
-local Backpack = setmetatable( { }, { __index = BagBase } )
-local Keyring  = setmetatable( { }, { __index = BagBase } )
-
-ReAction.Button.Bag = BagBase
-
---
--- Bag Button base class
---
-
-function BagBase:New( idx, moduleConfig, bar, idHint )
-  local name = format("ReAction_%s_Bag_%d",bar:GetName(),idx)
-
-  -- use a variable private leaf implementation class
-  -- unlike traditional OO programming, we can initialize the leaf
-  -- class before initializing its derived class
-  local class = Bag
-  if idx == 1 then
-    class = Backpack
-  elseif idx == 6 then
-    class = Keyring
-  end
-  self = class:New(name,moduleConfig.buttons[bar:GetName()][idx], bar, idx)
-  self.moduleConfig = moduleConfig
-
-  local f = self:GetFrame()
-  local config = self:GetConfig()
-
-  -- set up the bag ID pool
-  self:SetActionIDPool("bag",6)
-  config.bagID = self:AcquireActionID(config.bagID, idHint, true)
-
-  -- non secure scripts
-  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
-  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
-  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
-  f:SetScript("OnReceiveDrag", function(frame, ...) self:OnReceiveDrag(...) end)
-  f:SetScript("OnClick", function(frame, ...) self:OnClick(...) end)
-
-  -- secure handlers
-  -- (none)
-
-  -- event registration
-  f:EnableMouse(true)
-  f:RegisterForClicks("LeftButtonUp","RightButtonUp")
-  f:RegisterEvent("UPDATE_BINDINGS")
-
-  -- frame setup
-  f:SetID(self:GetBagID())
-
-  if not f.hotkey then
-    local h = f:CreateFontString(name.."HotKey","ARTWORK","NumberFontNormalSmallGray")
-    h:SetWidth(30)
-    h:SetHeight(10)
-    h:SetJustifyH("RIGHT")
-    h:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2)
-    h:Show()
-    f.hotkey = h
-  end
-
-  if not _G[name.."ItemAnim"] then
-    local anim = CreateFrame("Model",name.."ItemAnim",f,"ItemAnimTemplate")
-    anim:SetPoint("BOTTOMRIGHT",f,"BOTTOMRIGHT",-10,0)
-    anim:Hide()
-  end
-
-  if not f.border then
-    local b = f:CreateTexture(name.."Border","OVERLAY")
-    b:SetAllPoints()
-    b:SetWidth(f:GetWidth()*(62/36))
-    b:SetHeight(f:GetHeight()*(62/36))
-    b:SetTexture("Interface\\Buttons\UI-ActionButton-Border")
-    b:SetBlendMode("ADD")
-    b:Hide()
-    f.border = b
-  end
-
-  self.frames.count:SetDrawLayer("ARTWORK")
-
-  self.frames.hotkey = f.hotkey
-  self.frames.border = _G[name.."Border"]
-  self.frames.icon = _G[name.."IconTexture"]
-  self.frames.anim = _G[name.."ItemAnim"]
-
-  -- initial display
-  if ReAction:GetConfigMode() then
-    self:GetFrame():Show()
-  end
-
-  self:Refresh()
-
-  return self
-end
-
-function BagBase:GetModuleConfig()
-  -- this is the Bag module config structure,
-  -- not the config structure of the bar itself
-  return self.moduleConfig
-end
-
-function BagBase:GetActionID()
-  return self.config.bagID
-end
-
-function BagBase:GetBagID()
-  return self:GetActionID() - 1
-end
-
-function BagBase:Refresh()
-  Super.Refresh(self)
-  self:UpdateHotkey()
-  self:Update()
-end
-
-function BagBase:Update()
-  self:UpdateChecked()
-end
-
-function BagBase:UpdateChecked(force)
-  if force == nil then
-    for i=1, NUM_CONTAINER_FRAMES do
-      local c = _G["ContainerFrame"..i]
-      if c:GetID() == self:GetBagID() and c:IsShown() then
-        self:GetFrame():SetChecked(1)
-        return
-      end
-    end
-    self:GetFrame():SetChecked(0)
-  end
-  self:GetFrame():SetChecked(force)
-end
-
-function BagBase:OnEvent(evt, ...)
-  if self[evt] then
-    self[evt](self, ...)
-  end
-end
-
-function BagBase:OnEnter()
-  self:SetTooltip()
-end
-
-function BagBase:OnLeave()
-  GameTooltip:Hide()
-end
-
-function BagBase:UPDATE_BINDINGS()
-  self:UpdateHotkey()
-end
-
-
---
--- Bag Button class
---
-function Bag:New(name, cfg, bar, idx)
-  self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
-
-  local f = self:GetFrame()
-
-  f:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight")
-
-  f:RegisterEvent("CURSOR_UPDATE")
-  f:RegisterEvent("BAG_UPDATE")
-  f:RegisterEvent("BAG_CLOSED")
-  f:SetScript("OnDragStart", function(frame, ...) self:OnDragStart(...) end)
-  f:RegisterForDrag("LeftButton")
-
-  -- attach to skinner
-  bar:SkinButton(self,
-    {
-      Icon = _G[name.."IconTexture"]
-    }
-  )
-
-  return self
-end
-
-function Bag:GetInventorySlot()
-  return ContainerIDToInventoryID(self:GetBagID())
-end
-
-function Bag:GetInventorySlotName()
-  return "Bag"..(self:GetBagID()-1).."Slot"
-end
-
-function Bag:SetTooltip()
-  GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_LEFT")
-  if not GameTooltip:SetInventoryItem("player", self:GetInventorySlot()) then
-    GameTooltip:SetText(EQUIP_CONTAINER, 1.0, 1.0, 1.0)
-  end
-end
-
-function Bag:Update()
-	local texture = GetInventoryItemTexture("player", self:GetInventorySlot())
-	if texture then
-    self.frames.icon:SetTexture(texture)
-    self.frames.icon:Show()
-    self:GetFrame():SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
-	else
-    local _, bgTex = GetInventorySlotInfo(self:GetInventorySlotName())
-    self.frames.icon:SetTexture(bgTex)
-    self:GetFrame():SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
-	end
-  self:UpdateChecked()
-end
-
-function Bag:OnClick()
-  if IsModifiedClick("OPENALLBAGS") then
-    OpenAllBags()
-  else
-    if not PutItemInBag(self:GetInventorySlot()) then
-      ToggleBag(self:GetBagID())
-    end
-  end
-  self:UpdateChecked()
-end
-
-function Bag:OnReceiveDrag()
-  if CursorHasItem() then
-    PutItemInBag(self:GetInventorySlot())
-  end
-end
-
-function Bag:OnDragStart()
-  PickupBagFromSlot(self:GetInventorySlot())
-  self:Update()
-end
-
-function Bag:BAG_UPDATE(bag)
-  if bag == self:GetBagID() then
-    self:Update()
-  end
-end
-
-function Bag:CURSOR_UPDATE()
-  if CursorCanGoInSlot(self:GetInventorySlot()) then
-    self:GetFrame():LockHighlight()
-  else
-    self:GetFrame():UnlockHighlight()
-  end
-end
-
-function Bag:BAG_CLOSED(bag)
-  if bag == self:GetBagID() then
-    self:Update()
-  end
-end
-
-
---
--- Backpack Button class
---
-function Backpack:New(name, cfg, bar, idx)
-  self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
-
-  local f = self:GetFrame()
-  local icon = _G[name.."IconTexture"]
-  icon:SetTexture("Interface\\Buttons\\Button-Backpack-Up")
-  icon:Show()
-  f:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight")
-  f:RegisterEvent("PLAYER_ENTERING_WORLD");
-  f:RegisterEvent("CVAR_UPDATE");
-  f:SetScript("OnShow", function(frame, ...) self:OnShow(...) end)
-
-  -- attach to skinner
-  bar:SkinButton(self,
-    {
-      Icon = _G[name.."IconTexture"]
-    }
-  )
-
-  return self
-end
-
-function Backpack:Update()
-  self:UpdateFreeSlots()
-  self:UpdateChecked()
-end
-
-function Backpack:UpdateFreeSlots()
-  if GetCVar("displayFreeBagSlots") == "1" then
-    local total = 0
-    for i = BACKPACK_CONTAINER, NUM_BAG_SLOTS do
-      local free, family = GetContainerNumFreeSlots(i)
-      if family == 0 then
-        total = total + free
-      end
-    end
-
-    self.freeSlots = total
-    self.frames.count:SetText(format("(%s)", self.freeSlots))
-    self.frames.count:Show()
-  elseif self.frames.count:IsShown() then
-    self.frames.count:Hide()
-  end
-end
-
-function Backpack:SetTooltip()
-  GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_LEFT")
-  GameTooltip:SetText(BACKPACK_TOOLTIP, 1.0, 1.0, 1.0)
-  GameTooltip:AddLine(string.format(NUM_FREE_SLOTS, (self.freeSlots or 0)))
-  GameTooltip:Show();
-end
-
-function Backpack:OnShow()
-  self:UpdateFreeSlots()
-end
-
-function Backpack:OnClick()
-  if IsModifiedClick("OPENALLBAGS") then
-    OpenAllBags()
-  else
-    if not PutItemInBackpack() then
-      ToggleBackpack()
-    end
-  end
-  self:UpdateChecked()
-end
-
-function Backpack:OnReceiveDrag()
-  if CursorHasItem() then
-    PutItemInBackpack()
-  end
-end
-
-function Backpack:PLAYER_ENTERING_WORLD()
-  self:CVAR_UPDATE("DISPLAY_FREE_BAG_SLOTS", GetCVar("displayFreeBagSlots"))
-end
-
-function Backpack:CVAR_UPDATE( cvar, value )
-  if cvar == "DISPLAY_FREE_BAG_SLOTS" then
-    if value == "1" then
-      self:GetFrame():RegisterEvent("BAG_UPDATE")
-    else
-      self:GetFrame():UnregisterEvent("BAG_UPDATE")
-    end
-    self:UpdateFreeSlots()
-  end
-end
-
-function Backpack:BAG_UPDATE(bag)
-  if bag >= BACKPACK_CONTAINER and bag <= NUM_BAG_SLOTS then
-    self:UpdateFreeSlots()
-  end
-end
-
-
---
--- Keyring Button class
---
-function Keyring:New(name, cfg, bar, idx)
-  self = Super.New(self, name, cfg, bar, idx, "ItemButtonTemplate" )
-
-  local f = self:GetFrame()
-
-  f:SetWidth(18)
-  f:SetHeight(39)
-
-  local tex = f:GetNormalTexture()
-  tex:ClearAllPoints()
-  tex:SetAllPoints()
-  
-  f:SetNormalTexture("Interface\\Buttons\\UI-Button-KeyRing")
-  f:SetHighlightTexture("Interface\\Buttons\\UI-Button-KeyRing-Highlight")
-  f:SetPushedTexture("Interface\\Buttons\\UI-Button-KeyRing-Down")
-  f:GetNormalTexture():SetTexCoord(0,0.5625,0,0.609375)
-  f:GetHighlightTexture():SetTexCoord(0,0.5625,0,0.609375)
-  f:GetPushedTexture():SetTexCoord(0,0.5625,0,0.609375)
-
-  if not HasKey() then
-    f:Hide()
-  end
-
-  -- DO NOT attach to skinner
-
-  return self
-end
-
-function Keyring:GetBagID()
-  return KEYRING_CONTAINER
-end
-
-function Keyring:Refresh()
-  local f = self:GetFrame()
-  self.bar:PlaceButton( self, f:GetHeight(), f:GetHeight() ) -- use height x height since it's an odd size
-  self:UpdateHotkey()
-  self:Update()
-end
-
-function Keyring:SetTooltip()
-  GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_RIGHT");
-  GameTooltip:SetText(KEYRING, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
-  GameTooltip:AddLine();
-end
-
-function Keyring:OnReceiveDrag()
-  if CursorHasItem() then
-    PutKeyInKeyRing()
-  end
-end
-
-function Keyring:OnClick()
-  if CursorHasItem() then
-    PutKeyInKeyRing()
-  else
-    ToggleKeyRing()
-  end
-  self:UpdateChecked()
-end
-
-function Keyring:ShowGridTemp(show)
-  if not HasKey() then
-    if show then 
-      self:GetFrame():Show()
-    else
-      self:GetFrame():Hide()
-    end
-  end
-end
-
--- a/classes/Bar.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,826 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local LKB = ReAction.LKB
-local _G = _G
-local CreateFrame = CreateFrame
-local floor = math.floor
-local fmod = math.fmod
-local format = string.format
-
-local LSG = LibStub("ReAction-LibShowActionGrid-1.0")
-
----- Secure snippets ----
-local _reaction_init = 
-[[
-  anchorKeys = newtable("point","relPoint","x","y")
-
-  state = nil
-  set_state = nil
-  state_override = nil
-  unit_exists = nil
-
-  showAll = false
-  hidden = false
-
-  defaultAlpha = 1.0
-  defaultScale = 1.0
-  defaultAnchor = newtable()
-
-  activeStates = newtable()
-  settings = newtable()
-  extensions = newtable()
-]]
-
-local _reaction_refresh = 
-[[
-  local oldState = state
-  state = state_override or set_state or state
-
-  local hide = nil
-  if state then
-    local settings = settings[state]
-    if settings then
-      -- show/hide
-      hide = settings.hide
-      -- re-anchor
-      local old_anchor = activeStates.anchor
-      activeStates.anchor = settings.anchorEnable and state
-      if old_anchor ~= activeStates.anchor or not set_state then
-        if activeStates.anchor then
-          if settings.anchorPoint then
-            self:ClearAllPoints()
-            local f = self:GetAttribute("frameref-anchor-"..state)
-            if f then
-              self:SetPoint(settings.anchorPoint, f, settings.anchorRelPoint, settings.anchorX, settings.anchorY)
-            end
-          end
-        elseif defaultAnchor.point then
-          self:ClearAllPoints()
-          self:SetPoint(defaultAnchor.point, defaultAnchor.frame, 
-                        defaultAnchor.relPoint, defaultAnchor.x, defaultAnchor.y)
-        end
-      end
-      -- re-scale
-      local old_scale = activeStates.scale
-      activeStates.scale = settings.enableScale and state
-      if old_scale ~= activeStates.scale or not set_state then
-        self:SetScale(activeStates.scale and settings.scale or defaultScale)
-      end
-      -- alpha
-      local old_alpha = activeStates.alpha
-      activeStates.alpha = settings.enableAlpha and state
-      if old_alpha ~= activeStates.alpha or not set_state then
-        self:SetAlpha(activeStates.alpha and settings.alpha or defaultAlpha)
-      end
-    end
-  end
-
-  -- hide if state or unit_exists says to
-  hide = not showAll and (hide or unithide)
-  if hide ~= hidden then
-    hidden = hide
-    if hide then
-      self:Hide()
-    else
-      self:Show()
-    end
-  end
-
-  for _, attr in pairs(extensions) do
-    control:RunAttribute(attr)
-  end
-  
-  control:ChildUpdate()
-
-  if showAll then
-    control:CallMethod("UpdateHiddenLabel", state and settings[state] and settings[state].hide)
-  end
-
-  if oldState ~= state then
-    control:CallMethod("StateRefresh", state)
-  end
-]]
-
-local _onstate_reaction = -- function( self, stateid, newstate )
-[[
-  set_state = newstate
-]] .. _reaction_refresh
-
-local _onstate_showgrid = -- function( self, stateid, newstate )
-[[
-  control:ChildUpdate(stateid,newstate)
-  control:CallMethod("UpdateShowGrid")
-]]
-
-local _onstate_unitexists = -- function( self, stateid, newstate )
-[[
-  unithide = not newstate or newstate == "hide"
-]] .. _reaction_refresh
-
-local _onclick =  -- function( self, button, down )
-[[
-  if state_override == button then
-    state_override = nil -- toggle
-  else
-    state_override = button
-  end
-]] .. _reaction_refresh
-
--- For reference
--- the option field names must match the field names of the options table, below
-local stateProperties = { 
-  hide = true,
-  --keybindState = true, TODO: broken
-  anchorEnable = true,
-  anchorFrame = true,
-  anchorPoint = true,
-  anchorRelPoint = true,
-  anchorX = true,
-  anchorY = true,
-  enableScale = true,
-  scale = true,
-  enableAlpha = true,
-  alpha = true,
-}
-
-
----- Utility functions ----
-
--- 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
-
-
----- Bar class ----
-local Bar   = { }
-local weak  = { __mode = "k" }
-local frameList = { }
-
-ReAction.Bar = Bar -- export to ReAction
-
-function Bar:New( name, config )
-  if type(config) ~= "table" then
-    error("ReAction.Bar: config table required")
-  end
-
-  -- create new self
-  self = setmetatable( 
-    { 
-      config  = config,
-      name    = name,
-      buttons = setmetatable( { }, weak ),
-      width   = config.width or 480,
-      height  = config.height or 40,
-    }, 
-    {__index = self} )
-  
-  -- The frame type is 'Button' in order to have an OnClick handler. However, the frame itself is
-  -- not mouse-clickable by the user.
-  local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent
-  name = name and "ReAction-"..name
-  local f = name and frameList[name]
-  if not f then
-    f = CreateFrame("Button", name, parent, "SecureHandlerStateTemplate, SecureHandlerClickTemplate")
-    if name then
-      frameList[name] = f
-    end
-  end
-  f:SetFrameStrata("MEDIUM")
-  f:SetWidth(self.width)
-  f:SetHeight(self.height)
-  f:SetAlpha(config.alpha or 1.0)
-  f:Show()
-  f:EnableMouse(false)
-  f:SetClampedToScreen(true)
-  LSG:AddFrame(f)
-
-  -- secure handlers
-  f:Execute(_reaction_init)
-  f:SetAttribute("_onstate-reaction",   _onstate_reaction)
-  f:SetAttribute("_onstate-showgrid",   _onstate_showgrid)
-  f:SetAttribute("_onstate-unitexists", _onstate_unitexists)
-  f:SetAttribute("_onclick",            _onclick)
-
-  -- secure handler CallMethod()s
-  f.UpdateShowGrid    = function() self:UpdateShowGrid() end
-  f.StateRefresh      = function() self:RefreshControls() end
-  f.UpdateHiddenLabel = function(f,hidden) self:SetLabelSubtext(hidden and L["Hidden"]) end
-
-  -- Override the default frame accessor to provide strict read-only access
-  function self:GetFrame()
-    return f
-  end
-
-  self:ApplyAnchor()
-  self:SetConfigMode(ReAction:GetConfigMode())
-  self:SetKeybindMode(ReAction:GetKeybindMode())
-
-  ReAction.RegisterCallback(self, "OnConfigModeChanged")
-
-  return self
-end
-
-function Bar:Destroy()
-  local f = self:GetFrame()
-  f:UnregisterAllEvents()
-  self:ShowControls(false)
-  ReAction.UnregisterAllCallbacks(self)
-  LKB.UnregisterAllCallbacks(self)
-  LSG:RemoveFrame(f)
-  f:SetParent(UIParent)
-  f:ClearAllPoints()
-  f:Hide()
-end
-
---
--- Events
---
-
-function Bar:OnConfigModeChanged(event, mode)
-  self:SetConfigMode(mode)
-end
-
---
--- Accessors
---
-
-function Bar:GetName()
-  return self.name
-end
-
--- only ReAction:RenameBar() should call this function. Calling from any other
--- context will desync the bar list in the ReAction class.
-function Bar:SetName(name)
-  self.name = name
-  if self.overlay then
-    self.overlay:SetLabel(self.name)
-  end
-end
-
-function Bar:GetFrame()
-  -- this method is included for documentation purposes. It is overridden
-  -- for each object in the :New() method.
-  error("Invalid Bar object: used without initialization")
-end
-
-function Bar:GetConfig()
-  return self.config
-end
-
-function Bar:GetAnchor()
-  local c = self.config
-  return (c.point or "CENTER"), 
-         (c.anchor or self:GetFrame():GetParent():GetName()), 
-         (c.relpoint or c.point or "CENTER"), 
-         (c.x or 0), 
-         (c.y or 0)
-end
-
-function Bar:SetAnchor(point, frame, relativePoint, x, y)
-  local c = self.config
-  c.point = point or c.point
-  c.anchor = frame or c.anchor
-  c.relpoint = relativePoint or c.relpoint
-  c.x = x or c.x
-  c.y = y or c.y
-  self:ApplyAnchor()
-  ReAction:RefreshBar(self)
-end
-
-function Bar:GetSize()
-  local f = self:GetFrame()
-  return f:GetWidth(), f:GetHeight()
-end
-
-function Bar:SetSize(w,h)
-  local f = self:GetFrame()
-  self.config.width = w
-  self.config.height = h
-  f:SetWidth(w)
-  f:SetHeight(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
-  ReAction:RefreshBar(self)
-end
-
-function Bar:GetNumButtons()
-  local r,c = self:GetButtonGrid()
-  return r*c
-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
-  ReAction:RefreshBar(self)
-end
-
-function Bar:GetAlpha()
-  return self.config.alpha or 1.0
-end
-
-function Bar:SetAlpha(value)
-  self.config.alpha = value
-  self:GetFrame():SetAlpha(value or 1.0)
-  self:UpdateDefaultStateAlpha()
-  ReAction:RefreshBar(self)
-end
-
-function Bar:IterateButtons()
-  -- iterator returns button, idx and does NOT iterate in index order
-  return pairs(self.buttons)
-end
-
---
--- Methods
---
-
-function Bar:SetConfigMode(mode)
-  self:SetSecureData("showAll",mode)
-  self:ShowControls(mode)
-  for b in self:IterateButtons() do
-    b:ShowGridTemp(mode)
-    b:UpdateActionIDLabel(mode)
-  end
-end
-
-function Bar:SetKeybindMode(mode)
-  self:SetSecureData("showAll",mode)
-  for b in self:IterateButtons() do
-    b:SetKeybindMode(mode)
-  end
-end
-
-function Bar:ApplyAnchor()
-  local f = self:GetFrame()
-  local c = self.config
-  local p = c.point
-
-  f:SetWidth(c.width)
-  f:SetHeight(c.height)
-  f:ClearAllPoints()
-  
-  if p then
-    local a = f:GetParent()
-    if c.anchor then
-      local bar = ReAction:GetBar(c.anchor)
-      if bar then
-        a = bar:GetFrame()
-      else
-        a = _G[c.anchor]
-      end
-    end
-    local fr = a or f:GetParent()
-    f:SetPoint(p, a or f:GetParent(), c.relpoint, c.x or 0, c.y or 0)
-  else
-    f:SetPoint("CENTER")
-  end
-
-  self:UpdateDefaultStateAnchor()
-end
-
-function Bar:ClipNButtons( n )
-  local cfg = self.config
-  local r = cfg.btnRows or 1
-  local c = cfg.btnColumns or 1
-
-  cfg.btnRows = ceil(n/c)
-  cfg.btnColumns = min(n,c)
-end
-
-function Bar:AddButton(idx, button)
-  local f = self:GetFrame()
-
-  -- store in a weak reverse-index array
-  self.buttons[button] = idx
-
-  -- Store a properly wrapped reference to the child frame as an attribute 
-  -- (accessible via "frameref-btn#")
-  f:SetFrameRef(format("btn%d",idx), button:GetFrame())
-end
-
-function Bar:RemoveButton(button)
-  local idx = self.buttons[button]
-  if idx then
-    self:GetFrame():SetAttribute(format("frameref-btn%d",idx),nil)
-    self.buttons[button] = nil
-  end
-end
-
-function Bar:PlaceButton(button, baseW, baseH)
-  local idx = self.buttons[button]
-  if idx then 
-    local r, c, s = self:GetButtonGrid()
-    local bh, bw = self:GetButtonSize()
-    local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based
-    local x, y = col*bw + (col+0.5)*s, -(row*bh + (row+0.5)*s)
-    local scale = bw/baseW
-    local b = button:GetFrame()
-
-    b:ClearAllPoints()
-    b:SetPoint("TOPLEFT",x/scale,y/scale)
-    b:SetScale(scale)
-  end
-end
-
-function Bar:SkinButton()
-  -- does nothing by default
-end
-
-function Bar:UpdateShowGrid()
-  for button in self:IterateButtons() do
-    button:UpdateShowGrid()
-  end
-end
-
-function Bar:ShowControls(show)
-  if show then
-    if not self.overlay then
-      self.overlay = Bar.Overlay:New(self) -- see Overlay.lua
-    end
-    self.overlay:Show()
-    self:RefreshSecureState()
-  elseif self.overlay then
-    self.overlay:Hide()
-  end
-end
-
-function Bar:RefreshControls()
-  if self.overlay and self.overlay:IsShown() then
-    self.overlay:RefreshControls()
-  end
-end
-
-function Bar:SetLabelSubtext(text)
-  if self.overlay then 
-    self.overlay:SetLabelSubtext(text) 
-  end
-end
-
---
--- Secure state functions
---
-
-function Bar:GetSecureState()
-  local env = GetManagedEnvironment(self:GetFrame())
-  return env and env.state
-end
-
-function Bar:GetStateProperty(state, propname)
-  -- override in modules/State.lua for now
-end
-
-function Bar:SetStateProperty(state, propname, value)
-  -- override in modules/State.lua for now
-end
-
-function Bar:RefreshSecureState()
-  self:GetFrame():Execute(_reaction_refresh)
-end
-
--- usage: SetSecureData(globalname, [tblkey1, tblkey2, ...], value)
-function Bar:SetSecureData( ... )
-  local n = select('#',...)
-  if n < 2 then
-    error("ReAction.Bar:SetSecureData() requires at least 2 arguments")
-  end
-  local f = self:GetFrame()
-  f:SetAttribute("data-depth",n-1)
-  f:SetAttribute("data-value",select(n,...))
-  for i = 1, n-1 do
-    local key = select(i,...)
-    if key == nil then
-      error("ReAction.Bar:SetSecureData() - nil table key in argument list (#"..i..")")
-    end
-    f:SetAttribute("data-key-"..i, key)
-  end
-  f:Execute(
-    [[
-      local n = self:GetAttribute("data-depth")
-      if n > 0 then
-        local value = self:GetAttribute("data-value")
-        local t = _G
-        for i = 1, n do
-          local key = self:GetAttribute("data-key-"..i)
-          if not key then return end
-          if not t[key] then
-            t[key] = newtable()
-          end
-          if i == n then
-            t[key] = value
-          else
-            t = t[key]
-          end
-        end
-      end
-    ]])
-  self:RefreshSecureState()
-end
-
-function Bar:SetSecureStateData( state, key, value )
-  self:SetSecureData("settings",state,key,value)
-end
-
--- sets a snippet to be run as an extension to _onstate-reaction
-function Bar:SetSecureStateExtension( id, snippet )
-  if id == nil then
-    error("ReAction.Bar:SetSecureStateExtension() requires an id")
-  end
-  local f = self:GetFrame()
-  f:SetAttribute("input-secure-ext-id",id)
-  f:SetAttribute("secure-ext-"..id,snippet)
-  f:Execute(
-    [[
-      local id = self:GetAttribute("input-secure-ext-id")
-      if id then
-        extensions[id] = self:GetAttribute("secure-ext-"..id) or nil
-      end
-    ]])
-  self:RefreshSecureState()
-end
-
-function Bar:SetFrameRef( name, refFrame )
-  if refFrame then
-    local _, explicit = refFrame:IsProtected()
-    if not explicit then
-      refFrame = nil
-    end
-  end
-  if refFrame then
-    self:GetFrame():SetFrameRef(name,refFrame)
-  else
-    self:GetFrame():SetAttribute("frameref-"..name,nil)
-  end
-end
-
-function Bar:SetStateDriver( states )
-  if states then
-    for state, props in pairs(states) do
-      self:SetSecureStateData(state, "active_", true) -- make sure there's a 'settings' field for this state
-      for propname, value in pairs(props) do
-        if propname == "anchorFrame" then
-          self:SetFrameRef("anchor-"..state, _G[value])
-        elseif propname == "rule" then
-          -- do nothing
-        else
-          self:SetSecureStateData(state, propname, value)
-        end
-      end
-    end
-  end
-  local rule = states and self:BuildStateRule(states)
-  if rule then
-    RegisterStateDriver(self:GetFrame(),"reaction",rule)
-  elseif self.statedriver then
-    UnregisterStateDriver(self:GetFrame(),"reaction")
-  end
-  self.statedriver = rule
-  self:BuildStateKeybinds(states)
-  self:RefreshSecureState()
-end
-
--- pass unit=nil to set up the unit elsewhere, if you want something more complex
-function Bar:RegisterUnitWatch( unit, enable )
-  local f = self:GetFrame()
-  if unit then
-    f:SetAttribute("unit",unit)
-  end
-  if enable then
-    RegisterUnitWatch(self:GetFrame(),true)
-  elseif self.unitwatch then
-    UnregisterUnitWatch(self:GetFrame())
-  end
-  self.unitwatch = enable
-  self:RefreshSecureState()
-end
-
-function Bar:SetStateKeybind( key, state )
-  local f = self:GetFrame()
-  local binds = self.statebinds
-  if not binds then
-    binds = { }
-    self.statebinds = binds
-  end
-
-  -- clear the old binding, if any
-  if binds[state] then
-    SetOverrideBinding(f, false, binds[state], nil)
-  end
-
-  if key then
-    SetOverrideBindingClick(f, false, key, f:GetName(), state) -- state name is virtual mouse button
-  end
-  binds[state] = key
-end
-
-function Bar:GetStateKeybind( state )
-  if self.statebinds and state then
-    return self.statebinds[state]
-  end
-end
-
-function Bar:UpdateDefaultStateAnchor()
-  local point, frame, relPoint, x, y = self:GetAnchor()
-  local f = self:GetFrame()
-  f:SetAttribute("defaultAnchor-point",point)
-  f:SetAttribute("defaultAnchor-relPoint",relPoint)
-  f:SetAttribute("defaultAnchor-x",x)
-  f:SetAttribute("defaultAnchor-y",y)
-  self:SetFrameRef("defaultAnchor",_G[frame or "UIParent"])
-  f:Execute([[
-    for _, k in pairs(anchorKeys) do
-      defaultAnchor[k] = self:GetAttribute("defaultAnchor-"..k)
-    end
-    defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor")
-  ]])
-end
-
-function Bar:UpdateDefaultStateAlpha()
-  local f = self:GetFrame()
-  f:SetAttribute("defaultAlpha",self:GetAlpha())
-  f:Execute([[
-    defaultAlpha = self:GetAttribute("defaultAlpha")
-  ]])
-end
-
----- secure state driver rules ----
-
-local playerClass = select(2, UnitClass("player"))
-local function ClassFilter(...)
-  for i = 1, select('#',...) do
-    if playerClass == select(i,...) then
-      return false
-    end
-  end
-  return true
-end
-
-local ruleformats = { 
-  stealth       = { format = "stealth",        filter = ClassFilter("ROGUE","DRUID") },
-  nostealth     = { format = "nostealth",      filter = ClassFilter("ROGUE","DRUID") },
-  shadowdance   = { format = "bonusbar:2",     filter = ClassFilter("ROGUE") },
-  shadowform    = { format = "form:1",         filter = ClassFilter("PRIEST") },
-  noshadowform  = { format = "noform",         filter = ClassFilter("PRIEST") },
-  battle        = { format = "stance:1",       filter = ClassFilter("WARRIOR") },
-  defensive     = { format = "stance:2",       filter = ClassFilter("WARRIOR") },
-  berserker     = { format = "stance:3",       filter = ClassFilter("WARRIOR") },
-  caster        = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") },
-  bear          = { format = "form:1",         filter = ClassFilter("DRUID") },
-  cat           = { format = "form:3",         filter = ClassFilter("DRUID") },
-  tree          = { format = "form:5",         filter = ClassFilter("DRUID") },
-  moonkin       = { format = "form:5",         filter = ClassFilter("DRUID") },
-  demon         = { format = "form:2",         filter = ClassFilter("WARLOCK") },
-  nodemon       = { format = "noform",         filter = ClassFilter("WARLOCK") },
-  pet           = { format = "pet" },
-  nopet         = { format = "nopet" },
-  harm          = { format = "@target,harm" },
-  help          = { format = "@target,help" },
-  notarget      = { format = "@target,noexists" },
-  focusharm     = { format = "@focus,harm" },
-  focushelp     = { format = "@focus,help" },
-  nofocus       = { format = "@focus,noexists" },
-  raid          = { format = "group:raid" },
-  party         = { format = "group:party" },
-  solo          = { format = "nogroup" },
-  combat        = { format = "combat" },
-  nocombat      = { format = "nocombat" },
-  possess       = { format = "@vehicle,noexists,bonusbar:5" },
-  vehicle       = { format = "@vehicle,exists,bonusbar:5" },
-}
-
-function Bar.InitRuleFormats()
-  local forms = { }
-  for i = 1, GetNumShapeshiftForms() do
-    local _, name = GetShapeshiftFormInfo(i)
-    forms[name] = i;
-  end
-    -- use 9 if not found since 9 is never a valid stance/form
-  local defensive = forms[GetSpellInfo(71)] or 9
-  local berserker = forms[GetSpellInfo(2458)] or 9
-  local bear      = forms[GetSpellInfo(5487)] or 9
-  local aquatic   = forms[GetSpellInfo(1066)] or 9
-  local cat       = forms[GetSpellInfo(768)] or 9
-  local travel    = forms[GetSpellInfo(783)] or 9
-  local tree      = forms[GetSpellInfo(33891)] or 9
-  local moonkin   = forms[GetSpellInfo(24858)] or 9
-  local flight    = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9
-
-  ruleformats.defensive.format = "stance:"..defensive
-  ruleformats.berserker.format = "stance:"..berserker
-  ruleformats.caster.format    = format("form:0/%d/%d/%d", aquatic, travel, flight)
-  ruleformats.bear.format      = "form:"..bear
-  ruleformats.cat.format       = "form:"..cat
-  ruleformats.tree.format      = "form:"..tree
-  ruleformats.moonkin.format   = "form:"..moonkin
-end
-
-function Bar:BuildStateRule(states)
-  -- states is a table :
-  --   states[statename].rule = {
-  --     order = #,
-  --     type = "default"/"custom"/"any"/"all",
-  --     values = { ... }, -- keys of ruleformats[]
-  --     custom = "...",
-  --   }
-  local rules = { }
-  local default
-
-  for idx, state in ipairs(fieldsort(states, "rule", "order")) do
-    local c = states[state].rule
-    local type = c.type
-    if type == "default" then
-      default = default or state
-    elseif type == "custom" then
-      if c.custom then
-        -- strip out all spaces from the custom rule
-        table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state))
-      end
-    elseif type == "any" or type == "all" then
-      if c.values then
-        local clauses = { }
-        for key, value in pairs(c.values) do
-          if ruleformats[key] and not ruleformats[key].filter then
-            table.insert(clauses, ruleformats[key].format)
-          end
-        end
-        if #clauses > 0 then
-          local sep = (type == "any") and "][" or ","
-          table.insert(rules, format("[%s] %s", table.concat(clauses,sep), state))
-        end
-      end
-    end
-  end
-  -- make sure that the default, if any, is last
-  if default then
-    table.insert(rules, default)
-  end
-  return table.concat(rules,";")
-end
-
-function Bar:BuildStateKeybinds( states )
-  if states then
-    for name, state in pairs(states) do
-      local rule = tfetch(state, "rule")
-      if rule and rule.type == "keybind" then
-        self:SetStateKeybind(rule.keybind, name)
-      else
-        self:SetStateKeybind(nil, name) -- this clears an existing keybind
-      end
-    end
-  end
-end
-
--- a/classes/Button.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,287 +0,0 @@
---[[
-  ReAction Button base class
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local LKB = ReAction.LKB
-local _G = _G
-local CreateFrame = CreateFrame
-local GetBindingKey = GetBindingKey
-local format = string.format
-
--- libraries
-local LBF = LibStub("LibButtonFacade",true) -- optional
-
--- private
-local trash = CreateFrame("Frame")
-local frameList = { }
-local idPools = { }
-
-local function kb_onEnter( frame )
-  LKB:Set(frame)
-end
-
--- Button class
-local Button = { } 
-
-ReAction.Button = Button -- export to ReAction
-
-function Button:New( name, config, bar, idx, inherits, buttonType )
-  buttonType = buttonType or "CheckButton"
-
-  -- create new self
-  self = setmetatable( 
-    { 
-      bar = bar,
-      idx = idx,
-      config = config,
-      name = name,
-    }, 
-    { __index = self } )
-
-  -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
-  -- existing globals. Can't set to nil in the global because it's then tainted.
-  -- Caller is responsible for ensuring global uniqueness of names.
-  local f = name and frameList[name]
-  if f then
-    f:SetParent(bar:GetFrame())
-  else
-    f = CreateFrame(buttonType, name, bar:GetFrame(), inherits)
-    if name then
-      frameList[name] = f
-    end
-  end
-
-  self.frame = f
-
-  local frames = { }
-  self.frames = frames
-  frames.icon          = _G[name.."Icon"]
-  frames.flash         = _G[name.."Flash"]
-  frames.hotkey        = _G[name.."HotKey"]
-  frames.count         = _G[name.."Count"]
-  frames.name          = _G[name.."Name"]
-  frames.border        = _G[name.."Border"]
-  frames.cooldown      = _G[name.."Cooldown"]
-  frames.normalTexture = _G[name.."NormalTexture"]
-
-  if config then
-    config.name = name
-  end
-
-  -- install LibKeyBound handlers onto frame
-  function f:GetActionName()
-    return format("%s:%s", bar:GetName(), idx)
-  end
-
-  local clickBinding = format("CLICK %s:LeftButton", name)
-  function f:GetHotkey()
-    return LKB:ToShortKey(GetBindingKey(clickBinding))
-  end
-
-  return self
-end
-
-function Button:Destroy()
-  local f = self:GetFrame()
-  f:UnregisterAllEvents()
-  self:ReleaseActionID(self:GetActionID())
-  if f then
-    f:Hide()
-    f:SetParent(trash)
-    f:ClearAllPoints()
-  end
-end
-
-function Button:GetBar()
-  return self.bar
-end
-
-function Button:GetFrame()
-  return self.frame
-end
-
-function Button:GetName()
-  return self.name
-end
-
-function Button:GetConfig()
-  return self.config
-end
-
-function Button:GetActionID()
-  -- derived classes should override this
-  return nil
-end
-
-function Button:SetActionIDPool( poolID, maxID )
-  self.actionPoolID = poolID
-  self.actionMaxID = maxID
-end
-
-function Button:AcquireActionID( id, hint, unique )
-  local poolID = self.actionPoolID
-  local maxID = self.actionMaxID
-  if not poolID or not maxID then
-    error("AcquireActionID: must setup pool first with SetActionIDPool")
-  end
-  local pool = idPools[poolID]
-  if not pool then
-    pool = { nWraps = 0, useCount = { } }
-    for i = 1, maxID do
-      pool.useCount[i] = 0
-    end
-    idPools[poolID] = pool
-  end
-  local useCount = pool.useCount
-  if id == nil then
-    repeat
-      local nWraps = pool.nWraps or 0
-      if hint and (useCount[hint] == nil or useCount[hint] == nWraps) then
-        id = hint
-      else
-        local start = hint or 1
-        for i = start, maxID do
-          if useCount[i] == nil or useCount[i] == nWraps then
-            id = i
-            break
-          end
-        end
-        if not id then
-          for i = 1, start do
-            if useCount[i] == nil or useCount[i] == nWraps then
-              id = i
-              break
-            end
-          end
-        end
-      end
-      if id == nil then
-        if unique then
-          return nil
-        end
-        pool.nWraps = nWraps + 1
-      end
-    until id ~= nil
-  end
-  useCount[id] = (useCount[id] or 0) + 1
-  return id
-end
-
-function Button:ReleaseActionID( id )
-  local poolID = self.actionPoolID
-  if not poolID  then
-    error("ReleaseActionID: must setup pool first with SetActionIDPool")
-  end
-  local pool = idPools[poolID]
-  if pool and id and pool.useCount[id] then
-    pool.useCount[id] = pool.useCount[id] - 1
-    pool.nWraps = min(pool.useCount[id], pool.nWraps)
-  end
-end
-
-function Button:Refresh()
-  local f = self:GetFrame()
-  self.bar:PlaceButton( self, f:GetWidth(), f:GetHeight() )
-end
-
-function Button:SetKeybindMode( mode )
-  local f = self.frame
-  if mode then
-    self.oldOnEnter = f:GetScript("OnEnter")
-    f:SetScript("OnEnter", kb_onEnter)
-  elseif self.oldOnEnter then
-    f:SetScript("OnEnter", self.oldOnEnter)
-    self.oldOnEnter = nil
-  end
-  self:ShowGridTemp(mode)
-  self:UpdateKeybindModeDisplay( mode )
-end
-
-function Button:UpdateKeybindModeDisplay( mode )
-  local border = self.frames.border or _G[format("%sBorder",tostring(self:GetName()))]
-  if border then
-    if mode then
-      border:SetVertexColor(LKB:GetColorKeyBoundMode())
-      border:Show()
-    else
-      border:Hide()
-    end
-  end
-end
-
-function Button:UpdateHotkey( hotkey )
-  hotkey = hotkey or self.frames.hotkey
-  if not hotkey then
-    hotkey = _G[self:GetName().."HotKey"]
-    self.frames.hotkey = hotkey
-  end
-  if hotkey then
-    local txt = self.frame:GetHotkey()
-    hotkey:SetText( txt )
-    if txt == nil or txt == "" then
-      hotkey:Hide()
-    else
-      hotkey:Show()
-    end
-  end
-end
-
-function Button:GetActionIDLabel( create )
-  local f = self:GetFrame()
-  if not f.actionIDLabel and create then
-    local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
-    label:SetAllPoints()
-    label:SetJustifyH("CENTER")
-    label:SetShadowColor(0,0,0,1)
-    label:SetShadowOffset(2,-2)
-    f.actionIDLabel = label -- store the label with the frame for recycling
-  end
-  return f.actionIDLabel
-end
-
-function Button:UpdateActionIDLabel( show )
-  local label = self:GetActionIDLabel( show )
-  if label then
-    if show then
-      local id = self:GetActionID()
-      if id then
-        label:SetText(tostring(id))
-        label:Show()
-        return
-      end
-    end
-    label:Hide()
-  end
-end
-
-function Button:SetNormalVertexColor( r, g, b, a )
-  if LBF then
-    LBF:SetNormalVertexColor(self:GetFrame(), r, g, b, a)
-  else
-    self:GetFrame():GetNormalTexture():SetVertexColor(r,g,b,a)
-  end
-end
-
-function Button:GetNormalVertexColor()
-  if LBF then
-    return LBF:GetNormalVertexColor(self:GetFrame())
-  else
-    return self:GetFrame():GetNormalTexture():GetVertexColor()
-  end
-end
-
-function Button:UpdateShowGrid()
- -- does nothing by default
-end
-
-function Button:ShowGridTemp(show)
-  -- does nothing by default
-end
-
-function Button:ShowGrid(show)
-  -- does nothing by default
-end
--- a/classes/MultiCastButton.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,744 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local unpack = unpack
-local GetCVar = GetCVar
-local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
-local CooldownFrame_SetTimer = CooldownFrame_SetTimer
-local InCombatLockdown = InCombatLockdown
-local IsUsableSpell = IsUsableSpell
-local IsUsableAction = IsUsableAction
-local IsSpellKnown = IsSpellKnown
-local IsSpellInRange = IsSpellInRange
-local IsActionInRange = IsActionInRange
-local GetSpellInfo = GetSpellInfo
-local GetSpellCooldown = GetSpellCooldown
-local GetActionCooldown = GetActionCooldown
-local GetSpellTexture = GetSpellTexture
-local GetActionTexture = GetActionTexture
-local GetMultiCastTotemSpells = GetMultiCastTotemSpells
-
---[[
-  Blizzard Constants:
-    - NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4
-    - NUM_MULTI_CAST_PAGES = 3
-    - SHAMAN_TOTEM_PRIORITIES = { } -- sets the order of the totems
-    - TOTEM_MULTI_CAST_SUMMON_SPELLS = { } -- list of summon spellIDs
-    - TOTEM_MULTI_CAST_RECALL_SPELLS = { } -- list of recall spellIDs
-
-  Blizzard Events:
-    - UPDATE_MULTI_CAST_ACTIONBAR
-
-  Blizzard APIs:
-    - GetMultiCastBarOffset() : returns 6
-
-    - SetMultiCastSpell(actionID, spellID) (protected) OR
-         SetAttribute("type","multispell")
-         SetAttribute("action",actionID)
-         SetAttribute("spell",spellID)
-
-         note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(),
-               so that's action ID 132-144.
-
-    - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot)
-        returns spellIDs for all known totems that fit that slot. This function is available in
-        the secure environment.
-
-  Blizzard textures:
-    All the textures for the multicast bar (arrows, empty-slot icons, etc) are part of a single
-    texture: each texture uses SetTexCoord() to display only a slice of the textures. I suppose
-    this is to slightly optimize texture load performance, but it makes the UI code more clumsy.
-
-    Each totem button and arrow has a colored border indicating its elemental type.
-
-    TODO: 
-      - make whether to show the colored border configurable (looks really bad with ButtonFacade:Zoomed)
-      - apply ButtonFacade to the flyout buttons? Or at least zoom the textures slightly?
-      - use a multiplier with SetTexCoord on totem bar texture?
-
-  Design Notes:
-    - Only the header has a secure context. All other frames execute in its context.
-
-    - Each button is either type "spell" (summon/recall) or type "action" (totem action IDs are 
-      GetBonusBarOffset()=6, 132-144) with 3 pages of 4 buttons. The paging is controlled by
-      the summon flyout, which is also paged with the summon spells (the recall button is not paged)
-    
-    - A spell list is updated in the secure context at setup time (TODO: redo setup when learning new 
-      spells) with the list of spells known for each slot.
-    
-    - Each button (except recall) has an arrow button which appears on mouseover and when clicked
-      opens the flyout via a wrapped OnClick handler. When the flyout is open, the arrow does not
-      appear.
-    
-    - A single flyout with N+1 (1 slot is to select no totem for the set) flyout-buttons is a child
-      of the bar. Each time the flyout panel is opened, the individual  buttons grab their corresponding
-      spell/type from the list, according to the slot which opened the flyout. Each button either sets
-      the current page (summon) or sets a multispell to an actionID via type="multispell". None of them
-      actually cast any spells (though, I suppose we could modify this so that e.g. configurable 
-      right-click casts the spell). The flyout also has a close button which closes the flyout: the
-      flyout-open code positions the close button anchored to the last button in the flyout (which 
-      changes dynamically because each slot has a different number of items in the list).
-
-    - Multicast sets are not stances, there's no need (or ability) to handle swapping sets if one of 
-      the summon spells is cast from elsewhere.
-
-    - The default UI has Call of the Elements always selected on UI load. This module remembers the last
-      selected one and restores it.
-
-
-]]--
-
-
---
--- Secure snippets
---
-
--- bar
-local _bar_init = -- function(self)
-[[
-  -- set up some globals in the secure environment
-  flyout               = self:GetFrameRef("flyout")
-  flyoutSlot           = nil
-  summonSlot           = self:GetAttribute("summonSlot")
-  recallSlot           = self:GetAttribute("recallSlot")
-  baseActionID         = self:GetAttribute("baseActionID")
-  slotsPerPage         = self:GetAttribute("slotsPerPage")
-  currentPage          = currentPage or self:GetAttribute("lastSummon") or 1
-
-  totemIDsBySlot = newtable()
-  for i = 1, slotsPerPage do
-    totemIDsBySlot[i] = self:GetAttribute("TOTEM_PRIORITY_"..i)
-  end
-
-  -- these are set up in bar:SetupBarHeader()
-  flyoutChildren = flyoutChildren or newtable()
-  summonSpells = summonSpells or newtable()
-]]
-
-local _onstate_multispellpage = -- function(self, stateid, newstate)
-[[
-  currentPage = tonumber(newstate)
-  control:CallMethod("UpdateLastSummon",currentPage)
-  control:ChildUpdate()
-]]
-
-
--- buttons
-local _childupdate = -- function(self, snippetid, message)
-[[
-  local t = self:GetAttribute("type")
-  self:SetAttribute(t, self:GetAttribute(t.."-page"..currentPage))
-]]
-
-local _onEnter = -- function(self)
-  -- for whatever reason, RegisterAutoHide is unreliable
-  -- unless you re-anchor the frame prior to calling it.
-  -- Even then, it's still not terribly reliable.
-[[
-  local slot = self:GetAttribute("bar-idx")
-  local arrow = owner:GetFrameRef("arrow-"..slot)
-  if arrow and not arrow:IsShown() and not (flyout:IsVisible() and flyoutSlot == slot) then
-    arrow:ClearAllPoints()
-    arrow:SetPoint("BOTTOM",self,"TOP",0,0)
-    arrow:Show()
-    arrow:RegisterAutoHide(0)
-    arrow:AddToAutoHide(self)
-  end
-]]
-
-
--- flyout arrow
-local _arrow_openFlyout = -- function(self)
-[[
-  local slot = self:GetAttribute("bar-idx")
-  local totemID = totemIDsBySlot[slot - (summonSlot or 0)]
-  if totemID == 0 then
-    totemID = "summon"
-  end
-
-  local lastButton, lastPage
-  for page, b in ipairs(flyoutChildren) do
-    b:Hide()
-    b:SetAttribute("totemSlot",totemID)
-    if slot == summonSlot then
-      local spellID = self:GetParent():GetAttribute("spell-page"..page)
-      if spellID then
-        b:SetAttribute("type","changePage")
-        b:SetAttribute("spell",spellID)
-        b:Show()
-        lastButton = b
-        lastPage = page
-      end
-    else
-      local spell = select(page, 0, GetMultiCastTotemSpells(totemID) )
-      if spell then
-        b:SetAttribute("type","multispell")
-        b:SetAttribute("action", baseActionID + (currentPage - 1)*slotsPerPage + totemID)
-        b:SetAttribute("spell", spell)
-        b:Show()
-        lastButton = b
-        lastPage = page
-      end
-    end
-  end
-
-  local close = owner:GetFrameRef("close")
-  if lastButton and close then
-    close:ClearAllPoints()
-    close:SetPoint("BOTTOM",lastButton,"TOP",0,0) -- TODO: better anchoring
-    close:Show()
-    control:CallMethod("UpdateFlyoutTextures",totemID)
-  end
-
-  flyout:ClearAllPoints()
-  flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0)  -- TODO: better anchoring
-  if lastPage then
-    flyout:SetHeight(lastPage * 27 + (close and close:GetHeight() or 0))
-  end
-  flyout:Show()
-  flyout:RegisterAutoHide(1) -- TODO: configurable
-  flyout:AddToAutoHide(owner)
-  flyoutSlot = slot
-  self:Hide()
-]]
-
-local _closeFlyout = -- function(self)
-[[
-  flyout:Hide()
-]]
-
-
--- flyout child buttons
-local _flyout_child_preClick = -- function(self, button, down)
-[[
-  local button = button
-  if self:GetAttribute("type") == "changePage" then
-    owner:SetAttribute("state-multispellpage",self:GetAttribute("index"))
-    self:GetParent():Hide()
-    return false
-  else
-    return nil, "close"
-  end
-]]
-
-local _flyout_child_postClick = -- function(self, message, button, down)
-[[
-  if message == "close" then
-    self:GetParent():Hide() -- hide flyout after selecting
-  end
-]]
-
-
---
--- The Blizzard totem bar textures are all actually one big texture,
--- with texcoord offsets. Shamelessly stolen from FrameXML/MultiCastActionBarFrame.lua
---
-local TOTEM_TEXTURE = "Interface\\Buttons\\UI-TotemBar"
-local FLYOUT_UP_BUTTON_HL_TCOORDS   = { 72/128,  92/128, 88/256,  98/256 }
-local FLYOUT_DOWN_BUTTON_HL_TCOORDS = { 72/128,  92/128, 69/256,  79/256 }
-
-local SLOT_EMPTY_TCOORDS = {
-  [EARTH_TOTEM_SLOT] = {  66/128,  96/128,   3/256,  33/256 },
-	[FIRE_TOTEM_SLOT]  = {  67/128,  97/128, 100/256, 130/256 },
-	[WATER_TOTEM_SLOT] = {  39/128,  69/128, 209/256, 239/256 },
-	[AIR_TOTEM_SLOT]   = {  66/128,  96/128,  36/256,  66/256 },
-}
-
-local SLOT_OVERLAY_TCOORDS = {
-	[EARTH_TOTEM_SLOT] = {   1/128,  35/128, 172/256, 206/256 },
-	[FIRE_TOTEM_SLOT]  = {  36/128,  70/128, 172/256, 206/256 },
-	[WATER_TOTEM_SLOT] = {   1/128,  35/128, 207/256, 240/256 },
-	[AIR_TOTEM_SLOT]   = {  36/128,  70/128, 137/256, 171/256 },
-}
-
-local FLYOUT_UP_BUTTON_TCOORDS = {
-	["summon"]         = {  99/128, 127/128,  84/256, 102/256 },
-	[EARTH_TOTEM_SLOT] = {  99/128, 127/128, 160/256, 178/256 },
-	[FIRE_TOTEM_SLOT]  = {  99/128, 127/128, 122/256, 140/256 },
-	[WATER_TOTEM_SLOT] = {  99/128, 127/128, 199/256, 217/256 },
-	[AIR_TOTEM_SLOT]   = {  99/128, 127/128, 237/256, 255/256 },
-}
-
-local FLYOUT_DOWN_BUTTON_TCOORDS = {
-	["summon"]         = {  99/128, 127/128,  65/256,  83/256 },
-	[EARTH_TOTEM_SLOT] = {  99/128, 127/128, 141/256, 159/256 },
-	[FIRE_TOTEM_SLOT]  = {  99/128, 127/128, 103/256, 121/256 },
-	[WATER_TOTEM_SLOT] = {  99/128, 127/128, 180/256, 198/256 },
-	[AIR_TOTEM_SLOT]   = {  99/128, 127/128, 218/256, 236/256 },
-}
-
-local FLYOUT_TOP_TCOORDS = {
-	["summon"]         = {  33/128,  65/128,   1/256,  23/256 },
-	[EARTH_TOTEM_SLOT] = {   0/128,  32/128,  46/256,  68/256 },
-	[FIRE_TOTEM_SLOT]  = {  33/128,  65/128,  46/256,  68/256 },
-	[WATER_TOTEM_SLOT] = {   0/128,  32/128,   1/256,  23/256 },
-	[AIR_TOTEM_SLOT]   = {   0/128,  32/128,  91/256, 113/256 },
-}
-
-local FLYOUT_MIDDLE_TCOORDS = {
-	["summon"]         = {  33/128,  65/128,  23/256,  43/256 },
-	[EARTH_TOTEM_SLOT] = {   0/128,  32/128,  68/256,  88/256 },
-	[FIRE_TOTEM_SLOT]  = {  33/128,  65/128,  68/256,  88/256 },
-	[WATER_TOTEM_SLOT] = {   0/128,  32/128,  23/256,  43/256 },
-	[AIR_TOTEM_SLOT]   = {   0/128,  32/128, 113/256, 133/256 },
-}
-
-local eventList = { 
-  "ACTIONBAR_SLOT_CHANGED",
-  "ACTIONBAR_UPDATE_STATE",
-  "ACTIONBAR_UPDATE_USABLE",
-  "ACTIONBAR_UPDATE_COOLDOWN",
-  "UPDATE_BINDINGS",
-  "UPDATE_MULTI_CAST_ACTIONBAR",
-}
-
---
--- MultiCast Button class
--- Inherits implementation methods from Action button class, but circumvents the constructor
--- and redefines/removes some methods.
---
-local Super = ReAction.Button
-local Action = ReAction.Button.Action
-local MultiCast = setmetatable( { }, { __index = Action } )
-ReAction.Button.MultiCast = MultiCast
-
-function MultiCast:New( idx, btnConfig, bar )
-  local maxIndex = bar.nTotemSlots or 0
-  if bar.summonSlot then
-    maxIndex = maxIndex + 1
-  end
-  if bar.recallSlot then
-    maxIndex = maxIndex + 1
-  end
-
-  if not bar.hasMulticast or idx > maxIndex then
-    return false
-  end
-
-  if idx < 1 then
-    error("invalid index")
-  end
-
-  local name = format("ReAction_%s_Totem_%d",bar:GetName(),idx)
- 
-  self = Super.New(self, name, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
-
-  local barFrame = bar:GetFrame()
-  local f = self:GetFrame()
-
-  -- attributes
-  local page = (idx == bar.recallSlot) and 1 or bar:GetConfig().lastSummon or 1
-  if idx == bar.recallSlot or idx == bar.summonSlot then
-    f:SetAttribute("type","spell")
-    local spells = (idx == bar.summonSlot) and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS
-    f:SetAttribute("spell",spells[page])
-    for i, spell in ipairs(spells) do 
-      if spell and IsSpellKnown(spell) then
-        f:SetAttribute("spell-page"..i, spell)
-      end
-    end
-  else
-    local offset = bar.summonSlot and 1 or 0
-    local slot = SHAMAN_TOTEM_PRIORITIES[idx - offset]
-    local baseAction = barFrame:GetAttribute("baseActionID") + slot
-    self.totemSlot = slot
-    f:SetAttribute("type","action")
-    f:SetAttribute("action", baseAction + (page - 1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
-    for i = 1, NUM_MULTI_CAST_PAGES do
-      f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE)
-    end
-    if not f.overlayTex then
-      local tx = f:CreateTexture("OVERLAY")
-      tx:SetTexture(TOTEM_TEXTURE)
-      tx:SetTexCoord(unpack(SLOT_OVERLAY_TCOORDS[self.totemSlot]))
-      tx:SetWidth(34)
-      tx:SetHeight(34)
-      tx:SetPoint("CENTER")
-      tx:Show()
-      f.overlayTex = tx
-    end
-  end
-  f:SetAttribute("bar-idx",idx)
-
-  -- non secure scripts
-  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
-  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
-  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
-  f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
-  f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
-
-  -- secure handlers
-  if idx ~= bar.recallSlot then
-    f:SetAttribute("_childupdate",_childupdate)
-  end
-  barFrame:WrapScript(f, "OnEnter", _onEnter)
-
-  -- event registration
-  f:EnableMouse(true)
-  f:RegisterForClicks("AnyUp")
-  for _, evt in pairs(eventList) do
-    f:RegisterEvent(evt)
-  end
-
-  -- Set up a proxy for the icon texture for use with ButtonFacade
-  local SetTexCoordRaw = self.frames.icon.SetTexCoord
-  self.frames.icon.SetTexCoord = function( tx, ... )
-    if self:GetIconTexture() == TOTEM_TEXTURE then
-      SetTexCoordRaw(tx,select(2,self:GetIconTexture()))
-    else
-      SetTexCoordRaw(tx,...)
-    end
-  end
-
-  -- attach to skinner
-  bar:SkinButton(self)
-
-  f:Show()
-
-  -- open arrow and flyout background textures
-  if idx ~= bar.recallSlot then
-    local arrow = f._arrowFrame or CreateFrame("Button", nil, f, "SecureFrameTemplate")
-    f._arrowFrame = arrow
-    arrow:SetWidth(28)
-    arrow:SetHeight(18)
-    arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring
-    arrow:SetNormalTexture(TOTEM_TEXTURE)
-    local slot = self.totemSlot or "summon"
-    arrow:GetNormalTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_TCOORDS[slot]) )
-    arrow:SetHighlightTexture(TOTEM_TEXTURE)
-    arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) )
-    arrow:SetAttribute("bar-idx",idx)
-    arrow:Hide()
-    barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout)
-    barFrame:SetFrameRef("arrow-"..idx,arrow)
-  end
-
-  self:Refresh()
-
-  return self
-end
-
-function MultiCast:Destroy()
-  local barFrame = self.bar:GetFrame()
-  local f = self:GetFrame()
-  pcall( barFrame.UnwrapScript, barFrame, f, "OnEnter" ) -- ignore errors
-  if f._arrowFrame then
-    pcall( barFrame.UnwrapScript, barFrame, f._arrowFrame,"OnClick" ) -- ignore errors
-  end
-  Super.Destroy(self)
-end
-
-function MultiCast:Refresh()
-  Super.Refresh(self)
-  self:UpdateAction()
-end
-
-function MultiCast:ShowGrid( show )
-end
-
-function MultiCast:ShowGridTemp( show )
-end
-
-function MultiCast:AcquireActionID()
-end
-
-function MultiCast:ReleaseActionID()
-end
-
-function MultiCast:UpdateShowGrid()
-end
-
-function MultiCast:UpdateBorder()
-end
-
-function MultiCast:UpdateMacroText()
-end
-
-function MultiCast:UpdateCount()
-end
-
-function MultiCast:UpdateCheckedState()
-  local action = self:GetActionID()
-  if action and IsCurrentAction(action) then
-    self:GetFrame():SetChecked(1)
-  else
-    self:GetFrame():SetChecked(0)
-  end
-end
-
-function MultiCast:RefreshHasActionAttributes()
-end
-
-function MultiCast:UpdateFlash()
-end
-
-function MultiCast:GetIconTexture()
-  local tx
-  if self.spellID then
-    tx = GetSpellTexture(GetSpellInfo(self.spellID))
-  elseif self.actionID then
-    tx = GetActionTexture(self.actionID)
-  end
-  if tx then
-    return tx
-  else
-    return TOTEM_TEXTURE, unpack(SLOT_EMPTY_TCOORDS[self.totemSlot or 1])
-  end
-end
-
-function MultiCast:UpdateAction()
-  local action = self:GetActionID()
-  if action then
-    if action ~= self.actionID then
-      self.actionID = action
-      self:UpdateAll()
-    end
-  else
-    local spellID = self:GetSpellID()
-    if spellID ~= self.spellID then
-      self.spellID = spellID
-      self:UpdateAll()
-    end
-  end
-end
-
-function MultiCast:GetActionID(page)
-  return self:GetFrame():GetAttribute("action")
-end
-
-function MultiCast:GetSpellID(page)
-  return self:GetFrame():GetAttribute("spell")
-end
-
-function MultiCast:SetActionID( id  )
-  error("Can not set action ID of multicast buttons")
-end
-
-function MultiCast:SetTooltip()
-  local barFrame = self:GetFrame()
-  if GetCVar("UberTooltips") == "1" then
-    GameTooltip_SetDefaultAnchor(GameTooltip, barFrame)
-  else
-    GameTooltip:SetOwner(barFrame)
-  end
-  if self.spellID then
-    GameTooltip:SetSpellByID(self.spellID,false,true)
-  elseif self.actionID then
-    GameTooltip:SetAction(self.actionID)
-  end
-end
-
-function MultiCast:GetUsable()
-  if self.spellID then
-    return IsUsableSpell((GetSpellInfo(self.spellID)))
-  elseif self.actionID then
-    return IsUsableAction(self.actionID)
-  end
-end
-
-function MultiCast:GetInRange()
-  if self.spellID then
-    return IsSpellInRange((GetSpellInfo(self.spellID))) == 0
-  elseif self.actionID then
-    return IsActionInRange(self.actionID) == 0
-  end
-end
-
-function MultiCast:GetCooldown()
-  if self.spellID then
-    return GetSpellCooldown((GetSpellInfo(self.spellID)))
-  elseif self.actionID then
-    return GetActionCooldown(self.actionID)
-  else
-    return 0, 0, 0
-  end
-end
-
-function MultiCast:UPDATE_MULTI_CAST_ACTIONBAR()
-  self:UpdateAll()
-end
-
-
---
--- flyout setup
---
-local function ShowFlyoutTooltip(frame)
-  if GetCVar("UberTooltips") == "1" then
-    GameTooltip_SetDefaultAnchor(GameTooltip, frame)
-  else
-    GameTooltip:SetOwner(frame)
-  end
-  local spell = frame:GetAttribute("spell")
-  if spell == nil or spell == 0 then
-    GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
-  else
-    GameTooltip:SetSpellByID(spell,false,true)
-  end
-end
-
-local function HideFlyoutTooltip()
-  GameTooltip:Hide()
-end
-
-local function UpdateFlyoutIcon(frame)
-  local spellID = frame:GetAttribute("spell")
-  if spellID == 0 or spellID == nil then
-    frame.icon:SetTexture(TOTEM_TEXTURE)
-    local slot = tonumber(frame:GetAttribute("totemSlot")) or 1
-    frame.icon:SetTexCoord( unpack(SLOT_EMPTY_TCOORDS[slot]) )
-  else
-    frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID)))
-    frame.icon:SetTexCoord(0,1,0,1)
-  end
-end
-
-function MultiCast.SetupBarHeader( bar ) -- call this as a static method
-  local slot = 0
-  local nTotemSlots = 0
-  local summonSlot = nil
-  local recallSlot = nil
-
-  -- figure out the capabilities of the character
-	for i, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do 
-    if spell and IsSpellKnown(spell) then
-      slot = 1
-      summonSlot = 1
-    end
-	end
-
-  for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do
-		local totem = SHAMAN_TOTEM_PRIORITIES[i];
-		if GetTotemInfo(totem) and GetMultiCastTotemSpells(totem) then
-      nTotemSlots = nTotemSlots + 1
-      slot = slot + 1
-    end
-  end
-
-  slot = slot + 1
-	for i, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do 
-    if spell and IsSpellKnown(spell) then
-      recallSlot = slot
-    end
-	end
-
-  if nTotemSlots == 0 then
-    bar.hasMulticast = false -- no multicast capability
-    return
-  end
-
-  bar.hasMulticast = true
-  bar.summonSlot   = summonSlot
-  bar.recallSlot   = recallSlot
-  bar.nTotemSlots  = nTotemSlots
-
-
-  local f = bar:GetFrame()
-
-  -- init bar secure environment
-  f:SetAttribute("lastSummon", bar:GetConfig().lastSummon)
-  f:SetAttribute("summonSlot", summonSlot)
-  f:SetAttribute("recallSlot", recallSlot)
-  f:SetAttribute("slotsPerPage", NUM_MULTI_CAST_BUTTONS_PER_PAGE)
-  f:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS)
-  for i, p in ipairs(SHAMAN_TOTEM_PRIORITIES) do
-    f:SetAttribute("TOTEM_PRIORITY_"..i,p)
-  end
-  f:SetAttribute("_onstate-multispellpage", _onstate_multispellpage)
-
-  function f:UpdateLastSummon(value)
-    bar:GetConfig().lastSummon = value
-  end
-
-  -- create flyout container frame and close arrow
-  local flyout = bar._flyoutFrame
-  if not flyout then
-    flyout = CreateFrame("Frame", nil, f, "SecureFrameTemplate")
-    bar._flyoutFrame = flyout
-    f:SetFrameRef("flyout",flyout)
-    flyout.buttons = { }
-    flyout:Hide()
-    flyout:SetWidth(24)
-    flyout:SetHeight(1)
-    flyout:SetPoint("BOTTOM",f,"TOP",0,0)
-
-    local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate")
-    close:SetWidth(28)
-    close:SetHeight(18)
-    close:SetPoint("BOTTOM",flyout,"TOP")
-    close:SetNormalTexture(TOTEM_TEXTURE)
-    close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS["summon"]))
-    close:SetHighlightTexture(TOTEM_TEXTURE)
-    close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) )
-    f:SetFrameRef("close",close)
-    f:WrapScript(close, "OnClick", _closeFlyout)
-    close:Show()
-
-    local midTx = flyout:CreateTexture("BACKGROUND")
-    midTx:SetWidth(32)
-    midTx:SetHeight(20)
-    midTx:SetPoint("BOTTOM")
-    midTx:SetTexture(TOTEM_TEXTURE)
-    midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS["summon"]))
-    midTx:Show()
-
-    local topTx = flyout:CreateTexture("BACKGROUND")
-    topTx:SetWidth(32)
-    topTx:SetHeight(20)
-    topTx:SetTexture(TOTEM_TEXTURE)
-    midTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS["summon"]))
-    topTx:SetPoint("BOTTOM",midTx,"TOP",0,-10)
-    topTx:Show()
-
-    function flyout:UpdateTextures(slot)
-      slot = slot or "summon"
-      close:GetNormalTexture():SetTexCoord(unpack(FLYOUT_DOWN_BUTTON_TCOORDS[slot]))
-      midTx:ClearAllPoints()
-      midTx:SetPoint("BOTTOM")
-      midTx:SetPoint("TOP",close,"BOTTOM",0,0)
-      midTx:SetTexCoord(unpack(FLYOUT_MIDDLE_TCOORDS[slot]))
-      topTx:SetTexCoord(unpack(FLYOUT_TOP_TCOORDS[slot]))
-    end
-
-    -- create flyout buttons
-    for i = 1, 10 do -- maximum 9 spells + 1 empty slot
-      local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate")
-      b:SetWidth(24)
-      b:SetHeight(24)
-      local prev = flyout.buttons[i-1]
-      b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring
-      b.icon = b:CreateTexture("BACKGROUND")
-      b.icon:SetAllPoints()
-      b.icon:Show()
-      b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
-      b:GetHighlightTexture():SetBlendMode("ADD")
-      b:RegisterForClicks("AnyUp")
-      b:SetScript("OnShow",UpdateFlyoutIcon)
-      b:SetScript("OnEnter",ShowFlyoutTooltip)
-      b:SetScript("OnLeave",HideFlyoutTooltip)
-      b:SetAttribute("index",i)
-      f:SetAttribute("flyout-child-idx",i)
-      f:SetFrameRef("flyout-child",b)
-      f:Execute([[
-          flyoutChildren = flyoutChildren or newtable()
-          flyoutChildren[self:GetAttribute("flyout-child-idx")] = self:GetFrameRef("flyout-child")
-        ]])
-      f:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick)
-      b:Show()
-      flyout.buttons[i] = b
-    end
-  end
-
-  -- scale flyout frame
-  local scale = bar:GetButtonSize() / 36
-  flyout:SetScale(scale)
-
-  function f:UpdateFlyoutTextures(slot)
-    flyout:UpdateTextures(slot)
-  end
-
-  f:Execute(_bar_init)
-end
-
--- a/classes/Overlay.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,754 +0,0 @@
-local addonName, addonTable = ...
-local ReAction               = addonTable.ReAction
-local L                      = ReAction.L
-local LKB                    = ReAction.LKB
-local CreateFrame            = CreateFrame
-local InCombatLockdown       = InCombatLockdown
-local floor                  = math.floor
-local min                    = math.min
-local format                 = string.format
-local GameTooltip            = GameTooltip
-local Bar                    = ReAction.Bar
-local GetSize                = Bar.GetSize
-local SetSize                = Bar.SetSize
-local GetButtonSize          = Bar.GetButtonSize
-local GetButtonGrid          = Bar.GetButtonGrid
-local SetButtonSize          = Bar.SetButtonSize
-local SetButtonGrid          = Bar.SetButtonGrid
-local ApplyAnchor            = Bar.ApplyAnchor
-local GameTooltipTextRight1  = GameTooltipTextRight1
-local GameTooltipTextRight2  = GameTooltipTextRight2
-local GameTooltipTextRight3  = GameTooltipTextRight3
-
---
--- Wrap some of the bar manipulators to make them state-aware
---
-local function SetAnchor( bar, point, frame, relPoint, x, y )
-  local state = bar:GetSecureState()
-  if state then
-    local anchorstate = bar:GetStateProperty(state, "anchorEnable")
-    if anchorstate then
-      bar:SetStateProperty(state, "anchorFrame", frame)
-      bar:SetStateProperty(state, "anchorPoint", point)
-      bar:SetStateProperty(state, "anchorRelPoint", relPoint)
-      bar:SetStateProperty(state, "anchorX", x or 0)
-      bar:SetStateProperty(state, "anchorY", y or 0)
-      bar:SetAnchor(bar:GetAnchor())
-      return
-    end
-  end
-  bar:SetAnchor(point, frame, relPoint, x, y)
-end
-
-local function GetStateScale( bar )
-  local state = bar:GetSecureState()
-  if state and bar:GetStateProperty(state, "enableScale") then
-    return bar:GetStateProperty(state, "scale")
-  end
-end
-
-local function SetStateScale( bar, scale )
-  local state = bar:GetSecureState()
-  if state and bar:GetStateProperty(state, "enableScale") then
-    bar:SetStateProperty(state, "scale", scale)
-  end
-end
-
-
---
--- Bar config overlay
---
-
-local function GetNormalTextColor()
-  return 1.0, 1.0, 1.0, 1.0
-end
-
-local function GetAnchoredTextColor()
-  return 1.0, 1.0, 1.0, 1.0
-end
-
-local function GetNormalBgColor()
-  return 0.7, 0.7, 1.0, 0.3
-end
-
-local function GetAnchoredBgColor()
-  return 0.9, 0.2, 0.7, 0.3
-end
-
-local function StoreSize(bar)
-  local f = bar:GetFrame()
-  SetSize( bar, f:GetWidth(), f:GetHeight() )
-end
-
-local function StoreExtents(bar)
-  local f = bar:GetFrame()
-  local p, fr, rp, x, y = f:GetPoint(1)
-  fr = fr and fr:GetName() or "UIParent"
-  SetAnchor( bar, p, fr, rp, x, y )
-  SetSize( bar, f:GetWidth(), f:GetHeight() )
-end
-
-local function RecomputeButtonSize(bar)
-  local w, h = GetSize(bar)
-  local bw, bh = GetButtonSize(bar)
-  local r, c, s = GetButtonGrid(bar)
-
-  local scaleW = (floor(w/c) - s) / bw
-  local scaleH = (floor(h/r) - s) / bh
-  local scale = min(scaleW, scaleH)
-
-  SetButtonSize(bar, scale * bw, scale * bh, s)
-end
-
-local function ComputeBarScale(bar, overlay)
-  local w, h = overlay:GetWidth() - 8, overlay:GetHeight() - 8
-  local bw, bh = GetButtonSize(bar)
-  local r, c, s = GetButtonGrid(bar)
-
-  local scaleW = w / (c*(bw+s))
-  local scaleH = h / (r*(bh+s))
-  local scale = min(scaleW, scaleH)
-
-  if scale > 2.5 then
-    scale = 2.5
-  elseif scale < 0.25 then
-    scale = 0.25
-  end
-
-  return scale
-end
-
-local function RecomputeButtonSpacing(bar)
-  local w, h = GetSize(bar)
-  local bw, bh = GetButtonSize(bar)
-  local r, c, s = GetButtonGrid(bar)
-
-  SetButtonGrid(bar,r,c,min(floor(w/c) - bw, floor(h/r) - bh))
-end
-
-local function RecomputeGrid(bar)
-  local w, h = GetSize(bar)
-  local bw, bh = GetButtonSize(bar)
-  local r, c, s = GetButtonGrid(bar)
-
-  SetButtonGrid(bar, floor(h/(bh+s)), floor(w/(bw+s)), s)
-end
-
-local function ClampToButtons(bar)
-  local bw, bh = GetButtonSize(bar)
-  local r, c, s = GetButtonGrid(bar)
-  SetSize(bar, (bw+s)*c + 1, (bh+s)*r + 1)
-end
-
-local function HideGameTooltip()
-  GameTooltip:Hide()
-end
-
-local anchorInside  = { inside = true }
-local anchorOutside = { outside = true }
-local edges = { "BOTTOM", "TOP", "LEFT", "RIGHT" }
-local oppositeEdges = {
-  TOP = "BOTTOM",
-  BOTTOM = "TOP",
-  LEFT = "RIGHT",
-  RIGHT = "LEFT"
-}
-local pointsOnEdge = {
-  BOTTOM = { "BOTTOM", "BOTTOMLEFT",  "BOTTOMRIGHT",  },
-  TOP    = { "TOP",    "TOPLEFT",     "TOPRIGHT",     },
-  RIGHT  = { "RIGHT",  "BOTTOMRIGHT", "TOPRIGHT",     },
-  LEFT   = { "LEFT",   "BOTTOMLEFT",  "TOPLEFT",      },
-}
-local edgeSelector = {
-  BOTTOM = 1,  -- select x of x,y
-  TOP    = 1,  -- select x of x,y
-  LEFT   = 2,  -- select y of x,y
-  RIGHT  = 2,  -- select y of x,y  
-}
-local snapPoints = {
-  [anchorOutside] = {
-    BOTTOMLEFT  = {"BOTTOMRIGHT","TOPLEFT","TOPRIGHT"},
-    BOTTOM      = {"TOP"},
-    BOTTOMRIGHT = {"BOTTOMLEFT","TOPRIGHT","TOPLEFT"},
-    RIGHT       = {"LEFT"},
-    TOPRIGHT    = {"TOPLEFT","BOTTOMRIGHT","BOTTOMLEFT"},
-    TOP         = {"BOTTOM"},
-    TOPLEFT     = {"TOPRIGHT","BOTTOMLEFT","BOTTOMRIGHT"},
-    LEFT        = {"RIGHT"},
-    CENTER      = {"CENTER"}
-  },
-  [anchorInside] = {
-    BOTTOMLEFT  = {"BOTTOMLEFT"},
-    BOTTOM      = {"BOTTOM"},
-    BOTTOMRIGHT = {"BOTTOMRIGHT"},
-    RIGHT       = {"RIGHT"},
-    TOPRIGHT    = {"TOPRIGHT"},
-    TOP         = {"TOP"},
-    TOPLEFT     = {"TOPLEFT"},
-    LEFT        = {"LEFT"},
-    CENTER      = {"CENTER"}
-  }
-}
-local insidePointOffsetFuncs = {
-  BOTTOMLEFT  = function(x, y) return x, y end,
-  BOTTOM      = function(x, y) return 0, y end,
-  BOTTOMRIGHT = function(x, y) return -x, y end,
-  RIGHT       = function(x, y) return -x, 0 end,
-  TOPRIGHT    = function(x, y) return -x, -y end,
-  TOP         = function(x, y) return 0, -y end,
-  TOPLEFT     = function(x, y) return x, -y end,
-  LEFT        = function(x, y) return x, 0 end,
-  CENTER      = function(x, y) return x, y end,
-}
-local pointCoordFuncs = {
-  BOTTOMLEFT  = function(f) return f:GetLeft(),  f:GetBottom() end,
-  BOTTOM      = function(f) return nil,          f:GetBottom() end,
-  BOTTOMRIGHT = function(f) return f:GetRight(), f:GetBottom() end,
-  RIGHT       = function(f) return f:GetRight(), nil end,
-  TOPRIGHT    = function(f) return f:GetRight(), f:GetTop() end,
-  TOP         = function(f) return nil,          f:GetTop() end,
-  TOPLEFT     = function(f) return f:GetLeft(),  f:GetTop() end,
-  LEFT        = function(f) return f:GetLeft(),  nil end,
-  CENTER      = function(f) return f:GetCenter() end,
-}
-local edgeBoundsFuncs = {
-  BOTTOM = function(f) return f:GetLeft(), f:GetRight() end,
-  LEFT   = function(f) return f:GetBottom(), f:GetTop() end
-}
-edgeBoundsFuncs.TOP   = edgeBoundsFuncs.BOTTOM
-edgeBoundsFuncs.RIGHT = edgeBoundsFuncs.LEFT
-local cornerTexCoords = {
-              -- ULx, ULy, LLx, LLy, URx, URy, LRx, LRy
-  TOPLEFT     = { 1,   1,   1,   0,   0,   1,   0,   0 },
-  TOPRIGHT    = { 1,   0,   0,   0,   1,   1,   0,   1 },
-  BOTTOMLEFT  = { 0,   1,   1,   1,   0,   0,   1,   0 },
-  BOTTOMRIGHT = { 0,   0,   0,   1,   1,   0,   1,   1 },
-}
-
--- Returns absolute coordinates x,y of the named point 'p' of frame 'f'
-local function GetPointCoords( f, p )
-  local x, y = pointCoordFuncs[p](f)
-  if not(x and y) then
-    local cx, cy = f:GetCenter()
-    x = x or cx
-    y = y or cy
-  end
-  return x, y
-end
-
-
--- Returns true if frame 'f1' can be anchored to frame 'f2'
-local function CheckAnchorable( f1, f2 )
-  -- can't anchor a frame to itself or to nil
-  if f1 == f2 or f2 == nil then
-    return false
-  end
-  
-  -- can always anchor to UIParent
-  if f2 == UIParent then
-    return true
-  end
-  
-  -- also can't do circular anchoring of frames 
-  -- walk the anchor chain, which generally shouldn't be that expensive
-  -- (who nests draggables that deep anyway?)
-  for i = 1, f2:GetNumPoints() do
-    local _, f = f2:GetPoint(i)
-    if not f then f = f2:GetParent() end
-    return CheckAnchorable(f1,f)
-  end
-  
-  return true
-end
-
--- Returns true if frames f1 and f2 specified edges overlap
-local function CheckEdgeOverlap( f1, f2, e )
-  local l1, u1 = edgeBoundsFuncs[e](f1)
-  local l2, u2 = edgeBoundsFuncs[e](f2)
-  return l1 <= l2 and l2 <= u1 or l2 <= l1 and l1 <= u2
-end
-
--- Returns true if point p1 on frame f1 overlaps edge e2 on frame f2
-local function CheckPointEdgeOverlap( f1, p1, f2, e2 )
-  local l, u = edgeBoundsFuncs[e2](f2)
-  local x, y = GetPointCoords(f1,p1)
-  x = select(edgeSelector[e2], x, y)
-  return l <= x and x <= u
-end
-
--- Returns the distance between corresponding edges. It is 
--- assumed that the passed in edges e1 and e2 are the same or opposites
-local function GetEdgeDistance( f1, f2, e1, e2 )
-  local x1, y1 = pointCoordFuncs[e1](f1)
-  local x2, y2 = pointCoordFuncs[e2](f2)
-  return math.abs((x1 or y1) - (x2 or y2))
-end
-
-local globalSnapTargets = { [UIParent] = anchorInside }
-
-local function GetClosestFrameEdge(f1,f2,a)
-  local dist, edge, opp
-  if f2:IsVisible() and CheckAnchorable(f1,f2) then
-    for _, e in pairs(edges) do
-      local o = a.inside and e or oppositeEdges[e]
-      if CheckEdgeOverlap(f1,f2,e) then
-        local d = GetEdgeDistance(f1, f2, e, o)
-        if not dist or (d < dist) then
-          dist, edge, opp = d, e, o
-        end
-      end
-    end
-  end
-  return dist, edge, opp
-end
-
-local function GetClosestVisibleEdge( f )
-  local r, o, e1, e2
-  local a = anchorOutside
-  for _, b in ReAction:IterateBars() do
-    local d, e, opp = GetClosestFrameEdge(f,b:GetFrame(),a)
-    if d and (not r or d < r) then
-      r, o, e1, e2 = d, b:GetFrame(), e, opp
-    end
-  end
-  for f2, a2 in pairs(globalSnapTargets) do
-    local d, e, opp = GetClosestFrameEdge(f,f2,a2)
-    if d and (not r or d < r) then
-      r, o, e1, e2, a = d, f2, e, opp, a2
-    end
-  end
-  return o, e1, e2, a
-end
-
-local function GetClosestVisiblePoint(f1)
-  local f2, e1, e2, a = GetClosestVisibleEdge(f1)
-  if f2 then
-    local rsq, p, rp, x, y
-    -- iterate pointsOnEdge in order and use < to prefer edge centers to corners
-    for _, p1 in ipairs(pointsOnEdge[e1]) do
-      if CheckPointEdgeOverlap(f1,p1,f2,e2) then
-        for _, p2 in pairs(snapPoints[a][p1]) do
-          local x1, y1 = GetPointCoords(f1,p1)
-          local x2, y2 = GetPointCoords(f2,p2)
-          local dx = x1 - x2
-          local dy = y1 - y2
-          local rsq2 = dx*dx + dy*dy
-          if not rsq or rsq2 < rsq then
-            rsq, p, rp, x, y = rsq2, p1, p2, dx, dy
-          end
-        end
-      end
-    end
-    return f2, p, rp, x, y
-  end
-end
-
-local function GetClosestPointSnapped(f1, rx, ry, xOff, yOff)
-  local o, p, rp, x, y = GetClosestVisiblePoint(f1)
-  local s = false
-
-  local insideOffsetFunc = p and insidePointOffsetFuncs[p]
-  local coordFunc = p and pointCoordFuncs[p]
-  if not insideOffsetFunc or not coordFunc then
-    return
-  end
-  
-  local sx, sy = insideOffsetFunc(xOff or 0, yOff or 0)
-  local xx, yy = coordFunc(f1)
-  if xx and yy then
-    if math.abs(x) <= rx then
-      if math.abs(y) <= ry then
-        x = sx
-        y = sy
-        s = true
-      elseif CheckEdgeOverlap(f1,o,"LEFT") then
-        x = sx
-        s = true
-      end
-    elseif math.abs(y) <= ry and CheckEdgeOverlap(f1,o,"TOP") then
-      y = sy
-      s = true
-    end
-  elseif xx then
-    if math.abs(x) <= rx then
-      x = sx
-      s = true
-      if math.abs(y) <= ry then
-        y = sy
-      end
-    end
-  elseif yy then
-    if math.abs(y) <= ry then
-      y = sy
-      s = true
-      if math.abs(x) <= rx then
-        x = sx
-      end
-    end
-  end
-
-  -- correct for some Lua oddities with doubles
-  if x == -0 then x = 0 end
-  if y == -0 then y = 0 end
-  
-  if s then
-    return o, p, rp, math.floor(x), math.floor(y)
-  end
-end
-
-local function CreateSnapIndicator()
-  local si = CreateFrame("Frame",nil,UIParent)
-  si:SetFrameStrata("HIGH")
-  si:SetHeight(16)
-  si:SetWidth(16)
-  local tex = si:CreateTexture()
-  tex:SetAllPoints()
-  tex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock")
-  tex:SetBlendMode("ADD")
-  tex:SetDrawLayer("OVERLAY")
-  return si
-end
-
-local si1 = CreateSnapIndicator()
-local si2 = CreateSnapIndicator()
-
-local function DisplaySnapIndicator( f, rx, ry, xOff, yOff )
-  local o, p, rp, x, y, snap = GetClosestPointSnapped(f, rx, ry, xOff, yOff)
-  if o then
-    si1:ClearAllPoints()
-    si2:ClearAllPoints()
-    si1:SetPoint("CENTER", f, p, 0, 0)
-    local xx, yy = pointCoordFuncs[rp](o)
-    x = math.abs(x) <=rx and xx and 0 or x
-    y = math.abs(y) <=ry and yy and 0 or y
-    si2:SetPoint("CENTER", o, rp, x, y)
-    si1:Show()
-    si2:Show()
-  else
-    if si1:IsVisible() then
-      si1:Hide()
-      si2:Hide()
-    end
-  end
-  return o, p
-end
-
-local function HideSnapIndicator()
-  if si1:IsVisible() then
-    si1:Hide()
-    si2:Hide()
-  end
-end
-
-local function UpdateLabelString(overlay)
-  local label = overlay.labelString
-  if label then
-    local name = overlay.labelName
-    if name and overlay.labelSubtext then
-      name = format("%s (%s)", name, overlay.labelSubtext)
-    end
-    label:SetText(name or "")
-  end
-end
-
-local function CreateControls(bar)
-  local f = bar:GetFrame()
-
-  f:SetMovable(true)
-  f:SetResizable(true)
-
-  -- child of UIParent so that alpha and scale doesn't propagate to it
-  local overlay = CreateFrame("Button", nil, UIParent)
-  overlay:EnableMouse(true)
-  overlay:SetFrameLevel(10) -- set it above the buttons
-  overlay:SetPoint("TOPLEFT", f, "TOPLEFT", -4, 4)
-  overlay:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 4, -4)
-  overlay:SetBackdrop({
-    edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
-    tile = true,
-    tileSize = 16,
-    edgeSize = 16,
-    insets = { left = 0, right = 0, top = 0, bottom = 0 },
-  })
-
-  -- textures
-  local bgTex = overlay:CreateTexture(nil,"BACKGROUND")
-  bgTex:SetTexture(0.7,0.7,1.0,0.2)
-  bgTex:SetPoint("TOPLEFT",4,-4)
-  bgTex:SetPoint("BOTTOMRIGHT",-4,4)
-  local hTex = overlay:CreateTexture(nil,"HIGHLIGHT")
-  hTex:SetTexture(0.7,0.7,1.0,0.2)
-  hTex:SetPoint("TOPLEFT",4,-4)
-  hTex:SetPoint("BOTTOMRIGHT",-4,4)
-  hTex:SetBlendMode("ADD")
-  local aTex = overlay:CreateTexture(nil,"ARTWORK")
-  aTex:SetTexture("Interface\\AddOns\\ReAction\\img\\lock")
-  aTex:SetWidth(16)
-  aTex:SetHeight(16)
-  aTex:Hide()
-
-  -- label
-  local label = overlay:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
-  label:SetAllPoints()
-  label:SetJustifyH("CENTER")
-  label:SetShadowColor(0,0,0,1)
-  label:SetShadowOffset(3,-3)
-  label:SetTextColor(GetNormalTextColor())
-  label:SetText(bar:GetName())
-  label:Show()
-  overlay.labelString = label
-  overlay.labelName = bar:GetName()
-
-  local function UpdateAnchorDecoration()
-    local point, anchor, relPoint, x, y = f:GetPoint(1)
-    if point then
-      local ofsx, ofsy = insidePointOffsetFuncs[point](x,y)
-      if (anchor and anchor ~= UIParent) or (ofsx == 0 and ofsy == 0) then
-        bgTex:SetTexture( GetAnchoredBgColor() )
-        hTex:SetTexture( GetAnchoredBgColor() )
-        label:SetTextColor( GetAnchoredTextColor() )
-        aTex:ClearAllPoints()
-        aTex:SetPoint(point)
-        aTex:Show()
-        return
-      end
-    end
-    bgTex:SetTexture( GetNormalBgColor() )
-    hTex:SetTexture( GetNormalBgColor() )
-    label:SetTextColor( GetNormalTextColor() )
-    aTex:Hide()
-  end
-
-  local function StopResize()
-    f:StopMovingOrSizing()
-    f.isMoving = false
-    f:SetScript("OnUpdate",nil)
-    StoreSize(bar)
-    ClampToButtons(bar)
-    ReAction:RefreshEditor()
-  end
-
-  local function CornerUpdate()
-    local bw, bh = GetButtonSize(bar)
-    local r, c, s = GetButtonGrid(bar)
-    local ss = GetStateScale(bar)
-    if IsShiftKeyDown() then
-      if ss then
-        f:SetMinResize( ((s+bw)*c*0.25)/ss, ((s+bh)*r*0.25)/ss )
-        f:SetMaxResize( ((s+bw)*c*2.5 + 1)/ss, ((s+bh)*r*2.5 + 1)/ss )
-        scale = ComputeBarScale(bar, overlay)
-      else
-        f:SetMinResize( (s+12)*c+1, (s+12)*r+1 )
-        f:SetMaxResize( (s+128)*c+1, (s+128)*r+1 )
-        RecomputeButtonSize(bar)
-      end
-    elseif not ss and IsAltKeyDown() then
-      f:SetMinResize( bw*c, bh*r )
-      f:SetMaxResize( 2*bw*c, 2*bh*r )
-      RecomputeButtonSpacing(bar)
-    else
-      f:SetMinResize( bw+s+1, bh+s+1 )
-      f:SetMaxResize( 50*(bw+s)+1, 50*(bh+s)+1 )
-      RecomputeGrid(bar)
-    end
-    GameTooltipTextRight2:SetText(format("%d x %d",r,c))
-
-    local ss = GetStateScale(bar)
-    if ss then
-      GameTooltipTextRight4:SetText(format("%d%%", scale*100))
-    else
-      local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh)
-      GameTooltipTextRight3:SetText(size)
-      GameTooltipTextRight4:SetText(tostring(s))
-    end
-  end
-
-  -- corner drag handles
-  for _, point in pairs({"BOTTOMLEFT","TOPLEFT","BOTTOMRIGHT","TOPRIGHT"}) do
-    local corner = CreateFrame("Frame",nil,overlay)
-    corner:EnableMouse(true)
-    corner:SetWidth(16)
-    corner:SetHeight(16)
-    corner:SetPoint(point)
-
-    local tex = corner:CreateTexture(nil,"HIGHLIGHT")
-    tex:SetTexture("Interface\\AddOns\\ReAction\\img\\corner")
-    tex:SetTexCoord(unpack(cornerTexCoords[point]))
-    tex:SetBlendMode("ADD")
-    tex:SetAlpha(0.6)
-    tex:SetAllPoints()
-    
-    corner:SetScript("OnMouseDown",
-      function(_,btn)
-        f:SetScript("OnUpdate", CornerUpdate)
-        f:StartSizing(point)
-      end
-    )
-    corner:SetScript("OnMouseUp",
-      function()
-        local ss = GetStateScale(bar)
-        if ss then
-          SetStateScale(bar, ComputeBarScale(bar, overlay))
-        end
-        StopResize()
-      end)
-    corner:SetScript("OnEnter",
-      function()
-        local bw, bh = GetButtonSize(bar)
-        local r, c, s = bar:GetButtonGrid()
-        local size = (bw == bh) and tostring(bw) or format("%d x %d",bw,bh)
-        local ss = GetStateScale(bar)
-        local state = bar:GetSecureState()
-        GameTooltip:SetOwner(f, "ANCHOR_"..point)
-        if ss then
-          GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
-        else
-          GameTooltip:AddLine(bar:GetName())
-        end
-        GameTooltip:AddDoubleLine(format("|cffcccccc%s|r %s",L["Drag"],L["to add/remove buttons:"]), format("%d x %d",r,c))
-        if ss then
-          GameTooltip:AddLine(L["State Scale Override"])
-          GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to change scale:"]), format("%d%%", bar:GetStateProperty(state,"scale")*100))
-        else
-          GameTooltip:AddDoubleLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to resize buttons:"]), tostring(floor(size)))
-          GameTooltip:AddDoubleLine(format("|cff0033cc%s|r %s",L["Hold Alt"],  L["to change spacing:"]), tostring(floor(s)))
-        end
-        GameTooltip:Show()
-      end
-    )
-    corner:SetScript("OnLeave", 
-      function()
-        GameTooltip:Hide()
-        f:SetScript("OnUpdate",nil)
-      end
-    )
-  end
-
-  overlay:RegisterForDrag("LeftButton")
-  overlay:RegisterForClicks("RightButtonUp")
-  
-  overlay:SetScript("OnDragStart",
-    function()
-      f:StartMoving()
-      f.isMoving = true
-      local w,h = bar:GetButtonSize()
-      f:ClearAllPoints()
-      UpdateAnchorDecoration()
-      f:SetScript("OnUpdate", function()
-          if IsShiftKeyDown() then
-            local f, p = DisplaySnapIndicator(f,w,h)
-          else
-            HideSnapIndicator()
-          end
-        end)
-    end
-  )
-
-  local function UpdateDragTooltip()
-    GameTooltip:SetOwner(f, "ANCHOR_TOPRIGHT")
-    local ss = GetStateScale(bar)
-    local state = bar:GetSecureState()
-    if ss then
-      GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
-    else
-      GameTooltip:AddLine(bar:GetName())
-    end
-    GameTooltip:AddLine(format("|cffcccccc%s|r %s",L["Drag"],L["to move"]))
-    GameTooltip:AddLine(format("|cff00ff00%s|r %s",L["Hold Shift"],L["to anchor to nearby frames"]))
-    GameTooltip:AddLine(format("|cff00cccc%s|r %s",L["Right-click"],L["for options..."]))
-    local point, frame, relpoint, x, y = bar:GetFrame():GetPoint(1)
-    if point then
-      local ofsx, ofsy = insidePointOffsetFuncs[point](x,y)
-      if (frame and frame ~= UIParent) or (ofsx == 0 and ofsy == 0) then
-        frame = frame or UIParent
-        GameTooltip:AddLine(format("%s <%s>",L["Currently anchored to"],frame:GetName()))
-      end
-    end
-    GameTooltip:Show()
-  end
-
-  overlay:SetScript("OnDragStop",
-    function()
-      f:StopMovingOrSizing()
-      f.isMoving = false
-      f:SetScript("OnUpdate",nil)
-
-      if IsShiftKeyDown() then
-        local w, h = bar:GetButtonSize()
-        local a, p, rp, x, y = GetClosestPointSnapped(f,w,h)
-        if a then
-          f:ClearAllPoints()
-          f:SetPoint(p,a,rp,x,y)
-        end
-        HideSnapIndicator()
-      end
-
-      StoreExtents(bar)
-      ReAction:RefreshEditor()
-      UpdateDragTooltip()
-      UpdateAnchorDecoration()
-    end
-  )
-
-  overlay:SetScript("OnEnter",
-    function()
-      UpdateDragTooltip()
-    end
-  )
-
-  overlay:SetScript("OnLeave", HideGameTooltip)
-
-  overlay:SetScript("OnClick",
-    function()
-      ReAction:ShowEditor(bar)
-    end
-  )
-
-  function overlay:RefreshControls()
-    UpdateAnchorDecoration()
-  end
-
-  overlay:SetScript("OnShow", overlay.RefreshControls)
-
-  if ReAction:GetKeybindMode() then
-    overlay:SetFrameLevel(1)
-  end
-
-  UpdateLabelString(overlay)
-  UpdateAnchorDecoration()
-
-  return overlay
-end
-
-
--- export methods to the Bar prototype
-Bar.Overlay = { }
-function Bar.Overlay:New( bar )
-  return setmetatable( {frame = CreateControls(bar)}, {__index=self} )
-end
-
-function Bar.Overlay:SetLabel(name)
-  self.frame.labelName = name
-  UpdateLabelString(self.frame)
-end
-
-function Bar.Overlay:SetLabelSubtext(text)
-  self.frame.labelSubtext = text
-  UpdateLabelString(self.frame)
-end
-
-function Bar.Overlay:Show()
-  self.frame:Show()
-end
-
-function Bar.Overlay:Hide()
-  self.frame:Hide()
-end
-
-function Bar.Overlay:IsShown()
-  return self.frame:IsShown()
-end
-
-function Bar.Overlay:RefreshControls()
-  self.frame:RefreshControls()
-end
\ No newline at end of file
--- a/classes/PetActionButton.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,286 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local GetCVar = GetCVar
-local InCombatLockdown = InCombatLockdown
-local GetPetActionInfo = GetPetActionInfo
-local GetPetActionSlotUsable = GetPetActionSlotUsable
-local GetPetActionCooldown = GetPetActionCooldown
-local AutoCastShine_AutoCastStart = AutoCastShine_AutoCastStart
-local AutoCastShine_AutoCastStop = AutoCastShine_AutoCastStop
-local SetDesaturation = SetDesaturation
-local CooldownFrame_SetTimer = CooldownFrame_SetTimer
-local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
-
---
--- Secure snippets
--- These are run within the context of the bar's sandbox, as the
--- buttons themselves do not have their own sandbox.
---
-local _onDragStart = -- function(self, button, kind, value, ...)
-[[
-  if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
-    return kind, value, ...
-  else
-    return "petaction", self:GetAttribute("action")
-  end
-]]
-
-local _onReceiveDrag = -- function(self, button, kind, value, ...)
-[[
-  if kind then -- pet spells on the cursor return nil from GetCursorInfo(), which is very strange
-    return kind, value, ...
-  end
-  return "petaction", self:GetAttribute("action")
-]]
-
---
--- private
---
-local eventList = {
-"PLAYER_CONTROL_LOST",
-"PLAYER_CONTROL_GAINED",
-"PLAYER_FARSIGHT_FOCUS_CHANGED",
-"UNIT_PET",
-"UNIT_FLAGS",
-"UNIT_AURA",
-"PET_BAR_UPDATE",
-"PET_BAR_UPDATE_COOLDOWN",
-"PET_BAR_UPDATE_USABLE",
-"UPDATE_BINDINGS",
-}
-
---
--- Pet Action Button class
---
-local Super = ReAction.Button
-local Pet = setmetatable( { }, { __index = Super } )
-ReAction.Button.PetAction = Pet
-
-function Pet:New( idx, config, bar, idHint )
-  local name = format("ReAction_%s_PetAction_%d",bar:GetName(),idx)
- 
-  self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
-
-  local f = self:GetFrame()
-  if not f.autoCastTexture then
-    -- store autocast stuff with the frame for recycling
-    local tex = f:CreateTexture(nil,"OVERLAY")
-    tex:SetTexture([[Interface\Buttons\UI-AutoCastableOverlay]])
-    tex:SetHeight(58)
-    tex:SetWidth(58)
-    tex:SetPoint("CENTER")
-    f.autoCastTexture = tex
-    f.autoCastShine = CreateFrame("Frame",name.."Shine",f,"AutoCastShineTemplate") -- create after autocast texture so it's on top
-    -- move the cooldown around
-    local cd = self.frames.cooldown
-    cd:ClearAllPoints()
-    cd:SetWidth(33)
-    cd:SetHeight(33)
-    cd:SetPoint("CENTER", f, "CENTER", -2, -1)
-    -- resize to 30x30
-    f:SetHeight(30)
-    f:SetWidth(30)
-    local nt = _G[name.."NormalTexture"]
-    nt:SetHeight(54)
-    nt:SetWidth(54)
-  end
-  local barFrame = bar:GetFrame()
-
-  -- set up the base action ID
-  self:SetActionIDPool("pet",10)
-  config.actionID = self:AcquireActionID(config.actionID, idHint, true)
-
-  -- attribute setup
-  -- There's no secure way to do PetAutoCastToggle by actionID, so use
-  -- a click-through proxy to the Blizzard pet buttons for right-click
-  -- Note that technically this doesn't do PetStopAttack() when 
-  -- IsPetAttackActive() is true: however that's only true when using
-  -- Eyes of the Beast and appears not to really do anything (at least
-  -- I can't find any difference)
-  f:SetAttribute("type","pet")
-  f:SetAttribute("type2","click")
-  f:SetAttribute("clickbutton2",_G["PetActionButton"..config.actionID])
-  f:SetAttribute("action",config.actionID)
-  f:SetAttribute("checkselfcast", true)
-  f:SetAttribute("checkfocuscast", true)
-
-  -- non secure scripts
-  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
-  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
-  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
-  f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
-  f:SetScript("PreClick", function(frame) self:PreClick() end)
-  f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
-  f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)
-
-  -- secure handlers
-  barFrame:WrapScript(f, "OnDragStart", _onDragStart)
-  barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
-
-  -- event registration
-  f:EnableMouse(true)
-  f:RegisterForDrag("LeftButton", "RightButton")
-  f:RegisterForClicks("AnyUp")
-  for _, evt in pairs(eventList) do
-    f:RegisterEvent(evt)
-  end
-
-  -- attach to skinner
-  bar:SkinButton(self,
-   {
-     AutoCast = f.autoCastShine,
-     AutoCastable = f.autoCastTexture
-   })
-
-  self:Refresh()
-  f:Show()
-
-  return self
-end
-
-function Pet:Refresh()
-  Super.Refresh(self)
-  self:Update()
-  self:UpdateHotkey()
-end
-
-function Pet:GetActionID()
-  return self.config.actionID
-end
-
-function Pet:SetActionID(id)
-  if not InCombatLockdown() then
-    if id < 0 or id > 10 then
-      ReAction:UserError(L["Pet action ID range is 1-10"])
-      return
-    end
-    self.config.actionID = id
-    f:SetAttribute("clickbutton2",_G["PetActionButton"..id])
-    f:SetAttribute("action",id)
-    self:Update()
-    self:UpdateHotkey()
-  end
-end
-
-function Pet:Update()
-  local action = self.config.actionID
-  local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(action)
-  local f = self:GetFrame()
-  local icon = self.frames.icon
-
-  if isToken then
-    icon:SetTexture(_G[texture])
-    self.tooltipName = _G[name]
-  else
-    icon:SetTexture(texture)
-    self.tooltipName = name
-  end
-
-  self.isToken = isToken
-	self.tooltipSubtext = subtext
-  f:SetChecked( isActive and 1 or 0 )
-
-  if autoCastAllowed then
-    f.autoCastTexture:Show()
-  else
-    f.autoCastTexture:Hide()
-  end
-
-  if autoCastEnabled then
-    AutoCastShine_AutoCastStart(f.autoCastShine)
-  else
-    AutoCastShine_AutoCastStop(f.autoCastShine)
-  end
-
-  if texture then
-    if GetPetActionSlotUsable(action) then
-      SetDesaturation(icon,nil)
-    else
-      SetDesaturation(icon,1)
-    end
-    icon:Show()
-    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
-  else
-    icon:Hide()
-    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
-  end
-
-  self:UpdateCooldown()
-end
-
-function Pet:UpdateCooldown()
-  CooldownFrame_SetTimer(self.frames.cooldown, GetPetActionCooldown(self.config.actionID))
-end
-
-function Pet:SetTooltip()
-  if self.tooltipName then
-    local f = self:GetFrame()
-    local uber = GetCVar("UberTooltips")
-    if self.isToken or (uber == "0") then
-      if uber == "0" then
-        GameTooltip:SetOwner(f, "ANCHOR_RIGHT")
-      else
-        GameTooltip_SetDefaultAnchor(GameTooltip, f)
-      end
-      GameTooltip:SetText(self.tooltipName)
-      if self.tooltipSubtext then
-        GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5)
-      end
-      GameTooltip:Show()
-    else
-      GameTooltip_SetDefaultAnchor(GameTooltip, f)
-      GameTooltip:SetPetAction(self.config.actionID)
-    end
-  else
-    GameTooltip:Hide()
-  end
-end
-
-function Pet:OnEvent(event, unit)
-  if event =="PET_BAR_UPDATE_COOLDOWN" then
-    self:UpdateCooldown()
-  elseif event == "UPDATE_BINDINGS" then
-    self:UpdateHotkey()
-  elseif event == "UNIT_PET" then
-    if unit == "player" then
-      self:Update()
-    end
-  elseif event == "UNIT_FLAGS" or event == "UNIT_AURA" then
-    if unit == "pet" then
-      self:Update()
-    end
-  else
-    self:Update()
-  end
-end
-
-function Pet:OnEnter()
-  self:SetTooltip()
-end
-
-function Pet:OnLeave()
-  GameTooltip:Hide()
-end
-
-function Pet:OnAttributeChanged(attr,value)
-  self:Update()
-end
-
-function Pet:PreClick()
-  self:GetFrame():SetChecked(0)
-end
-
-function Pet:OnDragStart()
-  self:SetChecked(0)
-  self:Update()
-end
-
-function Pet:OnReceiveDrag()
-  self:SetChecked(0)
-  self:Update()
-end
-
--- a/classes/StanceButton.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local GetCVar = GetCVar
-local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
-local CooldownFrame_SetTimer = CooldownFrame_SetTimer
-local InCombatLockdown = InCombatLockdown
-local GetNumShapeshiftForms = GetNumShapeshiftForms
-local GetShapeshiftFormInfo = GetShapeshiftFormInfo
-local IsUsableSpell = IsUsableSpell
-local GetSpellInfo = GetSpellInfo
-
---
--- private
---
-local playerClass = select(2,UnitClass("player"))
-
-local eventList = {
-  "PLAYER_REGEN_ENABLED",
-  "PLAYER_ENTERING_WORLD",
-  "UPDATE_SHAPESHIFT_FORM",
-  "UPDATE_SHAPESHIFT_FORMS",
-  "UPDATE_SHAPESHIFT_USABLE",
-  "UPDATE_SHAPESHIFT_COOLDOWN",
-  "UPDATE_BINDINGS",
-}
-
---
--- Stance Button class
---
-local Super = ReAction.Button
-local Stance = setmetatable( { }, { __index = Super } )
-ReAction.Button.Stance = Stance
-
-function Stance:New( idx, moduleConfig, bar, idHint )
-  local name = format("ReAction_%s_Stance_%d",bar:GetName(),idx)
- 
-  self = Super.New(self, name, moduleConfig.buttons[bar:GetName()][idx], bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
-  self.moduleConfig = moduleConfig
-
-  local f = self:GetFrame()
-  local barFrame = bar:GetFrame()
-  local config = self:GetConfig()
-
-  -- set up the base stance ID
-  self:SetActionIDPool("stance",8)
-  config.stanceID = self:AcquireActionID(config.stanceID, idHint, true)
-
-  -- attribute setup
-  f:SetAttribute("type","spell")
-
-  -- non secure scripts
-  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
-  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
-  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
-  f:SetScript("PreClick", function(frame, ...) self:PreClick(...) end)
-
-  -- secure handlers
-  -- (none)
-
-  -- event registration
-  f:EnableMouse(true)
-  f:RegisterForClicks("AnyUp")
-  for _, evt in pairs(eventList) do
-    f:RegisterEvent(evt)
-  end
-
-  -- attach to skinner
-  bar:SkinButton(self)
-
-  -- initial display
-  if ReAction:GetConfigMode() then
-    self:GetFrame():Show()
-  end
-
-  self:Refresh()
-
-  return self
-end
-
-function Stance:GetActionID()
-  return self.config.stanceID
-end
-
-function Stance:UpdateAction()
-  if InCombatLockdown() then
-    self.updatePending = true
-  else
-    self.updatePending = false
-    local idx = self:GetActionID()
-    local f = self:GetFrame()
-    if idx > GetNumShapeshiftForms() then
-      f:Hide()
-    else
-      f:SetAttribute("spell", select(2,GetShapeshiftFormInfo(idx)))
-      f:Show()
-      self:Update()
-    end
-  end
-end
-
-function Stance:Refresh()
-  Super.Refresh(self)
-  self:UpdateHotkey()
-  self:UpdateAction()
-end
-
-function Stance:Update()
-  local texture, _, isActive, isCastable = GetShapeshiftFormInfo(self:GetActionID())
-  
-  local icon = self.frames.icon
-  icon:SetTexture(texture)
-  self:GetFrame():SetChecked( isActive and 1 or 0 )
-  if isCastable then
-    self.frames.hotkey:Show()
-    icon:SetVertexColor(1.0, 1.0, 1.0)
-  else
-    icon:SetVertexColor(0.4, 0.4, 0.4)
-  end
-
-  self:UpdateCooldown()
-end
-
-function Stance:UpdateCooldown()
-  local start, duration, enabled = GetShapeshiftFormCooldown(self:GetActionID())
-  if start then
-    CooldownFrame_SetTimer(self.frames.cooldown, start, duration, enabled)
-  end
-end
-
-function Stance:SetTooltip()
-  if GetCVar("UberTooltips") == "1" then
-    GameTooltip_SetDefaultAnchor(GameTooltip, self:GetFrame())
-  else
-    GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_RIGHT")
-  end
-  GameTooltip:SetShapeshift(self:GetActionID())
-end
-
-function Stance:OnEnter()
-  self:SetTooltip()
-end
-
-function Stance:OnLeave()
-  GameTooltip:Hide()
-end
-
-function Stance:PreClick()
-  local f = self:GetFrame()
-  f:SetChecked( not f:GetChecked() )
-end
-
-function Stance:OnEvent(event, arg)
-  if event == "PLAYER_REGEN_ENABLED" then
-    if self.updatePending then
-      self:UpdateAction()
-    end
-  elseif event == "UPDATE_SHAPESHIFT_COOLDOWN" then
-    self:UpdateCooldown()
-  elseif event == "UPDATE_SHAPESHIFT_FORMS" then
-    self:UpdateAction()
-  elseif event == "UNIT_AURA" then
-    if arg == "player" then
-      self:Update()
-    end
-  elseif event == "UPDATE_BINDINGS" then
-    self:UpdateHotkey()
-  else
-    self:Update()
-  end
-end
-
-function Stance:ShowGridTemp(show)
-  if show then
-    self:GetFrame():Show()
-  else
-    self:UpdateAction()
-  end
-end
--- a/classes/VehicleExitButton.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local format = string.format
-
---
--- VExitButton Button class
---
-local Super = ReAction.Button
-local VExitButton = setmetatable( { }, { __index = Super } )
-ReAction.Button.VehicleExit = VExitButton
-
-function VExitButton:New( idx, config, bar )
-  local name = format("ReAction_%s_VehicleExit_%d",bar:GetName(),idx)
- 
-  self = Super.New(self, name, config, bar, idx, "SecureFrameTemplate, ActionButtonTemplate", "Button")
-
-  -- frame setup
-  local f = self:GetFrame()
-  self.frames.icon:SetTexture("Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up")
-  self.frames.icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
-
-  -- attribute setup
-  -- (none)
-
-  -- non secure scripts
-  f:SetScript("OnClick", VehicleExit)
-  f:SetScript("OnEnter", function(frame) GameTooltip_AddNewbieTip(frame, LEAVE_VEHICLE, 1.0, 1.0, 1.0, nil) end)
-  f:SetScript("OnLeave", GameTooltip_Hide)
-  f:SetScript("OnEvent", function(frame, evt, ...) self:OnEvent(evt,...) end)
-
-  -- event registration
-  f:EnableMouse(true)
-  f:RegisterForClicks("AnyUp")
-  f:RegisterEvent("UPDATE_BINDINGS")
-
-  -- attach to skinner
-  bar:SkinButton(self)
-
-  self:Refresh()
-  self:UpdateHotkey()
-
-  return self
-end
-
-function VExitButton:GetActionID()
-  return 1
-end
-
-function VExitButton:Refresh()
-  Super.Refresh(self)
-  -- it seems that setscale kills the texcoord, have to refresh it
-  self.frames.icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375) 
-end
-
-function VExitButton:OnEvent(event, ...)
-  if self[event] then
-    self[event](self, event, ...)
-  end
-end
-
-function VExitButton:UPDATE_BINDINGS()
-  self:UpdateHotkey()
-end
--- a/classes/classes.xml	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-<Ui xmlns="http://www.blizzard.com/wow/ui/" 
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-    xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
-
-<Script file="Bar.lua"/>
-<Script file="Overlay.lua"/>
-<Script file="Button.lua"/>
-<Script file="ActionButton.lua"/>
-<Script file="PetActionButton.lua"/>
-<Script file="StanceButton.lua"/>
-<Script file="BagButton.lua"/>
-<Script file="VehicleExitButton.lua"/>
-<Script file="MultiCastButton.lua"/>
-
-</Ui>
\ No newline at end of file
--- a/locale/enUS.lua	Thu Nov 18 13:11:08 2010 -0800
+++ b/locale/enUS.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -4,7 +4,6 @@
 for _, string in pairs({
 
 -- ReAction.lua
-"Bar ",
 "ReAction: name '%s' already in use",
 "ReAction config mode disabled during combat.",
 
@@ -80,13 +79,20 @@
 "Y offset",
 "Transparency",
 
--- PetActionButton.lua
-"Pet action ID range is 1-10",
-
--- ActionButton.lua
+-- classes/ActionButton.lua
+"Action Bar",
 "Action ID range is 1-120",
 
--- Overlay.lua
+-- classes/BagButton.lua --
+"Bag Bar",
+
+-- classes/Bar.lua
+"Hidden",
+
+-- classes/Button.lua --
+"Button Bar",
+
+-- classes/Overlay.lua
 "Hold Shift",
 "Hold Alt",
 "Right-click",
@@ -102,10 +108,20 @@
 "State",
 "State Scale Override",
 
--- Bar.lua
-"Hidden",
+-- classes/MultiCastButton.lua
+"Totem Bar",
 
--- State.lua
+-- classes/PetActionButton.lua
+"Pet Action Bar",
+"Pet action ID range is 1-10",
+
+-- classes/StanceButton.lua
+"Stance Bar",
+
+-- classes/VehicleExitButton.lua
+"Exit Vehicle Floater",
+
+-- modules/State.lua
 "State named '%s' already exists",
 "Battle Stance",
 "Defensive Stance",
@@ -187,8 +203,7 @@
 "Create State",
 "State named '%s' already exists",
 
--- Action
-"Action Bar",
+-- modules/Action.lua
 "Action Bars",
 "Hide Empty Buttons",
 "Lock Buttons",
@@ -219,12 +234,10 @@
 "Show Page #",
 "Action Buttons",
 
--- PetAction
-"Pet Action Bar",
+-- modules/PetAction.lua
 "Pet Buttons",
 
--- Stance
-"Stance Bar",
+-- modules/Stance.lua
 "Stance Buttons",
 "Show Aspects",
 "Show Hunter aspects as stances",
@@ -235,15 +248,7 @@
 "Hide Auras",
 "Do not show Paladin Auras as stances",
 
--- Totem
-"Totem Bar",
-"Totem Buttons",
-
--- Bag
-"Bag Bar",
-
--- VehicleExit
-"Exit Vehicle Floater",
+-- modules/VehicleExit.lua
 "Exit Vehicle",
 "Show only when passenger",
 "Only show the button when riding as a passenger in a vehicle (no vehicle controls)",
--- a/modules/Action.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,611 +0,0 @@
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-local wipe = wipe
-
-local weak = { __mode="k" }
-
--- module declaration
-local moduleID = "Action"
-local module = ReAction:NewModule( moduleID )
-
--- Class declarations
-local Button = ReAction.Button.Action -- see /classes/ActionButton.lua
-local Handle = { }
-local PropHandler = { }
-
--- Event handlers
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID,
-    { 
-      profile = {
-        bars = { },
-      }
-    }
-  )
-  self.handles = setmetatable({ }, weak)
-
-  ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
-
-  ReAction.RegisterCallback(self, "OnCreateBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnDestroyBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-end
-
-function module:OnEnable()
-  ReAction:RegisterBarType(L["Action Bar"], 
-    { 
-      type = moduleID,
-      defaultButtonSize = 36,
-      defaultBarRows = 1,
-      defaultBarCols = 12,
-      defaultBarSpacing = 3
-    }, true)
-  ReAction:GetModule("State"):RegisterStateProperty("page", nil, PropHandler.GetOptions(), PropHandler)
-end
-
-function module:OnDisable()
-  ReAction:UnregisterBarType(L["Action Bar"])
-  ReAction:GetModule("State"):UnregisterStateProperty("page")
-end
-
-function module:OnCreateBar(event, bar, name)
-  if bar.config.type == moduleID then
-    local profile = self.db.profile
-    if profile.bars[name] == nil then
-      profile.bars[name] = {
-        buttons = { }
-      }
-    end
-    if self.handles[bar] == nil then
-      self.handles[bar] = Handle:New(bar, profile.bars[name])
-    end
-  end
-end
-
-function module:OnRefreshBar(event, bar, name)
-  if self.handles[bar] then
-    self.handles[bar]:Refresh()
-  end
-end
-
-function module:OnDestroyBar(event, bar, name)
-  if self.handles[bar] then
-    self.handles[bar]:Destroy()
-    self.handles[bar] = nil
-  end
-end
-
-function module:OnEraseBar(event, bar, name)
-  self.db.profile.bars[name] = nil
-end
-
-function module:OnRenameBar(event, bar, oldname, newname)
-  b = self.db.profile.bars
-  b[newname], b[oldname] = b[oldname], nil
-end
-
----- Interface ----
-function module:GetBarOptions(bar)
-  local h = self.handles[bar]
-  if h then
-    return h:GetOptions()
-  end
-end
-
-
----- Bar Handle ----
-
-do
-  local options = {
-    hideEmpty = {
-      name = L["Hide Empty Buttons"],
-      order = 1,
-      type = "toggle",
-      width = "double",
-      get  = "GetHideEmpty",
-      set  = "SetHideEmpty",
-    },
-    lockButtons = {
-      name = L["Lock Buttons"],
-      desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"],
-      order = 2,
-      type = "toggle",
-      get = "GetLockButtons",
-      set = "SetLockButtons",
-    },
-    lockOnlyCombat = {
-      name = L["Only in Combat"],
-      desc = L["Only lock the buttons when in combat"],
-      order = 3,
-      type = "toggle",
-      disabled = "LockButtonsCombatDisabled",
-      get = "GetLockButtonsCombat",
-      set = "SetLockButtonsCombat",
-    },
-    pages = {
-      name  = L["# Pages"],
-      desc  = L["Use the Dynamic State tab to specify page transitions"],
-      order = 4,
-      type  = "range",
-      min   = 1,
-      max   = 10,
-      step  = 1,
-      get   = "GetNumPages",
-      set   = "SetNumPages",
-    },
-    mindcontrol = {
-      name = L["Mind Control Support"],
-      desc = L["When possessing a target (e.g. via Mind Control), map the first 12 buttons of this bar to the possessed target's actions."],
-      order = 5,
-      type = "toggle",
-      width = "double",
-      set = "SetMindControl",
-      get = "GetMindControl",
-    },
-    vehicle = {
-      name = L["Vehicle Support"],
-      desc = L["When on a vehicle, map the first 6 buttons of this bar to the vehicle actions. The vehicle-exit button is mapped to the 7th button. Pitch controls are not supported."],
-      order = 6,
-      type = "toggle",
-      width = "double",
-      get = "GetVehicle",
-      set = "SetVehicle",
-    },
-    actions = {
-      name   = L["Edit Action IDs"],
-      order  = 7,
-      type   = "group",
-      inline = true,
-      args   = {
-        method = {
-          name   = L["Assign"],
-          order  = 1,
-          type   = "select",
-          width  = "double",
-          values = { [0] = L["Choose Method..."],
-                     [1] = L["Individually"],
-                     [2] = L["All at Once"], },
-          get    = "GetActionEditMethod",
-          set    = "SetActionEditMethod",
-        },
-        rowSelect = {
-          name   = L["Row"],
-          desc   = L["Rows are numbered top to bottom"],
-          order  = 2,
-          type   = "select",
-          width  = "half",
-          hidden = "IsButtonSelectHidden",
-          values = "GetRowList",
-          get    = "GetSelectedRow",
-          set    = "SetSelectedRow",
-        },
-        colSelect = {
-          name   = L["Col"],
-          desc   = L["Columns are numbered left to right"],
-          order  = 3,
-          type   = "select",
-          width  = "half",
-          hidden = "IsButtonSelectHidden",
-          values = "GetColumnList",
-          get    = "GetSelectedColumn",
-          set    = "SetSelectedColumn",
-        },
-        pageSelect = {
-          name   = L["Page"],
-          order  = 4,
-          type   = "select",
-          width  = "half",
-          hidden = "IsPageSelectHidden",
-          values = "GetPageList",
-          get    = "GetSelectedPage",
-          set    = "SetSelectedPage",
-        },
-        single = {
-          name   = L["Action ID"],
-          usage  = L["Specify ID 1-120"],
-          order  = 5,
-          type   = "input",
-          width  = "half",
-          hidden = "IsButtonSelectHidden",
-          get    = "GetActionID",
-          set    = "SetActionID",
-          validate = "ValidateActionID",
-        },
-        multi = {
-          name   = L["ID List"],
-          usage  = L["Specify a comma-separated list of IDs for each button in the bar (in order). Separate multiple pages with semicolons (;)"],
-          order  = 6,
-          type   = "input",
-          multiline = true,
-          width  = "double",
-          hidden = "IsMultiIDHidden",
-          get    = "GetMultiID",
-          set    = "SetMultiID",
-          validate = "ValidateMultiID",
-        },
-      },
-    },
-  }
-
-  local meta = { __index = Handle }
-
-  function Handle:New( bar, config )
-    local self = setmetatable(
-      {
-        bar = bar,
-        config = config,
-        btns = { }
-      }, 
-      meta)
-    
-    if self.config.buttons == nil then
-      self.config.buttons = { }
-    end
-    self:Refresh()
-    return self
-  end
-
-  function Handle:Refresh()
-    local r, c = self.bar:GetButtonGrid()
-    local n = r*c
-    local btnCfg = self.config.buttons
-    if n ~= #self.btns then
-      for i = 1, n do
-        if btnCfg[i] == nil then
-          btnCfg[i] = {}
-        end
-        if self.btns[i] == nil then
-          local lastButton = self:GetLastButton()
-          local hint = lastButton and lastButton.config.actionID
-          local b = Button:New(i, self.config, self.bar, hint)
-          self.btns[i] = b
-          self.bar:AddButton(i,b)
-        end
-      end
-      for i = n+1, #self.btns do
-        if self.btns[i] then
-          self.bar:RemoveButton(self.btns[i])
-          self.btns[i]:Destroy()
-          self.btns[i] = nil
-          btnCfg[i] = nil
-        end
-      end
-    end
-    for _, b in ipairs(self.btns) do
-      b:Refresh()
-    end
-    Button.SetupBarHeader(self.bar,self.config)
-    self:UpdateButtonLock()
-  end
-
-  function Handle:Destroy()
-    for _,b in pairs(self.btns) do
-      if b then
-        b:Destroy()
-      end
-    end
-  end
-
-  function Handle:UpdateButtonLock()
-    Button.SetButtonLock(self.bar, self.config.lockButtons, self.config.lockButtonsCombat)
-  end
-
-  function Handle:GetLastButton()
-    return self.btns[#self.btns]
-  end
-
-    -- options handlers
-  function Handle:GetOptions()
-    return {
-      type = "group",
-      name = L["Action Buttons"],
-      handler = self,
-      args = options
-    }
-  end
-
-  function Handle:SetHideEmpty(info, value)
-    if value ~= self.config.hideEmpty then
-      self.config.hideEmpty = value
-      for _, b in pairs(self.btns) do
-        b:ShowGrid(not value)
-      end
-    end
-  end
-
-  function Handle:GetHideEmpty()
-    return self.config.hideEmpty
-  end
-
-  function Handle:GetLockButtons()
-    return self.config.lockButtons
-  end
-
-  function Handle:SetLockButtons(info, value)
-    self.config.lockButtons = value
-    self:UpdateButtonLock()
-  end
-
-  function Handle:GetLockButtonsCombat()
-    return self.config.lockButtonsCombat
-  end
-
-  function Handle:SetLockButtonsCombat(info, value)
-    self.config.lockButtonsCombat = value
-    self:UpdateButtonLock()
-  end
-
-  function Handle:LockButtonsCombatDisabled()
-    return not self.config.lockButtons
-  end
-
-  function Handle:GetNumPages()
-    return self.config.nPages
-  end
-
-  function Handle:SetNumPages(info, value)
-    self.config.nPages = value
-    self:Refresh()
-  end
-
-  function Handle:GetMindControl()
-    return self.config.mindcontrol
-  end
-
-  function Handle:SetMindControl(info, value)
-    self.config.mindcontrol = value
-    self:Refresh()
-  end
-
-  function Handle:GetVehicle()
-    return self.config.vehicle
-  end
-
-  function Handle:SetVehicle(info, value)
-    self.config.vehicle = value
-    self:Refresh()
-  end
-
-  function Handle:GetActionEditMethod()
-    return self.editMethod or 0
-  end
-
-  function Handle:SetActionEditMethod(info, value)
-    self.editMethod = value
-  end
-
-  function Handle:IsButtonSelectHidden()
-    return self.editMethod ~= 1
-  end
-
-  function Handle:GetRowList()
-    local r,c = self.bar:GetButtonGrid()
-    if self.rowList == nil or #self.rowList ~= r then
-      local list = { }
-      for i = 1, r do
-        table.insert(list,i)
-      end
-      self.rowList = list
-    end
-    return self.rowList
-  end
-
-  function Handle:GetSelectedRow()
-    local r, c = self.bar:GetButtonGrid()
-    local row = self.selectedRow or 1
-    if row > r then
-      row = 1
-    end
-    self.selectedRow = row
-    return row
-  end
-
-  function Handle:SetSelectedRow(info, value)
-    self.selectedRow = value
-  end
-
-  function Handle:GetColumnList()
-    local r,c = self.bar:GetButtonGrid()
-    if self.columnList == nil or #self.columnList ~= c then
-      local list = { }
-      for i = 1, c do
-        table.insert(list,i)
-      end
-      self.columnList = list
-    end
-    return self.columnList
-  end
-
-  function Handle:GetSelectedColumn()
-    local r, c = self.bar:GetButtonGrid()
-    local col = self.selectedColumn or 1
-    if col > c then
-      col = 1
-    end
-    self.selectedColumn = col
-    return col
-  end
-
-  function Handle:SetSelectedColumn(info, value)
-    self.selectedColumn = value
-  end
-
-  function Handle:IsPageSelectHidden()
-    return self.editMethod ~= 1 or (self.config.nPages or 1) < 2
-  end
-
-  function Handle:GetPageList()
-    local n = self.config.nPages or 1
-    if self.pageList == nil or #self.pageList ~= n then
-      local p = { }
-      for i = 1, n do
-        table.insert(p,i)
-      end
-      self.pageList = p
-    end
-    return self.pageList
-  end
-
-  function Handle:GetSelectedPage()
-    local p = self.selectedPage or 1
-    if p > (self.config.nPages or 1) then
-      p = 1
-    end
-    self.selectedPage = p
-    return p
-  end
-
-  function Handle:SetSelectedPage(info, value)
-    self.selectedPage = value
-  end
-
-  function Handle:GetActionID()
-    local row = self.selectedRow or 1
-    local col = self.selectedColumn or 1
-    local r, c = self.bar:GetButtonGrid()
-    local n = (row-1) * c + col
-    local btn = self.btns[n]
-    if btn then
-      return tostring(btn:GetActionID(self.selectedPage or 1))
-    end
-  end
-
-  function Handle:SetActionID(info, value)
-    local row = self.selectedRow or 1
-    local col = self.selectedColumn or 1
-    local r, c = self.bar:GetButtonGrid()
-    local n = (row-1) * c + col
-    local btn = self.btns[n]
-    if btn then
-      btn:SetActionID(tonumber(value), self.selectedPage or 1)
-    end
-  end
-
-  function Handle:ValidateActionID(info, value)
-    value = tonumber(value)
-    if value == nil or value < 1 or value > 120 then
-      return L["Specify ID 1-120"]
-    end
-    return true
-  end
-
-  function Handle:IsMultiIDHidden()
-    return self.editMethod ~= 2
-  end
-
-  function Handle:GetMultiID()
-    local p = { }
-    for i = 1, self.config.nPages or 1 do
-      local b = { }
-      for _, btn in ipairs(self.btns) do
-        table.insert(b, btn:GetActionID(i))
-      end
-      table.insert(p, table.concat(b,","))
-    end
-    return table.concat(p,";\n")
-  end
-
-
-  local function ParseMultiID(nBtns, nPages, s)
-    if s:match("[^%d%s,;]") then
-      return nil
-    end
-    local p = { }
-    for list in s:gmatch("[^;]+") do
-      local pattern = ("^%s?$"):format(("%s*(%d+)%s*,"):rep(nBtns))
-      local ids = { list:match(pattern) }
-      if #ids ~= nBtns then
-        return nil
-      end
-      table.insert(p,ids)
-    end
-    if #p ~= nPages then
-      return nil
-    end
-    return p
-  end
-
-  function Handle:SetMultiID(info, value)
-    local p = ParseMultiID(#self.btns, self.config.nPages or 1, value)
-    for page, b in ipairs(p) do
-      for button, id in ipairs(b) do
-        self.btns[button]:SetActionID(id, page)
-      end
-    end
-  end
-
-  function Handle:ValidateMultiID(info, value)
-    local bad = L["Invalid action ID list string"]
-    if value == nil or ParseMultiID(#self.btns, self.config.nPages or 1, value) == nil then
-      return bad
-    end
-    return true
-  end
-end
-
-
------- State property options ------
-do
-  local pageOptions = {
-    page = {
-      name     = L["Show Page #"],
-      order    = 11,
-      type     = "select",
-      width    = "half",
-      disabled = "IsPageDisabled",
-      hidden   = "IsPageHidden",
-      values   = "GetPageValues",
-      set      = "SetProp",
-      get      = "GetPage",
-    },
-  }
-
-  local function GetBarConfig(bar)
-    return module.db.profile.bars[bar:GetName()]
-  end
-
-  function PropHandler.GetOptions()
-    return pageOptions
-  end
-
-  function PropHandler:IsPageDisabled()
-    local c = GetBarConfig(self.bar)
-    local n = c and c.nPages or 1
-    return not (n > 1)
-  end
-
-  function PropHandler:IsPageHidden()
-    return not GetBarConfig(self.bar)
-  end
-
-  function PropHandler:GetPageValues()
-    if not self._pagevalues then
-      self._pagevalues = { }
-    end
-    local c = GetBarConfig(self.bar)
-    if c then
-      local n = c.nPages
-        -- cache the results
-      if self._npages ~= n then
-        self._npages = n
-        wipe(self._pagevalues)
-        for i = 1, n do
-          self._pagevalues["page"..i] = i
-        end
-      end
-    end
-    return self._pagevalues
-  end
-
-  function PropHandler:GetPage(info)
-    return self:GetProp(info) or 1
-  end
-
-end
-
--- a/modules/Bag.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
---[[
-  ReAction Bag button module
-
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-
--- Bag button 
-local Button = ReAction.Button.Bag
-
--- module declaration
-local moduleID = "Bag"
-local module = ReAction:NewModule( moduleID
-  -- mixins go here
-)
-
--- handlers
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID,
-    {
-      profile = { 
-        buttons = { }
-      }
-    }
-  )
-
-  self.buttons = { }
-
-  ReAction.RegisterCallback(self, "OnCreateBar", "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnDestroyBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-end
-
-function module:OnEnable()
-  ReAction:RegisterBarType(L["Bag Bar"], 
-    { 
-      type = moduleID ,
-      defaultButtonSize = 30,
-      defaultBarRows = 1,
-      defaultBarCols = 6,
-      defaultBarSpacing = 4
-    })
-end
-
-function module:OnDisable()
-  ReAction:UnregisterBarType(L["Bag Bar"])
-end
-
-function module:OnDestroyBar(event, bar, name)
-  local btns = self.buttons[bar]
-  if btns then
-    for _,b in pairs(btns) do
-      if b then
-        b:Destroy()
-      end
-    end
-    self.buttons[bar] = nil
-  end
-end
-
-function module:OnRefreshBar(event, bar, name)
-  if bar.config.type == moduleID then
-    local btns = self.buttons[bar]
-    if btns == nil then
-      btns = { }
-      self.buttons[bar] = btns
-    end
-    local profile = self.db.profile
-    if profile.buttons[name] == nil then
-      profile.buttons[name] = {}
-    end
-    local btnCfg = profile.buttons[name]
-
-    local r, c = bar:GetButtonGrid()
-    local n = r*c
-    for i = 1, n do
-      if btnCfg[i] == nil then
-        btnCfg[i] = {}
-      end
-      if btns[i] == nil then
-        local success, r = pcall(Button.New,Button,i,profile,bar,i>1 and btnCfg[i-1].bagID)
-        if success and r then
-          btns[i] = r
-          bar:AddButton(i,r)
-        else
-          n = i - 1
-          bar:ClipNButtons(n)
-          break
-        end
-      end
-      btns[i]:Refresh()
-    end
-    for i = n+1, #btns do
-      if btns[i] then
-        bar:RemoveButton(btns[i])
-        btns[i] = btns[i]:Destroy()
-        if btnCfg[i] then
-          btnCfg[i] = nil
-        end
-      end
-    end
-  end
-
-end
-
-function module:OnEraseBar(event, bar, name)
-  self.db.profile.buttons[name] = nil
-end
-
-function module:OnRenameBar(event, bar, oldName, newName)
-  local b = self.db.profile.buttons
-  b[newname], b[oldname] = b[oldname], nil
-end
-
-
--- hook some functions to propagate to our bag buttons
-hooksecurefunc("Disable_BagButtons", 
-  function()
-    for _, buttons in pairs(module.buttons) do
-      for _, b in pairs(buttons) do
-        local f = b:GetFrame()
-        f:Disable()
-        SetDesaturation(b.frames.icon,1)
-      end
-    end
-  end)
-
-hooksecurefunc("Enable_BagButtons",
-  function()
-    for _, buttons in pairs(module.buttons) do
-      for _, b in pairs(buttons) do
-        local f = b:GetFrame()
-        f:Enable()
-        SetDesaturation(b.frames.icon,nil)
-      end
-    end
-  end)
-
-hooksecurefunc("ContainerFrame_OnHide",
-  function()
-    for _, buttons in pairs(module.buttons) do
-      for _, b in pairs(buttons) do
-        b:Update()
-      end
-    end
-  end)
-
-hooksecurefunc("ContainerFrame_OnShow",
-  function()
-    for _, buttons in pairs(module.buttons) do
-      for _, b in pairs(buttons) do
-        b:Update()
-      end
-    end
-  end)
--- a/modules/HideBlizzard.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
---[[
-  ReAction 'Hide Blizzard' module
-
-  Hides Blizzard action bars. This hides the extra action bars, stance bar, pet bar, and 
-  main menu bar, which in turn hides the experience bar, bag bar, micro menu bar, and lag meter.
-
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-
--- module declaration
-local moduleID = "HideBlizzard"
-local module = ReAction:NewModule( moduleID )
-
-
--- module methods
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID,
-    { 
-      profile = {
-        hide = false
-      }
-    }
-  )
-  self.db.RegisterCallback(self,"OnProfileChanged")
-  self.db.RegisterCallback(self,"OnProfileCopied", "OnProfileChanged")
-  self.db.RegisterCallback(self,"OnProfileReset",  "OnProfileChanged")
-
-  self.hiddenFrame = CreateFrame("Frame")
-  self.hiddenFrame:Hide()
-
-  -- 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)
-
-end
-
-function module:OnEnable()
-  self:UpdateFrames()
-end
-
-function module:OnDisable()
-  self:UpdateFrames(true)
-end
-
-function module:OnProfileChanged()
-  self:UpdateFrames()
-end
-
-local frames = {
-  [ MainMenuBar         ] = { },
-  [ MultiBarLeft        ] = { },
-  [ MultiBarRight       ] = { },
-  [ MultiBarBottomLeft  ] = { },
-  [ MultiBarBottomRight ] = { },
-  [ VehicleMenuBar      ] = { field = "hideVehicle" },
-}
-
-function module:UpdateFrames( show )
-  show = show or not self.db.profile.hide
-  for frame, info in pairs(frames) do
-    local show = show  -- make a local copy for this frame
-    if info.field then
-      show = show or not self.db.profile[info.field]
-    end
-
-    if show then
-      if info.parent then
-        frame:SetParent(info.parent)
-      end
-      if frame:IsShown() then
-        frame:Show() -- refresh
-      end
-    else
-      if not info.parent then
-        info.parent = frame:GetParent()
-      end
-      frame:SetParent(self.hiddenFrame)
-    end
-  end
-end
-
-function module:IsHidden(info)
-  if info then
-    return self.db.profile.hide and self.db.profile[info[#info]]
-  else
-    return self.db.profile.hide
-  end
-end
-
-function module:SetHidden(info,value)
-  self.db.profile[info[#info]] = value
-  self:UpdateFrames()
-end
-
-function module:OptionDisabled(info)
-  local disabled = InCombatLockdown()
-  if not disabled and info[#info] ~= "hide" then
-    disabled = not self.db.profile.hide
-  end
-  return disabled
-end
-
-
--- reroute blizzard action bar config to ReAction config window
-InterfaceOptionsActionBarsPanel:HookScript("OnShow", 
-  function() 
-    if module:IsEnabled() and module:IsHidden() then
-      ReAction:ShowOptions()
-    end
-  end )
--- a/modules/LBF.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-
--- module declaration
-local moduleID = "ButtonFacade"
-local module = ReAction:NewModule( moduleID )
-
--- handlers
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID,
-    {
-      profile = {
-        -- default profile goes here
-      }
-    }
-  )
-
-  self.groups = { }
-
-  self.LBF = LibStub("LibButtonFacade",true)
-
-  if not self.LBF then -- no more initialization
-    return
-  end
-
-  -- override a method of ReAction.Bar
-  -- note that 'self' in this context refers to the bar
-  function ReAction.Bar:SkinButton( button, data )
-    module:GetGroup(self:GetName()):AddButton(button:GetFrame(), data)
-  end
-
-  -- register some common events
-  ReAction.RegisterCallback(self, "OnCreateBar")
-  ReAction.RegisterCallback(self, "OnDestroyBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-
-  self.LBF:RegisterSkinCallback("ReAction", self.OnSkinChanged, self)
-end
-
-function module:OnEnable()
-
-end
-
-function module:OnDisable()
-
-end
-
-function module:OnCreateBar(event, bar, name)
-  local c = self.db.profile[name]
-  if not c then
-     c = { 
-      skinID = "Blizzard",
-      backdrop = true,
-      gloss = 0,
-      colors = {},
-    }
-    self.db.profile[name] = c
-  end
-
-  local g = self:GetGroup(name)
-  g.SkinID   = c.skinID or "Blizzard"
-  g.Backdrop = c.backdrop
-  g.Gloss    = c.gloss
-  g.Colors   = c.colors
-end
-
-function module:OnDestroyBar(event, bar, name)
-  if self.groups[name] then
-    self.groups[name]:Delete()
-    self.groups[name] = nil
-  end
-end
-
-function module:OnRefreshBar(event, bar, name)
-  local c = self.db.profile[name]
-  local g = self.groups[name]
-  if c and g then
-    g:Skin(c.skinID, c.gloss, c.backdrop, c.colors)
-  end
-end
-
-function module:OnEraseBar(event, bar, name)
-  self:OnDestroyBar(event, bar, name)
-  self.db.profile[name] = nil
-end
-
-function module:OnRenameBar(event, bar, oldName, newName)
-  if self.groups[name] then
-    self.groups[name]:Delete(true)
-    self.db.profile[oldName], self.db.profile[newName] = nil, self.db.profile[oldName]
-    self:OnCreateBar(event, bar, newName)
-  end
-end
-
-function module:OnSkinChanged( skinID, gloss, backdrop, group, button, colors )
-  local c = self.db.profile[group]
-  if c then
-    c.skinID   = skinID
-    c.gloss    = gloss
-    c.backdrop = backdrop
-    c.colors   = colors
-  end  
-end
-
-function module:GetGroup( name )
-  if not self.groups[name] then
-    self.groups[name] = self.LBF:Group("ReAction", name)
-  end
-  return self.groups[name]
-end
--- a/modules/ModuleTemplate.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
---[[
-  ReAction module template
-
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-
--- module declaration
-local moduleID = "MyModuleName"
-local module = ReAction:NewModule( moduleID
-  -- mixins go here
-)
-
--- handlers
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID,
-    {
-      profile = {
-        -- default profile goes here
-      }
-    }
-  )
-
-  -- register some common events
-  ReAction.RegisterCallback(self, "OnCreateBar")
-  ReAction.RegisterCallback(self, "OnDestroyBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-end
-
-function module:OnEnable()
-
-end
-
-function module:OnDisable()
-
-end
-
--- apply module features and settings to a bar object (see Bar.lua for Bar API)
-function module:OnCreateBar(event, bar, name)
-
-end
-
--- remove module features and settings from a bar object
-function module:OnDestroyBar(event, bar, name)
-
-end
-
--- refresh module features and settings on a bar object
-function module:OnRefreshBar(event, bar, name)
-
-end
-
--- erase any local configuration entries for the supplied bar name
-function module:OnEraseBar(event, bar, name)
-
-end
-
--- update any local configuration/option entries with the new bar name index
-function module:OnRenameBar(event, bar, oldName, newName)
-
-end
-
-
--- a/modules/PetAction.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,209 +0,0 @@
---[[
-  ReAction Pet Action button module
-
-  The button module implements standard action button functionality by wrapping Blizzard's 
-  PetActionButton frame and associated functions.
-
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local CreateFrame = CreateFrame
-local format = string.format
-
--- module declaration
-local moduleID = "PetAction"
-local module = ReAction:NewModule( moduleID )
-
--- Button class
-local Button = ReAction.Button.PetAction
-
--- private
-local function UpdateButtonLock(bar)
-  local f = bar:GetFrame()
-  f:SetAttribute("lockbuttons",bar.config.lockButtons)
-  f:SetAttribute("lockbuttonscombat",bar.config.lockButtonsCombat)
-  f:Execute(
-    [[
-      lockButtons = self:GetAttribute("lockbuttons")
-      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
-    ]])
-end
-
--- module methods
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID,
-    { 
-      profile = {
-        buttons = { }
-      }
-    }
-  )
-  self.buttons = { }
-
-  ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
-
-  ReAction.RegisterCallback(self, "OnCreateBar")
-  ReAction.RegisterCallback(self, "OnDestroyBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-end
-
-function module:OnEnable()
-  ReAction:RegisterBarType(L["Pet Action Bar"], 
-    { 
-      type = moduleID ,
-      defaultButtonSize = 30,
-      defaultBarRows = 1,
-      defaultBarCols = 10,
-      defaultBarSpacing = 8
-    })
-end
-
-function module:OnDisable()
-  ReAction:UnregisterBarType(L["Pet Action Bar"])
-end
-
-function module:OnCreateBar(event, bar, name)
-  if bar.config.type == moduleID then
-    -- auto show/hide when pet exists
-    bar:RegisterUnitWatch("pet",true)
-    self:OnRefreshBar(event, bar, name)
-  end
-end
-
-function module:OnRefreshBar(event, bar, name)
-  if bar.config.type == moduleID then
-    if self.buttons[bar] == nil then
-      self.buttons[bar] = { }
-    end
-    local btns = self.buttons[bar]
-    local profile = self.db.profile
-    if profile.buttons[name] == nil then
-      profile.buttons[name] = {}
-    end
-    local btnCfg = profile.buttons[name]
-
-    local r, c = bar:GetButtonGrid()
-    local n = r*c
-    for i = 1, n do
-      if btnCfg[i] == nil then
-        btnCfg[i] = {}
-      end
-      if btns[i] == nil then
-        local success, r = pcall(Button.New,Button,i,btnCfg[i],bar,i>1 and btnCfg[i-1].actionID)
-        if success and r then
-          btns[i] = r
-          bar:AddButton(i,r)
-        else
-          n = i - 1
-          bar:ClipNButtons(n)
-          break
-        end
-      end
-      btns[i]:Refresh()
-    end
-    for i = n+1, #btns do
-      if btns[i] then
-        bar:RemoveButton(btns[i])
-        btns[i] = btns[i]:Destroy()
-        if btnCfg[i] then
-          btnCfg[i] = nil
-        end
-      end
-    end
-    UpdateButtonLock(bar)
-  end
-end
-
-function module:OnDestroyBar(event, bar, name)
-  if self.buttons[bar] then
-    local btns = self.buttons[bar]
-    for _,b in pairs(btns) do
-      if b then
-        b:Destroy()
-      end
-    end
-    self.buttons[bar] = nil
-  end
-end
-
-function module:OnEraseBar(event, bar, name)
-  self.db.profile.buttons[name] = nil
-end
-
-function module:OnRenameBar(event, bar, oldname, newname)
-  local b = self.db.profile.buttons
-  b[newname], b[oldname] = b[oldname], nil
-end
-
-
----- Options ----
-local Handler = { }
-local meta = { __index = Handler }
-
-function Handler:New(bar)
-  return setmetatable(
-    {
-      bar = bar,
-      config = bar.config
-    }, meta)
-end
-
-function Handler:GetLockButtons()
-  return self.config.lockButtons
-end
-
-function Handler:SetLockButtons(info, value)
-  self.config.lockButtons = value
-  UpdateButtonLock(self.bar)
-end
-
-function Handler:GetLockButtonsCombat()
-  return self.config.lockButtonsCombat
-end
-
-function Handler:SetLockButtonsCombat(info, value)
-  self.config.lockButtonsCombat = value
-  UpdateButtonLock(self.bar)
-end
-
-function Handler:LockButtonsCombatDisabled()
-  return not self.config.lockButtons
-end
-
-
-function module:GetBarOptions(bar)
-  if bar.config.type == moduleID then
-    return {
-      type = "group",
-      name = L["Pet Buttons"],
-      handler = Handler:New(bar),
-      args = {
-        lockButtons = {
-          name = L["Lock Buttons"],
-          desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"],
-          order = 2,
-          type = "toggle",
-          get = "GetLockButtons",
-          set = "SetLockButtons",
-        },
-        lockOnlyCombat = {
-          name = L["Only in Combat"],
-          desc = L["Only lock the buttons when in combat"],
-          order = 3,
-          type = "toggle",
-          disabled = "LockButtonsCombatDisabled",
-          get = "GetLockButtonsCombat",
-          set = "SetLockButtonsCombat",
-        },
-      }
-    }
-  end
-end
-
-
--- a/modules/Stance.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
---[[
-  ReAction Stance button module
-
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-
--- Stance button 
-local Button = ReAction.Button.Stance
-
--- module declaration
-local moduleID = "Stance"
-local module = ReAction:NewModule( moduleID
-  -- mixins go here
-)
-
--- handlers
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID,
-    {
-      profile = { 
-        buttons = { }
-      }
-    }
-  )
-
-  self.buttons = { }
-
-  ReAction.RegisterCallback(self, "OnCreateBar", "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnDestroyBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-end
-
-function module:OnEnable()
-  ReAction:RegisterBarType(L["Stance Bar"], 
-    { 
-      type = moduleID ,
-      defaultButtonSize = 36,
-      defaultBarRows = 1,
-      defaultBarCols = 6,
-      defaultBarSpacing = 3
-    })
-
-end
-
-function module:OnDisable()
-  ReAction:UnregisterBarType(L["Stance Bar"])
-end
-
-function module:OnDestroyBar(event, bar, name)
-  local btns = self.buttons[bar]
-  if btns then
-    for _,b in pairs(btns) do
-      if b then
-        b:Destroy()
-      end
-    end
-    self.buttons[bar] = nil
-  end
-end
-
-function module:OnRefreshBar(event, bar, name)
-  if bar.config.type == moduleID then
-    local btns = self.buttons[bar]
-    if btns == nil then
-      btns = { }
-      self.buttons[bar] = btns
-    end
-    local profile = self.db.profile
-    if profile.buttons[name] == nil then
-      profile.buttons[name] = {}
-    end
-    local btnCfg = profile.buttons[name]
-
-    local r, c = bar:GetButtonGrid()
-    local n = r*c
-    for i = 1, n do
-      if btnCfg[i] == nil then
-        btnCfg[i] = {}
-      end
-      if btns[i] == nil then
-        local success, r = pcall(Button.New,Button,i,profile,bar,i>1 and btnCfg[i-1].stanceID)
-        if success and r then
-          btns[i] = r
-          bar:AddButton(i,r)
-        else
-          n = i - 1
-          bar:ClipNButtons(n)
-          break
-        end
-      end
-      btns[i]:Refresh()
-    end
-    for i = n+1, #btns do
-      if btns[i] then
-        bar:RemoveButton(btns[i])
-        btns[i] = btns[i]:Destroy()
-        if btnCfg[i] then
-          btnCfg[i] = nil
-        end
-      end
-    end
-  end
-
-end
-
-function module:OnEraseBar(event, bar, name)
-  self.db.profile.buttons[name] = nil
-end
-
-function module:OnRenameBar(event, bar, oldName, newName)
-  local b = self.db.profile.buttons
-  b[newname], b[oldname] = b[oldname], nil
-end
-
-function module:RefreshAll()
-  for bar in pairs(self.buttons) do
-    self:OnRefreshBar(nil,bar,bar:GetName())
-  end
-end
-
--- a/modules/State.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,915 +0,0 @@
---[[
-  ReAction bar state driver interface
-
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-local format = string.format
-local InCombatLockdown = InCombatLockdown
-local RegisterStateDriver = RegisterStateDriver
-
--- module declaration
-local moduleID = "State"
-local module = ReAction:NewModule( moduleID, "AceEvent-3.0" )
-
--- Utility --
-
--- 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
-
-
-local ApplyStates, CleanupStates, SetProperty, GetProperty, RegisterProperty
-
--- PRIVATE --
-do
-  function GetProperty( bar, state, propname )
-    return tfetch(module.db.profile.bars, bar:GetName(), "states", state, propname)
-  end
-
-  function SetProperty( bar, state, propname, value )
-    local s = tbuild(module.db.profile.bars, bar:GetName(), "states", state)
-    s[propname] = value
-    bar:SetSecureStateData(state, propname, value)
-  end
-
-  function RegisterProperty( propname, snippet )
-    for _, bar in ReAction:IterateBars() do
-      if type(snippet) == "string" then
-        bar:SetSecureStateExtension(propname,snippet)
-      end
-      ApplyStates(bar)
-    end
-  end
-
-  function UnregisterProperty( propname )
-    for _, bar in ReAction:IterateBars() do
-      bar:SetSecureStateExtension(propname,nil)
-      ApplyStates(bar)
-    end
-  end
-
-  function ApplyStates( bar )
-    local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
-    if states then
-      bar:SetStateDriver(states)
-    end
-  end
-
-  function CleanupStates( bar )
-    bar:SetStateDriver(nil)
-  end
-end
-
-
-
--- module event handlers --
-
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID, 
-    {
-      profile = { 
-        bars = { },
-      }
-    }
-  )
-
-  self:RegisterEvent("UPDATE_SHAPESHIFT_FORMS")
-
-  ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
-
-  ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnDestroyBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-end
-
-function module:OnEnable()
-  self:UPDATE_SHAPESHIFT_FORMS() -- it doesn't fire on a /reloadui
-end
-
-function module: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. 
-  ReAction.Bar.InitRuleFormats()
-  for _, bar in ReAction:IterateBars() do
-    ApplyStates(bar)
-  end
-end
-
-function module:OnRefreshBar(event, bar, name)
-  local c = self.db.profile.bars[name]
-  if c then
-    ApplyStates(bar)
-  end
-end
-
-function module:OnDestroyBar(event, bar, name)
-  CleanupStates(bar)
-end
-
-function module:OnEraseBar(event, bar, name)
-  self.db.profile.bars[name] = nil
-end
-
-function module:OnRenameBar(event, bar, oldname, newname)
-  local bars = self.db.profile.bars
-  bars[newname], bars[oldname] = bars[oldname], nil
-end
-
-
-
--- Options --
-
-local CreateBarOptions, RegisterPropertyOptions
-do
-  -- pre-sorted by the order they should appear in
-  local rules = {
-    --  rule       fields
-    { "stance",  { {battle = L["Battle Stance"]}, {defensive = L["Defensive Stance"]}, {berserker = L["Berserker Stance"]} } },
-    { "form",    { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {tree = L["Tree of Life"]}, {moonkin = L["Moonkin Form"]} } },
-    { "stealth", { {stealth = L["Stealth"]}, {nostealth = L["No Stealth"]}, {shadowdance = L["Shadow Dance"]} } },
-    { "shadow",  { {shadowform = L["Shadowform"]}, {noshadowform = L["No Shadowform"]} } },
-    { "demon",   { {demon = L["Demon Form"]}, {nodemon = L["No Demon Form"]} } },
-    { "pet",     { {pet = L["With Pet"]}, {nopet = L["Without Pet"]} } },
-    { "target",  { {harm = L["Hostile Target"]}, {help = L["Friendly Target"]}, {notarget = L["No Target"]} } },
-    { "focus",   { {focusharm = L["Hostile Focus"]}, {focushelp = L["Friendly Focus"]}, {nofocus = L["No Focus"]} } },
-    { "possess", { {possess = L["Mind Control"]} } },
-    { "vehicle", { {vehicle = L["In a Vehicle"]} } },
-    { "group",   { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } },
-    { "combat",  { {combat = L["In Combat"]}, {nocombat = L["Out of Combat"]} } },
-  }
-
-  local ruleSelect = { }
-  local ruleMap    = { }
-  local optionMap  = setmetatable({},{__mode="k"})
-
-  local pointTable = {
-    NONE        = " ",
-    CENTER      = L["Center"], 
-    LEFT        = L["Left"],
-    RIGHT       = L["Right"],
-    TOP         = L["Top"],
-    BOTTOM      = L["Bottom"],
-    TOPLEFT     = L["Top Left"],
-    TOPRIGHT    = L["Top Right"],
-    BOTTOMLEFT  = L["Bottom Left"],
-    BOTTOMRIGHT = L["Bottom Right"],
-  }
-
-  -- unpack rules table into ruleSelect and ruleMap
-  for _, c in ipairs(rules) do
-    local rule, fields = unpack(c)
-    for _, field in ipairs(fields) do
-      local key, label = next(field)
-      table.insert(ruleSelect, label)
-      table.insert(ruleMap, key)
-    end
-  end
-
-  local stateOptions = {
-    ordering = {
-      name = L["Info"],
-      order = 1,
-      type = "group",
-      args = {
-        delete = {
-          name = L["Delete this State"],
-          order = -1,
-          type = "execute",
-          func = "DeleteState",
-        },
-        rename = {
-          name = L["Name"],
-          order = 1,
-          type = "input",
-          get  = "GetName",
-          set  = "SetStateName",
-          pattern = "^%w*$",
-          usage = L["State names must be alphanumeric without spaces"],
-        },
-        ordering = {
-          name = L["Evaluation Order"],
-          desc = L["State transitions are evaluated in the order listed:\nMove a state up or down to change the order"],
-          order = 2,
-          type = "group",
-          inline = true,
-          args = {
-            up = {
-              name  = L["Up"],
-              order = 1,
-              type  = "execute",
-              width = "half",
-              func  = "MoveStateUp",
-            },
-            down = {
-              name  = L["Down"],
-              order = 2,
-              type  = "execute",
-              width = "half",
-              func  = "MoveStateDown",
-            }
-          }
-        }
-      }
-    },
-    properties = {
-      name = L["Properties"],
-      order = 2,
-      type = "group",
-      args = { 
-        desc = {
-          name = L["Set the properties for the bar when in this state"],
-          order = 1,
-          type = "description"
-        },
-        hide = {
-          name = L["Hide Bar"],
-          order = 90,
-          type = "toggle",
-          set  = "SetProp",
-          get  = "GetProp",
-        },
-        --[[ BROKEN
-        keybindState = {
-          name  = L["Override Keybinds"],
-          desc  = L["Set this state to maintain its own set of keybinds which override the defaults when active"],
-          order = 91,
-          type  = "toggle",
-          set   = "SetProp",
-          get   = "GetProp",
-        }, ]]
-        position = {
-          name  = L["Position"],
-          order = 92,
-          type  = "group",
-          inline = true,
-          args = {
-            anchorEnable = {
-              name  = L["Reposition"],
-              order = 1,
-              type  = "toggle",
-              set   = "SetProp",
-              get   = "GetProp",
-            },
-            anchorFrame = {
-              name   = L["Anchor Frame"],
-              order  = 2,
-              type   = "select",
-              values = "GetAnchorFrames",
-              set    = "SetAnchorFrame",
-              get    = "GetAnchorFrame",
-              disabled = "GetAnchorDisabled",
-              hidden = "GetAnchorDisabled",
-            },
-            anchorPoint = {
-              name  = L["Point"],
-              order = 3,
-              type  = "select",
-              values = pointTable,
-              set   = "SetAnchorPointProp",
-              get   = "GetAnchorPointProp",
-              disabled = "GetAnchorDisabled",
-              hidden = "GetAnchorDisabled",
-            },
-            anchorRelPoint = {
-              name  = L["Relative Point"],
-              order = 4,
-              type  = "select",
-              values = pointTable,
-              set   = "SetAnchorPointProp",
-              get   = "GetAnchorPointProp",
-              disabled = "GetAnchorDisabled",
-              hidden = "GetAnchorDisabled",
-            },
-            anchorX = {
-              name  = L["X Offset"],
-              order = 5,
-              type  = "range",
-              min   = -100,
-              max   = 100,
-              step  = 1,
-              set   = "SetProp",
-              get   = "GetProp",
-              disabled = "GetAnchorDisabled",
-              hidden = "GetAnchorDisabled",
-            },
-            anchorY = {
-              name  = L["Y Offset"],
-              order = 6,
-              type  = "range",
-              min   = -100,
-              max   = 100,
-              step  = 1,
-              set   = "SetProp",
-              get   = "GetProp",
-              disabled = "GetAnchorDisabled",
-              hidden = "GetAnchorDisabled",
-            },
-          },
-        },
-        scale = {
-          name  = L["Scale"],
-          order = 93,
-          type  = "group",
-          inline = true,
-          args = {
-            enableScale = {
-              name  = L["Set New Scale"],
-              order = 1,
-              type  = "toggle",
-              set   = "SetProp",
-              get   = "GetProp",
-            },
-            scale = {
-              name  = L["Scale"],
-              order = 2,
-              type  = "range",
-              min   = 0.25,
-              max   = 2.5,
-              step  = 0.05,
-              isPercent = true,
-              set   = "SetProp",
-              get   = "GetScale",
-              disabled = "GetScaleDisabled",
-              hidden = "GetScaleDisabled",
-            },
-          },
-        },
-        alpha = {
-          name  = L["Transparency"],
-          order = 94,
-          type  = "group",
-          inline = true,
-          args = {
-            enableAlpha = {
-              name  = L["Set Transparency"],
-              order = 1,
-              type  = "toggle",
-              set   = "SetProp",
-              get   = "GetProp",
-            },
-            alpha = {
-              name  = L["Transparency"],
-              order = 2,
-              type  = "range",
-              min   = 0,
-              max   = 1,
-              step  = 0.01,
-              bigStep = 0.05,
-              isPercent = true,
-              set   = "SetProp",
-              get   = "GetAlpha",
-              disabled = "GetAlphaDisabled",
-              hidden = "GetAlphaDisabled",
-            },
-          },
-        },
-      },
-      plugins = { }
-    },
-    rules = {
-      name   = L["Rule"],
-      order  = 3,
-      type   = "group",
-      args   = {
-        mode = {
-          name   = L["Select this state"],
-          order  = 2,
-          type   = "select",
-          style  = "radio",
-          values = { 
-            default = L["by default"], 
-            any = L["when ANY of these"], 
-            all = L["when ALL of these"], 
-            custom = L["via custom rule"],
-            keybind = L["via keybinding"],
-          },
-          set    = "SetType",
-          get    = "GetType",
-        },
-        clear = {
-          name     = L["Clear All"],
-          order    = 3,
-          type     = "execute",
-          hidden   = "GetClearAllDisabled",
-          disabled = "GetClearAllDisabled",
-          func     = "ClearAllConditions",
-        },
-        inputs = {
-          name     = L["Conditions"],
-          order    = 4,
-          type     = "multiselect",
-          hidden   = "GetConditionsDisabled",
-          disabled = "GetConditionsDisabled",
-          values   = ruleSelect,
-          set      = "SetCondition",
-          get      = "GetCondition",
-        },
-        custom = {
-          name = L["Custom Rule"],
-          order = 5,
-          type = "input",
-          multiline = true,
-          hidden = "GetCustomDisabled",
-          disabled = "GetCustomDisabled",
-          desc = L["Syntax like macro rules: see preset rules for examples"],
-          set  = "SetCustomRule",
-          get  = "GetCustomRule",
-          validate = "ValidateCustomRule",
-        },
-        keybind = {
-          name = L["Keybinding"],
-          order = 6,
-          inline = true,
-          hidden = "GetKeybindDisabled",
-          disabled = "GetKeybindDisabled",
-          type = "group",
-          args = {
-            desc = {
-              name = L["Invoking a state keybind toggles an override of all other transition rules."],
-              order = 1,
-              type = "description",
-            },
-            keybind = {
-              name = L["State Hotkey"],
-              desc = L["Define an override toggle keybind"],
-              order = 2,
-              type = "keybinding",
-              set  = "SetKeybind",
-              get  = "GetKeybind",
-            },
-          },
-        },
-      },
-    },
-  }
-
-  local handlers = { }
-  local meta = {
-    __index = function(self, key)
-      for _, h in pairs(handlers) do
-        if h[key] then
-          return h[key]
-        end
-      end
-    end,
-  }
-  local StateHandler = setmetatable({ }, meta)
-  local proto        = { __index = StateHandler }
-
-  function RegisterPropertyOptions( field, options, handler )
-    stateOptions.properties.plugins[field] = options
-    handlers[field] = handler
-  end
-
-  function UnregisterPropertyOptions( field )
-    stateOptions.properties.plugins[field] = nil
-    handlers[field] = nil
-  end
-
-  function StateHandler:New( bar, opts )
-    local self = setmetatable(
-      { 
-        bar = bar 
-      }, 
-      proto )
-
-    function self:GetName()
-      return opts.name
-    end
-
-    function self:SetName(name)
-      opts.name = name
-    end
-
-    function self:GetOrder()
-      return opts.order
-    end
-
-    -- get reference to states table: even if the bar
-    -- name changes the states table ref won't
-    self.states = tbuild(module.db.profile.bars, bar:GetName(), "states")
-    self.state  = tbuild(self.states, opts.name)
-
-    opts.order = self:GetRuleField("order")
-    if opts.order == nil then
-      -- add after the highest
-      opts.order = 100
-      for _, state in pairs(self.states) do
-        local x = tonumber(tfetch(state, "rule", "order"))
-        if x and x >= opts.order then
-          opts.order = x + 1
-        end
-      end
-      self:SetRuleField("order",opts.order)
-    end
-
-    return self
-  end
-
-  -- helper methods
-
-  function StateHandler:SetRuleField( key, value, ... )
-    tbuild(self.state, "rule", ...)[key] = value
-  end
-
-  function StateHandler:GetRuleField( ... )
-    return tfetch(self.state, "rule", ...)
-  end
-
-  function StateHandler:FixAll( setkey )
-    -- if multiple selections in the same group are chosen when 'all' is selected,
-    -- keep only one of them. If changing the mode, the first in the fields list will 
-    -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set,
-    -- it will be retained.
-    local notified = false
-    if self:GetRuleField("type") == "all" then
-      for _, c in ipairs(rules) do
-        local rule, fields = unpack(c)
-        local once = false
-        if setkey then
-          for idx, field in ipairs(fields) do
-            if next(field) == setkey then
-              once = true
-            end
-          end
-        end
-        for idx, field in ipairs(fields) do
-          local key = next(field)
-          if self:GetRuleField("values",key) then
-            if once and key ~= setkey then
-              self:SetRuleField(key,false,"values")
-              if not setkey and not notified then
-                ReAction:UserError(L["Warning: one or more incompatible rules were turned off"])
-                notified = true
-              end
-            end
-            once = true
-          end
-        end
-      end
-    end
-  end
-
-  function StateHandler:GetNeighbors()
-    local before, after
-    for k, v in pairs(self.states) do
-      local o = tonumber(tfetch(v, "rule", "order"))
-      if o and k ~= self:GetName() then
-        local obefore = tfetch(self.states,before,"rule","order")
-        local oafter  = tfetch(self.states,after,"rule","order")
-        if o < self:GetOrder() and (not obefore or obefore < o) then
-          before = k
-        end
-        if o > self:GetOrder() and (not oafter or oafter > o) then
-          after = k
-        end
-      end
-    end
-    return before, after
-  end
-
-  function StateHandler:SwapOrder( a, b )
-    -- do options table
-    local args = optionMap[self.bar].args
-    args[a].order, args[b].order = args[b].order, args[a].order
-    -- do profile
-    a = tbuild(self.states, a, "rule")
-    b = tbuild(self.states, b, "rule")
-    a.order, b.order = b.order, a.order
-  end
-
-  -- handler methods 
-
-  function StateHandler:GetProp( info )
-    -- gets property of the same name as the options arg
-    return GetProperty(self.bar, self:GetName(), info[#info])
-  end
-
-  function StateHandler:SetProp( info, value )
-    -- sets property of the same name as the options arg
-    SetProperty(self.bar, self:GetName(), info[#info], value)
-  end
-
-  function StateHandler:DeleteState()
-    if self.states[self:GetName()] then
-      self.states[self:GetName()] = nil
-      ApplyStates(self.bar)
-    end
-    optionMap[self.bar].args[self:GetName()] = nil
-  end
-
-  function StateHandler:SetStateName(info, value)
-    -- check for existing state name
-    if self.states[value] then
-      ReAction:UserError(format(L["State named '%s' already exists"],value))
-      return
-    end
-    local args = optionMap[self.bar].args
-    local name = self:GetName()
-    self.states[value], args[value], self.states[name], args[name] = self.states[name], args[name], nil, nil
-    self:SetName(value)
-    ApplyStates(self.bar)
-    ReAction:ShowEditor(self.bar, moduleID, value)
-    end
-
-  function StateHandler:MoveStateUp()
-    local before, after = self:GetNeighbors()
-    if before then
-      self:SwapOrder(before, self:GetName())
-      ApplyStates(self.bar)
-    end
-  end
-
-  function StateHandler:MoveStateDown()
-    local before, after = self:GetNeighbors()
-    if after then
-      self:SwapOrder(self:GetName(), after)
-      ApplyStates(self.bar)
-    end
-  end
-
-  function StateHandler:GetAnchorDisabled()
-    return not GetProperty(self.bar, self:GetName(), "anchorEnable")
-  end
-
-  function StateHandler:GetAnchorFrames(info)
-    self._anchorframes = self._anchorframes or { }
-    table.wipe(self._anchorframes)
-
-    table.insert(self._anchorframes, "UIParent")
-    for name, bar in ReAction:IterateBars() do
-      table.insert(self._anchorframes, bar:GetFrame():GetName())
-    end
-    return self._anchorframes
-  end
-
-  function StateHandler:GetAnchorFrame(info)
-    local value = self:GetProp(info)
-    for k,v in pairs(self._anchorframes) do
-      if v == value then
-        return k
-      end
-    end
-  end
-
-  function StateHandler:SetAnchorFrame(info, value)
-    local f = _G[self._anchorframes[value]]
-    if f then
-      self.bar:SetFrameRef("anchor-"..self:GetName(), f)
-      self:SetProp(info, f:GetName())
-    end
-  end
-
-  function StateHandler:SetAnchorPointProp(info, value)
-    self:SetProp(info, value ~= "NONE" and value or nil)
-  end
-
-  function StateHandler:GetAnchorPointProp(info)
-    return self:GetProp(info) or "NONE"
-  end
-
-  function StateHandler:GetScale(info)
-    return self:GetProp(info) or 1.0
-  end
-
-  function StateHandler:GetScaleDisabled()
-    return not GetProperty(self.bar, self:GetName(), "enableScale")
-  end
-
-  function StateHandler:GetAlpha(info)
-    return self:GetProp(info) or 1.0
-  end
-
-  function StateHandler:GetAlphaDisabled()
-    return not GetProperty(self.bar, self:GetName(), "enableAlpha")
-  end
-
-  function StateHandler:SetType(info, value)
-    self:SetRuleField("type", value)
-    self:FixAll()
-    ApplyStates(self.bar)
-  end
-
-  function StateHandler:GetType()
-    return self:GetRuleField("type")
-  end
-
-  function StateHandler:GetClearAllDisabled()
-    local t = self:GetRuleField("type")
-    return not( t == "any" or t == "all" or t == "custom")
-  end
-
-  function StateHandler:ClearAllConditions()
-    local t = self:GetRuleField("type")
-    if t == "custom" then
-      self:SetRuleField("custom","")
-    elseif t == "any" or t == "all" then
-      self:SetRuleField("values", {})
-    end
-    ApplyStates(self.bar)
-  end
-
-  function StateHandler:GetConditionsDisabled()
-    local t = self:GetRuleField("type")
-    return not( t == "any" or t == "all")
-  end
-
-  function StateHandler:SetCondition(info, key, value)
-    self:SetRuleField(ruleMap[key], value or nil, "values")
-    if value then
-      self:FixAll(ruleMap[key])
-    end
-    ApplyStates(self.bar)
-  end
-
-  function StateHandler:GetCondition(info, key)
-    return self:GetRuleField("values", ruleMap[key]) or false
-  end
-
-  function StateHandler:GetCustomDisabled()
-    return self:GetRuleField("type") ~= "custom"
-  end
-
-  function StateHandler:SetCustomRule(info, value)
-    self:SetRuleField("custom",value)
-    ApplyStates(self.bar)
-  end
-
-  function StateHandler:GetCustomRule()
-    return self:GetRuleField("custom") or ""
-  end
-
-  function StateHandler:ValidateCustomRule(info, value)
-    local s = value:gsub("%s","") -- remove all spaces
-    -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler
-    repeat
-      if s == "" then
-        return true
-      end
-      local c, r = s:match("(%b[])(.*)")
-      if c == nil and s and #s > 0 then
-        return format(L["Invalid custom rule '%s': each clause must appear within [brackets]"],value or "")
-      end
-      s = r
-    until c == nil
-    return true
-  end
-
-  function StateHandler:GetKeybindDisabled()
-    return self:GetRuleField("type") ~= "keybind"
-  end
-
-  function StateHandler:GetKeybind()
-    return self:GetRuleField("keybind")
-  end
-
-  function StateHandler:SetKeybind(info, value)
-    if value and #value == 0 then
-      value = nil
-    end
-    self:SetRuleField("keybind",value)
-    ApplyStates(self.bar)
-  end
-
-  local function CreateStateOptions(bar, name)
-    local opts = { 
-      type = "group",
-      name = name,
-      childGroups = "tab",
-      args = stateOptions
-    }
-
-    opts.handler = StateHandler:New(bar,opts)
-
-    return opts
-  end
-
-  function module:GetBarOptions(bar)
-    local private = { }
-    local states = tbuild(module.db.profile.bars, bar:GetName(), "states")
-    local options = {
-      name = L["Dynamic State"],
-      type = "group",
-      order = -1,
-      childGroups = "tree",
-      disabled = InCombatLockdown,
-      args = {
-        __desc__ = {
-          name = L["States are evaluated in the order they are listed"],
-          order = 1,
-          type = "description",
-        },
-        __new__ = {
-          name = L["New State..."],
-          order = 2,
-          type = "group",
-          args = {
-            name = {
-              name = L["State Name"],
-              desc = L["Set a name for the new state"],
-              order = 1,
-              type = "input",
-              get = function() return private.newstatename or "" end,
-              set = function(info,value) private.newstatename = value end,
-              pattern = "^%w*$",
-              usage = L["State names must be alphanumeric without spaces"],
-            },
-            create = {
-              name = L["Create State"],
-              order = 2,
-              type = "execute",
-              func = function ()
-                  local name = private.newstatename
-                  if states[name] then
-                    ReAction:UserError(format(L["State named '%s' already exists"],name))
-                  else
-                    -- TODO: select default state options and pass as final argument
-                    states[name] = { }
-                    optionMap[bar].args[name] = CreateStateOptions(bar,name)
-                    ReAction:ShowEditor(bar, moduleID, name)
-                    private.newstatename = ""
-                  end
-                end,
-              disabled = function()
-                  local name = private.newstatename or ""
-                  return #name == 0 or name:find("%W")
-                end,
-            }
-          }
-        }
-      }
-    }
-    for name, config in pairs(states) do
-      options.args[name] = CreateStateOptions(bar,name)
-    end
-    optionMap[bar] = options
-    return options
-  end
-end
-
--- Module API --
-
--- Pass in a property field-name, an implementation secure snippet, a static options table, and an 
--- optional options handler method-table
---
--- The options table is static, i.e. not bar-specific and should only reference handler method
--- strings (either existing ones or those added via optHandler). The existing options are ordered
--- 90-99. Order #1 is reserved for the heading.
---
--- The contents of optHandler, if provided, will be added to the existing StateHandler options metatable.
--- See above, for existing API. In particular see the properties set up in the New method: self.bar,
--- self.states, and self:GetName(), and the generic property handlers self:GetProp() and self:SetProp().
---
-function module:RegisterStateProperty( field, snippetHandler, options, optHandler )
-  RegisterProperty(field, snippetHandler)
-  RegisterPropertyOptions(field, options, optHandler)
-end
-
-function module:UnregisterStateProperty( field )
-  UnregisterProperty(field)
-  UnregisterPropertyOptions(field)
-end
-
-
--- Export methods to Bar class --
-
-ReAction.Bar.GetStateProperty = GetProperty
-ReAction.Bar.SetStateProperty = SetProperty
--- a/modules/Totem.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
---[[
-  ReAction Totem button module
-
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-local _G = _G
-
--- button 
-local Button = ReAction.Button.MultiCast
-
--- module declaration
-local moduleID = "Totem"
-local module = ReAction:NewModule( moduleID,
-  "AceEvent-3.0"
-  -- mixins go here
-)
-
--- handlers
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID,
-    {
-      profile = { 
-        buttons = { }
-      }
-    }
-  )
-
-  self.buttons = { }
-
-  ReAction.RegisterCallback(self, "OnCreateBar", "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnDestroyBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-
-  self:RegisterEvent("UPDATE_MULTI_CAST_ACTIONBAR","PLAYER_ENTERING_WORLD")
-end
-
-function module:OnEnable()
-  ReAction:RegisterBarType(L["Totem Bar"], 
-    { 
-      type = moduleID ,
-      defaultButtonSize = 36,
-      defaultBarRows = 1,
-      defaultBarCols = 6,
-      defaultBarSpacing = 3
-    })
-
-end
-
-function module:OnDisable()
-  ReAction:UnregisterBarType(L["Totem Bar"])
-end
-
-function module:OnDestroyBar(event, bar, name)
-  local btns = self.buttons[bar]
-  if btns then
-    for _,b in pairs(btns) do
-      if b then
-        b:Destroy()
-      end
-    end
-    self.buttons[bar] = nil
-  end
-end
-
-function module:OnRefreshBar(event, bar, name)
-  if bar.config.type == moduleID then
-    local btns = self.buttons[bar]
-    if btns == nil then
-      btns = { }
-      self.buttons[bar] = btns
-    end
-    local profile = self.db.profile
-    if profile.buttons[name] == nil then
-      profile.buttons[name] = {}
-    end
-    local btnCfg = profile.buttons[name]
-
-    local r, c = bar:GetButtonGrid()
-    local n = min(r*c,6)
-    Button.SetupBarHeader(bar)
-    for i = 1, n do
-      if btnCfg[i] == nil then
-        btnCfg[i] = {}
-      end
-      if not btns[i] then
-        local success, r = pcall(Button.New,Button,i,btnCfg,bar)
-        if success then
-          btns[i] = r
-          if r then
-            bar:AddButton(i,r)
-          end
-        else
-          geterrorhandler()(r)
-          n = i - 1
-          bar:ClipNButtons(n)
-          break
-        end
-      end
-      if btns[i] then
-        btns[i]:Refresh()
-      end
-    end
-    for i = n+1, #btns do
-      if btns[i] then
-        bar:RemoveButton(btns[i])
-        btns[i] = btns[i]:Destroy()
-        if btnCfg[i] then
-          btnCfg[i] = nil
-        end
-      end
-    end
-  end
-
-end
-
-function module:OnEraseBar(event, bar, name)
-  self.db.profile.buttons[name] = nil
-end
-
-function module:OnRenameBar(event, bar, oldName, newName)
-  local b = self.db.profile.buttons
-  b[newname], b[oldname] = b[oldname], nil
-end
-
-function module:RefreshAll()
-  for bar in pairs(self.buttons) do
-    self:OnRefreshBar(nil,bar,bar:GetName())
-  end
-end
-
-function module:UPDATE_MULTI_CAST_ACTIONBAR()
-  if not InCombatLockdown() then
-    for bar in pairs(self.buttons) do
-      self:OnRefreshBar("OnRefreshBar", bar, bar:GetName())
-    end
-  end
-end
-
-function module:PLAYER_ENTERING_WORLD()
-  for bar in pairs(self.buttons) do
-    self:OnRefreshBar("OnRefreshBar", bar, bar:GetName())
-  end
-end
-
-
--- a/modules/VehicleExit.lua	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
---[[
-  ReAction Vehicle Exit button module
-
-  The button module implements a single button which you can use
-  to exit a vehicle that doesn't have controls (replacement for
-  MainMenuBarLeaveVehicleButton).
-
---]]
-
--- local imports
-local addonName, addonTable = ...
-local ReAction = addonTable.ReAction
-local L = ReAction.L
-
--- module declaration
-local moduleID = "VehicleExit"
-local module = ReAction:NewModule( moduleID )
-
--- Button class
-local Button = ReAction.Button.VehicleExit
-
--- module methods
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID,
-    { 
-      profile = {
-        buttons = { }
-      }
-    }
-  )
-  self.registered = { }
-  self.buttons = { }
-
-  ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
-
-  ReAction.RegisterCallback(self, "OnCreateBar")
-  ReAction.RegisterCallback(self, "OnDestroyBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-end
-
-function module:OnEnable()
-  ReAction:RegisterBarType(L["Exit Vehicle Floater"], 
-    { 
-      type = moduleID ,
-      defaultButtonSize = 36,
-      defaultBarRows = 1,
-      defaultBarCols = 1,
-      defaultBarSpacing = 3
-    })
-end
-
-function module:OnDisable()
-  ReAction:UnregisterBarType(L["Exit Vehicle Floater"])
-end
-
-function module:OnCreateBar(event, bar, name)
-  if bar.config.type == moduleID then
-    self:OnRefreshBar(event, bar, name)
-  end
-end
-
-function module:OnRefreshBar(event, bar, name)
-  if bar.config.type == moduleID then
-    local profile = self.db.profile
-    if profile.buttons[name] == nil then
-      profile.buttons[name] = {}
-    end
-    local btnCfg = profile.buttons[name]
-
-    if profile.buttons[name] == nil then
-      profile.buttons[name] = { }
-    end
-    if self.buttons[bar] == nil then
-      local success, r = pcall(Button.New, Button, 1, profile.buttons[name], bar)
-      if success and r then
-        self.buttons[bar] = r
-        bar:AddButton(1,r)
-      end
-    else
-      self.buttons[bar]:Refresh()
-    end
-    bar:ClipNButtons(1)
-    self:UpdateRegistration(bar)
-  end
-end
-
-function module:OnDestroyBar(event, bar, name)
-  if self.buttons[bar] then
-    self.buttons[bar]:Destroy()
-    self.buttons[bar] = nil
-  end
-end
-
-function module:OnEraseBar(event, bar, name)
-  self.db.profile.buttons[name] = nil
-end
-
-function module:OnRenameBar(event, bar, oldname, newname)
-  local b = self.db.profile.buttons
-  b[newname], b[oldname] = b[oldname], nil
-end
-
-
-function module:UpdateRegistration(bar)
-  -- auto show/hide when on a vehicle
-  local config = self.db.profile.buttons[bar:GetName()]
-  local f = bar:GetFrame()
-  if config.withControls then
-    if bar.vehicleExitStateRegistered then
-      UnregisterStateDriver(f, "unitexists")
-      bar.vehicleExitStateRegistered = false
-    end
-    bar:RegisterUnitWatch("vehicle",true)
-  else
-    bar:RegisterUnitWatch("vehicle",false)
-    if not bar.vehicleExitStateRegistered then
-      f:SetAttribute("unit","vehicle")
-      RegisterStateDriver(f, "unitexists", "[target=vehicle,exists,novehicleui] show; hide") -- spoof onstate-unitexists
-      bar.vehicleExitStateRegistered = true
-    end
-  end
-end
-
----- Options ----
-local Handler = { }
-local meta = { __index = Handler }
-
-function Handler:New(bar)
-  return setmetatable(
-    {
-      bar = bar
-    }, meta)
-end
-
-function Handler:GetConfig()
-  return module.db.profile.buttons[self.bar:GetName()]
-end
-
-function Handler:GetPassengerOnly()
-  return not self:GetConfig().withControls
-end
-
-function Handler:SetPassengerOnly(info, value)
-  self:GetConfig().withControls = not value
-  module:UpdateRegistration(self.bar)
-end
-
-
-function module:GetBarOptions(bar)
-  if bar.config.type == moduleID then
-    return {
-      type = "group",
-      name = L["Exit Vehicle"],
-      handler = Handler:New(bar),
-      args = {
-        passengerOnly = {
-          name = L["Show only when passenger"],
-          desc = L["Only show the button when riding as a passenger in a vehicle (no vehicle controls)"],
-          order = 2,
-          width = "double",
-          type = "toggle",
-          get = "GetPassengerOnly",
-          set = "SetPassengerOnly",
-        },
-      }
-    }
-  end
-end
-
-
--- a/modules/modules.xml	Thu Nov 18 13:11:08 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-<Ui xmlns="http://www.blizzard.com/wow/ui/" 
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-    xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
-
-<Script file="State.lua"/>
-<Script file="LBF.lua"/>
-<Script file="HideBlizzard.lua"/>
-<Script file="Action.lua"/>
-<Script file="PetAction.lua"/>
-<Script file="Stance.lua"/>
-<Script file="Bag.lua"/>
-<Script file="VehicleExit.lua"/>
-<Script file="Totem.lua"/>
-
-</Ui>
\ No newline at end of file