changeset 155:806a61b331a0

Pushed the state implementation into Bar
author Flick <flickerstreak@gmail.com>
date Fri, 15 May 2009 22:38:19 +0000
parents df67685b340e
children 611e6ce08717
files classes/ActionButton.lua classes/Bar.lua classes/Overlay.lua locale/enUS.lua modules/State.lua
diffstat 5 files changed, 373 insertions(+), 368 deletions(-) [+]
line wrap: on
line diff
--- a/classes/ActionButton.lua	Fri May 08 17:30:22 2009 +0000
+++ b/classes/ActionButton.lua	Fri May 15 22:38:19 2009 +0000
@@ -52,8 +52,8 @@
     else
       action = 0
     end
-  elseif page and state and page[state] then
-    action = self:GetAttribute("action-"..page[state]) 
+  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")
--- a/classes/Bar.lua	Fri May 08 17:30:22 2009 +0000
+++ b/classes/Bar.lua	Fri May 15 22:38:19 2009 +0000
@@ -10,6 +10,119 @@
 
 local KB = LibStub("LibKeyBound-1.0")
 
+---- Secure snippets ----
+local _reaction_init = 
+[[
+  anchorKeys = newtable("point","relPoint","x","y")
+
+  state = nil
+  set_state = nil
+  state_override = 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
+
+  if state then
+    local settings = settings[state]
+    if settings then
+      -- show/hide
+      local h = settings.hide and not showAll
+      if h ~= hidden then
+        if h then
+          self:Hide()
+        else
+          self:Show()
+        end
+        hidden = h
+      end
+      -- 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
+
+  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 )
+[[
+
+]] .. _reaction_refresh
+
+local _onclick =  -- function( self, button, down )
+[[
+  if state_override == button then
+    state_override = nil -- toggle
+  else
+    state_override = button
+  end
+]] .. _reaction_refresh
+
+
 ---- Bar class ----
 local Bar   = { }
 local weak  = { __mode = "k" }
@@ -51,19 +164,19 @@
   f:Show()
   f:EnableMouse(false)
   f:SetClampedToScreen(true)
+  ReAction.gridProxy:AddFrame(f)
 
-  f:SetAttribute("_onstate-showgrid",
-    -- function(self,stateid,newstate)
-    [[
-      control:ChildUpdate(stateid,newstate)
-      control:CallMethod("UpdateShowGrid")
-    ]])
-  f.UpdateShowGrid = function(frame)
-    for button in self:IterateButtons() do
-      button:UpdateShowGrid()
-    end
-  end
-  ReAction.gridProxy: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()
@@ -215,11 +328,12 @@
 function Bar:SetAlpha(value)
   self.config.alpha = value
   self:GetFrame():SetAlpha(value or 1.0)
+  self:UpdateDefaultStateAlpha()
   ReAction:RefreshBar(self)
 end
 
--- iterator returns button, idx and does NOT iterate in index order
 function Bar:IterateButtons()
+  -- iterator returns button, idx and does NOT iterate in index order
   return pairs(self.buttons)
 end
 
@@ -228,15 +342,9 @@
 --
 
 function Bar:SetConfigMode(mode)
+  self:SetSecureData("showAll",mode)
+  self:UpdateUnitWatch()
   self:ShowControls(mode)
-  if self.unitwatch then
-    if mode then
-      UnregisterUnitWatch(self:GetFrame())
-      self:GetFrame():Show()
-    else
-      RegisterUnitWatch(self:GetFrame())
-    end
-  end
   for b in self:IterateButtons() do
     b:ShowGridTemp(mode)
     b:UpdateActionIDLabel(mode)
@@ -244,14 +352,8 @@
 end
 
 function Bar:SetKeybindMode(mode)
-  if self.unitwatch then
-    if mode then
-      UnregisterUnitWatch(self:GetFrame())
-      self:GetFrame():Show()
-    else
-      RegisterUnitWatch(self:GetFrame())
-    end
-  end
+  self:SetSecureData("showAll",mode)
+  self:UpdateUnitWatch()
   for b in self:IterateButtons() do
     b:SetKeybindMode(mode)
   end
@@ -281,6 +383,8 @@
   else
     f:SetPoint("CENTER")
   end
+
+  self:UpdateDefaultStateAnchor()
 end
 
 function Bar:ClipNButtons( n )
@@ -331,16 +435,34 @@
   -- does nothing by default
 end
 
+function Bar:UpdateShowGrid()
+  for button in self:IterateButtons() do
+    button:UpdateShowGrid()
+  end
+end
+
+function Bar:UpdateUnitWatch()
+  if self.unitwatch then
+    if self.unitwatchActive and (ReAction:GetConfigMode() or ReAction:GetKeybindMode()) then
+      UnregisterUnitWatch(self:GetFrame())
+      self.unitwatchActive = false
+    elseif not self.unitwatchActive then
+      RegisterUnitWatch(self:GetFrame())
+      self.unitwatchActive = true
+    end
+    self:RefreshSecureState()
+  end
+end
+
 function Bar:ShowControls(show)
-  local f = self.overlay
   if show then
-    if not f then
-      f = Bar.Overlay:New(self) -- see Overlay.lua
-      self.overlay = f
+    if not self.overlay then
+      self.overlay = Bar.Overlay:New(self) -- see Overlay.lua
     end
-    f:Show()
-  elseif f then
-    f:Hide()
+    self.overlay:Show()
+    self:RefreshSecureState()
+  elseif self.overlay then
+    self.overlay:Hide()
   end
 end
 
@@ -360,19 +482,164 @@
 -- 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( rule )
+  if rule then
+    RegisterStateDriver(self:GetFrame(),"reaction",rule)
+  elseif self.statedriver then
+    UnregisterStateDriver(self:GetFrame(),"reaction")
+  end
+  self.statedriver = rule
+  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 not ReAction:GetConfigMode() then
-    if enable then
-      RegisterUnitWatch(f)
-    elseif self.unitwatch then
-      UnregisterUnitWatch(f)
-    end
-  end
   self.unitwatch = enable
+  self:UpdateUnitWatch()
 end
 
+-- set a keybind to push a value into "state-reaction" attribute
+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
+    SetOverrideBinding(f, false, key, state, nil) -- 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
--- a/classes/Overlay.lua	Fri May 08 17:30:22 2009 +0000
+++ b/classes/Overlay.lua	Fri May 15 22:38:19 2009 +0000
@@ -27,7 +27,7 @@
 -- Wrap some of the bar manipulators to make them state-aware
 --
 local function SetAnchor( bar, point, frame, relPoint, x, y )
-  local state = bar:GetState()
+  local state = bar:GetSecureState()
   if state then
     local anchorstate = bar:GetStateProperty(state, "anchorEnable")
     if anchorstate then
@@ -44,14 +44,14 @@
 end
 
 local function GetStateScale( bar )
-  local state = bar:GetState()
+  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:GetState()
+  local state = bar:GetSecureState()
   if state and bar:GetStateProperty(state, "enableScale") then
     bar:SetStateProperty(state, "scale", scale)
   end
@@ -557,7 +557,6 @@
     GameTooltipTextRight2:SetText(format("%d x %d",r,c))
 
     local ss = GetStateScale(bar)
-    local state = bar:GetState()
     if ss then
       GameTooltipTextRight4:SetText(format("%d%%", scale*100))
     else
@@ -592,7 +591,6 @@
       function()
         local ss = GetStateScale(bar)
         if ss then
-          local state = bar:GetState()
           SetStateScale(bar, ComputeBarScale(bar, overlay))
         end
         StopResize()
@@ -603,7 +601,7 @@
         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:GetState()
+        local state = bar:GetSecureState()
         GameTooltip:SetOwner(f, "ANCHOR_"..point)
         if ss then
           GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
@@ -652,7 +650,7 @@
   local function UpdateDragTooltip()
     GameTooltip:SetOwner(f, "ANCHOR_TOPRIGHT")
     local ss = GetStateScale(bar)
-    local state = bar:GetState()
+    local state = bar:GetSecureState()
     if ss then
       GameTooltip:AddLine(format("%s (%s: %s)", bar:GetName(), L["State"], state))
     else
@@ -760,3 +758,11 @@
 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/locale/enUS.lua	Fri May 08 17:30:22 2009 +0000
+++ b/locale/enUS.lua	Fri May 15 22:38:19 2009 +0000
@@ -55,8 +55,10 @@
 "State",
 "State Scale Override",
 
+-- Bar.lua
+"Hidden",
+
 -- State.lua
-"Hidden",
 "State named '%s' already exists",
 "Battle Stance",
 "Defensive Stance",
--- a/modules/State.lua	Fri May 08 17:30:22 2009 +0000
+++ b/modules/State.lua	Fri May 15 22:38:19 2009 +0000
@@ -53,24 +53,8 @@
   return r
 end
 
--- set a frame-ref, if the frame is valid, or set nil to the
--- corresponding attribute
-local function SetFrameRef(frame, name, refFrame)
-  if refFrame then
-    local _, explicit = refFrame:IsProtected()
-    if not explicit then
-      refFrame = nil
-    end
-  end
-  if refFrame then
-    frame:SetFrameRef(name,refFrame)
-  else
-    frame:SetAttribute("frameref-"..name,nil)
-  end
-end
 
-
-local InitRules, ApplyStates, CleanupStates, SetProperty, GetProperty, RegisterProperty, ShowAll
+local InitRules, ApplyStates, CleanupStates, SetProperty, GetProperty, RegisterProperty
 
 -- PRIVATE --
 do
@@ -78,250 +62,20 @@
   -- the field names must match the field names of the options table, below
   -- the field values are secure snippets or 'true' to skip the snippet for that property.
   local properties = { 
-    hide = 
-      [[
-        local h = hide and hide[state] and not showAll
-        if h ~= hidden then
-          if h then
-            self:Hide()
-          else
-            self:Show()
-          end
-          hidden = h
-        end
-        if showAll then
-          control:CallMethod("UpdateHiddenLabel", hide and hide[state])
-        end
-      ]],
-
-    --keybindState  TODO: broken
-
-    anchorEnable = 
-      [[
-        local old_anchor = anchorstate
-        anchorstate = (anchorEnable and anchorEnable[state]) and state
-        if old_anchor ~= anchorstate or not set_state then
-          if anchorstate and anchorPoint then
-            if anchorPoint[state] then
-              self:ClearAllPoints()
-              local f = self:GetAttribute("frameref-anchor-"..anchorstate)
-              if f then
-                self:SetPoint(anchorPoint[state], f, anchorRelPoint[state], anchorX[state], anchorY[state])
-              end
-            end
-          elseif defaultAnchor and defaultAnchor.point then
-            self:ClearAllPoints()
-            self:SetPoint(defaultAnchor.point, defaultAnchor.frame, 
-                          defaultAnchor.relPoint, defaultAnchor.x, defaultAnchor.y)
-          end
-        end
-      ]],
-      -- anchorEnable handles all the other bits
+    hide = true,
+    --keybindState = true, TODO: broken
+    anchorEnable = true,
     anchorFrame = true,
     anchorPoint = true,
     anchorRelPoint = true,
     anchorX = true,
     anchorY = true,
-
-
-    enableScale = 
-      [[
-        local old_scale = scalestate
-        scalestate = (enableScale and enableScale[state]) and state
-        if old_scale ~= scalestate or not set_state then
-          if scalestate and scale then
-            if scale[state] then
-              self:SetScale(scale[state])
-            end
-          else
-            self:SetScale(1.0)
-          end
-        end
-      ]],
-      -- enableScale handles scale
+    enableScale = true,
     scale = true,
-
-    enableAlpha = 
-      [[
-        local old_alpha = alphastate
-        alphastate = (enableAlpha and enableAlpha[state]) and state
-        if old_alpha ~= alphastate or not set_state then
-          control:CallMethod("UpdateAlpha", alphastate and alpha[state] or defaultAlpha)
-        end
-      ]],
-      -- enableAlpha handles alpha
+    enableAlpha = true,
     alpha = true,
   }
 
-  local weak         = { __mode = "k" }
-  local statedrivers = setmetatable( { }, weak )
-  local keybinds     = setmetatable( { }, weak )
-
-  --
-  -- Secure Handler Snippets
-  --
-  local SetHandlerData, SetStateDriver, SetStateKeybind, RefreshState
-  do
-    local stateHandler_propInit = 
-    [[
-      propfuncs = table.new()
-      local proplist = self:GetAttribute("prop-func-list")
-      for s in string.gmatch(proplist, "(%w+)") do
-        table.insert(propfuncs, s)
-      end
-    ]]
-
-    local onStateHandler = 
-    -- function _onstate-reaction( self, stateid, newstate )
-    [[
-      set_state = newstate
-
-      local oldState = state
-      state = state_override or set_state or state
-      for i = 1, #propfuncs do
-        control:RunAttribute("func-"..propfuncs[i])
-      end
-      
-      control:ChildUpdate()
-
-      if oldState ~= state then
-        control:CallMethod("StateRefresh", state)
-      end
-    ]]
-
-    local onClickHandler = 
-    -- function OnClick( self, button, down )
-    [[
-      if state_override == button then
-        state_override = nil -- toggle
-      else
-        state_override = button
-      end
-    ]] .. onStateHandler
-
-    local function UpdateAlpha( frame, alpha )
-      if alpha then
-        frame:SetAlpha(alpha)
-      end
-    end
-
-    -- Construct a lua assignment as a code string and execute it within the header
-    -- frame's sandbox. 'value' must be a string, boolean, number, or nil. If called
-    -- with four arguments, then it treats 'varname' as an existing global table and
-    -- sets a key-value pair. For a slight efficiency boost, pass the values in as
-    -- attributes and fetch them as attributes from the snippet code, to leverage snippet
-    -- caching.
-    function SetHandlerData( bar, varname, value, key )
-      local f = bar:GetFrame()
-      f:SetAttribute("data-varname",varname)
-      f:SetAttribute("data-value",  value)
-      f:SetAttribute("data-key",    key)
-      f:Execute(
-        [[
-          local name  = self:GetAttribute("data-varname")
-          local value = self:GetAttribute("data-value")
-          local key   = self:GetAttribute("data-key")
-          if name then
-            if key then
-              if not _G[name] then
-                _G[name] = table.new()
-              end
-              _G[name][key] = value
-            else
-              _G[name] = value
-            end
-          end
-        ]])
-    end
-
-    function SetDefaultAnchor( bar )
-      local point, frame, relPoint, x, y = bar:GetAnchor()
-      SetHandlerData(bar, "defaultAnchor", point, "point")
-      SetHandlerData(bar, "defaultAnchor", relPoint, "relPoint")
-      SetHandlerData(bar, "defaultAnchor", x, "x")
-      SetHandlerData(bar, "defaultAnchor", y, "y")
-      SetHandlerData(bar, "defaultAlpha",  bar:GetAlpha())
-
-      local f = bar:GetFrame()
-      f.UpdateAlpha = UpdateAlpha
-      SetFrameRef(f, "defaultAnchor", _G[frame or "UIParent"])
-      f:Execute(
-        [[
-          defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor")
-        ]])
-    end
-
-    function RefreshState( bar )
-      SetDefaultAnchor(bar)
-      bar:GetFrame():Execute(
-        [[
-          if self:GetAttribute("reaction-refresh") then
-            control:RunAttribute("reaction-refresh")
-          end
-        ]])
-    end
-
-    function SetStateDriver( bar, rule )
-      local f = bar:GetFrame()
-
-      if not f.UpdateHiddenLabel then
-        function f:UpdateHiddenLabel(hide)
-          bar:SetLabelSubtext( hide and L["Hidden"] )
-        end
-      end
-
-      function f:StateRefresh( state )
-        bar:RefreshControls()
-      end
-
-      local props = { }
-      for p, h in pairs(properties) do
-        if type(h) == "string" then
-          table.insert(props,p)
-          f:SetAttribute("func-"..p, h)
-        end
-      end
-      f:SetAttribute("prop-func-list", table.concat(props," "))
-      f:Execute(stateHandler_propInit)
-      f:SetAttribute("reaction-refresh", onStateHandler)
-      
-      if rule and #rule > 0 then
-        f:SetAttribute( "_onstate-reaction", onStateHandler )
-        RegisterStateDriver(f, "reaction", rule)
-        statedrivers[bar] = rule
-      elseif statedrivers[bar] then
-        UnregisterStateDriver(f, "reaction")
-        f:SetAttribute( "_onstate-reaction", nil )
-        statedrivers[bar] = nil
-      end
-    end
-
-    function SetStateKeybind( bar, key, state )
-      local f = bar:GetFrame()
-
-      local kb = keybinds[bar]
-      if kb == nil then
-        if key == nil then
-          -- nothing to do
-          return
-        end
-        kb = { }
-        keybinds[bar] = kb
-      end
-
-      -- clear the old binding, if any
-      if kb[state] then
-        SetOverrideBinding(f, false, kb[state], nil)
-      end
-      kb[state] = key
-
-      if key then
-        f:SetAttribute("_onclick", onClickHandler)
-        SetOverrideBindingClick(f, false, key, state, nil) -- state name is the virtual mouse button
-      end
-    end
-  end
-
   local playerClass = select(2, UnitClass("player"))
   local function ClassFilter(...)
     for i = 1, select('#',...) do
@@ -345,7 +99,7 @@
     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: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") },
     pet           = { format = "pet" },
@@ -365,35 +119,25 @@
     vehicle       = { format = "target=vehicle,exists,bonusbar:5" },
   }
 
-  -- Have to do these shenanigans instead of hardcoding the stances/forms because the 
-  -- ordering varies if the character is missing a form. For warriors this is rarely
-  -- a problem (c'mon, who actually skips the level 10 def stance quest?) but for druids
-  -- it can be. Some people never bother to do the aquatic form quest until well past
-  -- when they get cat form, and stance 5/6 can be flight, tree, or moonkin depending
-  -- on talents.
+  -- Determine the stance #'s programmatically: they can vary if for some reason the
+  -- player is missing a stance/form (due to not training it). Also moonkin/flight/tree form
+  -- can be stance 5 or 6, depending.
   function InitRules()
     local forms = { }
-      -- sort by icon since it's locale-independent
     for i = 1, GetNumShapeshiftForms() do
-      local icon, name, active = GetShapeshiftFormInfo(i)
-      -- if it's the current form, the icon is wrong (Spell_Nature_WispSplode)
-      -- so capture it from the spell info directly
-      if active then
-        local _1, _2
-        _1, _2, icon = GetSpellInfo(name)
-      end
-      forms[icon] = i;
+      local _, name = GetShapeshiftFormInfo(i)
+      forms[name] = i;
     end
       -- use 9 if not found since 9 is never a valid stance/form
-    local defensive = forms["Interface\\Icons\\Ability_Warrior_DefensiveStance"] or 9
-    local berserker = forms["Interface\\Icons\\Ability_Racial_Avatar"] or 9
-    local bear      = forms["Interface\\Icons\\Ability_Racial_BearForm"] or 9 -- bear and dire bear share the same icon
-    local aquatic   = forms["Interface\\Icons\\Ability_Druid_AquaticForm"] or 9
-    local cat       = forms["Interface\\Icons\\Ability_Druid_CatForm"] or 9
-    local travel    = forms["Interface\\Icons\\Ability_Druid_TravelForm"] or 9
-    local tree      = forms["Interface\\Icons\\Ability_Druid_TreeofLife"] or 9
-    local moonkin   = forms["Interface\\Icons\\Spell_Nature_ForceOfNature"] or 9
-    local flight    = forms["Interface\\Icons\\Ability_Druid_FlightForm"] or 9 -- flight and swift flight share the same icon
+    local defensive = forms[GetSpellInfo(71)] or 9
+    local berserker = forms[GetSpellInfo(2458)] or 9
+    local bear      = forms[GetSpellInfo(9634)] or 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 = format("stance:%d",defensive)
     ruleformats.berserker.format = format("stance:%d",berserker)
@@ -445,9 +189,9 @@
       local type = tfetch(state, "rule", "type")
       if type == "keybind" then
         local key = tfetch(state, "rule", "keybind")
-        SetStateKeybind(bar, key, name)
+        bar:SetStateKeybind(key, name)
       else
-        SetStateKeybind(bar, nil, name) -- this clears an existing keybind
+        bar:SetStateKeybind(nil, name) -- this clears an existing keybind
       end
     end
   end
@@ -459,20 +203,21 @@
   function SetProperty( bar, state, propname, value )
     local s = tbuild(module.db.profile.bars, bar:GetName(), "states", state)
     s[propname] = value
-    SetHandlerData(bar, propname, value, state)
-    RefreshState(bar)
+    bar:SetSecureStateData(state, propname, value)
   end
 
   function RegisterProperty( propname, snippet )
-    properties[propname] = snippet or true
+    properties[propname] = true
     for _, bar in ReAction:IterateBars() do
       local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
       if states then
         for name, s in pairs(states) do
-          SetHandlerData(bar, propname, s[propname], name)
+          bar:SetSecureStateData(name, propname, s[propname])
         end
-        SetStateDriver(bar, BuildRule(states))
-        RefreshState(bar)
+        bar:SetStateDriver(BuildRule(states))
+      end
+      if type(snippet) == "string" then
+        bar:SetSecureStateExtension(propname,snippet)
       end
     end
   end
@@ -480,9 +225,14 @@
   function UnregisterProperty( propname )
     properties[propname] = nil
     for _, bar in ReAction:IterateBars() do
-      SetHandlerData(bar, propname, nil)
-      SetStateDriver(bar, BuildRule(states))
-      RefreshState(bar)
+      local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
+      if states then
+        for name, s in pairs(states) do
+          bar:SetSecureStateData(name, propname, nil)
+        end
+      end
+      bar:SetStateDriver(BuildRule(states))
+      bar:SetSecureStateExtension(propname,nil)
     end
   end
 
@@ -492,28 +242,19 @@
       for propname in pairs(properties) do
         for name, s in pairs(states) do
           if propname == "anchorFrame" then
-            SetFrameRef(bar:GetFrame(), "anchor-"..name, _G[s.anchorFrame])
+            bar:SetFrameRef("anchor-"..name, _G[s.anchorFrame])
           else
-            SetHandlerData(bar, propname, s[propname], name)
+            bar:SetSecureStateData(name, propname, s[propname])
           end
         end
       end
       BuildKeybinds(bar, states)
-      SetHandlerData(bar, "showAll", ReAction:GetConfigMode())
-      SetStateDriver(bar, BuildRule(states))
-      RefreshState(bar)
+      bar:SetStateDriver(BuildRule(states))
     end
   end
 
   function CleanupStates( bar )
-    SetStateDriver(bar, nil)
-  end
-
-  function ShowAll( bar, show )
-    if statedrivers[bar] then
-      SetHandlerData(bar, "showAll", show)
-      RefreshState(bar)
-    end
+    bar:SetStateDriver(nil)
   end
 end
 
@@ -539,7 +280,6 @@
   ReAction.RegisterCallback(self, "OnRefreshBar")
   ReAction.RegisterCallback(self, "OnEraseBar")
   ReAction.RegisterCallback(self, "OnRenameBar")
-  ReAction.RegisterCallback(self, "OnConfigModeChanged")
 end
 
 function module:OnEnable()
@@ -551,8 +291,8 @@
   -- This happens both at initial login (after PLAYER_ENTERING_WORLD)
   -- as well as when gaining new abilities. 
   InitRules()
-  for name, bar in ReAction:IterateBars() do
-    self:OnRefreshBar(nil,bar,name)
+  for _, bar in ReAction:IterateBars() do
+    ApplyStates(bar)
   end
 end
 
@@ -576,14 +316,6 @@
   bars[newname], bars[oldname] = bars[oldname], nil
 end
 
-function module:OnConfigModeChanged(event, mode)
-  for name, bar in ReAction:IterateBars() do
-    if self.db.profile.bars[name] then
-      ShowAll(bar, mode)
-    end
-  end
-end
-
 
 
 -- Options --
@@ -1123,7 +855,7 @@
   function StateHandler:SetAnchorFrame(info, value)
     local f = _G[self._anchorframes[value]]
     if f then
-      SetFrameRef(self.bar:GetFrame(), "anchor-"..self:GetName(), f)
+      bar:SetFrameRef("anchor-"..self:GetName(), f)
       self:SetProp(info, f:GetName())
     end
   end
@@ -1341,10 +1073,5 @@
 
 -- Export methods to Bar class --
 
-function ReAction.Bar:GetState()
-  local env = GetManagedEnvironment(self:GetFrame())
-  return env and env.state
-end
-
 ReAction.Bar.GetStateProperty = GetProperty
 ReAction.Bar.SetStateProperty = SetProperty