flickerstreak@10
|
1 --[[
|
flickerstreak@10
|
2 Name: ReBound-1.0
|
flickerstreak@10
|
3 Revision: $Rev: 1 $
|
flickerstreak@10
|
4 Author: Flick
|
flickerstreak@10
|
5 Website:
|
flickerstreak@10
|
6 Documentation:
|
flickerstreak@10
|
7 SVN:
|
flickerstreak@10
|
8 Description: Library for point-and-click key binding interfaces
|
flickerstreak@10
|
9 License: MIT
|
flickerstreak@10
|
10 Dependencies: AceLibrary, AceEvent-2.0, AceLocale-2.2
|
flickerstreak@10
|
11 ]]
|
flickerstreak@10
|
12
|
flickerstreak@10
|
13
|
flickerstreak@10
|
14 local version_major, version_minor = "ReBound-1.0", "$Rev: 1 $"
|
flickerstreak@10
|
15
|
flickerstreak@10
|
16 if not AceLibrary then error(version_major .. " requires AceLibrary.") end
|
flickerstreak@10
|
17 if not AceLibrary:IsNewVersion(version_major, version_minor) then return end
|
flickerstreak@10
|
18 if not AceLibrary:HasInstance("AceEvent-2.0") then error(version_major .. " requires AceEvent-2.0.") end
|
flickerstreak@10
|
19 if not AceLibrary:HasInstance("AceLocale-2.2") then error(version_major .. " requires AceLocale-2.2.") end
|
flickerstreak@10
|
20
|
flickerstreak@10
|
21 local L = AceLibrary("AceLocale-2.2"):new("ReBound")
|
flickerstreak@10
|
22
|
flickerstreak@10
|
23 local colorGreen = "|cff00ff00"
|
flickerstreak@10
|
24 local colorOff = "|r"
|
flickerstreak@10
|
25
|
flickerstreak@10
|
26 local mouseButtonConvert = {
|
flickerstreak@10
|
27 MiddleButton = "BUTTON3",
|
flickerstreak@10
|
28 Button4 = "BUTTON4",
|
flickerstreak@10
|
29 Button5 = "BUTTON5"
|
flickerstreak@10
|
30 }
|
flickerstreak@10
|
31
|
flickerstreak@10
|
32 -- localization
|
flickerstreak@10
|
33 L:RegisterTranslations( "enUS", function()
|
flickerstreak@10
|
34 return {
|
flickerstreak@10
|
35 ["none"] = true,
|
flickerstreak@10
|
36 ["Right-click"] = true,
|
flickerstreak@10
|
37 ["Click to select for binding"] = true,
|
flickerstreak@10
|
38 ["Shift-click to clear binding"] = true,
|
flickerstreak@10
|
39 ["Press a key to assign binding"] = true,
|
flickerstreak@10
|
40 ["is now unbound"] = true,
|
flickerstreak@10
|
41 }
|
flickerstreak@10
|
42 end )
|
flickerstreak@10
|
43
|
flickerstreak@10
|
44
|
flickerstreak@10
|
45
|
flickerstreak@10
|
46
|
flickerstreak@10
|
47 local ReBound = { }
|
flickerstreak@10
|
48
|
flickerstreak@10
|
49
|
flickerstreak@10
|
50 --[[
|
flickerstreak@10
|
51 Arguments:
|
flickerstreak@10
|
52 key: A string representation of a key, suitable for passing to SetBinding.
|
flickerstreak@10
|
53 target: The frame with an OnClick handler to attach a click-binding to
|
flickerstreak@10
|
54 [button]: The mouse button to emulate. Default is "LeftButton".
|
flickerstreak@10
|
55
|
flickerstreak@10
|
56 Returns:
|
flickerstreak@10
|
57 nothing.
|
flickerstreak@10
|
58
|
flickerstreak@10
|
59 Notes:
|
flickerstreak@10
|
60 This does not save the bindings.
|
flickerstreak@10
|
61 ]]
|
flickerstreak@10
|
62 function ReBound:SetBinding( key, target, button )
|
flickerstreak@10
|
63 if not key then self:error("ReBound:SetBinding() requires a key argument.") end
|
flickerstreak@10
|
64 if not target then self:error("ReBound:SetBinding() requires a binding target argument") end
|
flickerstreak@10
|
65 button = button or "LeftButton"
|
flickerstreak@10
|
66
|
flickerstreak@10
|
67 -- prevent setting a binding that's already set
|
flickerstreak@10
|
68 local current = { self:GetBinding(target,button) }
|
flickerstreak@10
|
69 for _, b in pairs(current) do
|
flickerstreak@10
|
70 if b == key then
|
flickerstreak@10
|
71 return
|
flickerstreak@10
|
72 end
|
flickerstreak@10
|
73 end
|
flickerstreak@10
|
74
|
flickerstreak@10
|
75 -- clear the old binding for the key. This isn't strictly necessary, but it allows us to collect
|
flickerstreak@10
|
76 -- notification of the unbinding in one place (ClearBinding).
|
flickerstreak@10
|
77 self:ClearBinding( key )
|
flickerstreak@10
|
78
|
flickerstreak@10
|
79 -- clear the old binding for the target and button (silently)
|
flickerstreak@10
|
80 self:ClearBinding( nil, target, button, true )
|
flickerstreak@10
|
81
|
flickerstreak@10
|
82 -- set the new binding
|
flickerstreak@10
|
83 SetBindingClick(key, target:GetName(), button)
|
flickerstreak@10
|
84
|
flickerstreak@10
|
85 -- notify listeners, e.g. for storing the setting
|
flickerstreak@10
|
86 self.event:TriggerEvent("REBOUND_BIND", key, target:GetName(), button)
|
flickerstreak@10
|
87 end
|
flickerstreak@10
|
88
|
flickerstreak@10
|
89
|
flickerstreak@10
|
90 --[[
|
flickerstreak@10
|
91 Arguments:
|
flickerstreak@10
|
92 [key]: A string representation of a key, suitable for passing to SetBinding. This can be nil if target is specified.
|
flickerstreak@10
|
93 [target]: The frame with a click keybinding to search for a key.
|
flickerstreak@10
|
94 [button]: The mouse button to emulate. Default is "LeftButton". Only used with [target].
|
flickerstreak@10
|
95 [silent]: if true, omits printout.
|
flickerstreak@10
|
96
|
flickerstreak@10
|
97 Returns:
|
flickerstreak@10
|
98 nothing.
|
flickerstreak@10
|
99
|
flickerstreak@10
|
100 Notes:
|
flickerstreak@10
|
101 If key is provided, then the binding for that key is cleared. If key is not provided and target is provided, then
|
flickerstreak@10
|
102 all the bindings attached to the click-binding for that target are cleared.
|
flickerstreak@10
|
103
|
flickerstreak@10
|
104 This does NOT save the bindings. Call SaveBindings() to commit the bindings to disk.
|
flickerstreak@10
|
105 ]]
|
flickerstreak@10
|
106 function ReBound:ClearBinding( key, target, button, silent )
|
flickerstreak@10
|
107 if not target and not key then self:error("ReBound:ClearBinding() requires a key or click-binding target argument") end
|
flickerstreak@10
|
108 button = button or "LeftButton"
|
flickerstreak@10
|
109
|
flickerstreak@10
|
110 local keys = key and { key } or { self:GetBinding(target,button) }
|
flickerstreak@10
|
111 for _, k in ipairs(keys) do
|
flickerstreak@10
|
112 -- Print a notification message
|
flickerstreak@10
|
113 if k and not silent then
|
flickerstreak@10
|
114 local action = GetBindingAction(k)
|
flickerstreak@10
|
115 if action then
|
flickerstreak@10
|
116 local name = GetBindingText(action,"BINDING_NAME_")
|
flickerstreak@10
|
117 local keyTxt = GetBindingText(k,"KEY_")
|
flickerstreak@10
|
118 -- make click-bindings look prettier
|
flickerstreak@10
|
119 local f, b = name:match("CLICK (.+)\:(.+)")
|
flickerstreak@10
|
120 if f then
|
flickerstreak@10
|
121 name = f
|
flickerstreak@10
|
122 if b ~= "LeftButton" then
|
flickerstreak@10
|
123 if b == "RightButton" then b = "Right Click" end
|
flickerstreak@10
|
124 name = f .."-"..b
|
flickerstreak@10
|
125 end
|
flickerstreak@10
|
126 end
|
flickerstreak@10
|
127 if name and #name > 0 then
|
flickerstreak@10
|
128 UIErrorsFrame:AddMessage(name.." ("..colorGreen..keyTxt..colorOff..") "..L["is now unbound"].."!")
|
flickerstreak@10
|
129 end
|
flickerstreak@10
|
130 end
|
flickerstreak@10
|
131 end
|
flickerstreak@10
|
132 SetBinding(k,nil)
|
flickerstreak@10
|
133 self.event:TriggerEvent("REBOUND_UNBIND", k)
|
flickerstreak@10
|
134 end
|
flickerstreak@10
|
135 end
|
flickerstreak@10
|
136
|
flickerstreak@10
|
137
|
flickerstreak@10
|
138 --[[
|
flickerstreak@10
|
139 Gets the keys bound to clicking a frame.
|
flickerstreak@10
|
140
|
flickerstreak@10
|
141 Arguments:
|
flickerstreak@10
|
142 target: target frame to query
|
flickerstreak@10
|
143 [button]: mouse button to emulate ("LeftButton", "RightButton")
|
flickerstreak@10
|
144
|
flickerstreak@10
|
145 Returns:
|
flickerstreak@10
|
146 key1, key2, key3, etc, as strings.
|
flickerstreak@10
|
147 ]]
|
flickerstreak@10
|
148 function ReBound:GetBinding( target, button )
|
flickerstreak@10
|
149 if not target then self:error("ReBound:GetBinding() requires a target frame argument") end
|
flickerstreak@10
|
150 button = button or "LeftButton"
|
flickerstreak@10
|
151 return GetBindingKey("CLICK "..target:GetName()..":"..button)
|
flickerstreak@10
|
152 end
|
flickerstreak@10
|
153
|
flickerstreak@10
|
154
|
flickerstreak@10
|
155 --[[
|
flickerstreak@10
|
156 Registers a target frame by creating a click-binding frame and putting that frame in the list of
|
flickerstreak@10
|
157 registered frames, which can then be all shown/hidden as one unit.
|
flickerstreak@10
|
158
|
flickerstreak@10
|
159 Arguments:
|
flickerstreak@10
|
160 target = the frame whose OnClick handler should be the target of keybinding
|
flickerstreak@10
|
161
|
flickerstreak@10
|
162 Returns:
|
flickerstreak@10
|
163 A clickbinder frame.
|
flickerstreak@10
|
164 ]]
|
flickerstreak@10
|
165 function ReBound:Register( target )
|
flickerstreak@10
|
166 local f = self:CreateClickBindingFrame(target)
|
flickerstreak@10
|
167 self.frames[target] = f
|
flickerstreak@10
|
168 return f
|
flickerstreak@10
|
169 end
|
flickerstreak@10
|
170
|
flickerstreak@10
|
171
|
flickerstreak@10
|
172 --[[
|
flickerstreak@10
|
173 Unregisters a target frame by removing it from the internal list. Does nothing to the clickbinding frame.
|
flickerstreak@10
|
174
|
flickerstreak@10
|
175 Arguments:
|
flickerstreak@10
|
176 target = the frame whose OnClick handler should no longer be the target of keybinding
|
flickerstreak@10
|
177
|
flickerstreak@10
|
178 Returns:
|
flickerstreak@10
|
179 nothing.
|
flickerstreak@10
|
180 ]]
|
flickerstreak@10
|
181 function ReBound:Unregister( target )
|
flickerstreak@10
|
182 self.frames[target] = nil
|
flickerstreak@10
|
183 end
|
flickerstreak@10
|
184
|
flickerstreak@10
|
185
|
flickerstreak@10
|
186 --[[
|
flickerstreak@10
|
187 Shows all the registered click binding frames.
|
flickerstreak@10
|
188 ]]
|
flickerstreak@10
|
189 function ReBound:ShowAll()
|
flickerstreak@10
|
190 if InCombatLockdown() then
|
flickerstreak@10
|
191 -- can't set bindings while in combat, so don't bother showing them
|
flickerstreak@10
|
192 UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT)
|
flickerstreak@10
|
193 else
|
flickerstreak@10
|
194 for _, f in pairs(self.frames) do
|
flickerstreak@10
|
195 f:Show()
|
flickerstreak@10
|
196 end
|
flickerstreak@10
|
197 end
|
flickerstreak@10
|
198 end
|
flickerstreak@10
|
199
|
flickerstreak@10
|
200
|
flickerstreak@10
|
201 --[[
|
flickerstreak@10
|
202 Hides all the registered click binding frames.
|
flickerstreak@10
|
203 ]]
|
flickerstreak@10
|
204 function ReBound:HideAll()
|
flickerstreak@10
|
205 for _, f in pairs(self.frames) do
|
flickerstreak@10
|
206 f:Hide()
|
flickerstreak@10
|
207 end
|
flickerstreak@10
|
208 end
|
flickerstreak@10
|
209
|
flickerstreak@10
|
210 -- click binding frame implementation functions
|
flickerstreak@10
|
211 local function ShowTooltip1( self )
|
flickerstreak@10
|
212 local target = self:GetParent()
|
flickerstreak@10
|
213
|
flickerstreak@10
|
214 GameTooltip:ClearLines()
|
flickerstreak@10
|
215 GameTooltip:SetOwner(self,"ANCHOR_TOPRIGHT")
|
flickerstreak@10
|
216 -- line 1: button name and current binding
|
flickerstreak@10
|
217 GameTooltip:AddDoubleLine(target:GetName(), colorGreen.."("..(self.ReBound:GetBinding(target,"LeftButton") or L["none"])..")"..colorOff)
|
flickerstreak@10
|
218 -- line 2: current right-click binding (if any)
|
flickerstreak@10
|
219 local binding2 = self.ReBound:GetBinding(target,"RightButton")
|
flickerstreak@10
|
220 if binding2 then
|
flickerstreak@10
|
221 GameTooltip:AddDoubleLine(L["Right-click"]..":", colorGreen.."("..binding2..")"..colorOff)
|
flickerstreak@10
|
222 end
|
flickerstreak@10
|
223 -- line 3: instructions
|
flickerstreak@10
|
224 GameTooltip:AddLine(L["Click to select for binding"])
|
flickerstreak@10
|
225 GameTooltip:AddLine(L["Shift-click to clear binding"])
|
flickerstreak@10
|
226 GameTooltip:Show()
|
flickerstreak@10
|
227 end
|
flickerstreak@10
|
228
|
flickerstreak@10
|
229 local function ShowTooltip2( self )
|
flickerstreak@10
|
230 if GameTooltip:IsOwned(self) then
|
flickerstreak@10
|
231 local target = self:GetParent()
|
flickerstreak@10
|
232 GameTooltip:ClearLines()
|
flickerstreak@10
|
233 GameTooltip:SetOwner(self)
|
flickerstreak@10
|
234 local clickSuffix = self.selectedButton == "RightButton" and (" ("..L["Right-click"]..")") or ""
|
flickerstreak@10
|
235 -- line 1: button name and binding to be set
|
flickerstreak@10
|
236 GameTooltip:AddDoubleLine(target:GetName()..clickSuffix, colorGreen.."("..(self.ReBound:GetBinding(target,self.selectedButton) or L["none"])..")"..colorOff)
|
flickerstreak@10
|
237 -- line 2: instructions
|
flickerstreak@10
|
238 GameTooltip:AddLine(colorGreen..L["Press a key to assign binding"]..colorOff)
|
flickerstreak@10
|
239 GameTooltip:Show()
|
flickerstreak@10
|
240 end
|
flickerstreak@10
|
241 end
|
flickerstreak@10
|
242
|
flickerstreak@10
|
243 local function OnClick( self, button )
|
flickerstreak@10
|
244 if button == "LeftButton" or button == "RightButton" then
|
flickerstreak@10
|
245 if IsShiftKeyDown() then
|
flickerstreak@10
|
246 self.ReBound:ClearBinding( nil, self:GetParent(), button )
|
flickerstreak@10
|
247 self.selectedButton = nil
|
flickerstreak@10
|
248 self:EnableKeyboard(false)
|
flickerstreak@10
|
249 ShowTooltip1(self)
|
flickerstreak@10
|
250 else
|
flickerstreak@10
|
251 self.selectedButton = button
|
flickerstreak@10
|
252 self:EnableKeyboard(true)
|
flickerstreak@10
|
253 ShowTooltip2(self)
|
flickerstreak@10
|
254 end
|
flickerstreak@10
|
255 elseif self.selectedButton then
|
flickerstreak@10
|
256 self.ReBound:SetBinding( mouseButtonConvert[button], self:GetParent(), self.selectedButton )
|
flickerstreak@10
|
257 self.selectedButton = nil
|
flickerstreak@10
|
258 self:EnableKeyboard(false)
|
flickerstreak@10
|
259 ShowTooltip1(self)
|
flickerstreak@10
|
260 end
|
flickerstreak@10
|
261 end
|
flickerstreak@10
|
262
|
flickerstreak@10
|
263 local function OnEnter( self )
|
flickerstreak@10
|
264 -- clear current binding button
|
flickerstreak@10
|
265 self.selectedButton = nil
|
flickerstreak@10
|
266 -- show tooltip 1
|
flickerstreak@10
|
267 ShowTooltip1(self)
|
flickerstreak@10
|
268 end
|
flickerstreak@10
|
269
|
flickerstreak@10
|
270 local function OnLeave( self )
|
flickerstreak@10
|
271 -- disable keyboard input, if it was enabled
|
flickerstreak@10
|
272 self:EnableKeyboard(false)
|
flickerstreak@10
|
273 -- hide tooltip
|
flickerstreak@10
|
274 if GameTooltip:IsOwned(self) then
|
flickerstreak@10
|
275 GameTooltip:Hide()
|
flickerstreak@10
|
276 end
|
flickerstreak@10
|
277 end
|
flickerstreak@10
|
278
|
flickerstreak@10
|
279 local function OnKeyDown( self, key )
|
flickerstreak@10
|
280 if key == nil or key == "UNKNOWN" or key == "SHIFT" or key == "CTRL" or key == "ALT" then
|
flickerstreak@10
|
281 return
|
flickerstreak@10
|
282 end
|
flickerstreak@10
|
283 if IsShiftKeyDown() then key = "SHIFT-"..key end
|
flickerstreak@10
|
284 if IsControlKeyDown() then key = "CTRL-"..key end
|
flickerstreak@10
|
285 if IsAltKeyDown() then key = "ALT-"..key end
|
flickerstreak@10
|
286
|
flickerstreak@10
|
287 if key ~= "ESCAPE" then
|
flickerstreak@10
|
288 self.ReBound:SetBinding( key, self:GetParent(), self.selectedButton )
|
flickerstreak@10
|
289 end
|
flickerstreak@10
|
290
|
flickerstreak@10
|
291 self:EnableKeyboard(false)
|
flickerstreak@10
|
292 self.selectedButton = nil
|
flickerstreak@10
|
293 ShowTooltip1(self)
|
flickerstreak@10
|
294 end
|
flickerstreak@10
|
295
|
flickerstreak@10
|
296 --[[
|
flickerstreak@10
|
297 Creates a click-binding frame attached to the target frame, which can be used for point-and-click keybind assignments. The
|
flickerstreak@10
|
298 frame is initially hidden by default. It is not registered with ReBound for automatic show/hide: use Register() for that.
|
flickerstreak@10
|
299
|
flickerstreak@10
|
300 Arguments:
|
flickerstreak@10
|
301 target - the frame whose OnClick handler should be the target of keybinding
|
flickerstreak@10
|
302
|
flickerstreak@10
|
303 Returns:
|
flickerstreak@10
|
304 A clickbinder frame.
|
flickerstreak@10
|
305 ]]
|
flickerstreak@10
|
306 function ReBound:CreateClickBindingFrame( target )
|
flickerstreak@10
|
307 local f = CreateFrame("Button", nil, target)
|
flickerstreak@10
|
308 f.ReBound = self
|
flickerstreak@10
|
309 f:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
|
flickerstreak@10
|
310 f:SetToplevel(1)
|
flickerstreak@10
|
311 f:SetFrameStrata("DIALOG")
|
flickerstreak@10
|
312 f:RegisterForClicks("AnyUp")
|
flickerstreak@10
|
313 f:SetScript("OnClick", OnClick)
|
flickerstreak@10
|
314 f:SetScript("OnEnter", OnEnter)
|
flickerstreak@10
|
315 f:SetScript("OnLeave", OnLeave)
|
flickerstreak@10
|
316 f:SetScript("OnKeyDown", OnKeyDown)
|
flickerstreak@10
|
317 f:SetAllPoints(target)
|
flickerstreak@10
|
318 f:Hide()
|
flickerstreak@10
|
319 return f
|
flickerstreak@10
|
320 end
|
flickerstreak@10
|
321
|
flickerstreak@10
|
322
|
flickerstreak@10
|
323
|
flickerstreak@10
|
324 -- library setup
|
flickerstreak@10
|
325
|
flickerstreak@10
|
326 local function activate( self, oldLib, oldDeactivate )
|
flickerstreak@10
|
327 -- set initial values
|
flickerstreak@10
|
328 self.mode = oldLib and oldLib.mode or "char"
|
flickerstreak@10
|
329 self.frames = { }
|
flickerstreak@10
|
330
|
flickerstreak@10
|
331 self.event = AceLibrary("AceOO-2.0").Class("AceEvent-2.0"):new()
|
flickerstreak@10
|
332 self.event:RegisterEvent("PLAYER_REGEN_DISABLED", function() self:HideAll() end)
|
flickerstreak@10
|
333
|
flickerstreak@10
|
334 if oldDeactivate then
|
flickerstreak@10
|
335 oldDeactivate(oldLib)
|
flickerstreak@10
|
336 end
|
flickerstreak@10
|
337 end
|
flickerstreak@10
|
338
|
flickerstreak@10
|
339 local function deactivate( self )
|
flickerstreak@10
|
340 self.event:UnregisterEvent("PLAYER_REGEN_DISABLED")
|
flickerstreak@10
|
341 end
|
flickerstreak@10
|
342
|
flickerstreak@10
|
343 AceLibrary:Register(ReBound, version_major, version_minor, activate, deactivate)
|
flickerstreak@10
|
344 ReBound = nil
|