changeset 69:a785d6708388

moved State.lua to a top level file
author Flick <flickerstreak@gmail.com>
date Tue, 03 Jun 2008 23:05:16 +0000
parents fcb5dad031f9
children 2c12e2b1752e
files ReAction.xml State.lua locale/enUS.lua modules/ReAction_State/ReAction_State.lua modules/ReAction_State/ReAction_State.toc modules/ReAction_State/ReAction_State.xml modules/modules.xml
diffstat 7 files changed, 992 insertions(+), 996 deletions(-) [+]
line wrap: on
line diff
--- a/ReAction.xml	Tue Jun 03 22:57:34 2008 +0000
+++ b/ReAction.xml	Tue Jun 03 23:05:16 2008 +0000
@@ -7,6 +7,7 @@
 
 <Script file="ReAction.lua"/>
 <Script file="Bar.lua"/>
+<Script file="State.lua"/>
 
 <Include file="modules\modules.xml"/>
 <Include file="bindings.lua"/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/State.lua	Tue Jun 03 23:05:16 2008 +0000
@@ -0,0 +1,927 @@
+--[[
+  ReAction bar state driver interface
+
+--]]
+
+-- local imports
+local ReAction = ReAction
+local L = ReAction.L
+local _G = _G
+local InCombatLockdown = InCombatLockdown
+
+-- 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
+
+-- PRIVATE --
+
+local InitRules, ApplyStates, SetProperty, GetProperty
+do
+  -- As far as I can tell the macro clauses are NOT locale-specific.
+  local ruleformats = { 
+    stealth       = "stealth",
+    nostealth     = "nostealth",
+    shadowform    = "form:1",
+    noshadowform  = "noform",
+    pet           = "pet",
+    nopet         = "nopet",
+    harm          = "target=target,harm",
+    help          = "target=target,help",
+    notarget      = "target=target,noexists",
+    focusharm     = "target=focus,harm",
+    focushelp     = "target=focus,help",
+    nofocus       = "target=focus,noexists",
+    raid          = "group:raid",
+    party         = "group:party",
+    solo          = "nogroup",
+    combat        = "combat",
+    nocombat      = "nocombat",
+  }
+
+  -- 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 can be flight, tree, or moonkin
+  -- depending on talents.
+  function InitRules()
+    local forms = { }
+      -- sort by icon since it's locale-independent
+    for i = 1, GetNumShapeshiftForms() do
+      local icon = GetShapeshiftFormInfo(i)
+      forms[icon] = 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 treekin   = forms["Interface\\Icons\\Ability_Druid_TreeofLife"] or 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
+
+    ruleformats.battle        = "stance:1"
+    ruleformats.defensive     = ("stance:%d"):format(defensive)
+    ruleformats.berserker     = ("stance:%d"):format(berserker)
+    ruleformats.caster        = ("form:0/%d/%d/%d"):format(aquatic, travel, flight)
+    ruleformats.bear          = ("form:%d"):format(bear)
+    ruleformats.cat           = ("form:%d"):format(cat)
+    ruleformats.treeOrMoonkin = ("form:%d"):format(treekin)
+  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 dotdotdot = { ... }
+    table.sort(r, function(lhs, rhs)
+       local olhs = tfetch(t[lhs], unpack(dotdotdot)) or 0
+       local orhs = tfetch(t[rhs], unpack(dotdotdot)) or 0
+       return olhs < orhs
+      end)
+    return r
+  end
+
+  local function BuildRuleString(states)
+    local s = ""
+    local default
+    local sorted = fieldsort(states, "rule", "order")
+    for idx, name in ipairs(sorted) do
+      local state = states[name]
+      local semi = #s > 0 and "; " or ""
+      local mode = tfetch(state,"rule","type")
+      if mode == "default" then
+        default = name
+      elseif mode == "custom" then
+        if state.rule.custom then
+          -- strip out all spaces from the custom rule
+          s = ("%s%s%s %s"):format(s, semi, state.rule.custom:gsub("%s",""), name)
+        end
+      elseif mode == "any" then
+        if state.rule.values then
+          local clause = ""
+          for key, value in pairs(state.rule.values) do
+            clause = ("%s[%s]"):format(clause,ruleformats[key])
+          end
+          if #clause > 0 then
+            s = ("%s%s%s %s"):format(s, semi, clause, name)
+          end
+        end
+      elseif mode == "all" then
+        if state.rule.values then
+          local clause = ""
+          for key, value in pairs(state.rule.values) do
+            clause = ("%s%s%s"):format(clause,#clause > 0 and "," or "", ruleformats[key])
+          end
+          if #clause > 0 then
+            s = ("%s%s[%s] %s"):format(s, semi, clause, name)
+          end
+        end
+      end
+    end
+    if default then
+      s = ("%s%s%s"):format(s, #s > 0 and "; " or "", default)
+    end
+    return s, default
+  end
+
+  local drivers = setmetatable({},{__mode="k"})
+  local propertyFuncs = { }
+
+  function ApplyStates( bar )
+    local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
+    if states then
+      local frame = bar:GetFrame()
+      local string, default = BuildRuleString(states)
+      if string and #string > 0 then
+        drivers[bar] = true
+        -- register a map for each "statemap-reaction-XXX" to set 'state' to 'XXX'
+        -- UNLESS we're in a keybound state AND there's a default state, in which case
+        -- all keybound states go back to themselves.
+        local keybindprefix
+        if default then
+          local tmp = { }
+          for state, config in pairs(states) do
+            if tfetch(config, "rule", "type") == "keybind" then
+              bar:SetStateKeybind(tfetch(config,"rule","keybind"), state, tfetch(config,"rule","keybindreturn") or default or 0)
+              table.insert(tmp, ("%s:%s"):format(state,state))
+            end
+          end
+          if #tmp > 0 then
+            table.insert(tmp,"") -- to get a final ';'
+          end
+          keybindprefix = table.concat(tmp,";")
+        end
+        for state in pairs(states) do
+          frame:SetAttribute(("statemap-reaction-%s"):format(state), ("%s%s"):format(keybindprefix or "",state))
+        end
+        -- register a handler to set the value of attribute "state-reaction" 
+        -- in response to events as per the rule string
+        RegisterStateDriver(frame, "reaction", string)
+        SecureStateHeader_Refresh(frame)
+      elseif drivers[bar] then
+        UnregisterStateDriver(frame, "reaction")
+        drivers[bar] = nil
+      end
+      for k, f in pairs(propertyFuncs) do
+        f(bar, states)
+      end
+    end
+  end
+
+  function GetProperty( bar, state, propname )
+    return tfetch(module.db.profile.bars, bar:GetName(), "states", state, propname)
+  end
+
+  function SetProperty( bar, state, propname, value )
+    local states = tbuild(module.db.profile.bars, bar:GetName(), "states")
+    tbuild(states, state)[propname] = value
+    local f = propertyFuncs[propname]
+    if f then
+      f(bar, states)
+    end
+  end
+
+  -- state property functions
+  function propertyFuncs.hide( bar, states )
+    local tmp = { }
+    for state, config in pairs(states) do
+      if config.hide then
+        table.insert(tmp, state)
+      end
+    end
+    local s = table.concat(tmp,",")
+    bar:SetHideStates(s)
+  end
+
+  function propertyFuncs.page( bar, states )
+    local map = { }
+    for state, config in pairs(states) do
+      map[state] = config.page
+    end
+    bar:SetStatePageMap(state, map)
+  end
+
+  function propertyFuncs.keybindstate( bar, states )
+    local map = { }
+    for state, config in pairs(states) do
+      if config.keybindstate then
+        table.insert(map,state)
+      end
+    end
+    bar:SetStateKeybindOverrideMap(map)
+  end
+
+  function propertyFuncs.enableanchor( bar, states )
+
+  end
+
+  function propertyFuncs.anchorPoint( bar, states )
+
+  end
+
+  function propertyFuncs.anchorRelPoint( bar, states )
+
+  end
+
+  function propertyFuncs.anchorX( bar, states )
+
+  end
+
+  function propertyFuncs.anchorY( bar, states )
+
+  end
+
+  function propertyFuncs.enablescale( bar, states )
+
+  end
+
+  function propertyFuncs.scale( bar, states )
+
+  end
+
+end
+
+
+
+-- module event handlers --
+
+function module:OnInitialize()
+  self.db = ReAction.db:RegisterNamespace( moduleID, 
+    {
+      profile = { 
+        bars = { },
+      }
+    }
+  )
+
+  InitRules()
+  self:RegisterEvent("PLAYER_AURAS_CHANGED")
+
+  ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
+
+  ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar")
+  ReAction.RegisterCallback(self, "OnRefreshBar")
+  ReAction.RegisterCallback(self, "OnEraseBar")
+  ReAction.RegisterCallback(self, "OnRenameBar")
+  ReAction.RegisterCallback(self, "OnConfigModeChanged")
+end
+
+function module:PLAYER_AURAS_CHANGED()
+  self:UnregisterEvent("PLAYER_AURAS_CHANGED")
+  -- on login the number of stances is 0 until this event fires during the init sequence.
+  -- however if you reload just the UI the number of stances is correct immediately
+  -- and this event won't fire until you gain/lose buffs/debuffs, at which point you might
+  -- be in combat.
+  if not InCombatLockdown() then
+    InitRules()
+    for name, bar in ReAction:IterateBars() do
+      self:OnRefreshBar(nil,bar,name)
+    end
+  end
+end
+
+function module:OnRefreshBar(event, bar, name)
+  local c = self.db.profile.bars[name]
+  if c then
+    ApplyStates(bar)
+  end
+end
+
+function module:OnEraseBar(event, bar, name)
+  self.db.profile.bars[name] = nil
+end
+
+function module:OnRenameBar(event, bar, oldname, newname)
+  local b = self.db.profile.bars
+  bars[newname], bars[oldname] = bars[oldname], nil
+end
+
+function module:OnConfigModeChanged(event, mode)
+  -- TODO: unregister all state drivers (temporarily) and hidestates
+end
+
+
+
+-- Options --
+
+local CreateBarOptions
+do
+  local function ClassCheck(...)
+    for i = 1, select('#',...) do
+      local _, c = UnitClass("player")
+      if c == select(i,...) then
+        return false
+      end
+    end
+    return true
+  end
+
+  -- pre-sorted by the order they should appear in
+  local rules = {
+    --  rule          hidden                          fields
+    { "stance",  ClassCheck("WARRIOR"),          { {battle = L["Battle Stance"]}, {defensive = L["Defensive Stance"]}, {berserker = L["Berserker Stance"]} } },
+    { "form",    ClassCheck("DRUID"),            { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {treeOrMoonkin = L["Tree/Moonkin"]}  } },
+    { "stealth", ClassCheck("ROGUE","DRUID"),    { {stealth = L["Stealth"]}, {nostealth = L["No Stealth"]} } },
+    { "shadow",  ClassCheck("PRIEST"),           { {shadowform = L["Shadowform"]}, {noshadowform = L["No Shadowform"]} } },
+    { "pet",     ClassCheck("HUNTER","WARLOCK"), { {pet = L["With Pet"]}, {nopet = L["Without Pet"]} } },
+    { "target",  false,                          { {harm = L["Hostile Target"]}, {help = L["Friendly Target"]}, {notarget = L["No Target"]} } },
+    { "focus",   false,                          { {focusharm = L["Hostile Focus"]}, {focushelp = L["Friendly Focus"]}, {nofocus = L["No Focus"]} } },
+    { "group",   false,                          { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } },
+    { "combat",  false,                          { {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, hidden, fields = unpack(c)
+    if not hidden then
+      for _, field in ipairs(fields) do
+        local key, label = next(field)
+        table.insert(ruleSelect, label)
+        table.insert(ruleMap, key)
+      end
+    end
+  end
+
+  local function CreateStateOptions(bar, name)
+    local opts = { 
+      type = "group",
+      name = name,
+      childGroups = "tab",
+    }
+
+    local states = tbuild(module.db.profile.bars, bar:GetName(), "states")
+
+    local function update()
+      ApplyStates(bar)
+    end
+
+    local function setrule( key, value, ... )
+      tbuild(states, opts.name, "rule", ...)[key] = value
+    end
+
+    local function getrule( ... )
+      return tfetch(states, opts.name, "rule", ...)
+    end
+
+    local function setprop(info, value)
+      SetProperty(bar, opts.name, info[#info], value)
+    end
+
+    local function getprop(info)
+      return GetProperty(bar, opts.name, info[#info])
+    end
+
+    local function 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
+      for _, c in ipairs(rules) do
+        local rule, hidden, fields = unpack(c)
+        local found = false
+        for key in ipairs(fields) do
+          if getrule("values",key) then
+            if (found or setkey) and key ~= setkey then
+              setrule(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
+            found = true
+          end
+        end
+      end
+    end
+
+    local function getNeighbors()
+      local before, after
+      for k, v in pairs(states) do
+        local o = tonumber(tfetch(v, "rule", "order"))
+        if o and k ~= opts.name then
+          local obefore = tfetch(states,before,"rule","order")
+          local oafter  = tfetch(states,after,"rule","order")
+          if o < opts.order and (not obefore or obefore < o) then
+            before = k
+          end
+          if o > opts.order and (not oafter or oafter > o) then
+            after = k
+          end
+        end
+      end
+      return before, after
+    end
+
+    local function swapOrder( a, b )
+      -- do options table
+      local args = optionMap[bar].args
+      args[a].order, args[b].order = args[b].order, args[a].order
+      -- do profile
+      a = tbuild(states, a, "rule")
+      b = tbuild(states, b, "rule")
+      a.order, b.order = b.order, a.order
+    end
+
+    local function anchordisable()
+      return not GetProperty(bar, opts.name, "enableanchor")
+    end
+
+    tbuild(states, name)
+
+    opts.order = getrule("order")
+    if opts.order == nil then
+      -- add after the highest
+      opts.order = 100
+      for _, state in pairs(states) do
+        local x = tonumber(tfetch(state, "rule", "order"))
+        if x and x >= opts.order then
+          opts.order = x + 1
+        end
+      end
+      setrule("order",opts.order)
+    end
+
+    opts.args = {
+      ordering = {
+        name = L["Info"],
+        order = 1,
+        type = "group",
+        args = {
+          delete = {
+            name = L["Delete this State"],
+            order = -1,
+            type = "execute",
+            func = function(info) 
+                if states[opts.name] then
+                  states[opts.name] = nil
+                  ApplyStates(bar)
+                end
+                optionMap[bar].args[opts.name] = nil
+              end,
+          },
+          rename = {
+            name = L["Name"],
+            order = 1,
+            type = "input",
+            get  = function() return opts.name end,
+            set  = function(info, value) 
+                     -- check for existing state name
+                     if states[value] then
+                       L["State named '%s' already exists"]:format(value)
+                     end
+                     local args = optionMap[bar].args
+                     states[value], args[value], states[opts.name], args[opts.name] = states[opts.name], args[opts.name], nil, nil
+                     opts.name = value
+                     update()
+                   end, 
+            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  = function()
+                          local before, after = getNeighbors()
+                          if before then
+                            swapOrder(before, opts.name)
+                            update()
+                          end
+                        end,
+              },
+              down = {
+                name  = L["Down"],
+                order = 2,
+                type  = "execute",
+                width = "half",
+                func  = function() 
+                          local before, after = getNeighbors()
+                          if after then
+                            swapOrder(opts.name, after)
+                            update()
+                          end
+                        end,
+              }
+            }
+          }
+        }
+      },
+      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 = 2,
+            type = "toggle",
+            set  = setprop,
+            get  = getprop,
+          },
+          page = {
+            name  = L["Show Page #"],
+            order = 3,
+            type  = "select",
+            disabled = function()
+                         return bar:GetNumPages() < 2
+                       end,
+            hidden   = function()
+                         return bar:GetNumPages() < 2
+                       end,
+            values   = function()
+                         local pages = { none = " " }
+                         for i = 1, bar:GetNumPages() do
+                           pages[i] = i
+                         end
+                         return pages
+                       end,
+            set      = function(info, value)
+                         if value == "none" then
+                           setprop(info, nil)
+                         else
+                           setprop(info, value)
+                         end
+                       end,
+            get      = function(info)
+                         return getprop(info) or "none"
+                       end,
+          },
+          keybindstate = {
+            name  = L["Override Keybinds"],
+            desc  = L["Set this state to maintain its own set of keybinds which override the defaults when active"],
+            order = 4,
+            type  = "toggle",
+            set   = setprop,
+            get   = getprop,
+          },
+          position = {
+            name  = L["Position"],
+            order = 5,
+            type  = "group",
+            inline = true,
+            args = {
+              enableanchor = {
+                name  = L["Set New Position"],
+                order = 1,
+                type  = "toggle",
+                set   = setprop,
+                get   = getprop,
+              },
+              anchorPoint = {
+                name  = L["Point"],
+                order = 2,
+                type  = "select",
+                values = pointTable,
+                set   = function(info, value) setprop(info, value ~= "NONE" and value or nil) end,
+                get   = function(info) return getprop(info) or "NONE" end,
+                disabled = anchordisable,
+                hidden = anchordisable,
+              },
+              anchorRelPoint = {
+                name  = L["Relative Point"],
+                order = 3,
+                type  = "select",
+                values = pointTable,
+                set   = function(info, value) setprop(info, value ~= "NONE" and value or nil) end,
+                get   = function(info) return getprop(info) or "NONE" end,
+                disabled = anchordisable,
+                hidden = anchordisable,
+              },
+              anchorX = {
+                name  = L["X Offset"],
+                order = 4,
+                type  = "range",
+                min   = -100,
+                max   = 100,
+                step  = 1,
+                set   = setprop,
+                get   = getprop,
+                disabled = anchordisable,
+                hidden = anchordisable,
+              },
+              anchorY = {
+                name  = L["Y Offset"],
+                order = 5,
+                type  = "range",
+                min   = -100,
+                max   = 100,
+                step  = 1,
+                set   = setprop,
+                get   = getprop,
+                disabled = anchordisable,
+                hidden = anchordisable,
+              },
+            },
+          },
+          scale = {
+            name  = L["Scale"],
+            order = 6,
+            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.1,
+                max   = 2.5,
+                step  = 0.05,
+                isPercent = true,
+                set   = setprop,
+                get   = function(info) return getprop(info) or 1 end,
+                disabled = function() return not GetProperty(bar, opts.name, "enablescale") end,
+                hidden = function() return not GetProperty(bar, opts.name, "enablescale") end,
+              },
+            },
+          },
+        },
+      },
+      rules = {
+        name   = L["Selection 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    = function( info, value )
+                       setrule("type", value)
+                       fixall()
+                       update()
+                     end,
+            get    = function( info )
+                       return getrule("type")
+                     end,
+          },
+          clear = {
+            name     = L["Clear All"],
+            order    = 3,
+            type     = "execute",
+            hidden   = function()
+                         local t = getrule("type")
+                         return t ~= "any" and t ~= "all"
+                       end,
+            disabled = function()
+                         local t = getrule("type")
+                         return t ~= "any" and t ~= "all"
+                       end,
+            func     = function()
+                         local type = getrule("type")
+                         if type == "custom" then
+                           setrule("custom","")
+                         elseif type == "any" or type == "all" then
+                           setrule("values", {})
+                         end
+                         update()
+                       end,
+          },
+          inputs = {
+            name     = L["Conditions"],
+            order    = 4,
+            type     = "multiselect",
+            hidden   = function()
+                         local t = getrule("type")
+                         return t ~= "any" and t ~= "all"
+                       end,
+            disabled = function()
+                         local t = getrule("type")
+                         return t ~= "any" and t ~= "all"
+                       end,
+            values   = ruleSelect,
+            set      = function(info, key, value )
+                         setrule(ruleMap[key], value or nil, "values")
+                         if value then
+                           fixall(ruleMap[key])
+                         end
+                         update()
+                       end,
+            get      = function(info, key)
+                         return getrule("values", ruleMap[key]) or false
+                       end,
+          },
+          custom = {
+            name = L["Custom Rule"],
+            order = 5,
+            type = "input",
+            multiline = true,
+            hidden = function()
+                       return getrule("type") ~= "custom"
+                     end,
+            disabled = function()
+                         return getrule("type") ~= "custom"
+                       end,
+            desc = L["Syntax like macro rules: see preset rules for examples"],
+            set  = function(info, value) 
+                     setrule("custom",value)
+                     update()
+                   end,
+            get  = function(info)
+                     return getrule("custom") or ""
+                   end,
+            validate = function (info, rule)
+                local s = rule: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 L["Invalid custom rule '%s': each clause must appear within [brackets]"]:format(rule)
+                  end
+                  s = r
+                until c == nil
+                return true
+              end,
+          },
+          keybind = {
+            name = L["Keybinding"],
+            order = 6,
+            inline = true,
+            hidden = function() return getrule("type") ~= "keybind" end,
+            disabled = function() return getrule("type") ~= "keybind" end,
+            type = "group",
+            args = {
+              desc = {
+                name = L["Invoking a state keybind overrides all other transition rules. Toggle the keybind again to remove the override and return to the specified toggle-off state."],
+                order = 1,
+                type = "description",
+              },
+              keybind = {
+                name = L["State Hotkey"],
+                desc = L["Define an override toggle keybind"],
+                order = 2,
+                type = "keybinding",
+                set  = function(info, value)
+                         setrule("keybind",value)
+                         update()
+                       end,
+                get  = function() return getrule("keybind") end,
+              },
+              default = {
+                name = L["Toggle Off State"],
+                desc = L["Select a state to return to when the keybind override is toggled off"],
+                order = 3,
+                type = "select",
+                values = function()
+                           local t = { }
+                           for k in pairs(states) do
+                             if k ~= opts.name then
+                               t[k] = k
+                             end
+                           end
+                           return t
+                         end,
+                set = function(info, value)
+                        setrule("keybindreturn",value)
+                        update()
+                      end,
+                get = function() return getrule("keybindreturn") end,
+              },
+            },
+          },
+        },
+      },
+    }
+    return opts
+  end
+
+
+  CreateBarOptions = function(bar)
+    local private = { }
+    local options = {
+      type = "group",
+      name = L["Dynamic State"],
+      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(L["State named '%s' already exists"]:format(name))
+                  else
+                    -- TODO: select default state options and pass as final argument
+                    states[name] = { }
+                    optionMap[bar].args[name] = CreateStateOptions(bar,name)
+                    private.newstatename = ""
+                  end
+                end,
+              disabled = function()
+                  local name = private.newstatename or ""
+                  return #name == 0 or name:find("%W")
+                end,
+            }
+          }
+        }
+      }
+    }
+    local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
+    if states then
+      for name, config in pairs(states) do
+        options.args[name] = CreateStateOptions(bar,name)
+      end
+    end
+    optionMap[bar] = options
+    return options
+  end
+end
+
+function module:GetBarOptions(bar)
+  return CreateBarOptions(bar)
+end
--- a/locale/enUS.lua	Tue Jun 03 22:57:34 2008 +0000
+++ b/locale/enUS.lua	Tue Jun 03 23:05:16 2008 +0000
@@ -38,69 +38,7 @@
 "Remove the bar from the current profile",
 "Are you sure you want to remove this bar?",
 
--- modules/ReAction_HideBlizzard
-"Hide Blizzard Action Bars",
-"Hide the default main bar and extra action bars",
-
--- modules/ReAction_Action
-"Action Bar",
-"Action Bars",
-"Hide Empty Buttons",
-"Action Buttons",
-
--- modules/ReAction_PetAction
-"Pet Action Bar",
-"Pet Buttons",
-
--- modules/ReAction_PossessBar
-"Possess Bar",
-"Hide Empty Possess Bar Buttons",
-"Possess Buttons",
-
--- modules/ReAction_ConfigUI
-"Center",
-"Left",
-"Right",
-"Top",
-"Bottom",
-"Top Left",  
-"Top Right",
-"Bottom Left",
-"Bottom Right",
-"Edit Bars...",
-"Show the ReAction Bar Editor dialogue",
-"Close on Launch",
-"Close the Interface Options window when launching the ReAction Bar Editor",
-"Bar Editor",
-"Global Config",
-"Opens ReAction global configuration settings panel",
-"Close the Bar Editor when opening the ReAction global Interface Options",
-"New Bar...",
-"Choose a name, type, and initial grid for your new action bar:",
-"Bar Name",
-"Enter a name for your new action bar",
-"Button Type",
-"Create Bar",
-"General",
-"Rename Bar",
-"Delete Bar",
-"Anchor",
-"Frame",
-"The frame that the bar is anchored to",
-"Point",
-"Anchor point on the bar frame",
-"Relative Point",
-"Anchor point on the target frame",
-"X offset",
-"Y offset",
-"Button Grid",
-"Rows",
-"Columns",
-"Size",
-"Spacing",
-"Use the mouse to arrange and resize the bars on screen. Tooltips on bars indicate additional functionality.",
-
--- modules/ReAction_State
+-- State.lua
 "State named '%s' already exists",
 "Battle Stance",
 "Defensive Stance",
@@ -176,6 +114,69 @@
 "State named '%s' already exists",
 
 
+-- modules/ReAction_HideBlizzard
+"Hide Blizzard Action Bars",
+"Hide the default main bar and extra action bars",
+
+-- modules/ReAction_Action
+"Action Bar",
+"Action Bars",
+"Hide Empty Buttons",
+"Action Buttons",
+
+-- modules/ReAction_PetAction
+"Pet Action Bar",
+"Pet Buttons",
+
+-- modules/ReAction_PossessBar
+"Possess Bar",
+"Hide Empty Possess Bar Buttons",
+"Possess Buttons",
+
+-- modules/ReAction_ConfigUI
+"Center",
+"Left",
+"Right",
+"Top",
+"Bottom",
+"Top Left",  
+"Top Right",
+"Bottom Left",
+"Bottom Right",
+"Edit Bars...",
+"Show the ReAction Bar Editor dialogue",
+"Close on Launch",
+"Close the Interface Options window when launching the ReAction Bar Editor",
+"Bar Editor",
+"Global Config",
+"Opens ReAction global configuration settings panel",
+"Close the Bar Editor when opening the ReAction global Interface Options",
+"New Bar...",
+"Choose a name, type, and initial grid for your new action bar:",
+"Bar Name",
+"Enter a name for your new action bar",
+"Button Type",
+"Create Bar",
+"General",
+"Rename Bar",
+"Delete Bar",
+"Anchor",
+"Frame",
+"The frame that the bar is anchored to",
+"Point",
+"Anchor point on the bar frame",
+"Relative Point",
+"Anchor point on the target frame",
+"X offset",
+"Y offset",
+"Button Grid",
+"Rows",
+"Columns",
+"Size",
+"Spacing",
+"Use the mouse to arrange and resize the bars on screen. Tooltips on bars indicate additional functionality.",
+
+
 }) do
   L[string] = true
 end
--- a/modules/ReAction_State/ReAction_State.lua	Tue Jun 03 22:57:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,927 +0,0 @@
---[[
-  ReAction bar state driver interface
-
---]]
-
--- local imports
-local ReAction = ReAction
-local L = ReAction.L
-local _G = _G
-local InCombatLockdown = InCombatLockdown
-
--- 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
-
--- PRIVATE --
-
-local InitRules, ApplyStates, SetProperty, GetProperty
-do
-  -- As far as I can tell the macro clauses are NOT locale-specific.
-  local ruleformats = { 
-    stealth       = "stealth",
-    nostealth     = "nostealth",
-    shadowform    = "form:1",
-    noshadowform  = "noform",
-    pet           = "pet",
-    nopet         = "nopet",
-    harm          = "target=target,harm",
-    help          = "target=target,help",
-    notarget      = "target=target,noexists",
-    focusharm     = "target=focus,harm",
-    focushelp     = "target=focus,help",
-    nofocus       = "target=focus,noexists",
-    raid          = "group:raid",
-    party         = "group:party",
-    solo          = "nogroup",
-    combat        = "combat",
-    nocombat      = "nocombat",
-  }
-
-  -- 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 can be flight, tree, or moonkin
-  -- depending on talents.
-  function InitRules()
-    local forms = { }
-      -- sort by icon since it's locale-independent
-    for i = 1, GetNumShapeshiftForms() do
-      local icon = GetShapeshiftFormInfo(i)
-      forms[icon] = 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 treekin   = forms["Interface\\Icons\\Ability_Druid_TreeofLife"] or 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
-
-    ruleformats.battle        = "stance:1"
-    ruleformats.defensive     = ("stance:%d"):format(defensive)
-    ruleformats.berserker     = ("stance:%d"):format(berserker)
-    ruleformats.caster        = ("form:0/%d/%d/%d"):format(aquatic, travel, flight)
-    ruleformats.bear          = ("form:%d"):format(bear)
-    ruleformats.cat           = ("form:%d"):format(cat)
-    ruleformats.treeOrMoonkin = ("form:%d"):format(treekin)
-  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 dotdotdot = { ... }
-    table.sort(r, function(lhs, rhs)
-       local olhs = tfetch(t[lhs], unpack(dotdotdot)) or 0
-       local orhs = tfetch(t[rhs], unpack(dotdotdot)) or 0
-       return olhs < orhs
-      end)
-    return r
-  end
-
-  local function BuildRuleString(states)
-    local s = ""
-    local default
-    local sorted = fieldsort(states, "rule", "order")
-    for idx, name in ipairs(sorted) do
-      local state = states[name]
-      local semi = #s > 0 and "; " or ""
-      local mode = tfetch(state,"rule","type")
-      if mode == "default" then
-        default = name
-      elseif mode == "custom" then
-        if state.rule.custom then
-          -- strip out all spaces from the custom rule
-          s = ("%s%s%s %s"):format(s, semi, state.rule.custom:gsub("%s",""), name)
-        end
-      elseif mode == "any" then
-        if state.rule.values then
-          local clause = ""
-          for key, value in pairs(state.rule.values) do
-            clause = ("%s[%s]"):format(clause,ruleformats[key])
-          end
-          if #clause > 0 then
-            s = ("%s%s%s %s"):format(s, semi, clause, name)
-          end
-        end
-      elseif mode == "all" then
-        if state.rule.values then
-          local clause = ""
-          for key, value in pairs(state.rule.values) do
-            clause = ("%s%s%s"):format(clause,#clause > 0 and "," or "", ruleformats[key])
-          end
-          if #clause > 0 then
-            s = ("%s%s[%s] %s"):format(s, semi, clause, name)
-          end
-        end
-      end
-    end
-    if default then
-      s = ("%s%s%s"):format(s, #s > 0 and "; " or "", default)
-    end
-    return s, default
-  end
-
-  local drivers = setmetatable({},{__mode="k"})
-  local propertyFuncs = { }
-
-  function ApplyStates( bar )
-    local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
-    if states then
-      local frame = bar:GetFrame()
-      local string, default = BuildRuleString(states)
-      if string and #string > 0 then
-        drivers[bar] = true
-        -- register a map for each "statemap-reaction-XXX" to set 'state' to 'XXX'
-        -- UNLESS we're in a keybound state AND there's a default state, in which case
-        -- all keybound states go back to themselves.
-        local keybindprefix
-        if default then
-          local tmp = { }
-          for state, config in pairs(states) do
-            if tfetch(config, "rule", "type") == "keybind" then
-              bar:SetStateKeybind(tfetch(config,"rule","keybind"), state, tfetch(config,"rule","keybindreturn") or default or 0)
-              table.insert(tmp, ("%s:%s"):format(state,state))
-            end
-          end
-          if #tmp > 0 then
-            table.insert(tmp,"") -- to get a final ';'
-          end
-          keybindprefix = table.concat(tmp,";")
-        end
-        for state in pairs(states) do
-          frame:SetAttribute(("statemap-reaction-%s"):format(state), ("%s%s"):format(keybindprefix or "",state))
-        end
-        -- register a handler to set the value of attribute "state-reaction" 
-        -- in response to events as per the rule string
-        RegisterStateDriver(frame, "reaction", string)
-        SecureStateHeader_Refresh(frame)
-      elseif drivers[bar] then
-        UnregisterStateDriver(frame, "reaction")
-        drivers[bar] = nil
-      end
-      for k, f in pairs(propertyFuncs) do
-        f(bar, states)
-      end
-    end
-  end
-
-  function GetProperty( bar, state, propname )
-    return tfetch(module.db.profile.bars, bar:GetName(), "states", state, propname)
-  end
-
-  function SetProperty( bar, state, propname, value )
-    local states = tbuild(module.db.profile.bars, bar:GetName(), "states")
-    tbuild(states, state)[propname] = value
-    local f = propertyFuncs[propname]
-    if f then
-      f(bar, states)
-    end
-  end
-
-  -- state property functions
-  function propertyFuncs.hide( bar, states )
-    local tmp = { }
-    for state, config in pairs(states) do
-      if config.hide then
-        table.insert(tmp, state)
-      end
-    end
-    local s = table.concat(tmp,",")
-    bar:SetHideStates(s)
-  end
-
-  function propertyFuncs.page( bar, states )
-    local map = { }
-    for state, config in pairs(states) do
-      map[state] = config.page
-    end
-    bar:SetStatePageMap(state, map)
-  end
-
-  function propertyFuncs.keybindstate( bar, states )
-    local map = { }
-    for state, config in pairs(states) do
-      if config.keybindstate then
-        table.insert(map,state)
-      end
-    end
-    bar:SetStateKeybindOverrideMap(map)
-  end
-
-  function propertyFuncs.enableanchor( bar, states )
-
-  end
-
-  function propertyFuncs.anchorPoint( bar, states )
-
-  end
-
-  function propertyFuncs.anchorRelPoint( bar, states )
-
-  end
-
-  function propertyFuncs.anchorX( bar, states )
-
-  end
-
-  function propertyFuncs.anchorY( bar, states )
-
-  end
-
-  function propertyFuncs.enablescale( bar, states )
-
-  end
-
-  function propertyFuncs.scale( bar, states )
-
-  end
-
-end
-
-
-
--- module event handlers --
-
-function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID, 
-    {
-      profile = { 
-        bars = { },
-      }
-    }
-  )
-
-  InitRules()
-  self:RegisterEvent("PLAYER_AURAS_CHANGED")
-
-  ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
-
-  ReAction.RegisterCallback(self, "OnCreateBar","OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnRefreshBar")
-  ReAction.RegisterCallback(self, "OnEraseBar")
-  ReAction.RegisterCallback(self, "OnRenameBar")
-  ReAction.RegisterCallback(self, "OnConfigModeChanged")
-end
-
-function module:PLAYER_AURAS_CHANGED()
-  self:UnregisterEvent("PLAYER_AURAS_CHANGED")
-  -- on login the number of stances is 0 until this event fires during the init sequence.
-  -- however if you reload just the UI the number of stances is correct immediately
-  -- and this event won't fire until you gain/lose buffs/debuffs, at which point you might
-  -- be in combat.
-  if not InCombatLockdown() then
-    InitRules()
-    for name, bar in ReAction:IterateBars() do
-      self:OnRefreshBar(nil,bar,name)
-    end
-  end
-end
-
-function module:OnRefreshBar(event, bar, name)
-  local c = self.db.profile.bars[name]
-  if c then
-    ApplyStates(bar)
-  end
-end
-
-function module:OnEraseBar(event, bar, name)
-  self.db.profile.bars[name] = nil
-end
-
-function module:OnRenameBar(event, bar, oldname, newname)
-  local b = self.db.profile.bars
-  bars[newname], bars[oldname] = bars[oldname], nil
-end
-
-function module:OnConfigModeChanged(event, mode)
-  -- TODO: unregister all state drivers (temporarily) and hidestates
-end
-
-
-
--- Options --
-
-local CreateBarOptions
-do
-  local function ClassCheck(...)
-    for i = 1, select('#',...) do
-      local _, c = UnitClass("player")
-      if c == select(i,...) then
-        return false
-      end
-    end
-    return true
-  end
-
-  -- pre-sorted by the order they should appear in
-  local rules = {
-    --  rule          hidden                          fields
-    { "stance",  ClassCheck("WARRIOR"),          { {battle = L["Battle Stance"]}, {defensive = L["Defensive Stance"]}, {berserker = L["Berserker Stance"]} } },
-    { "form",    ClassCheck("DRUID"),            { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {treeOrMoonkin = L["Tree/Moonkin"]}  } },
-    { "stealth", ClassCheck("ROGUE","DRUID"),    { {stealth = L["Stealth"]}, {nostealth = L["No Stealth"]} } },
-    { "shadow",  ClassCheck("PRIEST"),           { {shadowform = L["Shadowform"]}, {noshadowform = L["No Shadowform"]} } },
-    { "pet",     ClassCheck("HUNTER","WARLOCK"), { {pet = L["With Pet"]}, {nopet = L["Without Pet"]} } },
-    { "target",  false,                          { {harm = L["Hostile Target"]}, {help = L["Friendly Target"]}, {notarget = L["No Target"]} } },
-    { "focus",   false,                          { {focusharm = L["Hostile Focus"]}, {focushelp = L["Friendly Focus"]}, {nofocus = L["No Focus"]} } },
-    { "group",   false,                          { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } },
-    { "combat",  false,                          { {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, hidden, fields = unpack(c)
-    if not hidden then
-      for _, field in ipairs(fields) do
-        local key, label = next(field)
-        table.insert(ruleSelect, label)
-        table.insert(ruleMap, key)
-      end
-    end
-  end
-
-  local function CreateStateOptions(bar, name)
-    local opts = { 
-      type = "group",
-      name = name,
-      childGroups = "tab",
-    }
-
-    local states = tbuild(module.db.profile.bars, bar:GetName(), "states")
-
-    local function update()
-      ApplyStates(bar)
-    end
-
-    local function setrule( key, value, ... )
-      tbuild(states, opts.name, "rule", ...)[key] = value
-    end
-
-    local function getrule( ... )
-      return tfetch(states, opts.name, "rule", ...)
-    end
-
-    local function setprop(info, value)
-      SetProperty(bar, opts.name, info[#info], value)
-    end
-
-    local function getprop(info)
-      return GetProperty(bar, opts.name, info[#info])
-    end
-
-    local function 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
-      for _, c in ipairs(rules) do
-        local rule, hidden, fields = unpack(c)
-        local found = false
-        for key in ipairs(fields) do
-          if getrule("values",key) then
-            if (found or setkey) and key ~= setkey then
-              setrule(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
-            found = true
-          end
-        end
-      end
-    end
-
-    local function getNeighbors()
-      local before, after
-      for k, v in pairs(states) do
-        local o = tonumber(tfetch(v, "rule", "order"))
-        if o and k ~= opts.name then
-          local obefore = tfetch(states,before,"rule","order")
-          local oafter  = tfetch(states,after,"rule","order")
-          if o < opts.order and (not obefore or obefore < o) then
-            before = k
-          end
-          if o > opts.order and (not oafter or oafter > o) then
-            after = k
-          end
-        end
-      end
-      return before, after
-    end
-
-    local function swapOrder( a, b )
-      -- do options table
-      local args = optionMap[bar].args
-      args[a].order, args[b].order = args[b].order, args[a].order
-      -- do profile
-      a = tbuild(states, a, "rule")
-      b = tbuild(states, b, "rule")
-      a.order, b.order = b.order, a.order
-    end
-
-    local function anchordisable()
-      return not GetProperty(bar, opts.name, "enableanchor")
-    end
-
-    tbuild(states, name)
-
-    opts.order = getrule("order")
-    if opts.order == nil then
-      -- add after the highest
-      opts.order = 100
-      for _, state in pairs(states) do
-        local x = tonumber(tfetch(state, "rule", "order"))
-        if x and x >= opts.order then
-          opts.order = x + 1
-        end
-      end
-      setrule("order",opts.order)
-    end
-
-    opts.args = {
-      ordering = {
-        name = L["Info"],
-        order = 1,
-        type = "group",
-        args = {
-          delete = {
-            name = L["Delete this State"],
-            order = -1,
-            type = "execute",
-            func = function(info) 
-                if states[opts.name] then
-                  states[opts.name] = nil
-                  ApplyStates(bar)
-                end
-                optionMap[bar].args[opts.name] = nil
-              end,
-          },
-          rename = {
-            name = L["Name"],
-            order = 1,
-            type = "input",
-            get  = function() return opts.name end,
-            set  = function(info, value) 
-                     -- check for existing state name
-                     if states[value] then
-                       L["State named '%s' already exists"]:format(value)
-                     end
-                     local args = optionMap[bar].args
-                     states[value], args[value], states[opts.name], args[opts.name] = states[opts.name], args[opts.name], nil, nil
-                     opts.name = value
-                     update()
-                   end, 
-            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  = function()
-                          local before, after = getNeighbors()
-                          if before then
-                            swapOrder(before, opts.name)
-                            update()
-                          end
-                        end,
-              },
-              down = {
-                name  = L["Down"],
-                order = 2,
-                type  = "execute",
-                width = "half",
-                func  = function() 
-                          local before, after = getNeighbors()
-                          if after then
-                            swapOrder(opts.name, after)
-                            update()
-                          end
-                        end,
-              }
-            }
-          }
-        }
-      },
-      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 = 2,
-            type = "toggle",
-            set  = setprop,
-            get  = getprop,
-          },
-          page = {
-            name  = L["Show Page #"],
-            order = 3,
-            type  = "select",
-            disabled = function()
-                         return bar:GetNumPages() < 2
-                       end,
-            hidden   = function()
-                         return bar:GetNumPages() < 2
-                       end,
-            values   = function()
-                         local pages = { none = " " }
-                         for i = 1, bar:GetNumPages() do
-                           pages[i] = i
-                         end
-                         return pages
-                       end,
-            set      = function(info, value)
-                         if value == "none" then
-                           setprop(info, nil)
-                         else
-                           setprop(info, value)
-                         end
-                       end,
-            get      = function(info)
-                         return getprop(info) or "none"
-                       end,
-          },
-          keybindstate = {
-            name  = L["Override Keybinds"],
-            desc  = L["Set this state to maintain its own set of keybinds which override the defaults when active"],
-            order = 4,
-            type  = "toggle",
-            set   = setprop,
-            get   = getprop,
-          },
-          position = {
-            name  = L["Position"],
-            order = 5,
-            type  = "group",
-            inline = true,
-            args = {
-              enableanchor = {
-                name  = L["Set New Position"],
-                order = 1,
-                type  = "toggle",
-                set   = setprop,
-                get   = getprop,
-              },
-              anchorPoint = {
-                name  = L["Point"],
-                order = 2,
-                type  = "select",
-                values = pointTable,
-                set   = function(info, value) setprop(info, value ~= "NONE" and value or nil) end,
-                get   = function(info) return getprop(info) or "NONE" end,
-                disabled = anchordisable,
-                hidden = anchordisable,
-              },
-              anchorRelPoint = {
-                name  = L["Relative Point"],
-                order = 3,
-                type  = "select",
-                values = pointTable,
-                set   = function(info, value) setprop(info, value ~= "NONE" and value or nil) end,
-                get   = function(info) return getprop(info) or "NONE" end,
-                disabled = anchordisable,
-                hidden = anchordisable,
-              },
-              anchorX = {
-                name  = L["X Offset"],
-                order = 4,
-                type  = "range",
-                min   = -100,
-                max   = 100,
-                step  = 1,
-                set   = setprop,
-                get   = getprop,
-                disabled = anchordisable,
-                hidden = anchordisable,
-              },
-              anchorY = {
-                name  = L["Y Offset"],
-                order = 5,
-                type  = "range",
-                min   = -100,
-                max   = 100,
-                step  = 1,
-                set   = setprop,
-                get   = getprop,
-                disabled = anchordisable,
-                hidden = anchordisable,
-              },
-            },
-          },
-          scale = {
-            name  = L["Scale"],
-            order = 6,
-            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.1,
-                max   = 2.5,
-                step  = 0.05,
-                isPercent = true,
-                set   = setprop,
-                get   = function(info) return getprop(info) or 1 end,
-                disabled = function() return not GetProperty(bar, opts.name, "enablescale") end,
-                hidden = function() return not GetProperty(bar, opts.name, "enablescale") end,
-              },
-            },
-          },
-        },
-      },
-      rules = {
-        name   = L["Selection 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    = function( info, value )
-                       setrule("type", value)
-                       fixall()
-                       update()
-                     end,
-            get    = function( info )
-                       return getrule("type")
-                     end,
-          },
-          clear = {
-            name     = L["Clear All"],
-            order    = 3,
-            type     = "execute",
-            hidden   = function()
-                         local t = getrule("type")
-                         return t ~= "any" and t ~= "all"
-                       end,
-            disabled = function()
-                         local t = getrule("type")
-                         return t ~= "any" and t ~= "all"
-                       end,
-            func     = function()
-                         local type = getrule("type")
-                         if type == "custom" then
-                           setrule("custom","")
-                         elseif type == "any" or type == "all" then
-                           setrule("values", {})
-                         end
-                         update()
-                       end,
-          },
-          inputs = {
-            name     = L["Conditions"],
-            order    = 4,
-            type     = "multiselect",
-            hidden   = function()
-                         local t = getrule("type")
-                         return t ~= "any" and t ~= "all"
-                       end,
-            disabled = function()
-                         local t = getrule("type")
-                         return t ~= "any" and t ~= "all"
-                       end,
-            values   = ruleSelect,
-            set      = function(info, key, value )
-                         setrule(ruleMap[key], value or nil, "values")
-                         if value then
-                           fixall(ruleMap[key])
-                         end
-                         update()
-                       end,
-            get      = function(info, key)
-                         return getrule("values", ruleMap[key]) or false
-                       end,
-          },
-          custom = {
-            name = L["Custom Rule"],
-            order = 5,
-            type = "input",
-            multiline = true,
-            hidden = function()
-                       return getrule("type") ~= "custom"
-                     end,
-            disabled = function()
-                         return getrule("type") ~= "custom"
-                       end,
-            desc = L["Syntax like macro rules: see preset rules for examples"],
-            set  = function(info, value) 
-                     setrule("custom",value)
-                     update()
-                   end,
-            get  = function(info)
-                     return getrule("custom") or ""
-                   end,
-            validate = function (info, rule)
-                local s = rule: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 L["Invalid custom rule '%s': each clause must appear within [brackets]"]:format(rule)
-                  end
-                  s = r
-                until c == nil
-                return true
-              end,
-          },
-          keybind = {
-            name = L["Keybinding"],
-            order = 6,
-            inline = true,
-            hidden = function() return getrule("type") ~= "keybind" end,
-            disabled = function() return getrule("type") ~= "keybind" end,
-            type = "group",
-            args = {
-              desc = {
-                name = L["Invoking a state keybind overrides all other transition rules. Toggle the keybind again to remove the override and return to the specified toggle-off state."],
-                order = 1,
-                type = "description",
-              },
-              keybind = {
-                name = L["State Hotkey"],
-                desc = L["Define an override toggle keybind"],
-                order = 2,
-                type = "keybinding",
-                set  = function(info, value)
-                         setrule("keybind",value)
-                         update()
-                       end,
-                get  = function() return getrule("keybind") end,
-              },
-              default = {
-                name = L["Toggle Off State"],
-                desc = L["Select a state to return to when the keybind override is toggled off"],
-                order = 3,
-                type = "select",
-                values = function()
-                           local t = { }
-                           for k in pairs(states) do
-                             if k ~= opts.name then
-                               t[k] = k
-                             end
-                           end
-                           return t
-                         end,
-                set = function(info, value)
-                        setrule("keybindreturn",value)
-                        update()
-                      end,
-                get = function() return getrule("keybindreturn") end,
-              },
-            },
-          },
-        },
-      },
-    }
-    return opts
-  end
-
-
-  CreateBarOptions = function(bar)
-    local private = { }
-    local options = {
-      type = "group",
-      name = L["Dynamic State"],
-      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(L["State named '%s' already exists"]:format(name))
-                  else
-                    -- TODO: select default state options and pass as final argument
-                    states[name] = { }
-                    optionMap[bar].args[name] = CreateStateOptions(bar,name)
-                    private.newstatename = ""
-                  end
-                end,
-              disabled = function()
-                  local name = private.newstatename or ""
-                  return #name == 0 or name:find("%W")
-                end,
-            }
-          }
-        }
-      }
-    }
-    local states = tfetch(module.db.profile.bars, bar:GetName(), "states")
-    if states then
-      for name, config in pairs(states) do
-        options.args[name] = CreateStateOptions(bar,name)
-      end
-    end
-    optionMap[bar] = options
-    return options
-  end
-end
-
-function module:GetBarOptions(bar)
-  return CreateBarOptions(bar)
-end
--- a/modules/ReAction_State/ReAction_State.toc	Tue Jun 03 22:57:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-## Interface: 20300
-## Title: ReAction: State
-## Notes: Dynamic bar states for ReAction
-## DefaultState: enabled
-## LoadOnDemand: 1
-## Author: Flick
-## Version: 1.0
-## X-Category: Action Bars
-## Dependencies: ReAction
-
-ReAction_State.xml
--- a/modules/ReAction_State/ReAction_State.xml	Tue Jun 03 22:57:34 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +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="ReAction_State.lua"/>
-
-</Ui>
\ No newline at end of file
--- a/modules/modules.xml	Tue Jun 03 22:57:34 2008 +0000
+++ b/modules/modules.xml	Tue Jun 03 23:05:16 2008 +0000
@@ -6,8 +6,6 @@
 <Include file="ReAction_ConfigUI\ReAction_ConfigUI.xml"/>
 <Include file="ReAction_HideBlizzard\ReAction_HideBlizzard.xml"/>
 
-<!-- general utility modules -->
-<Include file="ReAction_State\ReAction_State.xml"/>
 
 <!-- button modules -->
 <Include file="ReAction_Action\ReAction_Action.xml"/>