comparison libs/ReBound-1.0/ReBound-1.0.lua @ 12:2735edcf9ab7

Version 0.34
author Flick <flickerstreak@gmail.com>
date Wed, 21 Mar 2007 00:13:27 +0000
parents f3a7bfebc283
children 639282f3a0e0
comparison
equal deleted inserted replaced
11:88df7235ad8b 12:2735edcf9ab7
1 --[[ 1 --[[
2 Name: ReBound-1.0 2 Name: ReBound-1.0
3 Revision: $Rev: 1 $ 3 Revision: $Rev: 2 $
4 Author: Flick 4 Author: Flick
5 Website: 5 Website:
6 Documentation: 6 Documentation:
7 SVN: 7 SVN:
8 Description: Library for point-and-click key binding interfaces 8 Description: A library to assist with click-binding
9 License: MIT 9 License: MIT
10 Dependencies: AceLibrary, AceEvent-2.0, AceLocale-2.2 10 Dependencies: AceLibrary, AceEvent-2.0, AceLocale-2.2, AceOO-2.0
11 ]] 11 ]]
12 12
13 13
14 local version_major, version_minor = "ReBound-1.0", "$Rev: 1 $" 14 local version_major, version_minor = "ReBound-1.0", "$Rev: 2 $"
15 15
16 if not AceLibrary then error(version_major .. " requires AceLibrary.") end 16 if not AceLibrary then error(version_major .. " requires AceLibrary.") end
17 if not AceLibrary:IsNewVersion(version_major, version_minor) then return end 17 if not AceLibrary:IsNewVersion(version_major, version_minor) then return end
18 if not AceLibrary:HasInstance("AceEvent-2.0") then error(version_major .. " requires AceEvent-2.0.") end 18 if not AceLibrary:HasInstance("AceEvent-2.0") then error(version_major .. " requires AceEvent-2.0.") end
19 if not AceLibrary:HasInstance("AceLocale-2.2") then error(version_major .. " requires AceLocale-2.2.") end 19 if not AceLibrary:HasInstance("AceLocale-2.2") then error(version_major .. " requires AceLocale-2.2.") end
20 if not AceLibrary:HasInstance("AceOO-2.0") then error(version_major .. " requires AceOO-2.0.") end
20 21
21 local L = AceLibrary("AceLocale-2.2"):new("ReBound") 22 local L = AceLibrary("AceLocale-2.2"):new("ReBound")
22 23
23 local colorGreen = "|cff00ff00" 24 local colorGreen = "|cff00ff00"
24 local colorOff = "|r" 25 local colorOff = "|r"
25 26
26 local mouseButtonConvert = { 27 local mouseButtonConvert = {
28 LeftButton = "BUTTON1",
29 RightButton = "BUTTON2",
27 MiddleButton = "BUTTON3", 30 MiddleButton = "BUTTON3",
28 Button4 = "BUTTON4", 31 Button4 = "BUTTON4",
29 Button5 = "BUTTON5" 32 Button5 = "BUTTON5"
30 } 33 }
34
35 --local BINDING_PENDING = { } -- a constant
31 36
32 -- localization 37 -- localization
33 L:RegisterTranslations( "enUS", function() 38 L:RegisterTranslations( "enUS", function()
34 return { 39 return {
35 ["none"] = true, 40 ["none"] = true,
36 ["Right-click"] = true, 41 ["Right-click"] = true,
42 ["Right Click"] = true,
37 ["Click to select for binding"] = true, 43 ["Click to select for binding"] = true,
38 ["Shift-click to clear binding"] = true, 44 ["Shift-click to clear binding"] = true,
39 ["Press a key to assign binding"] = true, 45 ["Press a key to assign binding"] = true,
40 ["is now unbound"] = true, 46 ["is now unbound"] = true,
41 } 47 }
42 end ) 48 end )
43 49
44 50
45 51 local ReBound = AceLibrary("AceOO-2.0").Class("AceEvent-2.0")
46 52
47 local ReBound = { } 53 --[[
54 ReBound publishes the following events:
55
56 -- temporary bindings (prior to SaveBindings() being called)
57 REBOUND_BIND_TEMP (id, key, targetFrameName, mouseButton)
58 REBOUND_UNBIND_TEMP (id, key)
59
60 -- permanent bindings (fired all at once when SaveBindings() is called)
61 REBOUND_BIND (id, key, targetFrameName, mouseButton)
62 REBOUND_UNBIND (id, key)
63
64 These events are published in response to click actions ONLY. This means
65 that if a key is unbound from a click-binding frame, and bound to some
66 other action, then REBOUND_UNBIND(id,key) will be fired.
67 ]]
68
69
70 --[[
71 Calls to new() which share ids will return an existing object with that id, similar
72 to AceLocale-2.2.
73 ]]
74 local super_new = ReBound.new
75 function ReBound:new( id )
76 self.instances = self.instances or { }
77 if self.instances[id] then
78 return self.instances[id]
79 else
80 local i = super_new(self,id)
81 self.instances[id] = i
82 return i
83 end
84 end
85
86
87 --[[
88 Class object constructor
89
90 arguments:
91 id : the ID that will be provided in events. This can be absolutely
92 anything, but a string is recommended.
93 ]]
94 local super_init = ReBound.prototype.init
95 function ReBound.prototype:init( id )
96 super_init(self)
97
98 self.id = id
99 self.frames = { }
100 self.pending = { }
101 self.bindings = { }
102 end
103
104
48 105
49 106
50 --[[ 107 --[[
51 Arguments: 108 Arguments:
52 key: A string representation of a key, suitable for passing to SetBinding. 109 key: A string representation of a key, suitable for passing to SetBinding.
53 target: The frame with an OnClick handler to attach a click-binding to 110 target: The frame with an OnClick handler to which the click-binding should be attached
54 [button]: The mouse button to emulate. Default is "LeftButton". 111 [button]: The mouse button to emulate. Default is "LeftButton".
55 112
56 Returns: 113 Returns:
57 nothing. 114 nothing.
58 115
59 Notes: 116 Notes:
60 This does not save the bindings. 117 This does not save the bindings.
61 ]] 118 ]]
62 function ReBound:SetBinding( key, target, button ) 119 function ReBound.prototype:SetBinding( key, target, button )
63 if not key then self:error("ReBound:SetBinding() requires a key argument.") end 120 if not key then error("ReBound:SetBinding() requires a key argument.") end
64 if not target then self:error("ReBound:SetBinding() requires a binding target argument") end 121 if not target then error("ReBound:SetBinding() requires a binding target argument") end
65 button = button or "LeftButton" 122 button = button or "LeftButton"
66 123
67 -- prevent setting a binding that's already set 124 -- prevent setting a binding that's already set
68 local current = { self:GetBinding(target,button) } 125 local current = { self:GetBinding(target,button) }
69 for _, b in pairs(current) do 126 for _, b in pairs(current) do
80 self:ClearBinding( nil, target, button, true ) 137 self:ClearBinding( nil, target, button, true )
81 138
82 -- set the new binding 139 -- set the new binding
83 SetBindingClick(key, target:GetName(), button) 140 SetBindingClick(key, target:GetName(), button)
84 141
85 -- notify listeners, e.g. for storing the setting 142 -- store the temporary binding as "pending" for later notification
86 self.event:TriggerEvent("REBOUND_BIND", key, target:GetName(), button) 143 table.insert(self.pending, key)
144
145 -- notify listeners, e.g. for displaying the setting
146 self:TriggerEvent("REBOUND_BIND_TEMP", self.id, key, target:GetName(), button)
87 end 147 end
88 148
89 149
90 --[[ 150 --[[
91 Arguments: 151 Arguments:
101 If key is provided, then the binding for that key is cleared. If key is not provided and target is provided, then 161 If key is provided, then the binding for that key is cleared. If key is not provided and target is provided, then
102 all the bindings attached to the click-binding for that target are cleared. 162 all the bindings attached to the click-binding for that target are cleared.
103 163
104 This does NOT save the bindings. Call SaveBindings() to commit the bindings to disk. 164 This does NOT save the bindings. Call SaveBindings() to commit the bindings to disk.
105 ]] 165 ]]
106 function ReBound:ClearBinding( key, target, button, silent ) 166 function ReBound.prototype:ClearBinding( key, target, button, silent )
107 if not target and not key then self:error("ReBound:ClearBinding() requires a key or click-binding target argument") end 167 if not target and not key then error("ReBound:ClearBinding() requires a key or click-binding target argument") end
108 button = button or "LeftButton" 168 button = button or "LeftButton"
109 169
110 local keys = key and { key } or { self:GetBinding(target,button) } 170 local keys = key and { key } or { self:GetBinding(target,button) }
111 for _, k in ipairs(keys) do 171 for _, k in ipairs(keys) do
112 -- Print a notification message 172 -- Print a notification message
118 -- make click-bindings look prettier 178 -- make click-bindings look prettier
119 local f, b = name:match("CLICK (.+)\:(.+)") 179 local f, b = name:match("CLICK (.+)\:(.+)")
120 if f then 180 if f then
121 name = f 181 name = f
122 if b ~= "LeftButton" then 182 if b ~= "LeftButton" then
123 if b == "RightButton" then b = "Right Click" end 183 if b == "RightButton" then b = L["Right Click"] end
124 name = f .."-"..b 184 name = f .."-"..b
125 end 185 end
126 end 186 end
127 if name and #name > 0 then 187 if name and #name > 0 then
128 UIErrorsFrame:AddMessage(name.." ("..colorGreen..keyTxt..colorOff..") "..L["is now unbound"].."!") 188 UIErrorsFrame:AddMessage(name.." ("..colorGreen..keyTxt..colorOff..") "..L["is now unbound"].."!")
129 end 189 end
130 end 190 end
131 end 191 end
132 SetBinding(k,nil) 192 SetBinding(k,nil)
133 self.event:TriggerEvent("REBOUND_UNBIND", k) 193 table.insert(self.pending,k)
134 end 194 self:TriggerEvent("REBOUND_UNBIND_TEMP", self.id, k)
135 end 195 end
136 196 end
137 197
138 --[[ 198
139 Gets the keys bound to clicking a frame. 199 --[[
200 Gets the keys currently click-bound to a frame.
140 201
141 Arguments: 202 Arguments:
142 target: target frame to query 203 target: target frame to query
143 [button]: mouse button to emulate ("LeftButton", "RightButton") 204 [button]: mouse button to emulate ("LeftButton", "RightButton")
144 205
145 Returns: 206 Returns:
146 key1, key2, key3, etc, as strings. 207 key1, key2, key3, etc, as strings.
147 ]] 208 ]]
148 function ReBound:GetBinding( target, button ) 209 function ReBound.prototype:GetBinding( target, button )
149 if not target then self:error("ReBound:GetBinding() requires a target frame argument") end 210 if not target then error("ReBound:GetBinding() requires a target frame argument") end
150 button = button or "LeftButton" 211 button = button or "LeftButton"
151 return GetBindingKey("CLICK "..target:GetName()..":"..button) 212 return GetBindingKey("CLICK "..target:GetName()..":"..button)
152 end 213 end
153 214
154 215
155 --[[ 216 --[[
217 Publishes permanent binding notification events.
218 ]]
219 local function PublishBindings(self)
220 for _, key in ipairs(self.pending) do
221 local action = GetBindingAction(key)
222 local frame, button
223 if action then
224 frame, button = action:match("CLICK (.+)\:(.+)")
225 end
226 if frame == nil then
227 self:TriggerEvent("REBOUND_UNBIND", self.id, key)
228 else
229 self:TriggerEvent("REBOUND_BIND", self.id, key, frame, button)
230 end
231 end
232 self.pending = { }
233 end
234
235
236 --[[
237 Saves the bindings using the current scheme. Also publishes events indicating that the
238 bindings have been saved/cleared permanently.
239 ]]
240 function ReBound.prototype:SaveBindings()
241 SaveBindings(GetCurrentBindingSet()) -- will trigger an UPDATE_BINDINGS event.
242 PublishBindings(self)
243 end
244
245
246 --[[
247 Reverts the bindings to the ones previously saved. Also publishes events indicating that the
248 bindings have been reverted.
249 ]]
250 function ReBound.prototype:RevertBindings()
251 LoadBindings(GetCurrentBindingSet()) -- should trigger an UPDATE_BINDINGS event.
252 PublishBindings(self)
253 end
254
255
256 --[[
257 Clears all bindings associated with registered frames. This is useful, for example, when switching profiles
258 and the keybinding data is stored in the profile.
259 ]]
260 function ReBound.prototype:ClearRegisteredBindings()
261 for f, _ in pairs(self.frames) do
262 self:ClearBinding(nil,f,"LeftButton",true)
263 self:ClearBinding(nil,f,"RightButton",true)
264 end
265 end
266
267
268 --[[
156 Registers a target frame by creating a click-binding frame and putting that frame in the list of 269 Registers a target frame by creating a click-binding frame and putting that frame in the list of
157 registered frames, which can then be all shown/hidden as one unit. 270 registered frames, which can then be all shown/hidden as one unit.
158 271
159 Arguments: 272 Arguments:
160 target = the frame whose OnClick handler should be the target of keybinding 273 target = the frame whose OnClick handler should be the target of keybinding
161 274
162 Returns: 275 Returns:
163 A clickbinder frame. 276 A clickbinder frame.
164 ]] 277 ]]
165 function ReBound:Register( target ) 278 function ReBound.prototype:Register( target )
166 local f = self:CreateClickBindingFrame(target) 279 local f = self:CreateClickBindingFrame(target)
167 self.frames[target] = f 280 self.frames[target] = f
168 return f 281 return f
169 end 282 end
170 283
171 284
172 --[[ 285 --[[
173 Unregisters a target frame by removing it from the internal list. Does nothing to the clickbinding frame. 286 Unregisters a target frame by removing it from the internal list. Does nothing to the clickbinding frame.
174 287
175 Arguments: 288 Arguments:
176 target = the frame whose OnClick handler should no longer be the target of keybinding 289 target = the frame whose OnClick handler should no longer be managed. do NOT pass the clickbinding frame.
177 290
178 Returns: 291 Returns:
179 nothing. 292 nothing.
180 ]] 293 ]]
181 function ReBound:Unregister( target ) 294 function ReBound.prototype:Unregister( target )
182 self.frames[target] = nil 295 self.frames[target] = nil
183 end 296 end
184 297
185 298
186 --[[ 299 --[[
300 Unregisters all registered frames.
301 ]]
302 function ReBound.prototype:UnregisterAll()
303 self.frames = { }
304 end
305
306
307
308 --[[
187 Shows all the registered click binding frames. 309 Shows all the registered click binding frames.
188 ]] 310 ]]
189 function ReBound:ShowAll() 311 function ReBound.prototype:ShowFrames()
190 if InCombatLockdown() then 312 if InCombatLockdown() then
191 -- can't set bindings while in combat, so don't bother showing them 313 -- can't set bindings while in combat, so don't bother showing them
192 UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT) 314 UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT)
193 else 315 else
194 for _, f in pairs(self.frames) do 316 for _, f in pairs(self.frames) do
199 321
200 322
201 --[[ 323 --[[
202 Hides all the registered click binding frames. 324 Hides all the registered click binding frames.
203 ]] 325 ]]
204 function ReBound:HideAll() 326 function ReBound.prototype:HideFrames()
327 -- because these frames aren't protected, there's no restriction
328 -- on hiding them while in combat.
205 for _, f in pairs(self.frames) do 329 for _, f in pairs(self.frames) do
206 f:Hide() 330 f:Hide()
207 end 331 end
208 end 332 end
209 333
301 target - the frame whose OnClick handler should be the target of keybinding 425 target - the frame whose OnClick handler should be the target of keybinding
302 426
303 Returns: 427 Returns:
304 A clickbinder frame. 428 A clickbinder frame.
305 ]] 429 ]]
306 function ReBound:CreateClickBindingFrame( target ) 430 function ReBound.prototype:CreateClickBindingFrame( target )
307 local f = CreateFrame("Button", nil, target) 431 local f = CreateFrame("Button", nil, target)
308 f.ReBound = self 432 f.ReBound = self
309 f:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square") 433 f:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
310 f:SetToplevel(1) 434 f:SetToplevel(1)
311 f:SetFrameStrata("DIALOG") 435 f:SetFrameStrata("DIALOG")
322 446
323 447
324 -- library setup 448 -- library setup
325 449
326 local function activate( self, oldLib, oldDeactivate ) 450 local function activate( self, oldLib, oldDeactivate )
327 -- set initial values 451 -- copy the list of active instances
328 self.mode = oldLib and oldLib.mode or "char" 452 self.instances = { }
329 self.frames = { } 453 if oldLib and oldLib.instances then
330 454 for k,v in pairs(oldLib.instances) do
331 self.event = AceLibrary("AceOO-2.0").Class("AceEvent-2.0"):new() 455 self.instances[k] = v
332 self.event:RegisterEvent("PLAYER_REGEN_DISABLED", function() self:HideAll() end) 456 end
333 457 end
458
334 if oldDeactivate then 459 if oldDeactivate then
335 oldDeactivate(oldLib) 460 oldDeactivate(oldLib)
336 end 461 end
337 end 462 end
338 463
339 local function deactivate( self ) 464 AceLibrary:Register(ReBound, version_major, version_minor, activate)
340 self.event:UnregisterEvent("PLAYER_REGEN_DISABLED")
341 end
342
343 AceLibrary:Register(ReBound, version_major, version_minor, activate, deactivate)
344 ReBound = nil 465 ReBound = nil