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 |
