Mercurial > wow > reaction
changeset 72:aa88aed52124
Fixed bugs with state keybinds.
Simplified state driver API
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Thu, 05 Jun 2008 18:34:36 +0000 |
parents | 3d2cef5dc459 |
children | dd01feae0d89 |
files | Bar.lua State.lua locale/enUS.lua |
diffstat | 3 files changed, 103 insertions(+), 105 deletions(-) [+] |
line wrap: on
line diff
--- a/Bar.lua Wed Jun 04 21:46:51 2008 +0000 +++ b/Bar.lua Thu Jun 05 18:34:36 2008 +0000 @@ -51,6 +51,9 @@ f:SetParent(UIParent) f:ClearAllPoints() ReAction.UnregisterAllCallbacks(self) + if self.statedriver then + UnregisterStateDriver(f, "reaction") + end self.labelString = nil self.controlFrame = nil self.frame = nil @@ -176,6 +179,49 @@ return self.config.nPages or 1 end + -- + -- 'rule' is a rule-string to pass to RegisterStateDriver + -- 'states' is a { ["statename"] = <don't care> } 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)) + 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, "<state>_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") + end +end + function Bar:SetHideStates(s) for f in pairs(self.buttons) do if f:GetParent() == self.frame then @@ -186,36 +232,36 @@ end function Bar:SetStateKeybind(key, state, defaultstate) - -- set a keybind to toggle transitioning unconditionally to a state - -- use a tiny offscreen button to get around making the bar itself a clickable button + -- Lazily create a tiny offscreen button which sends "<state>_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 - local off = ("%s_off"):format(state) if key then if not f then - f = CreateFrame("Button",self:GetName().."_statebutton",UIParent,"SecureActionButtonTemplate") + f = CreateFrame("Button",self:GetName().."_statebutton",self.frame,"SecureActionButtonTemplate") f:SetPoint("BOTTOMRIGHT",UIParent,"TOPLEFT") f:SetWidth(1) f:SetHeight(1) - f:SetAttribute("attribute-name", "state") - f:SetAttribute("attribute-frame",self.frame) - f:SetAttribute("stateheader",self.frame) + f:SetAttribute("type*","attribute") + f:SetAttribute("attribute-name*","state-reaction") + f:SetAttribute("attribute-frame*",self.frame) f:Show() + f.bindings = { } self.statebuttonframe = f end - -- map two virtual buttons to toggle between the state and the default - f:SetAttribute(("statebutton-%s"):format(state),("%s:%s;%s"):format(state,off,state)) - f:SetAttribute(("type-%s"):format(state),"attribute") - f:SetAttribute(("type-%s"):format(off),"attribute") - f:SetAttribute(("attribute-value-%s"):format(state), state) - f:SetAttribute(("attribute-value-%s"):format(off), defaultstate) - SetBindingClick(key, f:GetName(), state) + 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 - f:SetAttribute(("type-%s"):format(state),ATTRIBUTE_NOOP) - f:SetAttribute(("type-%s"):format(off),ATTRIBUTE_NOOP) - local action = ("CLICK %s:%s"):format(f:GetName(),state) - key = GetBindingKey(action) + key = f.bindings[state] if key then - SetBinding(key,nil) + SetOverrideBinding(self.frame, false, key, nil) + f.bindings[state] = nil end end end @@ -227,7 +273,10 @@ table.insert(tmp, ("%s:page%d"):format(s,p)) end local spec = table.concat(tmp,";") - f:SetAttribute("statebutton",spec) + local current = f:GetAttribute("statebutton") + if spec ~= f:GetAttribute("statebutton") then + f:SetAttribute("statebutton", spec) + end SecureStateHeader_Refresh(f) end
--- a/State.lua Wed Jun 04 21:46:51 2008 +0000 +++ b/State.lua Thu Jun 05 18:34:36 2008 +0000 @@ -106,87 +106,58 @@ return r end - local function BuildRuleString(states) - local s = "" + local function BuildRules(states) + local rules = { } + local keybinds = { } 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 + 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 - s = ("%s%s%s %s"):format(s, semi, state.rule.custom:gsub("%s",""), name) + table.insert(rules, fmt:format(c.custom:gsub("%s",""), state)) 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]) + 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 #clause > 0 then - s = ("%s%s%s %s"):format(s, semi, clause, name) + if #clauses > 0 then + table.insert(rules, fmt:format(table.concat(clauses), state)) 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]) + 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 #clause > 0 then - s = ("%s%s[%s] %s"):format(s, semi, clause, name) + if #clauses > 0 then + table.insert(rules, fmt:format(("[%s]"):format(table.concat(clauses, ",")), state)) end end end end if default then - s = ("%s%s%s"):format(s, #s > 0 and "; " or "", default) + table.insert(rules, default) end - return s, default + return rules, keybinds 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 + local rules, keybinds = BuildRules(states) + bar:SetStateDriver(table.concat(rules,";"), states, keybinds) for k, f in pairs(propertyFuncs) do f(bar, states) end @@ -816,7 +787,7 @@ 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."], + name = L["Invoking a state keybind toggles an override of all other transition rules."], order = 1, type = "description", }, @@ -834,26 +805,6 @@ 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, - }, }, }, },
--- a/locale/enUS.lua Wed Jun 04 21:46:51 2008 +0000 +++ b/locale/enUS.lua Thu Jun 05 18:34:36 2008 +0000 @@ -99,11 +99,9 @@ "Syntax like macro rules: see preset rules for examples", "Invalid custom rule '%s': each clause must appear within [brackets]", "Keybinding", -"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.", +"Invoking a state keybind toggles an override of all other transition rules.", "State Hotkey", "Define an override toggle keybind", -"Toggle Off State", -"Select a state to return to when the keybind override is toggled off", "Dynamic State", "States are evaluated in the order they are listed", "New State...",