comparison Bar.lua @ 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
comparison
equal deleted inserted replaced
71:3d2cef5dc459 72:aa88aed52124
49 f:UnregisterAllEvents() 49 f:UnregisterAllEvents()
50 f:Hide() 50 f:Hide()
51 f:SetParent(UIParent) 51 f:SetParent(UIParent)
52 f:ClearAllPoints() 52 f:ClearAllPoints()
53 ReAction.UnregisterAllCallbacks(self) 53 ReAction.UnregisterAllCallbacks(self)
54 if self.statedriver then
55 UnregisterStateDriver(f, "reaction")
56 end
54 self.labelString = nil 57 self.labelString = nil
55 self.controlFrame = nil 58 self.controlFrame = nil
56 self.frame = nil 59 self.frame = nil
57 self.config = nil 60 self.config = nil
58 end 61 end
174 -- multi-state functions -- 177 -- multi-state functions --
175 function Bar:GetNumPages() 178 function Bar:GetNumPages()
176 return self.config.nPages or 1 179 return self.config.nPages or 1
177 end 180 end
178 181
182 --
183 -- 'rule' is a rule-string to pass to RegisterStateDriver
184 -- 'states' is a { ["statename"] = <don't care> } table of all state names
185 -- 'keybinds' is a { ["statename"] = keybind } table of all keybound states
186 --
187 function Bar:SetStateDriver( rule, states, keybinds )
188 local f = self.frame
189 local kbprefix = ""
190 do
191 local tmp = { }
192 for s, k in pairs(keybinds) do
193 if k and #k > 0 then -- filter out false table entries
194 -- if in a keybound state, set the stack to the new state but stay in the keybound state.
195 -- use $s as a placeholder for the current state, it will be gsub()'d in later
196 table.insert(tmp,("%s:$s set() %s"):format(s,s))
197 end
198 end
199 table.insert(tmp,kbprefix) -- to get a trailing ';' if the table is not empty
200 kbprefix = table.concat(tmp,";")
201 end
202 for state in pairs(states) do
203 -- For all states: if in a keybound state, stay there (with stack manipulation, see above).
204 -- Otherwise, go to the state
205 f:SetAttribute(("statemap-reaction-%s"):format(state),("%s%s"):format(kbprefix:gsub("%$s",state),state))
206
207 local binding = keybinds[state]
208 self:SetStateKeybind(binding, state) -- set the binding even if nil, to clear it unconditionally
209 if binding then
210 -- for key bindings, use the state-stack to toggle between the last state and the keybound state
211 -- use a different 'virtual state' passed to attribute 'reaction-state' for key bindings, "<state>_binding"
212 f:SetAttribute(("statemap-reaction-%s_binding"):format(state), ("%s:pop();*:set(%s)"):format(state,state))
213 end
214 end
215
216 if rule and #rule > 0 then
217 self.stateDriver = true
218 RegisterStateDriver(f, "reaction", rule)
219 elseif self.statedriver then
220 self.statedriver = false
221 UnregisterStateDriver(f, "reaction")
222 end
223 end
224
179 function Bar:SetHideStates(s) 225 function Bar:SetHideStates(s)
180 for f in pairs(self.buttons) do 226 for f in pairs(self.buttons) do
181 if f:GetParent() == self.frame then 227 if f:GetParent() == self.frame then
182 f:SetAttribute("hidestates",s) 228 f:SetAttribute("hidestates",s)
183 end 229 end
184 end 230 end
185 SecureStateHeader_Refresh(self.frame) 231 SecureStateHeader_Refresh(self.frame)
186 end 232 end
187 233
188 function Bar:SetStateKeybind(key, state, defaultstate) 234 function Bar:SetStateKeybind(key, state, defaultstate)
189 -- set a keybind to toggle transitioning unconditionally to a state 235 -- Lazily create a tiny offscreen button which sends "<state>_binding" values to the
190 -- use a tiny offscreen button to get around making the bar itself a clickable button 236 -- bar frame's state-reaction attribute, by using an override binding to generate a
237 -- click on the button with a virtual mouse button "state".
238 -- This gets around making the bar itself a clickable button, which is not desirable
191 local f = self.statebuttonframe 239 local f = self.statebuttonframe
192 local off = ("%s_off"):format(state)
193 if key then 240 if key then
194 if not f then 241 if not f then
195 f = CreateFrame("Button",self:GetName().."_statebutton",UIParent,"SecureActionButtonTemplate") 242 f = CreateFrame("Button",self:GetName().."_statebutton",self.frame,"SecureActionButtonTemplate")
196 f:SetPoint("BOTTOMRIGHT",UIParent,"TOPLEFT") 243 f:SetPoint("BOTTOMRIGHT",UIParent,"TOPLEFT")
197 f:SetWidth(1) 244 f:SetWidth(1)
198 f:SetHeight(1) 245 f:SetHeight(1)
199 f:SetAttribute("attribute-name", "state") 246 f:SetAttribute("type*","attribute")
200 f:SetAttribute("attribute-frame",self.frame) 247 f:SetAttribute("attribute-name*","state-reaction")
201 f:SetAttribute("stateheader",self.frame) 248 f:SetAttribute("attribute-frame*",self.frame)
202 f:Show() 249 f:Show()
250 f.bindings = { }
203 self.statebuttonframe = f 251 self.statebuttonframe = f
204 end 252 end
205 -- map two virtual buttons to toggle between the state and the default 253 f:SetAttribute(("attribute-value-%s"):format(state),("%s_binding"):format(state))
206 f:SetAttribute(("statebutton-%s"):format(state),("%s:%s;%s"):format(state,off,state)) 254 -- clear the old binding, if any, for this state
207 f:SetAttribute(("type-%s"):format(state),"attribute") 255 if f.bindings[state] then
208 f:SetAttribute(("type-%s"):format(off),"attribute") 256 SetOverrideBinding(self.frame, false, f.bindings[state], nil)
209 f:SetAttribute(("attribute-value-%s"):format(state), state) 257 end
210 f:SetAttribute(("attribute-value-%s"):format(off), defaultstate) 258 SetOverrideBindingClick(self.frame, false, key, f:GetName(), state) -- the state name is used as the virtual button
211 SetBindingClick(key, f:GetName(), state) 259 f.bindings[state] = key
212 elseif f then 260 elseif f then
213 f:SetAttribute(("type-%s"):format(state),ATTRIBUTE_NOOP) 261 key = f.bindings[state]
214 f:SetAttribute(("type-%s"):format(off),ATTRIBUTE_NOOP)
215 local action = ("CLICK %s:%s"):format(f:GetName(),state)
216 key = GetBindingKey(action)
217 if key then 262 if key then
218 SetBinding(key,nil) 263 SetOverrideBinding(self.frame, false, key, nil)
264 f.bindings[state] = nil
219 end 265 end
220 end 266 end
221 end 267 end
222 268
223 function Bar:SetStatePageMap(state, map) -- map is a { ["statename"] = pagenumber } table 269 function Bar:SetStatePageMap(state, map) -- map is a { ["statename"] = pagenumber } table
225 local tmp = { } 271 local tmp = { }
226 for s, p in pairs(map) do 272 for s, p in pairs(map) do
227 table.insert(tmp, ("%s:page%d"):format(s,p)) 273 table.insert(tmp, ("%s:page%d"):format(s,p))
228 end 274 end
229 local spec = table.concat(tmp,";") 275 local spec = table.concat(tmp,";")
230 f:SetAttribute("statebutton",spec) 276 local current = f:GetAttribute("statebutton")
277 if spec ~= f:GetAttribute("statebutton") then
278 f:SetAttribute("statebutton", spec)
279 end
231 SecureStateHeader_Refresh(f) 280 SecureStateHeader_Refresh(f)
232 end 281 end
233 282
234 function Bar:SetStateKeybindOverrideMap(states) -- 'states' is an array of state-names that should have keybind overrides enabled 283 function Bar:SetStateKeybindOverrideMap(states) -- 'states' is an array of state-names that should have keybind overrides enabled
235 local f = self.frame 284 local f = self.frame