changeset 12:2735edcf9ab7

Version 0.34
author Flick <flickerstreak@gmail.com>
date Wed, 21 Mar 2007 00:13:27 +0000
parents 88df7235ad8b
children 2b2dd11e5cc2
files Buttons.lua README.html ReAction.toc classes/ReBar.lua libs/ReBound-1.0/ReBound-1.0.lua main.lua
diffstat 6 files changed, 256 insertions(+), 101 deletions(-) [+]
line wrap: on
line diff
--- a/Buttons.lua	Tue Mar 20 21:38:47 2007 +0000
+++ b/Buttons.lua	Wed Mar 21 00:13:27 2007 +0000
@@ -4,7 +4,7 @@
 --
 
 local AceOO = AceLibrary("AceOO-2.0")
-local ReBound = AceLibrary("ReBound-1.0")
+local ReBound = AceLibrary("ReBound-1.0"):new("REACTION")
 
 local Action = AceOO.Class(
   ReAction, 
--- a/README.html	Tue Mar 20 21:38:47 2007 +0000
+++ b/README.html	Wed Mar 21 00:13:27 2007 +0000
@@ -14,9 +14,9 @@
 <body bgcolor="#FFFFFF" text="#000000">
 <h1 align="center">ReAction</h1>
 <h3 align="center">AddOn for World of Warcraft</h3>
-<p><font size="2">Current Version: 0.33 (alpha)<br>
-  Released: 02 Mar 2007</font><font size="2"><br>
-  WoW Version Compatibility/TOC: 2.0.8 / TOC 20003</font></p>
+<p><font size="2">Current Version: 0.34 (alpha)<br>
+  Released: 09 Mar 2007</font><font size="2"><br>
+  WoW Version Compatibility: v2.0.10 / TOC 20003</font></p>
 <h2>The Basics</h2>
 <p>ReAction is a replacement for the default Blizzard action bars. It allows you 
   redefine your action button layout any way you like.</p>
@@ -44,13 +44,12 @@
   development framework.</p>
 <h2>Using ReAction</h2>
 <h3>Installation</h3>
-<p>To install ReAction, drag the ReAction folder to World of Warcraft/Interface/AddOns. 
-  Exit World of Warcraft if it's running, then restart.</p>
+<p>To install ReAction, drag the ReAction folder to your World of Warcraft/Interface/AddOns 
+  folder. Exit World of Warcraft if it's running, then restart.</p>
 <h3>Welcome to ReAction</h3>
 <p>When you first enter World of Warcraft with ReAction installed, it will look 
   very similar to the default Blizzard UI, depending on what other AddOns are 
-  installed. Any keybindings you have made to the action bars, however, are not 
-  in effect. Also, only the main menu bar is shown by default. Other bars can 
+  installed. However, only the main menu bar is shown by default. Other bars can 
   be created as desired.</p>
 <p>If you have FuBar installed, on the left side you should see the ReAction plugin 
   icon and label. If not, there should be a button on your minimap. In either 
@@ -62,6 +61,8 @@
   <li>Configuration (&quot;unlocked&quot;)</li>
   <li>Keybinding</li>
 </ul>
+<p>(Technically it's 4 modes, because Config and Keybinding modes can both be 
+  active at the same time).</p>
 <p>You can toggle Configuration mode by shift-clicking the ReAction Control Button 
   and toggle Keybinding mode by alt-clicking the button. Global configuration 
   options are also available by right-clicking the ReAction button. There are 
@@ -88,24 +89,34 @@
   mode by alt-clicking the ReAction Control Button (or choosing 'keybinding mode' 
   from the right-click menu). <b>ReAction button keybindings are not available 
   from the standard keybindings menu!</b> You <i>must</i> use the ReAction keybinding 
-  interface. They're even greyed out in the keybinding menu to remind you.</p>
+  interface. They're even greyed out in the keybinding menu with a textual reminder, 
+  so there's no excuse!</p>
 <p>Like configuration mode, normal button operation is disabled while in keybinding 
-  mode (though again, any hotkeys you have assigned will work).</p>
-<p>With the keybinding interface out, you can mouseover any ReAction button to 
-  see what its current keybinding is. You can set the keybinding on a button by 
-  clicking the button, then pressing the key. To clear a keybinding from a ReAction 
-  button, shift-click the button. Tooltips will remind you of this interface. 
-  You can also right-click/shift-right-click to set/clear a right-click hotkey, 
-  which will simulate right-clicking the button (useful for complex macros, typically 
-  to save screen real estate). If you've set up bars with multiple pages, you 
-  can also bind a key to the page up/down buttons on a per-bar basis. Just make 
-  sure the buttons are showing (they can be hidden later) and assign the keybinding 
-  like any other ReAction button.</p>
-<p>Keybindings are saved on a per-character basis. Keybinding mode is not available 
+  mode (though again, any hotkeys you have assigned will work). With the keybinding 
+  interface out, you can mouseover any ReAction button to see what its current 
+  keybinding is. You can set the keybinding on a button by clicking the button, 
+  then pressing the key. To clear a keybinding from a ReAction button, shift-click 
+  the button. Tooltips will remind you of this interface. You can also right-click/shift-right-click 
+  to set/clear a right-click hotkey, which will simulate right-clicking the button 
+  (useful for complex macro actions, typically to save screen real estate). If 
+  you've set up bars with multiple pages, you can also bind a key to the page 
+  up/down buttons on a per-bar basis. Just make sure the buttons are showing (they 
+  can be hidden later) and assign the keybinding like any other ReAction button.</p>
+<p>Keybindings are saved on a per-profile basis. Keybinding mode is not available 
   if you are in combat, and is automatically cancelled if you enter combat. When 
-  you first log in with ReAction, it steals the keybindings from the default main 
-  action bar (buttons 1-12) and assigns them to the corresponding buttons on the 
-  default ReAction bar.</p>
+  you first log in with ReAction, it steals the current keybindings from the default 
+  main action bar (buttons 1-12) and assigns them to the corresponding buttons 
+  on the default ReAction bar. This means that if you install ReAction, run with 
+  it, and then disable it, your main bar will no longer have any keybindings and 
+  they'll need to be reset. If you later enable ReAction again, it will remember 
+  its own keybindings.</p>
+<p>If a profile assigns a keybinding to a ReAction button, switching away from 
+  that profile will clear the binding but will <b>not</b> restore the binding 
+  to its previous state. If the new profile assigns that binding then, of course, 
+  it will be in use. What this means is that any 'standard' keybinding action 
+  that's bound to a key will become unbound when switching to a profile that uses 
+  the key, and will have to be manually rebound later if you switch away from 
+  that profile.</p>
 <p><b>Remember to click the 'Save' button to save your keybindings! </b>If you 
   do not, they will automatically revert to the previous bindings when exiting 
   keybinding mode. This can be useful for &quot;trying out&quot; certain layouts 
@@ -121,12 +132,10 @@
   a new skill that doesn't fit on your current layout.</p>
 <h2>Limitations</h2>
 <ul>
-  <li>Due to a lack of certain functionality being made available by Blizzard, 
-    dragging and dropping actions onto action bars while in combat is a little 
-    funky. You have to click the destination button rather than just release drag 
-    on it.</li>
-  <li>You can't configure the pet bar unless you actually have a pet out at the 
-    moment. </li>
+  <li>Due to a lack of certain functionality made available by Blizzard, dragging 
+    and dropping actions onto action bars while in combat is a little funky. You 
+    have to click the destination button rather than just release drag on it.</li>
+  <li>You can't configure the pet bar unless you actually have a pet out. </li>
   <li>No support for shapeshift/stance bar (yet)</li>
   <li>If you have a bar with empty buttons, even though they're invisible they 
     still block mouse input from reaching whatever might be under the button. 
@@ -134,9 +143,10 @@
     during combat. This workaround can be disabled via a configuration option, 
     but then you can't drag and drop actions onto slots during combat. Pick your 
     poison, it's a limitation of Blizzard's protection scheme.</li>
-  <li>If you hide the default main menu bar, there is no substitute provided for 
-    the XP bar, bag bar, or micro menu bar (although the hotkeys for them still 
-    work). Other addons can provide these features until ReAction supports them.</li>
+  <li>If you hide the default main menu bar, there is no substitute provided (yet) 
+    for the XP bar, bag bar, or micro menu bar (although the hotkeys for them 
+    still work). Other addons can provide these features until ReAction supports 
+    them.</li>
 </ul>
 <h2>Known Issues</h2>
 <ul>
@@ -145,12 +155,15 @@
     a hunter to get Eyes of the Beast :-P) is required.</li>
   <li>The initial mapping of action IDs for shapeshift forms doesn't exactly match 
     Blizzard's mapping. When first starting up as a warrior, druid, or rogue, 
-    you will probably need to move your actions around.</li>
+    you will probably need to move your actions around, and it will likely screw 
+    up your layout if you swap back to the default UI.</li>
   <li>Action IDs may not always be laid out in sequence, meaning that similar 
-    layouts on different machines may put the actions in a different order.</li>
+    layouts on different machines may put the actions in a different order. For 
+    best results, copy the WTF/Account/&lt;AccountName&gt;/SavedVariables/ReAction.lua 
+    from one computer to the other, when you get a setup you like.</li>
   <li>There seems to be a big performance hit when first dragging a bar after 
-    entering configuration mode, and when first enabling keybinding mode. More 
-    investigation is necessary.</li>
+    entering configuration mode, and when first enabling keybinding mode, if there 
+    are several bars and a lot of buttons out. More investigation is necessary.</li>
 </ul>
 <h2>Future Plans</h2>
 <ul>
@@ -170,9 +183,15 @@
     bars) </li>
   <li>Yet more configurable button display options (disable cooldown flash, different 
     borders, etc)</li>
+  <li>Button styles (Dreamlayout, CyCircled)</li>
   <li>Localization</li>
 </ul>
 <h2>Version History</h2>
+<p>Version 0.34:</p>
+<ul>
+  <li>Fixed some bugs in the keybinding code, and further refined the ReBound 
+    library. </li>
+</ul>
 <p>Version 0.33:</p>
 <ul>
   <li>Rewrote the keybinding interface (again). I think I finally like this version. 
@@ -244,8 +263,13 @@
   the success of this addon. Similarly, enormous credit goes to <a href="http://ckknight.wowinterface.com">ckknight</a>, 
   whose Dewdrop menuing system and FuBar plugin system are ridiculously easy to 
   use.</p>
+<p>Thanks to the authors of certain action bar mods that came before ReAction: 
+  Bartender3, Bongos, FlexBar 2, and Trinity Bars. While I didn't steal any code 
+  directly from you guys, your addons provided inspiration for various features 
+  and options. Hopefully ReAction differentiates itself sufficiently that it's 
+  not seen as simply a clone.</p>
 <p>Finally, thanks to my alpha testers and stalwart adventuring companions: Deor, 
-  Nogrim, Sorabel, and Yngvi.</p>
+  Nogrim, Sorabel, and Yngvi (or, more to the point, their alts :-P).</p>
 <h2>Copyright &amp; License</h2>
 <p>ReAction is distributed under the MIT license.</p>
 <p>ReAction Copyright &copy; 2007 Ryan Findley.</p>
--- a/ReAction.toc	Tue Mar 20 21:38:47 2007 +0000
+++ b/ReAction.toc	Wed Mar 21 00:13:27 2007 +0000
@@ -4,7 +4,7 @@
 ## DefaultState: enabled
 ## LoadOnDemand: 0
 ## Author: Flick
-## Version: 0.33
+## Version: 0.34
 ## X-Description: An action bar and button layout tool
 ## X-Category: Action Bars
 ## SavedVariables: ReActionDB
--- a/classes/ReBar.lua	Tue Mar 20 21:38:47 2007 +0000
+++ b/classes/ReBar.lua	Wed Mar 21 00:13:27 2007 +0000
@@ -81,7 +81,6 @@
 end
 
 local AceOO = AceLibrary("AceOO-2.0")
-local ReBound = AceLibrary("ReBound-1.0")
 
 -- ReBar is an Ace 2 class prototype object.
 ReBar = AceOO.Class("AceEvent-2.0", ReAnchor, ReAnchor.IAnchorable)
@@ -183,10 +182,6 @@
     self:RefreshPageControls()
   end
 
-  -- register page up/down buttons with ReBound for keybinding
-  ReBound:Register(self.upArrow)
-  ReBound:Register(self.downArrow)
-
   -- add bar to anchorTargets list
   table.insert(ReBar.anchorTargets, self)
 end
--- a/libs/ReBound-1.0/ReBound-1.0.lua	Tue Mar 20 21:38:47 2007 +0000
+++ b/libs/ReBound-1.0/ReBound-1.0.lua	Wed Mar 21 00:13:27 2007 +0000
@@ -1,22 +1,23 @@
 --[[
 Name: ReBound-1.0
-Revision: $Rev: 1 $
+Revision: $Rev: 2 $
 Author: Flick
 Website: 
 Documentation: 
 SVN: 
-Description: Library for point-and-click key binding interfaces
+Description: A library to assist with click-binding
 License: MIT
-Dependencies: AceLibrary, AceEvent-2.0, AceLocale-2.2
+Dependencies: AceLibrary, AceEvent-2.0, AceLocale-2.2, AceOO-2.0
 ]]
 
 
-local version_major, version_minor = "ReBound-1.0", "$Rev: 1 $"
+local version_major, version_minor = "ReBound-1.0", "$Rev: 2 $"
 
 if not AceLibrary then error(version_major .. " requires AceLibrary.") end
 if not AceLibrary:IsNewVersion(version_major, version_minor) then return end
 if not AceLibrary:HasInstance("AceEvent-2.0") then error(version_major .. " requires AceEvent-2.0.") end
 if not AceLibrary:HasInstance("AceLocale-2.2") then error(version_major .. " requires AceLocale-2.2.") end
+if not AceLibrary:HasInstance("AceOO-2.0") then error(version_major .. " requires AceOO-2.0.") end
 
 local L = AceLibrary("AceLocale-2.2"):new("ReBound")
 
@@ -24,16 +25,21 @@
 local colorOff = "|r"
 
 local mouseButtonConvert = {
+  LeftButton = "BUTTON1",
+  RightButton = "BUTTON2",
   MiddleButton = "BUTTON3",
   Button4 = "BUTTON4",
   Button5 = "BUTTON5"
 }
 
+--local BINDING_PENDING = { }  -- a constant
+
 -- localization
 L:RegisterTranslations( "enUS", function()
   return {
     ["none"] = true,
     ["Right-click"] = true,
+    ["Right Click"] = true,
     ["Click to select for binding"] = true,
     ["Shift-click to clear binding"] = true,
     ["Press a key to assign binding"] = true,
@@ -42,15 +48,66 @@
 end )
 
 
+local ReBound = AceLibrary("AceOO-2.0").Class("AceEvent-2.0")
 
+--[[
+  ReBound publishes the following events:
 
-local ReBound = { }
+  -- temporary bindings (prior to SaveBindings() being called)
+  REBOUND_BIND_TEMP   (id, key, targetFrameName, mouseButton)
+  REBOUND_UNBIND_TEMP (id, key)
+
+  -- permanent bindings (fired all at once when SaveBindings() is called)
+  REBOUND_BIND        (id, key, targetFrameName, mouseButton)
+  REBOUND_UNBIND      (id, key)
+
+  These events are published in response to click actions ONLY. This means
+  that if a key is unbound from a click-binding frame, and bound to some 
+  other action, then REBOUND_UNBIND(id,key) will be fired.
+]]
+
+
+--[[
+  Calls to new() which share ids will return an existing object with that id, similar
+  to AceLocale-2.2.
+]]
+local super_new = ReBound.new
+function ReBound:new( id )
+  self.instances = self.instances or { }
+  if self.instances[id] then
+    return self.instances[id]
+  else
+    local i = super_new(self,id)
+    self.instances[id] = i
+    return i
+  end
+end
+
+
+--[[
+  Class object constructor
+
+  arguments:
+    id : the ID that will be provided in events. This can be absolutely 
+         anything, but a string is recommended.
+]]
+local super_init = ReBound.prototype.init
+function ReBound.prototype:init( id )
+  super_init(self)
+
+  self.id = id
+  self.frames = { }
+  self.pending = { }
+  self.bindings = { }
+end
+
+
 
 
 --[[
   Arguments:
   key: A string representation of a key, suitable for passing to SetBinding.
-  target: The frame with an OnClick handler to attach a click-binding to
+  target: The frame with an OnClick handler to which the click-binding should be attached
   [button]: The mouse button to emulate. Default is "LeftButton".
 
   Returns:
@@ -59,9 +116,9 @@
   Notes:
   This does not save the bindings.
 ]]
-function ReBound:SetBinding( key, target, button )
-  if not key then self:error("ReBound:SetBinding() requires a key argument.") end
-  if not target then self:error("ReBound:SetBinding() requires a binding target argument") end
+function ReBound.prototype:SetBinding( key, target, button )
+  if not key then error("ReBound:SetBinding() requires a key argument.") end
+  if not target then error("ReBound:SetBinding() requires a binding target argument") end
   button = button or "LeftButton"
 
   -- prevent setting a binding that's already set
@@ -82,8 +139,11 @@
   -- set the new binding
   SetBindingClick(key, target:GetName(), button)
 
-  -- notify listeners, e.g. for storing the setting
-  self.event:TriggerEvent("REBOUND_BIND", key, target:GetName(), button)
+  -- store the temporary binding as "pending" for later notification
+  table.insert(self.pending, key)
+
+  -- notify listeners, e.g. for displaying the setting
+  self:TriggerEvent("REBOUND_BIND_TEMP", self.id, key, target:GetName(), button)
 end
 
 
@@ -103,8 +163,8 @@
 
   This does NOT save the bindings. Call SaveBindings() to commit the bindings to disk.
 ]]
-function ReBound:ClearBinding( key, target, button, silent ) 
-  if not target and not key then self:error("ReBound:ClearBinding() requires a key or click-binding target argument") end
+function ReBound.prototype:ClearBinding( key, target, button, silent ) 
+  if not target and not key then error("ReBound:ClearBinding() requires a key or click-binding target argument") end
   button = button or "LeftButton"
 
   local keys = key and { key } or { self:GetBinding(target,button) }
@@ -120,7 +180,7 @@
         if f then
           name = f
           if b ~= "LeftButton" then
-            if b == "RightButton" then b = "Right Click" end
+            if b == "RightButton" then b = L["Right Click"] end
             name = f .."-"..b
           end
         end
@@ -130,13 +190,14 @@
       end
     end
     SetBinding(k,nil)
-    self.event:TriggerEvent("REBOUND_UNBIND", k)
+    table.insert(self.pending,k)
+    self:TriggerEvent("REBOUND_UNBIND_TEMP", self.id, k)
   end
 end
 
 
 --[[
-  Gets the keys bound to clicking a frame.
+  Gets the keys currently click-bound to a frame.
 
   Arguments:
   target: target frame to query
@@ -145,14 +206,66 @@
   Returns:
   key1, key2, key3, etc, as strings.
 ]]
-function ReBound:GetBinding( target, button )
-  if not target then self:error("ReBound:GetBinding() requires a target frame argument") end
+function ReBound.prototype:GetBinding( target, button )
+  if not target then error("ReBound:GetBinding() requires a target frame argument") end
   button = button or "LeftButton"
   return GetBindingKey("CLICK "..target:GetName()..":"..button)
 end
 
 
 --[[
+  Publishes permanent binding notification events.
+]]
+local function PublishBindings(self)
+  for _, key in ipairs(self.pending) do
+    local action = GetBindingAction(key)
+    local frame, button
+    if action then
+      frame, button = action:match("CLICK (.+)\:(.+)")
+    end
+    if frame == nil then
+      self:TriggerEvent("REBOUND_UNBIND", self.id, key)
+    else
+      self:TriggerEvent("REBOUND_BIND", self.id, key, frame, button)
+    end
+  end
+  self.pending = { }
+end
+
+
+--[[
+  Saves the bindings using the current scheme. Also publishes events indicating that the
+  bindings have been saved/cleared permanently.
+]]
+function ReBound.prototype:SaveBindings()
+  SaveBindings(GetCurrentBindingSet()) -- will trigger an UPDATE_BINDINGS event.
+  PublishBindings(self)
+end
+
+
+--[[
+  Reverts the bindings to the ones previously saved. Also publishes events indicating that the 
+  bindings have been reverted.
+]]
+function ReBound.prototype:RevertBindings()
+  LoadBindings(GetCurrentBindingSet()) -- should trigger an UPDATE_BINDINGS event.
+  PublishBindings(self)
+end
+
+
+--[[
+  Clears all bindings associated with registered frames. This is useful, for example, when switching profiles
+  and the keybinding data is stored in the profile.
+]]
+function ReBound.prototype:ClearRegisteredBindings()
+  for f, _ in pairs(self.frames) do
+    self:ClearBinding(nil,f,"LeftButton",true)
+    self:ClearBinding(nil,f,"RightButton",true)
+  end
+end
+
+
+--[[
   Registers a target frame by creating a click-binding frame and putting that frame in the list of 
   registered frames, which can then be all shown/hidden as one unit.
 
@@ -162,7 +275,7 @@
   Returns:
   A clickbinder frame.
 ]]
-function ReBound:Register( target )
+function ReBound.prototype:Register( target )
   local f = self:CreateClickBindingFrame(target)
   self.frames[target] = f
   return f
@@ -173,20 +286,29 @@
   Unregisters a target frame by removing it from the internal list. Does nothing to the clickbinding frame.
 
   Arguments:
-  target = the frame whose OnClick handler should no longer be the target of keybinding
+  target = the frame whose OnClick handler should no longer be managed. do NOT pass the clickbinding frame.
 
   Returns:
   nothing.
 ]]
-function ReBound:Unregister( target )
+function ReBound.prototype:Unregister( target )
   self.frames[target] = nil
 end
 
 
 --[[
+  Unregisters all registered frames.
+]]
+function ReBound.prototype:UnregisterAll()
+  self.frames = { }
+end
+
+
+
+--[[
   Shows all the registered click binding frames.
 ]]
-function ReBound:ShowAll()
+function ReBound.prototype:ShowFrames()
   if InCombatLockdown() then
     -- can't set bindings while in combat, so don't bother showing them
     UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT)
@@ -201,7 +323,9 @@
 --[[
   Hides all the registered click binding frames.
 ]]
-function ReBound:HideAll()
+function ReBound.prototype:HideFrames()
+  -- because these frames aren't protected, there's no restriction 
+  -- on hiding them while in combat.
   for _, f in pairs(self.frames) do
     f:Hide()
   end
@@ -303,7 +427,7 @@
   Returns:
   A clickbinder frame.
 ]]
-function ReBound:CreateClickBindingFrame( target )
+function ReBound.prototype:CreateClickBindingFrame( target )
   local f = CreateFrame("Button", nil, target)
   f.ReBound = self
   f:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
@@ -324,21 +448,18 @@
 -- library setup
 
 local function activate( self, oldLib, oldDeactivate )
-  -- set initial values
-  self.mode = oldLib and oldLib.mode or "char"
-  self.frames = { }
-
-  self.event = AceLibrary("AceOO-2.0").Class("AceEvent-2.0"):new()
-  self.event:RegisterEvent("PLAYER_REGEN_DISABLED", function() self:HideAll() end)
-
+  -- copy the list of active instances
+  self.instances = { }
+  if oldLib and oldLib.instances then
+    for k,v in pairs(oldLib.instances) do
+      self.instances[k] = v
+    end
+  end
+  
   if oldDeactivate then
     oldDeactivate(oldLib)
   end
 end
 
-local function deactivate( self )
-  self.event:UnregisterEvent("PLAYER_REGEN_DISABLED")
-end
-
-AceLibrary:Register(ReBound, version_major, version_minor, activate, deactivate)
+AceLibrary:Register(ReBound, version_major, version_minor, activate)
 ReBound = nil
--- a/main.lua	Tue Mar 20 21:38:47 2007 +0000
+++ b/main.lua	Wed Mar 21 00:13:27 2007 +0000
@@ -9,7 +9,7 @@
 local L       = AceLibrary("AceLocale-2.2"):new("ReAction")
 local dewdrop = AceLibrary("Dewdrop-2.0")
 local tablet  = AceLibrary("Tablet-2.0")
-local ReBound = AceLibrary("ReBound-1.0")
+local ReBound = AceLibrary("ReBound-1.0"):new("REACTION")
 
 -- private functions
 local function tcopy(t)
@@ -54,21 +54,31 @@
   self:RegisterEvent("PLAYER_ENTERING_WORLD","HideDefaultBars")
   self:DisableDefaultKeybindings()
 
+  -- create update function for keybinding frame
+  ReActionKeybindDialog:SetScript("OnHide", function(frame)
+    main:SetKeybindMode(false)
+    if frame.save then
+      ReBound:SaveBindings()
+    else
+      ReBound:RevertBindings()
+    end
+    frame.save = false
+  end )
+
   -- initial non-persistent state
   self.locked = true
   self.bars   = { }
 end
 
--- OnEnable is called at startup (startup = true, oldConfig = nil),
--- and when the profile is changed (startup = false, oldConfig ~= nil )
-function main:OnEnable( startup, oldConfig )
+-- OnEnable is called at startup and when the profile is changed (via OnProfileEnable)
+function main:OnEnable( )
   if self.db.profile.firstRunDone ~= true then
     self.db.profile.bars = tcopy(ReAction_DefaultBlizzardBars)
   end
   self:DestroyAllBars()
   self:SetupBars()
   self:UpgradeProfile()
-  self:SetupKeybindings( oldConfig and oldConfig.bindings )
+  self:SetupKeybindings()
   if self.db.profile.firstRunDone ~= true then
     self:Unlock()
   end
@@ -81,7 +91,10 @@
 
 -- OnProfileEnable() is only called when switching profiles, NOT for the initial profile at load time.
 function main:OnProfileEnable( oldName, oldData )
-  self:OnEnable(false, oldData)
+  self:UnregisterEvent("REBOUND_BIND")
+  self:UnregisterEvent("REBOUND_UNBIND")
+  ReBound:ClearRegisteredBindings()
+  self:OnEnable()
 end
 
 function main:UpgradeProfile()
@@ -164,22 +177,18 @@
   BINDING_NAME_PREVIOUSACTIONPAGE = label
 end
 
-function main:SetupKeybindings( previous )
-  if previous then
-    self:UnregisterEvent("REBOUND_BIND")
-    self:UnregisterEvent("REBOUND_UNBIND")
-    for key, binding in pairs(previous) do
-      ReBound:ClearBinding(key, getglobal(binding.target), binding.button, true)
-    end
-  end
+function main:SetupKeybindings()
   if self.db.profile.firstRunDone ~= true then
     self:StealKeyBindings()
   else
     for key, binding in pairs(self.db.profile.bindings) do
-      ReBound:SetBinding(key, getglobal(binding.target), binding.button)
+      local target = getglobal(binding.target) 
+      if target then
+        ReBound:SetBinding(key, target, binding.button)
+      end
     end
   end
-  SaveBindings(GetCurrentBindingSet())
+  ReBound:SaveBindings()
   self:RegisterEvent("REBOUND_BIND")
   self:RegisterEvent("REBOUND_UNBIND")
 end
@@ -193,17 +202,17 @@
       ReBound:SetBinding(key, self.bars[1].buttons[i]:GetActionFrame(), "LeftButton")
     end
   end
-  SaveBindings(GetCurrentBindingSet())
+  ReBound:SaveBindings()
 end
 
-function main:REBOUND_BIND(key, target, button)
-  if key and target then
+function main:REBOUND_BIND(id, key, target, button)
+  if id == "REACTION" and key and target then
     self.db.profile.bindings[key] = { target = target, button = button }
   end
 end
 
-function main:REBOUND_UNBIND(key)
-  if key then
+function main:REBOUND_UNBIND(id, key)
+  if id == "REACTION" and key then
     self.db.profile.bindings[key] = nil
   end
 end
@@ -227,10 +236,10 @@
       end
     end
     if enabled then
-      ReBound:ShowAll()
+      ReBound:ShowFrames()
       ReActionKeybindDialog:Show()
     else
-      ReBound:HideAll()
+      ReBound:HideFrames()
       if ReActionKeybindDialog:IsShown() then
         ReActionKeybindDialog:Hide()
       end
@@ -468,6 +477,10 @@
       end
     )
 
+    -- register page up/down buttons with ReBound for keybinding
+    ReBound:Register(bar.upArrow)
+    ReBound:Register(bar.downArrow)
+
     if not self.locked then
       bar:ShowControls()
     end