Mercurial > wow > skeletonkey
comparison SkeletonKey/KeyBinds.lua @ 0:69e828f4238a
Initial Commit
author | Nenue |
---|---|
date | Mon, 20 Jun 2016 06:35:11 -0400 |
parents | |
children | cd7d06bcd98d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:69e828f4238a |
---|---|
1 -------------------------------------------- | |
2 -- KrakTool | |
3 -- Nick | |
4 -- @project-revision@ @project-hash@ | |
5 -- @file-revision@ @file-hash@ | |
6 -- Created: 6/16/2016 3:47 AM | |
7 -------------------------------------------- | |
8 -- kb | |
9 -- .bind(button, key) bind current keystroke to command | |
10 -- .assign(button, command, name, icon) set button command | |
11 -- .release(button) clear button command | |
12 -- .refresh(button) update button contents | |
13 -- .ui() invoke interface | |
14 -- .profile(name) set profile character | |
15 -- .loadbinds(bindings) walk table with SetBinding() | |
16 | |
17 local kb = KeyBinder | |
18 local KT = select(2,...) | |
19 KT.register(KeyBinder) | |
20 local MIN_BIND_SLOTS = 32 | |
21 local BINDS_PER_ROW = 8 | |
22 local KEY_BUTTON_SIZE = 40 | |
23 local TAB_OFFSET = 12 | |
24 local TAB_HEIGHT = 40 | |
25 local TAB_SPACING = 2 | |
26 local BUTTON_SPACING = 4 | |
27 local BUTTON_PADDING = 12 | |
28 local HEADER_OFFSET | |
29 local FOOTER_OFFSET | |
30 local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544; | |
31 local BINDING_TYPE_SPECIALIZATION = 3 | |
32 local BINDING_TYPE_CHARACTER = 2 | |
33 local BINDING_TYPE_GLOBAL = 1 | |
34 local BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).' | |
35 local BINDING_FAILED_PROTECTED = '|cFF00FF00%s|r used by |cFFFFFF00%s|r!' | |
36 local BINDING_MODE = { | |
37 [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s', | |
38 [BINDING_TYPE_CHARACTER] = 'Character: %s', | |
39 [BINDING_TYPE_GLOBAL] = 'Global Binds' | |
40 } | |
41 local BINDING_SCHEME_COLOR = { | |
42 [BINDING_TYPE_SPECIALIZATION] = {0,0,0,0.5}, | |
43 [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.5}, | |
44 [BINDING_TYPE_GLOBAL] = {0,.125,.5,.5} | |
45 } | |
46 local BINDING_SCHEME_VERTEX = { | |
47 | |
48 [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1}, | |
49 [BINDING_TYPE_CHARACTER] = {0,1,0,1}, | |
50 [BINDING_TYPE_GLOBAL] = {0,.5,1,1} | |
51 } | |
52 | |
53 local BINDING_SCHEME_TEXT = { | |
54 [BINDING_TYPE_SPECIALIZATION] = {1, 1, 0}, | |
55 [BINDING_TYPE_CHARACTER] = {0, 1, 0}, | |
56 [BINDING_TYPE_GLOBAL] = {0, 1, 1} | |
57 } | |
58 local ACTION_SCRIPT = { | |
59 ['mount'] = "/script C_MountJournal.SummonByID(%d)", | |
60 ['equipset'] = "/script UseEquipmentSet(%d)", | |
61 } | |
62 | |
63 local COMMAND_SPELL = "^SPELL (%S.+)" | |
64 local COMMAND_MACRO = "^MACRO (%S.+)" | |
65 local COMMAND_ITEM = "^ITEM (%S.+)" | |
66 local COMMAND_MOUNT = "^CLICK KeyBinderMacro:mount(%d+)" | |
67 local COMMAND_EQUIPSET = "^CLICK KeyBinderMacro:equipset(%d+)" | |
68 | |
69 local PICKUP_TYPES = { | |
70 [COMMAND_SPELL] = PickupSpell, | |
71 [COMMAND_MACRO] = PickupMacro, | |
72 [COMMAND_ITEM] = PickupItem, | |
73 [COMMAND_MOUNT] = C_MountJournal.Pickup, | |
74 [COMMAND_EQUIPSET] = PickupEquipmentSet | |
75 } | |
76 local PICKUP_VALUES = { | |
77 [COMMAND_SPELL] = function(name) return select(7, GetSpellInfo(name)) end | |
78 } | |
79 local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES" | |
80 local BORDER_UNASSIGNED = {0.2,0.2,0.2,1 } | |
81 local BORDER_ASSIGNED = {0.5,0.5,0.5,1 } | |
82 local BORDER_PENDING = {1,0.5,0,1 } | |
83 | |
84 | |
85 | |
86 local bindMode = 3 -- not to be confused with db.bindMode which is boolean | |
87 local bindHeader = '' | |
88 local specHeader, specTexture, characterHeader = 'SPEC_NAME', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME' | |
89 local bindsCommitted = true | |
90 | |
91 local profile | |
92 local character | |
93 local specialization | |
94 local global | |
95 local priority = {} | |
96 local numButtons = BINDS_PER_ROW * 4 | |
97 local buttons = {} | |
98 local reverts = {} | |
99 local KeyButton = {} -- collection of KeyButton template handlers | |
100 local Action = {} -- collection of special action buttons for special binds | |
101 local protected = { | |
102 ['OPENCHATSLASH'] = true, | |
103 ['OPENCHAT'] = true, | |
104 } | |
105 local saveButton, restoreButton, clearButton | |
106 | |
107 --- Returns a value for use with Texture:SetDesaturated() | |
108 local CommandIsLocked = function(self) | |
109 print('command check: 1-'..(bindMode-1)) | |
110 local desaturated, layer = false, 3 | |
111 for i = 1, bindMode-1 do | |
112 local tier = priority[i] | |
113 local existing = tier.commands[self.command] | |
114 print(' ', i, tier.commands[self.command]) | |
115 if existing then | |
116 if self:GetID() ~= existing then | |
117 -- sanitize bad data | |
118 tier.commands[self.command] = nil | |
119 else | |
120 layer = i | |
121 desaturated = true | |
122 break | |
123 end | |
124 end | |
125 end | |
126 return desaturated, layer | |
127 end | |
128 | |
129 --- Returns a value for use with Texture:SetDesaturated() | |
130 local BindingIsLocked = function(key) | |
131 local success = false | |
132 for i = 1, bindMode-1 do | |
133 local tier = priority[i] | |
134 if tier.bindings[key] then | |
135 success = true | |
136 break | |
137 end | |
138 end | |
139 return success | |
140 end | |
141 | |
142 --- Translates GetBindingKey() results into a printable string. | |
143 local BindingString = function(...) | |
144 local stack = {} | |
145 for i = 1, select('#', ...) do | |
146 local key = select(i, ...) | |
147 stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp') | |
148 end | |
149 | |
150 if #stack >= 1 then | |
151 return table.concat(stack, ',') | |
152 else | |
153 return nil | |
154 end | |
155 end | |
156 | |
157 --- This keeps our KeyDown handler from getting stuck with game controls | |
158 KeyButton.OnUpdate = function(self) | |
159 if not self.command then | |
160 return | |
161 end | |
162 | |
163 if self:IsMouseOver() then | |
164 if not self.active then | |
165 -- only set this handler when the button is activated/mouseOver | |
166 self.active = true | |
167 self:SetScript('OnKeyDown', kb.bind) | |
168 | |
169 local bindText = self.command | |
170 if self.bind:GetText() then | |
171 bindText = bindText .. ': |cFF00FF00' .. self.bind:GetText() | |
172 end | |
173 | |
174 kb.bindlist:SetText(bindText) | |
175 GameTooltip:SetOwner(self) | |
176 GameTooltip:SetAnchorType('ANCHOR_BOTTOMRIGHT') | |
177 GameTooltip:SetText(self.actionName) | |
178 GameTooltip:Show() | |
179 end | |
180 else | |
181 if self.active then | |
182 GameTooltip:Hide() | |
183 self.active = nil | |
184 self:SetScript('OnKeyDown', nil) | |
185 end | |
186 end | |
187 end | |
188 | |
189 --- Cursor pickup handler | |
190 -- Walks through PICKUP_TYPES and runs the function if match(command, key) turns up a result. | |
191 -- Passes the result through PICKUP_VALUES[pattern]() if defined. | |
192 | |
193 kb.pickup = function(self) | |
194 for pattern, pickup in pairs(PICKUP_TYPES) do | |
195 local value = self.command:match(pattern) | |
196 if value then | |
197 if PICKUP_VALUES[pattern] then | |
198 value = PICKUP_VALUES[pattern](value) | |
199 end | |
200 | |
201 pickup(value) | |
202 kb.release(self) | |
203 break | |
204 end | |
205 end | |
206 end | |
207 | |
208 --- Setup an action button base on template info | |
209 kb.action = function(type, id) | |
210 | |
211 local macroName = type .. id | |
212 macroName = macroName:gsub(' ', '') | |
213 | |
214 local attribute = '*macrotext-'..macroName | |
215 local value = ACTION_SCRIPT[type]:format(id) | |
216 local command = 'CLICK KeyBinderMacro:'.. macroName | |
217 profile.macros[attribute] = {value, command} | |
218 | |
219 KeyBinderMacro:SetAttribute(attribute, value) | |
220 return command | |
221 end | |
222 | |
223 KeyButton.OnDragStart = function(self) | |
224 if not self.command then | |
225 return | |
226 end | |
227 kb.pickup(self) | |
228 end | |
229 | |
230 KeyButton.OnReceiveDrag = function(self, ...) | |
231 print(self:GetName(),'|cFF0088FFreceived|r', ...) | |
232 local type, value, subType, subData = GetCursorInfo() | |
233 print('GetCursorInfo', type, value, subType, subData) | |
234 if type then | |
235 if type == 'spell' then | |
236 value = subData | |
237 end | |
238 | |
239 local command, name, icon, _ | |
240 if type == 'spell' then | |
241 name, _, icon = GetSpellInfo(value) | |
242 command = 'SPELL ' .. name | |
243 name = '' | |
244 elseif type == 'macro' then | |
245 name, icon = GetMacroInfo(value) | |
246 command = 'MACRO ' .. name | |
247 elseif type == 'mount' then | |
248 if subType == 0 then | |
249 name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) | |
250 value= 0 | |
251 else | |
252 name, _, icon = C_MountJournal.GetMountInfoByID(value) | |
253 end | |
254 command = kb.action(type, value) | |
255 elseif type == 'item' then | |
256 name = GetItemInfo(value) | |
257 icon = GetItemIcon(value) | |
258 command = 'ITEM ' .. name | |
259 end | |
260 kb.assign(self, command, name, icon) | |
261 kb.refresh(self) | |
262 ClearCursor() | |
263 end | |
264 end | |
265 | |
266 KeyButton.OnMouseDown = function(self, click) | |
267 print(self:GetName(), 'OnMouseDown', click) | |
268 if click == 'LeftButton' then | |
269 KeyButton.OnReceiveDrag(self) | |
270 elseif click == 'RightButton' then | |
271 kb.release(self) | |
272 else | |
273 kb.bind(self) | |
274 end | |
275 end | |
276 | |
277 | |
278 --- Updates the current KeyBinding for the button's command | |
279 kb.bind = function(self, key) | |
280 | |
281 print('|cFFFFFF00bind|cFFFFFF00', self:GetID(), '|cFF00FFFF', key) | |
282 if not self.command then | |
283 return | |
284 end | |
285 | |
286 if key:match('[RL]SHIFT') or key:match('[RL]ALT') or key:match('[RL]CTRL') then | |
287 return | |
288 end | |
289 | |
290 if protected[GetBindingAction(key)] then | |
291 return | |
292 kb.bindlist:SetText(BINDING_FAILED_PROTECTED:format(key, GetBindingAction(key))) | |
293 end | |
294 | |
295 if key == 'ESCAPE' then | |
296 local key1, key2 = GetBindingKey(self.command) | |
297 if key1 then | |
298 SetBinding(key1, nil) | |
299 print('Unbound', key1) | |
300 end | |
301 if key2 then | |
302 SetBinding(key2, nil) | |
303 print('Unbound', key2) | |
304 end | |
305 self.active = false | |
306 return | |
307 end | |
308 | |
309 local modifier = '' | |
310 if IsAltKeyDown() then | |
311 modifier = 'ALT-' | |
312 end | |
313 if IsControlKeyDown() then | |
314 modifier = modifier.. 'CTRL-' | |
315 end | |
316 if IsShiftKeyDown() then | |
317 modifier = modifier..'SHIFT-' | |
318 end | |
319 | |
320 if self.command then | |
321 self.binding = modifier..key | |
322 self.pending = true | |
323 self.border:SetColorTexture(1,.5,0, 1) | |
324 | |
325 local old = GetBindingAction(self.binding) | |
326 local binding1, binding2, new1, new2 | |
327 if old and old ~= self.command then | |
328 print('Discarding keybind for', old) | |
329 local binding1, binding2 = GetBindingKey(old) | |
330 -- need to preserve argument order | |
331 end | |
332 tinsert(reverts, {old, binding1, binding2, new1, new2}) | |
333 | |
334 | |
335 bindsCommitted = false | |
336 SetBinding(self.binding, self.command) | |
337 for level, profile in ipairs(priority) do | |
338 profile.bindings[self.binding] = (level == bindMode) and self.command or nil | |
339 end | |
340 print(BINDING_ASSIGNED:format(self.binding, self.command, BINDING_MODE[bindMode]:format(bindHeader))) | |
341 | |
342 kb.refresh(self) | |
343 end | |
344 end | |
345 | |
346 --- Resets button command | |
347 kb.release = function(self) | |
348 local index = self:GetID() | |
349 self.command = nil | |
350 self.actionName = nil | |
351 self.macro:SetText(nil) | |
352 self.profile = nil | |
353 self.bind:SetText(nil) | |
354 self.icon:SetTexture(nil) | |
355 self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) | |
356 self:EnableKeyboard(false) | |
357 self:SetScript('OnKeyDown', nil) | |
358 | |
359 | |
360 if profile.buttons[index] then | |
361 profile.buttons[index] = nil | |
362 end | |
363 end | |
364 | |
365 -- Sets button command | |
366 | |
367 kb.assign = function(self, command, name, icon) | |
368 local index = self:GetID() | |
369 print('|cFF00FFFFassign|cFF0088FF', index, '|cFFFFFF00'.. (command or 'none'), '|cFF00FF00'.. (name or ''), '|cFF00FFFF' .. (icon or '')) | |
370 | |
371 | |
372 if command then | |
373 if command:match(COMMAND_SPELL) then | |
374 name = command:match(COMMAND_SPELL) | |
375 end | |
376 | |
377 | |
378 self:EnableKeyboard(true) | |
379 print('profile.buttons['..index..'] |cFF00FFFF=|r ', command, name, icon) | |
380 profile.buttons[index] = {command, name, icon} | |
381 | |
382 --- Clean up any residual buttons | |
383 local previous = profile.commands[command] | |
384 if previous ~= index and buttons[previous] then | |
385 kb.release(buttons[previous]) | |
386 end | |
387 | |
388 profile.commands[command] = index | |
389 end | |
390 | |
391 self.profile = bindMode | |
392 self.actionName = name | |
393 self.command = command | |
394 self.icon:SetTexture(icon) | |
395 self:RegisterForDrag('LeftButton') | |
396 end | |
397 | |
398 --- Retrieves button at index; creates said button and instates any stored parameters | |
399 kb.keyslot = function(index) | |
400 if not buttons[index] then | |
401 local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, kb, 'KeyButton') | |
402 button:SetScript('OnMouseDown', KeyButton.OnMouseDown) | |
403 button:SetScript('OnMouseUp', KeyButton.OnMouseUp) | |
404 button:SetScript('OnUpdate', KeyButton.OnUpdate) | |
405 button:SetScript('OnDragStart', KeyButton.OnDragStart) | |
406 button:SetScript('OnReceiveDrag', KeyButton.OnReceiveDrag) | |
407 button:SetID(index) | |
408 | |
409 if profile.buttons[index] and type(profile.buttons[index] ) == 'table' then | |
410 kb.assign(button, unpack(profile.buttons[index] )) | |
411 else | |
412 kb.release(button) | |
413 end | |
414 | |
415 local x, y = BUTTON_PADDING, - (BUTTON_PADDING + HEADER_OFFSET) | |
416 if index ~= 1 then | |
417 local col = mod(index, BINDS_PER_ROW) | |
418 if col == 0 then | |
419 col = BINDS_PER_ROW - 1 | |
420 else | |
421 col = col - 1 | |
422 end | |
423 x = col * (KEY_BUTTON_SIZE + BUTTON_SPACING) + BUTTON_PADDING | |
424 y = (ceil(index/ BINDS_PER_ROW)-1) * - (KEY_BUTTON_SIZE + BUTTON_SPACING) - BUTTON_PADDING - HEADER_OFFSET | |
425 end | |
426 button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE) | |
427 button:SetPoint('TOPLEFT', kb, 'TOPLEFT', x, y) | |
428 button:Show() | |
429 buttons[index] = button | |
430 end | |
431 return buttons[index] | |
432 end | |
433 | |
434 --- Updates profile assignment and button contents | |
435 kb.refresh = function(self) | |
436 if self.profile ~= bindMode then | |
437 if profile.buttons[self:GetID()] then | |
438 kb.assign(self, unpack(profile.buttons[self:GetID()])) | |
439 else | |
440 kb.release(self) | |
441 end | |
442 end | |
443 | |
444 if self.command then | |
445 if self.pending then | |
446 self.border:SetColorTexture(unpack(BORDER_PENDING)) | |
447 else | |
448 self.border:SetColorTexture(unpack(BORDER_ASSIGNED)) | |
449 end | |
450 --self.macro:SetText(self.actionName) | |
451 self.bind:SetText(BindingString(GetBindingKey(self.command))) | |
452 local locked, layer = CommandIsLocked(self) | |
453 self.icon:SetDesaturated(locked) | |
454 self.icon:SetVertexColor(unpack(BINDING_SCHEME_VERTEX[layer])) | |
455 else | |
456 self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) | |
457 --self.macro:SetText(nil) | |
458 self.bind:SetText(nil) | |
459 end | |
460 end | |
461 | |
462 local SetupUI = function() | |
463 | |
464 | |
465 kb.tabAnchor = {'TOPLEFT', kb, 'TOPRIGHT', 2, -TAB_OFFSET} | |
466 kb.tabGrowth = {'TOPLEFT', nil,'BOTTOMLEFT', 0, -TAB_SPACING} | |
467 kb.tabSize = {TAB_HEIGHT, TAB_HEIGHT } | |
468 kb.UIPanelAnchor = {'TOPLEFT', kb, 'TOPLEFT', BUTTON_PADDING + 12, -BUTTON_PADDING} | |
469 kb.UIPanelGrowth = {'TOPLEFT', nil, 'TOPRIGHT', 14, 0 } | |
470 kb.controlsAnchor = {'BOTTOMLEFT', kb, BUTTON_PADDING, BUTTON_PADDING } | |
471 kb.controlsGrowth = {'BOTTOMLEFT', nil, 'BOTTOMRIGHT', BUTTON_SPACING, 0} | |
472 | |
473 --tab() frame, name, tooltip, texture, coords | |
474 kb:tab('KeyBinderGlobalTab', BINDING_MODE[1], "Interface\\ICONS\\item_azereansphere", {0.15,.85,.15,.85}) | |
475 kb:tab('KeyBinderCharacterTab', characterHeader, nil) | |
476 kb:tab('KeyBinderSpecTab', specHeader, specTexture) | |
477 SetPortraitTexture(KeyBinderCharacterTab.icon, 'player') | |
478 KeyBinderCharacterTab.icon:SetTexCoord(0.15,.85,.15,.85) | |
479 | |
480 saveButton = kb:button('KeyBinderSaveButton', 'Save', 'Commit all changes.', nil, kb.save) | |
481 restoreButton = kb:button('KeyBinderRestoreButton', 'Discard', 'Revert all changes.', nil, kb.restore) | |
482 clearButton = kb:button('KeyBinderClearButton', 'Clear Page', 'Release all buttons.', nil, kb.ResetProfile) | |
483 | |
484 kb:uibutton( | |
485 'KeyBinderSpellBookButton', 'SpellBook', nil, | |
486 function() ToggleSpellBook(BOOKTYPE_SPELL) end, | |
487 "Interface\\Spellbook\\Spellbook-Icon") | |
488 kb:uibutton( | |
489 'KeyBinderTalentFrameButton', 'Talents', nil, | |
490 function() ToggleTalentFrame() end, | |
491 "Interface\\TargetingFrame\\UI-Classes-Circles", | |
492 CLASS_ICON_TCOORDS[strupper(select(2,UnitClass("player")))]) | |
493 | |
494 kb:uibutton( | |
495 'KeyBinderMacroFrameButton', 'Macros', nil, | |
496 function() if MacroFrame then HideUIPanel(MacroFrame) else ShowMacroFrame() end end, | |
497 "Interface\\MacroFrame\\MacroFrame-Icon") | |
498 | |
499 kb:uibutton( | |
500 'KeyBinderInventoryButton', 'Bags', nil, | |
501 function() OpenAllBags() end, | |
502 "Interface\\BUTTONS\\Button-Backpack-Up") | |
503 | |
504 kb.info:SetPoint('TOPLEFT', kb.UIPanels[1], 'BOTTOMLEFT', 0, -BUTTON_SPACING) | |
505 HEADER_OFFSET = kb.UIPanels[1]:GetHeight() + BUTTON_PADDING | |
506 FOOTER_OFFSET = saveButton:GetHeight() + BUTTON_PADDING | |
507 end | |
508 | |
509 --- Invokes the KeyBinder frame (from the /kb function or some other source) | |
510 kb.ui = function() | |
511 if not KT.db.bindMode then | |
512 return | |
513 end | |
514 | |
515 if not kb:IsVisible() then | |
516 kb:Show() | |
517 KT.db.bindMode = true | |
518 end | |
519 | |
520 if not kb.loaded then | |
521 SetupUI() | |
522 kb.loaded = true | |
523 end | |
524 | |
525 for i = 1, numButtons do | |
526 kb.refresh(kb.keyslot(i)) | |
527 end | |
528 | |
529 if bindMode == BINDING_TYPE_SPECIALIZATION then | |
530 bindHeader = select(2,GetSpecializationInfo(GetSpecialization())) | |
531 elseif bindMode == BINDING_TYPE_CHARACTER then | |
532 bindHeader = UnitName('player') | |
533 else | |
534 bindHeader = '' | |
535 end | |
536 | |
537 if bindsCommitted then | |
538 KeyBinderSaveButton:Disable() | |
539 KeyBinderRestoreButton:Disable() | |
540 else | |
541 KeyBinderSaveButton:Enable() | |
542 KeyBinderRestoreButton:Enable() | |
543 end | |
544 | |
545 --- panel attributes | |
546 local numRows = numButtons/BINDS_PER_ROW | |
547 kb:SetHeight( numRows * (KEY_BUTTON_SIZE) + (numRows - 1) * BUTTON_SPACING + HEADER_OFFSET + FOOTER_OFFSET + BUTTON_PADDING * 2) | |
548 kb:SetWidth((BINDS_PER_ROW - 1) * BUTTON_SPACING + BINDS_PER_ROW * KEY_BUTTON_SIZE + BUTTON_PADDING * 2) | |
549 kb.bg:SetColorTexture(unpack(BINDING_SCHEME_COLOR[bindMode])) | |
550 | |
551 | |
552 for i, tab in ipairs(kb.tabButtons) do | |
553 | |
554 local n = tab:GetNormalTexture() | |
555 local tabTexture = "Interface\\Buttons\\UI-Quickslot2" | |
556 local left, top, right, bottom = -12, 12, 13, -13 | |
557 if i == bindMode then | |
558 tabTexture = "Interface\\Buttons\\CheckButtonGlow" | |
559 left, top, right, bottom = -14, 14, 15, -15 | |
560 end | |
561 n:SetTexture(tabTexture) | |
562 n:SetPoint('TOPLEFT', tab, 'TOPLEFT', left, top) | |
563 n:SetPoint('BOTTOMRIGHT', tab, 'BOTTOMRIGHT', right, bottom) | |
564 end | |
565 end | |
566 | |
567 kb.loadbinds = function (bindings) | |
568 for key, command in pairs(bindings) do | |
569 -- store for reversion | |
570 local oldAction = GetBindingAction(key) | |
571 if oldAction ~= command then | |
572 local bind1, bind2 = GetBindingKey(oldAction) | |
573 if bind1 and not reverts[bind1] then | |
574 reverts[bind1] = oldAction | |
575 end | |
576 if bind2 and not reverts[bind2] then | |
577 reverts[bind2] = oldAction | |
578 end | |
579 end | |
580 SetBindings(key, command) | |
581 end | |
582 SaveBindings() | |
583 end | |
584 | |
585 local ACTION_BARS = { | |
586 'MultiBarBottomLeftButton', | |
587 'MultiBarBottomRighttButton', | |
588 'MultiBarLeftButton', | |
589 'MultiBarRightButton', | |
590 'ActionButton' | |
591 } | |
592 kb.HotKeyText = function () | |
593 for _, prefix in ipairs(ACTION_BARS) do | |
594 for i = 1,12 do | |
595 local button = _G[prefix .. i] | |
596 if button and button.action then | |
597 local type, id, subType, subID = GetActionInfo(button.action) | |
598 if type == 'spell' then | |
599 local name = GetSpellInfo(id) | |
600 local bind, bind2 = GetBindingKey('SPELL '..name) | |
601 if bind or bind2 then | |
602 --print('SPELL '..name, GetBindingKey('SPELL '..name)) | |
603 button.HotKey:SetText(BindingString(bind)) | |
604 button.HotKey:Show() | |
605 end | |
606 end | |
607 end | |
608 end | |
609 end | |
610 end | |
611 | |
612 kb.InitProfile = function(profile) | |
613 profile.buttons = profile.buttons or {} | |
614 profile.commands = profile.commands or {} | |
615 profile.bindings = profile.bindings or {} | |
616 profile.macros = profile.macros or {} | |
617 return profile | |
618 end | |
619 kb.ResetProfile = function() | |
620 | |
621 for i, button in pairs(buttons) do | |
622 kb.release(button) | |
623 end | |
624 | |
625 profile.commands = {} | |
626 profile.bindings = {} | |
627 profile.macros = {} | |
628 end | |
629 | |
630 --- Gives us the profile structure to work with while instating data | |
631 kb.profile = function(name) | |
632 KT.db = KT.db or {} | |
633 global = kb.InitProfile(KT.db) | |
634 profile = global | |
635 local subtitle | |
636 if name then | |
637 KT.db[name] = KT.db[name] or {} | |
638 KT.db[name] = kb.InitProfile(KT.db[name]) | |
639 character = KT.db[name] | |
640 local spec = GetSpecialization() | |
641 if spec then | |
642 KT.db[name][spec] = KT.db[name][spec] or {} | |
643 profile = kb.InitProfile(KT.db[name][spec]) | |
644 bindMode = BINDING_TYPE_SPECIALIZATION | |
645 subtitle = select(2,GetSpecializationInfo(spec)) | |
646 specialization = KT.db[name][spec] | |
647 else | |
648 profile = kb.InitProfile(KT.db[name]) | |
649 bindMode = BINDING_TYPE_CHARACTER | |
650 subtitle = name | |
651 specialization = character | |
652 end | |
653 end | |
654 priority = {global, character, specialization } | |
655 | |
656 | |
657 | |
658 if not KT.db.bindsPage then | |
659 KT.db.bindsPage = bindMode | |
660 end | |
661 bindMode = KT.db.bindsPage | |
662 | |
663 | |
664 if not BINDING_MODE[bindMode] then | |
665 bindMode = 3 | |
666 KT.db.bindsPage = 3 | |
667 print('overriding', bindMode) | |
668 end | |
669 | |
670 profile = priority[bindMode] | |
671 | |
672 | |
673 local _ | |
674 _, specHeader, _, specTexture = GetSpecializationInfo(GetSpecialization()) | |
675 print(GetSpecializationInfo(GetSpecialization())) | |
676 specHeader = BINDING_MODE[2]:format(specHeader) | |
677 characterHeader = BINDING_MODE[2]:format(UnitName('player')) | |
678 | |
679 print('Using binding profile |cFF00FF88'..BINDING_MODE[bindMode]:format(subtitle)..'|r') | |
680 end | |
681 | |
682 kb.SelectTab = function(self) | |
683 bindMode = self:GetID() | |
684 profile = priority[self:GetID()] | |
685 KT.db.bindsPage = self:GetID() | |
686 kb.ui() | |
687 end | |
688 kb.save = function() | |
689 SaveBindings(GetCurrentBindingSet()) | |
690 bindsCommitted = true | |
691 for i, button in ipairs(buttons) do | |
692 button.pending = false | |
693 end | |
694 | |
695 kb.ui() | |
696 print('Bindings saved.') | |
697 end | |
698 kb.restore = function() | |
699 for i, button in pairs(buttons) do | |
700 button.pending = false | |
701 end | |
702 bindsCommitted = true | |
703 LoadBindings(GetCurrentBindingSet()) | |
704 print('All changes discarded.') | |
705 end | |
706 | |
707 --- Tells all the hud buttons what to do | |
708 kb.init = function() | |
709 KeyBinderMacro:SetAttribute('*type*', 'macro') | |
710 end | |
711 | |
712 --- Get started | |
713 kb.variables = function() | |
714 kb.profile(GetUnitName('player', true)) | |
715 for i = 1, 3 do | |
716 for attribute, data in pairs(priority[i].macros) do | |
717 KeyBinderMacro:SetAttribute(attribute, data[1]) | |
718 end | |
719 end | |
720 | |
721 kb.UPDATE_BINDINGS() | |
722 kb:RegisterEvent('UPDATE_BINDINGS') | |
723 kb:RegisterEvent('UPDATE_MACROS') | |
724 kb:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED') | |
725 kb:RegisterEvent('PLAYER_EQUIPMENT_CHANGED') | |
726 kb:RegisterEvent('PLAYER_REGEN_DISABLED') | |
727 kb:RegisterEvent('PLAYER_REGEN_ENABLED') | |
728 kb:RegisterEvent('ACTIONBAR_SLOT_CHANGED') | |
729 end | |
730 | |
731 kb.close = function() | |
732 KT.db.bindMode = false | |
733 kb:Hide() | |
734 end | |
735 | |
736 kb.PLAYER_REGEN_DISABLED = function() | |
737 if KT.db.bindMode then | |
738 | |
739 kb:Hide() | |
740 end | |
741 end | |
742 | |
743 kb.PLAYER_REGEN_ENABLED = function() | |
744 if KT.db.bindMode then | |
745 kb.ui() | |
746 end | |
747 end | |
748 --- Refresh buttons if macros are updated | |
749 kb.UPDATE_BINDINGS = function() | |
750 if KT.db.bindMode then | |
751 kb.ui() | |
752 end | |
753 kb.HotKeyText() | |
754 end | |
755 | |
756 kb.ACTIONBAR_SLOT_CHANGED = function() | |
757 kb.HotKeyText() | |
758 end | |
759 | |
760 | |
761 | |
762 kb.UPDATE_MACROS = kb.UPDATE_BINDINGS | |
763 | |
764 | |
765 SLASH_KB1 = "/kb" | |
766 SlashCmdList.KB = function() | |
767 if KT.db.bindMode then | |
768 KT.db.bindMode = false | |
769 print('|cFFFFFF00KeyBinds|r trace, |cFFFF0000OFF|r.') | |
770 kb:Hide() | |
771 else | |
772 KT.db.bindMode = true | |
773 print('|cFFFFFF00KeyBinds|r trace, |cFF00FF00ON|r.') | |
774 kb.ui() | |
775 end | |
776 end |