# HG changeset patch # User Flick # Date 1213641968 0 # Node ID 06cd74bdc7dad217647e4f83dfa723f95b84182d # Parent 00e28094e1a37ccf64b5dc1838027754b19900c9 - Cleaned up Bar interface - Move all attribute setting from Bar into State - Separated Moonkin and Tree of Life - Removed PossessBar module - Added some infrastructure for paged/mind control support to Action diff -r 00e28094e1a3 -r 06cd74bdc7da Bar.lua --- a/Bar.lua Tue Jun 10 22:25:15 2008 +0000 +++ b/Bar.lua Mon Jun 16 18:46:08 2008 +0000 @@ -3,84 +3,91 @@ local _G = _G local CreateFrame = CreateFrame local floor = math.floor +local fmod = math.fmod +local format = string.format local SecureStateHeader_Refresh = SecureStateHeader_Refresh - -- update ReAction revision if this file is newer local revision = tonumber(("$Revision$"):match("%d+")) if revision > ReAction.revision then ReAction.revision = revision end + ------ BAR CLASS ------ local Bar = { _classID = {} } local function Constructor( self, name, config ) - self.name, self.config = name, config - self.buttons = setmetatable({},{__mode="k"}) - if type(config) ~= "table" then error("ReAction.Bar: config table required") end + config.width = config.width or 480 + config.height = config.height or 40 + + self.name, self.config = name, config + self.buttons = setmetatable({},{__mode="k"}) + self.statedrivers = { } + self.keybinds = { } local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent - local f = CreateFrame("Frame",nil,parent,"SecureStateHeaderTemplate") + local f = CreateFrame("Button",name and format("ReAction-%s",name),parent,"SecureStateHeaderTemplate, SecureActionButtonTemplate") + + -- The frame itself is read-only + function self:GetFrame() + return f + end + + -- The bar itself is also a Button derived from SecureActionButtonTemplate, so it has an OnClick handler + -- which we can use as a virtual button for keybinds, which will send attribute-value changes to itself. + -- However, we don't ever want the user to be able to click it directly. + f:EnableMouse(false) + f:SetAttribute("type","attribute") f:SetFrameStrata("MEDIUM") - config.width = config.width or 480 - config.height = config.height or 40 f:SetWidth(config.width) f:SetWidth(config.height) + f:Show() + self:ApplyAnchor() ReAction.RegisterCallback(self, "OnConfigModeChanged") - - self.frame = f - self:ApplyAnchor() - f:Show() - self:RefreshLayout() end function Bar:Destroy() - local f = self.frame + local f = self:GetFrame() f:UnregisterAllEvents() f:Hide() f:SetParent(UIParent) f:ClearAllPoints() ReAction.UnregisterAllCallbacks(self) - if self.statedriver then - UnregisterStateDriver(f, "reaction") + for driver in pairs(self.statedrivers) do + UnregisterStateDriver(f, driver) end self.labelString = nil self.controlFrame = nil - self.frame = nil self.config = nil end function Bar:OnConfigModeChanged(event, mode) - self:ShowControls(mode) -- ShowControls() defined in Overlay.lua -end - -function Bar:RefreshLayout() - ReAction:RefreshBar(self) + self:ShowControls(mode) -- Bar:ShowControls() defined in Overlay.lua end function Bar:ApplyAnchor() - local f, config = self.frame, self.config + local f, config = self:GetFrame(), self.config f:SetWidth(config.width) f:SetHeight(config.height) - local anchor = config.anchor + local point = config.point f:ClearAllPoints() - if anchor then - local anchorTo = f:GetParent() - if config.anchorTo then - local bar = ReAction:GetBar(config.anchorTo) + if point then + local anchor = f:GetParent() + if config.anchor then + local bar = ReAction:GetBar(config.anchor) if bar then - anchorTo = bar:GetFrame() + anchor = bar:GetFrame() else - anchorTo = _G[config.anchorTo] + anchor = _G[config.anchor] end end - f:SetPoint(anchor, anchorTo or f:GetParent(), config.relativePoint, config.x or 0, config.y or 0) + f:SetPoint(point, anchor or f:GetParent(), config.relpoint, config.x or 0, config.y or 0) else f:SetPoint("CENTER") end @@ -88,9 +95,9 @@ function Bar:SetAnchor(point, frame, relativePoint, x, y) local c = self.config - c.anchor = point or c.anchor - c.anchorTo = frame and frame:GetName() or c.anchorTo - c.relativePoint = relativePoint or c.relativePoint + c.point = point or c.point + c.anchor = frame and frame:GetName() or c.anchor + c.relpoint = relativePoint or c.relpoint c.x = x or c.x c.y = y or c.y self:ApplyAnchor() @@ -98,20 +105,20 @@ function Bar:GetAnchor() local c = self.config - return (c.anchor or "CENTER"), (c.anchorTo or self.frame:GetParent():GetName()), (c.relativePoint or c.anchor or "CENTER"), (c.x or 0), (c.y or 0) -end - -function Bar:GetFrame() - return self.frame + return (c.point or "CENTER"), (c.anchor or self:GetFrame():GetParent():GetName()), (c.relpoint or c.point or "CENTER"), (c.x or 0), (c.y or 0) end function Bar:GetSize() - return self.frame:GetWidth() or 200, self.frame:GetHeight() or 200 + local f = self:GetFrame() + return f:GetWidth(), f:GetHeight() end function Bar:SetSize(w,h) self.config.width = w self.config.height = h + local f = self:GetFrame() + f:SetWidth(w) + f:SetHeight(h) end function Bar:GetButtonSize() @@ -126,6 +133,7 @@ self.config.btnWidth = w self.config.btnHeight = h end + ReAction:RefreshBar(self) end function Bar:GetButtonGrid() @@ -143,188 +151,128 @@ cfg.btnColumns = c cfg.spacing = s end + ReAction:RefreshBar(self) end function Bar:GetName() return self.name end +-- only ReAction:RenameBar() should call this function function Bar:SetName(name) self.name = name + -- controlLabelString is defined in Overlay.lua if self.controlLabelString then self.controlLabelString:SetText(self.name) end end -function Bar:PlaceButton(f, idx, baseW, baseH) +function Bar:AddButton(idx, button) + self.buttons[button] = idx + SecureStateHeader_Refresh(self:GetFrame()) +end + +function Bar:RemoveButton(button) + self.buttons[button] = nil +end + +function Bar:IterateButtons() -- iterator returns button, idx + return pairs(self.buttons) +end + +function Bar:PlaceButton(button, baseW, baseH) + local idx = self.buttons[button] + if not idx then return end local r, c, s = self:GetButtonGrid() local bh, bw = self:GetButtonSize() - local row, col = floor((idx-1)/c), mod((idx-1),c) -- zero-based + local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s local scale = bw/baseW + local f = button:GetFrame() f:ClearAllPoints() f:SetPoint("TOPLEFT",x/scale,-y/scale) f:SetScale(scale) - self.buttons[f] = true end +-- Creates (or updates) a named binding which binds a key press to a call to SetAttribute() +-- pass a nil key to unbind +function Bar:SetAttributeBinding( name, key, attribute, value ) + if not name then + error("usage - Bar:SetAttributeBinding(name [, key, attribute, value]") + end + local f = self:GetFrame() --- multi-state functions -- -function Bar:GetNumPages() - return self.config.nPages or 1 + -- clear the old binding, if any + if self.keybinds[name] then + SetOverrideBinding(f, false, self.keybinds[name], nil) + end + if key then + f:SetAttribute(format("attribute-name-%s",name), attribute) + f:SetAttribute(format("attribute-value-%s",name), value) + SetOverrideBindingClick(f, false, key, f:GetName(), name) -- binding name is the virtual mouse button + end + self.keybinds[name] = key end - -- - -- 'rule' is a rule-string to pass to RegisterStateDriver - -- 'states' is a { ["statename"] = } table of all state names - -- 'keybinds' is a { ["statename"] = keybind } table of all keybound states - -- -function Bar:SetStateDriver( rule, states, keybinds ) - local f = self.frame - local kbprefix = "" - do - local tmp = { } - for s, k in pairs(keybinds) do - if k and #k > 0 then -- filter out false table entries - -- if in a keybound state, set the stack to the new state but stay in the keybound state. - -- use $s as a placeholder for the current state, it will be gsub()'d in later - table.insert(tmp,("%s:$s set() %s"):format(s,s)) +-- Sets up a state driver 'name' for the bar, using the provided 'rule' +-- Also sets attributes 'statemap--'= for each entry in the passed map +-- if 'rule' is nil or an empty string, the driver is unregistered. +function Bar:SetStateDriver( name, rule, map ) + local f = self:GetFrame() + if rule and #rule > 0 then + if map then + for key, value in pairs(map) do + f:SetAttribute( format("statemap-%s-%s",name,key), value ) end end - table.insert(tmp,kbprefix) -- to get a trailing ';' if the table is not empty - kbprefix = table.concat(tmp,";") - end - for state in pairs(states) do - -- For all states: if in a keybound state, stay there (with stack manipulation, see above). - -- Otherwise, go to the state - f:SetAttribute(("statemap-reaction-%s"):format(state),("%s%s"):format(kbprefix:gsub("%$s",state),state)) - - local binding = keybinds[state] - self:SetStateKeybind(binding, state) -- set the binding even if nil, to clear it unconditionally - if binding then - -- for key bindings, use the state-stack to toggle between the last state and the keybound state - -- use a different 'virtual state' passed to attribute 'reaction-state' for key bindings, "_binding" - f:SetAttribute(("statemap-reaction-%s_binding"):format(state), ("%s:pop();*:set(%s)"):format(state,state)) - end - end - - if rule and #rule > 0 then - self.stateDriver = true - RegisterStateDriver(f, "reaction", rule) - elseif self.statedriver then - self.statedriver = false - UnregisterStateDriver(f, "reaction") + RegisterStateDriver(f, name, rule) + self.statedrivers[name] = true + elseif self.statedrivers[name] then + UnregisterStateDriver(f, name) + self.statedrivers[name] = nil end end -function Bar:SetHideStates(s) - for f in pairs(self.buttons) do - if f:GetParent() == self.frame then - f:SetAttribute("hidestates",s) +-- Set an attribute on the frame (or its buttons if 'doButtons' = true) +-- Either or both 'map' and 'default' can be passed: +-- - If 'map' is omitted, then 'default' is set to the attribute. +-- - If 'map' is provided, then it is interpreted as an unordered +-- table of the form { ["statename"] = ["value"] }, and will be +-- converted into a SecureStateHeaderTemplate style state-parsed +-- string, e.g. ":;:". If 'default' +-- is also provided, then its value will be converted to a string +-- and appended. +function Bar:SetStateAttribute( attribute, map, default, doButtons ) + local value = default + if map then + local tmp = { } + for state, value in pairs(map) do + table.insert(tmp, format("%s:%s",tostring(state),tostring(value))) end + if default then + table.insert(tmp, tostring(default)) + end + value = table.concat(tmp,";") end - SecureStateHeader_Refresh(self.frame) -end - -function Bar:SetStateKeybind(key, state, defaultstate) - -- Lazily create a tiny offscreen button which sends "_binding" values to the - -- bar frame's state-reaction attribute, by using an override binding to generate a - -- click on the button with a virtual mouse button "state". - -- This gets around making the bar itself a clickable button, which is not desirable - local f = self.statebuttonframe - if key then - if not f then - f = CreateFrame("Button",self:GetName().."_statebutton",self.frame,"SecureActionButtonTemplate") - f:SetPoint("BOTTOMRIGHT",UIParent,"TOPLEFT") - f:SetWidth(1) - f:SetHeight(1) - f:SetAttribute("type*","attribute") - f:SetAttribute("attribute-name*","state-reaction") - f:SetAttribute("attribute-frame*",self.frame) - f:Show() - f.bindings = { } - self.statebuttonframe = f - end - f:SetAttribute(("attribute-value-%s"):format(state),("%s_binding"):format(state)) - -- clear the old binding, if any, for this state - if f.bindings[state] then - SetOverrideBinding(self.frame, false, f.bindings[state], nil) - end - SetOverrideBindingClick(self.frame, false, key, f:GetName(), state) -- the state name is used as the virtual button - f.bindings[state] = key - elseif f then - key = f.bindings[state] - if key then - SetOverrideBinding(self.frame, false, key, nil) - f.bindings[state] = nil - end - end -end - -function Bar:SetStatePageMap(state, map) -- map is a { ["statename"] = pagenumber } table - local f = self.frame - local tmp = { } - for s, p in pairs(map) do - table.insert(tmp, ("%s:page%d"):format(s,p)) - end - local spec = table.concat(tmp,";") - local current = f:GetAttribute("statebutton") - if spec ~= f:GetAttribute("statebutton") then - f:SetAttribute("statebutton", spec) - end - SecureStateHeader_Refresh(f) -end - -function Bar:SetStateKeybindOverrideMap(states) -- 'states' is an array of state-names that should have keybind overrides enabled - local f = self.frame - for i = 1, #states do - local s = states[i] - states[i] = ("%s:%s"):format(s,s) - end - table.insert(states,"_defaultbindings") - f:SetAttribute("statebindings",table.concat(states,";")) - SecureStateHeader_Refresh(f) - for b in pairs(self.buttons) do - -- TODO: signal child frames that they should maintain multiple bindings - end -end - -local _ofskeys = { "point", "relpoint", "x", "y" } -function Bar:SetStateAnchorMap( map ) -- 'map' is a { ["statename"] = { point=point, relpoint=relpoint, x=x, y=y } } table - local f = self.frame - local c = self.config - local default = { point = c.anchor, relpoint = c.relativePoint, x = c.x, y = c.y } - for _, key in pairs(_ofskeys) do - local t = { } - for state, info in pairs(map) do - if info[key] then - table.insert(t, ("%s:%s"):format(state, info[key])) + if doButtons then + for b in pairs(self.buttons) do + local f = b.GetFrame and b:GetFrame() + if f then + f:SetAttribute(attribute, value) end end - if #t > 0 and default[key] then table.insert(t, tostring(default[key])) end - f:SetAttribute(("headofs%s"):format(key), table.concat(t,";") or "") + else + self:GetFrame():SetAttribute(attribute, value) end - SecureStateHeader_Refresh(f) + SecureStateHeader_Refresh(self:GetFrame()) end -function Bar:SetStateScaleMap( map ) -- 'map' is a { ["statename"] = scalevalue } table - local f = self.frame - local t = { } - for state, scale in pairs(map) do - table.insert( t, ("%s:%s"):format(state,scale) ) - end - if #t > 0 then table.insert(t, "1.0") end - f:SetAttribute("headscale",table.concat(t,";") or "") - SecureStateHeader_Refresh(f) -end - - ------ Export as a class-factory ------ ReAction.Bar = { prototype = Bar, - new = function(self, ...) + New = function(self, ...) local x = { } for k,v in pairs(Bar) do x[k] = v diff -r 00e28094e1a3 -r 06cd74bdc7da Overlay.lua --- a/Overlay.lua Tue Jun 10 22:25:15 2008 +0000 +++ b/Overlay.lua Mon Jun 16 18:46:08 2008 +0000 @@ -65,7 +65,7 @@ local ApplyAnchor = Bar.ApplyAnchor local function StoreExtents(bar) - local f = bar.frame + local f = bar:GetFrame() local point, relativeTo, relativePoint, x, y = f:GetPoint(1) relativeTo = relativeTo or f:GetParent() local anchorTo @@ -86,7 +86,7 @@ end local function StoreSize(bar) - local f = bar.frame + local f = bar:GetFrame() local c = bar.config c.width, c.height = f:GetWidth(), f:GetHeight() end @@ -407,7 +407,7 @@ end local function CreateControls(bar) - local f = bar.frame + local f = bar:GetFrame() f:SetMovable(true) f:SetResizable(true) @@ -493,7 +493,6 @@ f:SetScript("OnUpdate", function() RecomputeGrid(bar) - bar:RefreshLayout() end ) end @@ -540,7 +539,6 @@ f:SetScript("OnUpdate", function() RecomputeButtonSize(bar) - bar:RefreshLayout() updateTooltip() end ) @@ -549,7 +547,6 @@ f:SetScript("OnUpdate", function() RecomputeButtonSpacing(bar) - bar:RefreshLayout() updateTooltip() end ) diff -r 00e28094e1a3 -r 06cd74bdc7da ReAction.lua --- a/ReAction.lua Tue Jun 10 22:25:15 2008 +0000 +++ b/ReAction.lua Mon Jun 16 18:46:08 2008 +0000 @@ -297,7 +297,7 @@ until bars[name] == nil end profile.bars[name] = profile.bars[name] or config - local bar = self.Bar:new( name, profile.bars[name] ) -- ReAction.Bar defined in Bar.lua + local bar = self.Bar:New( name, profile.bars[name] ) -- ReAction.Bar defined in Bar.lua bars[name] = bar callbacks:Fire("OnCreateBar", bar, name) if private.configMode then diff -r 00e28094e1a3 -r 06cd74bdc7da State.lua --- a/State.lua Tue Jun 10 22:25:15 2008 +0000 +++ b/State.lua Mon Jun 16 18:46:08 2008 +0000 @@ -8,6 +8,7 @@ local L = ReAction.L local _G = _G local InCombatLockdown = InCombatLockdown +local format = string.format -- module declaration local moduleID = "State" @@ -33,9 +34,26 @@ return t end --- PRIVATE -- +-- return a new array of keys of table 't', sorted by comparing +-- sub-fields (obtained via tfetch) of the table values +local function fieldsort( t, ... ) + local r = { } + for k in pairs(t) do + table.insert(r,k) + end + local path = { ... } + table.sort(r, function(lhs, rhs) + local olhs = tfetch(t[lhs], unpack(path)) or 0 + local orhs = tfetch(t[rhs], unpack(path)) or 0 + return olhs < orhs + end) + return r +end + local InitRules, ApplyStates, SetProperty, GetProperty + +-- PRIVATE -- do -- As far as I can tell the macro clauses are NOT locale-specific. local ruleformats = { @@ -56,13 +74,14 @@ solo = "nogroup", combat = "combat", nocombat = "nocombat", + possess = "bonusbar:5", } -- Have to do these shenanigans instead of hardcoding the stances/forms because -- the ordering varies if the character is missing a form. For warriors -- this is rarely a problem (c'mon, who actually skips the level 10 def stance quest?) -- but for druids it can be. Some people never bother to do the aquatic form quest - -- until well past when they get cat form, and stance 5 can be flight, tree, or moonkin + -- until well past when they get cat form, and stance 5/6 can be flight, tree, or moonkin -- depending on talents. function InitRules() local forms = { } @@ -78,91 +97,109 @@ 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 tree = forms["Interface\\Icons\\Ability_Druid_TreeofLife"] or 9 + local moonkin = forms["Interface\\Icons\\Spell_Nature_ForceOfNature"] or 9 local flight = forms["Interface\\Icons\\Ability_Druid_FlightForm"] or 9 -- flight and swift flight share the same icon - 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) + ruleformats.battle = "stance:1" + ruleformats.defensive = format("stance:%d",defensive) + ruleformats.berserker = format("stance:%d",berserker) + ruleformats.caster = format("form:0/%d/%d/%d",aquatic, travel, flight) + ruleformats.bear = format("form:%d",bear) + ruleformats.cat = format("form:%d",cat) + ruleformats.tree = format("form:%d",tree) + ruleformats.moonkin = format("form:%d",moonkin) 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) + + -- state property functions + local ofskeys = { + anchorPoint = "point", + anchorRelPoint = "relpoint", + anchorX = "x", + anchorY = "y" + } + + local barofsidx = { + anchorPoint = 1, + anchorRelPoint = 3, + anchorX = 4, + anchorY = 5 + } + + local function UpdatePartialAnchor(bar, states, ckey) + local map = { } + local bc = bar.config + for state, c in pairs(states) do + if c.enableAnchor then + map[state] = c[ckey] + end 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 + local ofskey = ofskeys[ckey] + local default = select(barofsidx[ckey], bar:GetAnchor()) + bar:SetStateAttribute(format("headofs%s",ofskeys[ckey]), map, default) + end + + -- the name of the function maps to the name of the config element + local propertyFuncs = { + hide = function( bar, states ) + local hs = { } + for state, config in pairs(states) do + if config.hide then + table.insert(hs, state) + end + end + bar:SetStateAttribute("hidestates", nil, table.concat(hs,","), true) -- pass to buttons + end, + + page = function( bar, states ) + local map = { } + for state, config in pairs(states) do + if config.page then + map[state] = format("page%d",config.page) + end + end + bar:SetStateAttribute("statebutton", map) + end, + + keybindstate = function( bar, states ) + local map = { } + for state, config in pairs(states) do + local kbset = config.keybindstate and state + map[state] = kbset + for button in bar:IterateButtons() do + -- TODO: inform children they should maintain multiple binding sets + -- ?? button:UpdateBindingSet(kbset) + end + end + bar:SetStateAttribute("statebindings", map) + end, + + enableAnchor = function( bar, states ) + for ckey in pairs(ofskeys) do + UpdatePartialAnchor(bar, states, ckey) + end + end, + + enableScale = function( bar, states ) + local map = { } + for state, c in pairs(states) do + if c.enableScale then + map[state] = c.scale + end + end + bar:SetStateAttribute("headscale", map, 1.0) + end, + } + + -- generate some table entries + propertyFuncs.scale = propertyFuncs.enableScale + for ckey in pairs(ofskeys) do + propertyFuncs[ckey] = function( bar, states ) + UpdatePartialAnchor(bar, states, ckey) + end end - local function BuildRules(states) - local rules = { } - local keybinds = { } - local default - local fmt = "%s %s" - for idx, state in ipairs(fieldsort(states, "rule", "order")) do - local c = states[state].rule - local type = tfetch(c,"type") - if type == "default" then - default = default or state - elseif type == "keybind" then - keybinds[state] = c.keybind or false - elseif type == "custom" then - if c.custom then - -- strip out all spaces from the custom rule - table.insert(rules, fmt:format(c.custom:gsub("%s",""), state)) - end - elseif type == "any" then - if c.values then - local clauses = { } - for key, value in pairs(c.values) do - table.insert(clauses, ("[%s]"):format(ruleformats[key])) - end - if #clauses > 0 then - table.insert(rules, fmt:format(table.concat(clauses), state)) - end - end - elseif type == "all" then - if c.values then - local clauses = { } - for key, value in pairs(c.values) do - table.insert(clauses, ruleformats[key]) - end - if #clauses > 0 then - table.insert(rules, fmt:format(("[%s]"):format(table.concat(clauses, ",")), state)) - end - end - end - end - if default then - table.insert(rules, default) - end - return rules, keybinds - end - - local propertyFuncs = { } - - function ApplyStates( bar ) - local states = tfetch(module.db.profile.bars, bar:GetName(), "states") - if states then - local rules, keybinds = BuildRules(states) - bar:SetStateDriver(table.concat(rules,";"), states, keybinds) - 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) @@ -177,65 +214,111 @@ 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) + + + -- + -- Build a state-transition spec string and statemap to be passed to + -- Bar:SetStateDriver(). + -- + -- The statemap building is complex: keybound states override all + -- other transitions, so must remain in their current state, but must + -- also remember other transitions that happen while they're stuck there + -- so that when the binding is toggled off it can return to the proper state + -- + local function BuildStateMap(states) + local rules = { } + local statemap = { } + local keybinds = { } + local default + + -- first grab all the keybind override states + -- and construct an override template + local override + do + local overrides = { } + for name, state in pairs(states) do + local type = tfetch(state, "rule", "type") + if type == "keybind" then + -- use the state-stack to remember the current transition + -- use $s as a marker for a later call to gsub() + table.insert(overrides, format("%s:$s set() %s", name, name)) + end + end + if #overrides > 0 then + table.insert(overrides, "") -- for a trailing ';' + end + override = table.concat(overrides, ";") or "" + end + + -- now iterate the rules in order + for idx, state in ipairs(fieldsort(states, "rule", "order")) do + local c = states[state].rule + local type = c.type + if type == "default" then + default = default or state + elseif type == "custom" then + if c.custom then + -- strip out all spaces from the custom rule + table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state)) + end + elseif type == "any" then + if c.values then + local clauses = { } + for key, value in pairs(c.values) do + table.insert(clauses, format("[%s]", ruleformats[key])) + end + if #clauses > 0 then + table.insert(rules, format("%s %s", table.concat(clauses), state)) + end + end + elseif type == "all" then + if c.values then + local clauses = { } + for key, value in pairs(c.values) do + table.insert(clauses, ruleformats[key]) + end + if #clauses > 0 then + table.insert(rules, format("%s %s", format("[%s]", table.concat(clauses, ",")), state)) + end + end + end + + -- use a different virtual button for the actual keybind transition, + -- to implement a toggle. You have to clear it regardless of the type + -- (which is usually a no-op) to unbind state transitions when switching + -- transition types. + local bindbutton = format("%s_binding",state) + if type == "keybind" then + keybinds[bindbutton] = c.keybind or false + statemap[bindbutton] = format("%s:pop();*:set(%s)", state, state) + else + keybinds[bindbutton] = false + end + + -- construct the statemap. gsub() the state name into the override template. + statemap[state] = format("%s%s", override:gsub("%$s",state), state) + end + -- make sure that the default, if any, is last + if default then + table.insert(rules, default) + end + return table.concat(rules,";"), statemap, keybinds + end + + function ApplyStates( bar ) + local states = tfetch(module.db.profile.bars, bar:GetName(), "states") + if states then + local rule, statemap, keybinds = BuildStateMap(states) + bar:SetStateDriver("reaction", rule, statemap) + for state, key in pairs(keybinds) do + bar:SetAttributeBinding(state, key, "state-reaction", state) + end + for k, f in pairs(propertyFuncs) do + f(bar, states) 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 - - local function updateAnchor(bar, states) - local map = { } - for state, c in pairs(states) do - if c.enableAnchor then - map[state] = { point = c.anchorPoint, relpoint = c.anchorRelPoint, x = c.anchorX, y = c.anchorY } - end - end - bar:SetStateAnchorMap(map) - end - - propertyFuncs.enableAnchor = updateAnchor - propertyFuncs.anchorPoint = updateAnchor - propertyFuncs.anchorRelPoint = updateAnchor - propertyFuncs.anchorX = updateAnchor - propertyFuncs.anchorY = updateAnchor - - local function updateScale( bar, states ) - local map = { } - for state, c in pairs(states) do - if c.enablescale then - map[state] = c.scale - end - end - bar:SetStateScaleMap(map) - end - - propertyFuncs.enablescale = updateScale - propertyFuncs.scale = updateScale - end @@ -289,7 +372,7 @@ end function module:OnRenameBar(event, bar, oldname, newname) - local b = self.db.profile.bars + local bars = self.db.profile.bars bars[newname], bars[oldname] = bars[oldname], nil end @@ -317,12 +400,13 @@ 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"]} } }, + { "form", ClassCheck("DRUID"), { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {tree = L["Tree of Life"]}, {moonkin = L["Moonkin Form"]} } }, { "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"]} } }, + { "possess", false, { {possess = L["Mind Control"]} } }, { "group", false, { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } }, { "combat", false, { {combat = L["In Combat"]}, {nocombat = L["Out of Combat"]} } }, } @@ -482,7 +566,7 @@ set = function(info, value) -- check for existing state name if states[value] then - L["State named '%s' already exists"]:format(value) + format(L["State named '%s' already exists"],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 @@ -551,27 +635,27 @@ order = 3, type = "select", disabled = function() - return bar:GetNumPages() < 2 + --return bar:GetNumPages() < 2 + return true end, hidden = function() - return bar:GetNumPages() < 2 + --return bar:GetNumPages() < 2 + return true end, values = function() - local pages = { none = " " } - for i = 1, bar:GetNumPages() do - pages[i] = i - end + -- use off-by-one ordering to put (none) first in the list + local pages = { [1] = L["(none)"] } + --for i = 1, bar:GetNumPages() do + -- pages[i+1] = i + --end return pages end, set = function(info, value) - if value == "none" then - setprop(info, nil) - else - setprop(info, value) - end + value = value - 1 + setprop(info, value > 0 and value or nil) end, get = function(info) - return getprop(info) or "none" + return getprop(info) or L["(none)"] end, }, keybindstate = { @@ -647,7 +731,7 @@ type = "group", inline = true, args = { - enablescale = { + enableScale = { name = L["Set New Scale"], order = 1, type = "toggle", @@ -664,8 +748,8 @@ 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, + disabled = function() return not GetProperty(bar, opts.name, "enableScale") end, + hidden = function() return not GetProperty(bar, opts.name, "enableScale") end, }, }, }, @@ -771,7 +855,7 @@ 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) + return format(L["Invalid custom rule '%s': each clause must appear within [brackets]"],rule) end s = r until c == nil @@ -816,6 +900,7 @@ CreateBarOptions = function(bar) local private = { } + local states = tbuild(module.db.profile.bars, bar:GetName(), "states") local options = { type = "group", name = L["Dynamic State"], @@ -849,7 +934,7 @@ func = function () local name = private.newstatename if states[name] then - ReAction:UserError(L["State named '%s' already exists"]:format(name)) + ReAction:UserError(format(L["State named '%s' already exists"],name)) else -- TODO: select default state options and pass as final argument states[name] = { } diff -r 00e28094e1a3 -r 06cd74bdc7da locale/enUS.lua --- a/locale/enUS.lua Tue Jun 10 22:25:15 2008 +0000 +++ b/locale/enUS.lua Mon Jun 16 18:46:08 2008 +0000 @@ -46,7 +46,8 @@ "Caster Form", "Bear Form", "Cat Form", -"Tree/Moonkin", +"Tree of Life", +"Moonkin Form", "Stealth", "No Stealth", "Shadowform", @@ -59,6 +60,7 @@ "Hostile Focus", "Friendly Focus", "No Focus", +"Mind Control", "Raid", "Party", "Solo", @@ -76,6 +78,7 @@ "Set the properties for the bar when in this state", "Hide Bar", "Show Page #", +"(none)", "Override Keybinds", "Set this state to maintain its own set of keybinds which override the defaults when active", "Position", diff -r 00e28094e1a3 -r 06cd74bdc7da modules/ReAction_Action/ReAction_Action.lua --- a/modules/ReAction_Action/ReAction_Action.lua Tue Jun 10 22:25:15 2008 +0000 +++ b/modules/ReAction_Action/ReAction_Action.lua Mon Jun 16 18:46:08 2008 +0000 @@ -17,12 +17,28 @@ local moduleID = "Action" local module = ReAction:NewModule( moduleID ) +-- private -- +local function GetBarConfig(bar) + return module.db.profile.bars[bar:GetName()] +end + +local function RefreshLite(bar) + local btns = module.buttons[bar] + if btns then + for _, b in ipairs(btns) do + b:Refresh() + end + end +end + + -- module methods function module:OnInitialize() self.db = ReAction.db:RegisterNamespace( moduleID, { profile = { - buttons = { } + buttons = { }, + bars = { }, } } ) @@ -79,7 +95,11 @@ if profile.buttons[name] == nil then profile.buttons[name] = {} end + if profile.bars[name] == nil then + profile.bars[name] = {} + end local btnCfg = profile.buttons[name] + local barCfg = profile.bars[name] local r, c = bar:GetButtonGrid() local n = r*c @@ -88,22 +108,23 @@ btnCfg[i] = {} end if btns[i] == nil then - local ok, b = pcall(self.BtnClass.new, self.BtnClass, bar, i, btnCfg[i]) + local ok, b = pcall(self.BtnClass.New, self.BtnClass, bar, i, btnCfg[i], barCfg) if ok and b then btns[i] = b + bar:AddButton(i,b) end - else - btns[i]:Refresh(bar,i) end end for i = n+1, #btns do if btns[i] then + bar:RemoveButton(btns[i]) btns[i] = btns[i]:Destroy() if btnCfg[i] then btnCfg[i] = nil end end end + RefreshLite(bar) end end @@ -121,11 +142,15 @@ function module:OnEraseBar(event, bar, name) self.db.profile.buttons[name] = nil + self.db.profile.bars[name] = nil end function module:OnRenameBar(event, bar, oldname, newname) local b = self.db.profile.buttons b[newname], b[oldname] = b[oldname], nil + + b = self.db.profile.bars + b[newname], b[oldname] = b[oldname], nil end function module:SetHideEmptyButtons(hide) @@ -163,13 +188,20 @@ function module:showActionIDLabel(button) if not button.actionIDLabel and button:GetActionID() then - local label = button:GetFrame():CreateFontString(nil,"OVERLAY","GameFontNormalLarge") + local f = button:GetFrame() + local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") label:SetAllPoints() label:SetJustifyH("CENTER") label:SetShadowColor(0,0,0,1) label:SetShadowOffset(2,-2) label:SetText(tostring(button:GetActionID())) button.actionIDLabel = label + f:HookScript("OnAttributeChanged", + function(frame, attr, value) + if attr == "state-parent" then + label:SetText(tostring(button:GetActionID())) + end + end) end button.actionIDLabel:Show() end @@ -230,27 +262,33 @@ ------ Button class ------ local Button = { } -local function Constructor( self, bar, idx, config ) - self.bar, self.idx, self.config = bar, idx, config +local function Constructor( self, bar, idx, config, barConfig ) + self.bar, self.idx, self.config, self.barConfig = bar, idx, config, barConfig local barFrame = bar:GetFrame() config.name = config.name or ("ReAction_%s_%d"):format(bar:GetName(),idx) self.name = config.name config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured + self.nPages = 1 local f = CreateFrame("CheckButton", self.name, barFrame, "ActionBarButtonTemplate") -- TODO: re-implement ActionButton event handlers that don't do secure stuff - -- this will probably cause taint, using right now for display/debugging purposes + -- this will probably cause taint and/or performance problems, using right now for display/debugging purposes f:SetScript("OnAttributeChanged", ActionButton_UpdateAction) + f:SetAttribute("action", config.actionID) + -- install mind control action support for all buttons here just for simplicity + if self.idx <= 12 then + f:SetAttribute("action-mc", 120 + self.idx) + end barFrame:SetAttribute("addchild",f) self.frame = f - self:Refresh(bar,idx) + self:Refresh() if not module.db.profile.hideEmptyButtons then ActionButton_ShowGrid(self.frame) @@ -274,13 +312,23 @@ if self.config.actionID then ActionIDList[self.config.actionID] = nil end + if self.config.pages then + for _, id in ipairs(self.config.pages) do + ActionIDList[id] = nil + end + end self.frame = nil self.config = nil self.bar = nil end -function Button:Refresh(bar,idx) - bar:PlaceButton(self.frame, idx, 36, 36) +function Button:Refresh() + local f = self.frame + self.bar:PlaceButton(self, 36, 36) + if self.barConfig.mckeybinds then + f:SetAttribute("bindings-mc", self.barConfig.mckeybinds[self.idx]) + end + self:RefreshPages() end function Button:GetFrame() @@ -292,13 +340,36 @@ end function Button:GetActionID() - return self.config.actionID + return SecureButton_GetModifiedAttribute(self.frame, "action") end +function Button:RefreshPages() + local nPages = 1 --self.bar:GetNumPages() + if nPages ~= self.nPages then + local f = self:GetFrame() + local c = self.config.pages + if nPages > 1 and not c then + c = { } + self.config.pages = c + end + for i = 1, nPages do + c[i] = ActionIDList[c[i]] -- gets a free one if none configured + f:SetAttribute(("action-page%d"):format(i)) + end + for i = nPages+1, #c do + ActionIDList[c[i]] = nil + c[i] = nil + f:SetAttribute(("action-page%d"):format(i)) + end + + -- TODO: + -- apply next-page, prev-page, and direct-page keybinds (via bar:SetStateKeybind abstraction) + end +end -- export as a class-factory to module module.BtnClass = { - new = function(self, ...) + New = function(self, ...) local x = { } for k,v in pairs(Button) do x[k] = v diff -r 00e28094e1a3 -r 06cd74bdc7da modules/ReAction_PetAction/ReAction_PetAction.lua --- a/modules/ReAction_PetAction/ReAction_PetAction.lua Tue Jun 10 22:25:15 2008 +0000 +++ b/modules/ReAction_PetAction/ReAction_PetAction.lua Mon Jun 16 18:46:08 2008 +0000 @@ -84,6 +84,7 @@ local ok, b = pcall(self.BtnClass.new, self.BtnClass, bar, i, btnCfg[i]) if ok and b then btns[i] = b + bar:AddButton(i,b) end else btns[i]:Refresh(bar,i) @@ -91,6 +92,7 @@ end for i = n+1, #btns do if btns[i] then + bar:RemoveButton(b) btns[i] = btns[i]:Destroy() if btnCfg[i] then btnCfg[i] = nil @@ -296,7 +298,7 @@ end function Button:Refresh(bar,idx) - bar:PlaceButton(self.frame, idx, 30, 30) + bar:PlaceButton(self, 30, 30) self:Update() self:UpdateHotkey() end diff -r 00e28094e1a3 -r 06cd74bdc7da modules/ReAction_PossessBar/ReAction_PossessBar.lua --- a/modules/ReAction_PossessBar/ReAction_PossessBar.lua Tue Jun 10 22:25:15 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,391 +0,0 @@ ---[[ - ReAction Possess Bar (Mind Control/etc) button module. - - Wraps the standard Action buttons 121-132 with an automatic show/hide - when mind control (etc) is active - ---]] - --- local imports -local ReAction = ReAction -local L = ReAction.L -local _G = _G -local CreateFrame = CreateFrame - --- module declaration -local moduleID = "PossessBar" -local module = ReAction:NewModule( moduleID ) - --- module methods -function module:OnInitialize() - self.db = ReAction.db:RegisterNamespace( moduleID, - { - profile = { - buttons = { } - } - } - ) - self.buttons = { } - - ReAction:RegisterOptions(self, { - [moduleID] = { - type = "group", - name = L["Possess Bar"], - args = { - hideEmptyPossess = { - type = "toggle", - name = L["Hide Empty Possess Bar Buttons"], - get = function() return self.db.profile.hideEmptyButtons end, - set = function(info, val) module:SetHideEmptyButtons(val) end, - } - } - } - }) - - ReAction:RegisterBarOptionGenerator(self, "GetBarOptions") - - ReAction.RegisterCallback(self, "OnCreateBar") - ReAction.RegisterCallback(self, "OnDestroyBar") - ReAction.RegisterCallback(self, "OnRefreshBar") - ReAction.RegisterCallback(self, "OnEraseBar") - ReAction.RegisterCallback(self, "OnRenameBar") - ReAction.RegisterCallback(self, "OnConfigModeChanged") -end - -function module:OnEnable() - ReAction:RegisterBarType(L["Possess Bar"], - { - type = moduleID, - defaultButtonSize = 36, - defaultBarRows = 1, - defaultBarCols = 12, - defaultBarSpacing = 3 - }) -end - -function module:OnDisable() - ReAction:UnregisterBarType(L["Possess Bar"]) -end - -function module:OnCreateBar(event, bar, name) - if bar.config.type == moduleID then - bar:GetFrame():SetParent(PossessBarFrame) - bar.config.parent = "PossessBarFrame" - self:CreatePossessControlButtons(bar) - end - self:OnRefreshBar(event, bar, name) -end - -function module:OnRefreshBar(event, bar, name) - if bar.config.type == moduleID then - if self.buttons[bar] == nil then - self.buttons[bar] = { } - end - local btns = self.buttons[bar] - local profile = self.db.profile - if profile.buttons[name] == nil then - profile.buttons[name] = {} - end - local btnCfg = profile.buttons[name] - - local r, c = bar:GetButtonGrid() - local n = r*c - for i = 1, n do - if btnCfg[i] == nil then - btnCfg[i] = {} - end - if btns[i] == nil then - local ok, b = pcall(self.BtnClass.new, self.BtnClass, bar, i, btnCfg[i]) - if ok and b then - btns[i] = b - end - else - btns[i]:Refresh(bar,i) - end - end - for i = n+1, #btns do - if btns[i] then - btns[i] = btns[i]:Destroy() - if btnCfg[i] then - btnCfg[i] = nil - end - end - end - end -end - -function module:OnDestroyBar(event, bar, name) - if self.buttons[bar] then - local btns = self.buttons[bar] - for _,b in pairs(btns) do - if b then - b:Destroy() - end - end - self.buttons[bar] = nil - end -end - -function module:OnEraseBar(event, bar, name) - self.db.profile.buttons[name] = nil -end - -function module:OnRenameBar(event, bar, oldname, newname) - local b = self.db.profile.buttons - b[newname], b[oldname] = b[oldname], nil -end - -function module:SetHideEmptyButtons(hide) - if hide ~= self.db.profile.hideEmptyButtons then - for _, bar in pairs(self.buttons) do - for _, b in pairs(bar) do - if hide then - ActionButton_HideGrid(b.frame) - else - ActionButton_ShowGrid(b.frame) - end - end - end - self.db.profile.hideEmptyButtons = hide - end -end - -function module:OnConfigModeChanged(event, mode) - for _, bar in ReAction:IterateBars() do - if bar and self.buttons[bar] then - for _, b in pairs(self.buttons[bar]) do - if b then - if mode then - ActionButton_ShowGrid(b.frame) - self:showActionIDLabel(b) - else - ActionButton_HideGrid(b.frame) - self:hideActionIDLabel(b) - end - end - end - local f = bar:GetFrame() - if mode then - f:SetParent(UIParent) - f:Show() - else - f:SetParent(PossessBarFrame) - end - end - end -end - -function module:showActionIDLabel(button) - if not button.actionIDLabel and button:GetActionID() then - local label = button:GetFrame():CreateFontString(nil,"OVERLAY","GameFontNormalLarge") - label:SetAllPoints() - label:SetJustifyH("CENTER") - label:SetShadowColor(0,0,0,1) - label:SetShadowOffset(2,-2) - label:SetText(tostring(button:GetActionID())) - button.actionIDLabel = label - end - button.actionIDLabel:Show() -end - -function module:hideActionIDLabel(button) - if button.actionIDLabel then - button.actionIDLabel:Hide() - end -end - - --- possess-bar control buttons (shows buff, cancel buff) -function module:CreatePossessControlButton(bar,id,name) - -- guard against taint by reusing global variable frames - -- instead of nilling them out (e.g. create bar, delete bar, create bar with same name) - name = name or ("ReAction_%s_PossessCtrlButton%d"):format(bar:GetName(),id) - local b = name and _G[name] - if b then - b:SetParent(bar:GetFrame()) - else - b = CreateFrame("CheckButton", name, bar:GetFrame(), "PossessButtonTemplate") - end - b:SetID(id) - - b:RegisterEvent("PLAYER_AURAS_CHANGED"); - - local icon = _G[("%sIcon"):format(name)] - local cooldown = _G[("%sCooldown"):format(name)] - local nTex = _G[("%sNormalTexture"):format(name)] - nTex:SetWidth(54) - nTex:SetHeight(54) - - local function update() - local texture = GetPossessInfo(id); - icon:SetTexture(texture); - icon:Show() - cooldown:Hide(); - b:SetChecked(0); - icon:SetVertexColor(1.0, 1.0, 1.0); - end - update() - - b:HookScript("OnClick", function() b:SetChecked(0) end) - b:SetScript("OnEvent", update) - b:SetScript("OnShow", update) - - return b -end - -function module:CreatePossessControlButtons(bar) - if not bar.possessButtons then - bar.possessButtons = { } - bar.config.possessFrameNames = bar.config.possessFrameNames or { } - local previous - local n = NUM_POSSESS_SLOTS - for i = 1, n do - local name = bar.config.possessFrameNames[i] - local f = self:CreatePossessControlButton(bar,i,name) - bar.possessButtons[i] = f - bar.config.possessFrameNames[i] = f:GetName() - - local r, c, s = bar:GetButtonGrid() - local w, h = bar:GetButtonSize() - - local scale = ((h - (n-1)*s)/n)/30 - f:SetScale(scale) - - if previous then - f:SetPoint("TOP", previous, "BOTTOM", 0, -s/scale) - else - f:SetPoint("TOPRIGHT", bar:GetFrame(), "TOPLEFT", -s/scale, 0) - end - f:Show() - previous = f - end - end -end - ----- Options ---- -function module:GetBarOptions(bar) - return { - type = "group", - name = L["Possess Buttons"], - hidden = function() return bar.config.type ~= moduleID end, - args = { - } - } -end - - --- use-count of action IDs -local minActionID = 121 -local maxActionID = 132 -local ActionIDList = setmetatable( {}, { - __index = function(self, idx) - if idx == nil then - for i = minActionID, maxActionID do - if rawget(self,i) == nil then - rawset(self,i,1) - return i - end - end - error("ran out of action IDs") - else - local c = rawget(self,idx) or 0 - rawset(self,idx,c+1) - return idx - end - end, - __newindex = function(self,idx,value) - if value == nil then - value = rawget(self,idx) - if value == 1 then - value = nil - elseif value then - value = value - 1 - end - end - rawset(self,idx,value) - end -}) - - - - ------- Button class ------ -local Button = { } - -local function Constructor( self, bar, idx, config ) - self.bar, self.idx, self.config = bar, idx, config - - local barFrame = bar:GetFrame() - - config.name = config.name or ("ReAction_%s_Possess_%d"):format(bar:GetName(),idx) - self.name = config.name - config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured - - local f = CreateFrame("CheckButton", self.name, barFrame, "BonusActionButtonTemplate") - - -- TODO: re-implement ActionButton event handlers that don't do secure stuff - - -- this will probably cause taint, using right now for display/debugging purposes - f:SetScript("OnAttributeChanged", ActionButton_UpdateAction) - f:SetAttribute("action", config.actionID) - - barFrame:SetAttribute("addchild",f) - - self.frame = f - self:Refresh(bar,idx) - - if not module.db.profile.hideEmptyButtons then - ActionButton_ShowGrid(self.frame) - end - - if ReAction.configMode then - ActionButton_ShowGrid(self.frame) - module:showActionIDLabel(self) - end -end - -function Button:Destroy() - local f = self.frame - f:UnregisterAllEvents() - f:Hide() - f:SetParent(UIParent) - f:ClearAllPoints() - if self.name then - _G[self.name] = nil - end - if self.config.actionID then - ActionIDList[self.config.actionID] = nil - end - self.frame = nil - self.config = nil - self.bar = nil -end - -function Button:Refresh(bar,idx) - bar:PlaceButton(self.frame, idx, 36, 36) -end - -function Button:GetFrame() - return self.frame -end - -function Button:GetName() - return self.name -end - -function Button:GetActionID() - return self.config.actionID -end - - --- export as a class-factory to module -module.BtnClass = { - new = function(self, ...) - local x = { } - for k,v in pairs(Button) do - x[k] = v - end - Constructor(x, ...) - return x - end -} diff -r 00e28094e1a3 -r 06cd74bdc7da modules/ReAction_PossessBar/ReAction_PossessBar.toc --- a/modules/ReAction_PossessBar/ReAction_PossessBar.toc Tue Jun 10 22:25:15 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -## Interface: 20300 -## Title: ReAction: Possess Bar -## Notes: Possess Bar (Mind Control) module for ReAction -## DefaultState: enabled -## LoadOnDemand: 1 -## Author: Flick -## Version: 1.0 -## X-Category: Action Bars -## Dependencies: ReAction - -ReAction_PossessBar.xml diff -r 00e28094e1a3 -r 06cd74bdc7da modules/ReAction_PossessBar/ReAction_PossessBar.xml --- a/modules/ReAction_PossessBar/ReAction_PossessBar.xml Tue Jun 10 22:25:15 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ - - -