diff classes/Bar.lua @ 155:806a61b331a0

Pushed the state implementation into Bar
author Flick <flickerstreak@gmail.com>
date Fri, 15 May 2009 22:38:19 +0000
parents df67685b340e
children 611e6ce08717
line wrap: on
line diff
--- a/classes/Bar.lua	Fri May 08 17:30:22 2009 +0000
+++ b/classes/Bar.lua	Fri May 15 22:38:19 2009 +0000
@@ -10,6 +10,119 @@
 
 local KB = LibStub("LibKeyBound-1.0")
 
+---- Secure snippets ----
+local _reaction_init = 
+[[
+  anchorKeys = newtable("point","relPoint","x","y")
+
+  state = nil
+  set_state = nil
+  state_override = nil
+
+  showAll = false
+  hidden = false
+
+  defaultAlpha = 1.0
+  defaultScale = 1.0
+  defaultAnchor = newtable()
+
+  activeStates = newtable()
+  settings = newtable()
+  extensions = newtable()
+]]
+
+local _reaction_refresh = 
+[[
+  local oldState = state
+  state = state_override or set_state or state
+
+  if state then
+    local settings = settings[state]
+    if settings then
+      -- show/hide
+      local h = settings.hide and not showAll
+      if h ~= hidden then
+        if h then
+          self:Hide()
+        else
+          self:Show()
+        end
+        hidden = h
+      end
+      -- re-anchor
+      local old_anchor = activeStates.anchor
+      activeStates.anchor = settings.anchorEnable and state
+      if old_anchor ~= activeStates.anchor or not set_state then
+        if activeStates.anchor then
+          if settings.anchorPoint then
+            self:ClearAllPoints()
+            local f = self:GetAttribute("frameref-anchor-"..state)
+            if f then
+              self:SetPoint(settings.anchorPoint, f, settings.anchorRelPoint, settings.anchorX, settings.anchorY)
+            end
+          end
+        elseif defaultAnchor.point then
+          self:ClearAllPoints()
+          self:SetPoint(defaultAnchor.point, defaultAnchor.frame, 
+                        defaultAnchor.relPoint, defaultAnchor.x, defaultAnchor.y)
+        end
+      end
+      -- re-scale
+      local old_scale = activeStates.scale
+      activeStates.scale = settings.enableScale and state
+      if old_scale ~= activeStates.scale or not set_state then
+        self:SetScale(activeStates.scale and settings.scale or defaultScale)
+      end
+      -- alpha
+      local old_alpha = activeStates.alpha
+      activeStates.alpha = settings.enableAlpha and state
+      if old_alpha ~= activeStates.alpha or not set_state then
+        self:SetAlpha(activeStates.alpha and settings.alpha or defaultAlpha)
+      end
+    end
+  end
+
+  for _, attr in pairs(extensions) do
+    control:RunAttribute(attr)
+  end
+  
+  control:ChildUpdate()
+
+  if showAll then
+    control:CallMethod("UpdateHiddenLabel", state and settings[state] and settings[state].hide)
+  end
+
+  if oldState ~= state then
+    control:CallMethod("StateRefresh", state)
+  end
+]]
+
+local _onstate_reaction = -- function( self, stateid, newstate )
+[[
+  set_state = newstate
+]] .. _reaction_refresh
+
+local _onstate_showgrid = -- function( self, stateid, newstate )
+[[
+  control:ChildUpdate(stateid,newstate)
+  control:CallMethod("UpdateShowGrid")
+]]
+
+local _onstate_unitexists = -- function( self, stateid, newstate )
+[[
+
+]] .. _reaction_refresh
+
+local _onclick =  -- function( self, button, down )
+[[
+  if state_override == button then
+    state_override = nil -- toggle
+  else
+    state_override = button
+  end
+]] .. _reaction_refresh
+
+
 ---- Bar class ----
 local Bar   = { }
 local weak  = { __mode = "k" }
@@ -51,19 +164,19 @@
   f:Show()
   f:EnableMouse(false)
   f:SetClampedToScreen(true)
+  ReAction.gridProxy:AddFrame(f)
 
-  f:SetAttribute("_onstate-showgrid",
-    -- function(self,stateid,newstate)
-    [[
-      control:ChildUpdate(stateid,newstate)
-      control:CallMethod("UpdateShowGrid")
-    ]])
-  f.UpdateShowGrid = function(frame)
-    for button in self:IterateButtons() do
-      button:UpdateShowGrid()
-    end
-  end
-  ReAction.gridProxy:AddFrame(f)
+  -- secure handlers
+  f:Execute(_reaction_init)
+  f:SetAttribute("_onstate-reaction",   _onstate_reaction)
+  f:SetAttribute("_onstate-showgrid",   _onstate_showgrid)
+  f:SetAttribute("_onstate-unitexists", _onstate_unitexists)
+  f:SetAttribute("_onclick",            _onclick)
+
+  -- secure handler CallMethod()s
+  f.UpdateShowGrid    = function() self:UpdateShowGrid() end
+  f.StateRefresh      = function() self:RefreshControls() end
+  f.UpdateHiddenLabel = function(f,hidden) self:SetLabelSubtext(hidden and L["Hidden"]) end
 
   -- Override the default frame accessor to provide strict read-only access
   function self:GetFrame()
@@ -215,11 +328,12 @@
 function Bar:SetAlpha(value)
   self.config.alpha = value
   self:GetFrame():SetAlpha(value or 1.0)
+  self:UpdateDefaultStateAlpha()
   ReAction:RefreshBar(self)
 end
 
--- iterator returns button, idx and does NOT iterate in index order
 function Bar:IterateButtons()
+  -- iterator returns button, idx and does NOT iterate in index order
   return pairs(self.buttons)
 end
 
@@ -228,15 +342,9 @@
 --
 
 function Bar:SetConfigMode(mode)
+  self:SetSecureData("showAll",mode)
+  self:UpdateUnitWatch()
   self:ShowControls(mode)
-  if self.unitwatch then
-    if mode then
-      UnregisterUnitWatch(self:GetFrame())
-      self:GetFrame():Show()
-    else
-      RegisterUnitWatch(self:GetFrame())
-    end
-  end
   for b in self:IterateButtons() do
     b:ShowGridTemp(mode)
     b:UpdateActionIDLabel(mode)
@@ -244,14 +352,8 @@
 end
 
 function Bar:SetKeybindMode(mode)
-  if self.unitwatch then
-    if mode then
-      UnregisterUnitWatch(self:GetFrame())
-      self:GetFrame():Show()
-    else
-      RegisterUnitWatch(self:GetFrame())
-    end
-  end
+  self:SetSecureData("showAll",mode)
+  self:UpdateUnitWatch()
   for b in self:IterateButtons() do
     b:SetKeybindMode(mode)
   end
@@ -281,6 +383,8 @@
   else
     f:SetPoint("CENTER")
   end
+
+  self:UpdateDefaultStateAnchor()
 end
 
 function Bar:ClipNButtons( n )
@@ -331,16 +435,34 @@
   -- does nothing by default
 end
 
+function Bar:UpdateShowGrid()
+  for button in self:IterateButtons() do
+    button:UpdateShowGrid()
+  end
+end
+
+function Bar:UpdateUnitWatch()
+  if self.unitwatch then
+    if self.unitwatchActive and (ReAction:GetConfigMode() or ReAction:GetKeybindMode()) then
+      UnregisterUnitWatch(self:GetFrame())
+      self.unitwatchActive = false
+    elseif not self.unitwatchActive then
+      RegisterUnitWatch(self:GetFrame())
+      self.unitwatchActive = true
+    end
+    self:RefreshSecureState()
+  end
+end
+
 function Bar:ShowControls(show)
-  local f = self.overlay
   if show then
-    if not f then
-      f = Bar.Overlay:New(self) -- see Overlay.lua
-      self.overlay = f
+    if not self.overlay then
+      self.overlay = Bar.Overlay:New(self) -- see Overlay.lua
     end
-    f:Show()
-  elseif f then
-    f:Hide()
+    self.overlay:Show()
+    self:RefreshSecureState()
+  elseif self.overlay then
+    self.overlay:Hide()
   end
 end
 
@@ -360,19 +482,164 @@
 -- Secure state functions
 --
 
+function Bar:GetSecureState()
+  local env = GetManagedEnvironment(self:GetFrame())
+  return env and env.state
+end
+
+function Bar:GetStateProperty(state, propname)
+  -- override in modules/State.lua for now
+end
+
+function Bar:SetStateProperty(state, propname, value)
+  -- override in modules/State.lua for now
+end
+
+function Bar:RefreshSecureState()
+  self:GetFrame():Execute(_reaction_refresh)
+end
+
+-- usage: SetSecureData(globalname, [tblkey1, tblkey2, ...], value)
+function Bar:SetSecureData( ... )
+  local n = select('#',...)
+  if n < 2 then
+    error("ReAction.Bar:SetSecureData() requires at least 2 arguments")
+  end
+  local f = self:GetFrame()
+  f:SetAttribute("data-depth",n-1)
+  f:SetAttribute("data-value",select(n,...))
+  for i = 1, n-1 do
+    local key = select(i,...)
+    if key == nil then
+      error("ReAction.Bar:SetSecureData() - nil table key in argument list (#"..i..")")
+    end
+    f:SetAttribute("data-key-"..i, key)
+  end
+  f:Execute(
+    [[
+      local n = self:GetAttribute("data-depth")
+      if n > 0 then
+        local value = self:GetAttribute("data-value")
+        local t = _G
+        for i = 1, n do
+          local key = self:GetAttribute("data-key-"..i)
+          if not key then return end
+          if not t[key] then
+            t[key] = newtable()
+          end
+          if i == n then
+            t[key] = value
+          else
+            t = t[key]
+          end
+        end
+      end
+    ]])
+  self:RefreshSecureState()
+end
+
+function Bar:SetSecureStateData( state, key, value )
+  self:SetSecureData("settings",state,key,value)
+end
+
+-- sets a snippet to be run as an extension to _onstate-reaction
+function Bar:SetSecureStateExtension( id, snippet )
+  if id == nil then
+    error("ReAction.Bar:SetSecureStateExtension() requires an id")
+  end
+  local f = self:GetFrame()
+  f:SetAttribute("input-secure-ext-id",id)
+  f:SetAttribute("secure-ext-"..id,snippet)
+  f:Execute(
+    [[
+      local id = self:GetAttribute("input-secure-ext-id")
+      if id then
+        extensions[id] = self:GetAttribute("secure-ext-"..id) or nil
+      end
+    ]])
+  self:RefreshSecureState()
+end
+
+function Bar:SetFrameRef( name, refFrame )
+  if refFrame then
+    local _, explicit = refFrame:IsProtected()
+    if not explicit then
+      refFrame = nil
+    end
+  end
+  if refFrame then
+    self:GetFrame():SetFrameRef(name,refFrame)
+  else
+    self:GetFrame():SetAttribute("frameref-"..name,nil)
+  end
+end
+
+function Bar:SetStateDriver( rule )
+  if rule then
+    RegisterStateDriver(self:GetFrame(),"reaction",rule)
+  elseif self.statedriver then
+    UnregisterStateDriver(self:GetFrame(),"reaction")
+  end
+  self.statedriver = rule
+  self:RefreshSecureState()
+end
+
 -- pass unit=nil to set up the unit elsewhere, if you want something more complex
 function Bar:RegisterUnitWatch( unit, enable )
   local f = self:GetFrame()
   if unit then
     f:SetAttribute("unit",unit)
   end
-  if not ReAction:GetConfigMode() then
-    if enable then
-      RegisterUnitWatch(f)
-    elseif self.unitwatch then
-      UnregisterUnitWatch(f)
-    end
-  end
   self.unitwatch = enable
+  self:UpdateUnitWatch()
 end
 
+-- set a keybind to push a value into "state-reaction" attribute
+function Bar:SetStateKeybind( key, state )
+  local f = self:GetFrame()
+  local binds = self.statebinds
+  if not binds then
+    binds = { }
+    self.statebinds = binds
+  end
+
+  -- clear the old binding, if any
+  if binds[state] then
+    SetOverrideBinding(f, false, binds[state], nil)
+  end
+
+  if key then
+    SetOverrideBinding(f, false, key, state, nil) -- state name is virtual mouse button
+  end
+  binds[state] = key
+end
+
+function Bar:GetStateKeybind( state )
+  if self.statebinds and state then
+    return self.statebinds[state]
+  end
+end
+
+function Bar:UpdateDefaultStateAnchor()
+  local point, frame, relPoint, x, y = self:GetAnchor()
+  local f = self:GetFrame()
+  f:SetAttribute("defaultAnchor-point",point)
+  f:SetAttribute("defaultAnchor-relPoint",relPoint)
+  f:SetAttribute("defaultAnchor-x",x)
+  f:SetAttribute("defaultAnchor-y",y)
+  self:SetFrameRef("defaultAnchor",_G[frame or "UIParent"])
+  f:Execute([[
+    for _, k in pairs(anchorKeys) do
+      defaultAnchor[k] = self:GetAttribute("defaultAnchor-"..k)
+    end
+    defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor")
+  ]])
+end
+
+function Bar:UpdateDefaultStateAlpha()
+  local f = self:GetFrame()
+  f:SetAttribute("defaultAlpha",self:GetAlpha())
+  f:Execute([[
+    defaultAlpha = self:GetAttribute("defaultAlpha")
+  ]])
+end