annotate SkeletonKey/KeyBinds.lua @ 5:9ac29fe77455

- dynamic profession spell mapping - dynamic talent spell mapping - protection of dynamic slots that aren't in use - plugin abstractors for accessing state data - a lot of fixes related to the 7.0.3 API
author Nenue
date Tue, 26 Jul 2016 19:29:44 -0400
parents 07293831dd7b
children f6d1c192afc6
rev   line source
Nenue@0 1 --------------------------------------------
Nenue@5 2 -- SkeletonKey
Nenue@5 3 -- Krakyn-Mal'Ganis
Nenue@0 4 -- @project-revision@ @project-hash@
Nenue@0 5 -- @file-revision@ @file-hash@
Nenue@0 6 -- Created: 6/16/2016 3:47 AM
Nenue@0 7 --------------------------------------------
Nenue@0 8 -- kb
Nenue@5 9 -- .StoreBinding(button, key) bind current keystroke to command
Nenue@5 10 -- .GetSlot(index) return display slot
Nenue@5 11 -- .SetSlot(button, command, name, icon) assign display slot
Nenue@5 12 -- .ReleaseSlot(button) clear button command
Nenue@5 13 -- .UpdateSlot(button) update button contents
Nenue@5 14 -- .SelectProfile(name) set profile character
Nenue@5 15 -- .ApplyBindings(bindings) walk table with SetBinding()
Nenue@0 16
Nenue@5 17 local _
Nenue@5 18 local kb, print = LibStub("LibKraken").register(KeyBinder)
Nenue@1 19 local db
Nenue@5 20 local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end
Nenue@1 21
Nenue@5 22 --- Caps Lock literals
Nenue@5 23 local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:"
Nenue@5 24 local BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).'
Nenue@5 25 local BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.'
Nenue@5 26 local BINDING_FAILED_PROTECTED = '|cFFFF4400Unable to use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400)|r'
Nenue@5 27 local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES"
Nenue@5 28 local FOOTER_OFFSET
Nenue@5 29 local HEADER_OFFSET
Nenue@5 30 local HELP_1 = "Drag and drop spells/items from your inventory, spellbook, or collections panels."
Nenue@5 31 local HELP_2 = "While the cursor is above an icon, up to two key combinations will be bound to that action."
Nenue@5 32 local HELP_3 = "If that key used for a client binding (e.g. game menu), a confirmation popup will appear before making the change."
Nenue@5 33 local BINDS_PER_ROW = 2
Nenue@5 34 local BUTTON_HSPACING = 128
Nenue@5 35 local BUTTON_SPACING = 4
Nenue@5 36 local BUTTON_PADDING = 12
Nenue@5 37 local BINDING_TYPE_SPECIALIZATION = 3
Nenue@5 38 local BINDING_TYPE_CHARACTER = 2
Nenue@5 39 local BINDING_TYPE_GLOBAL = 1
Nenue@5 40 local KEY_BUTTON_SIZE = 48
Nenue@0 41 local MIN_BIND_SLOTS = 32
Nenue@5 42 local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544
Nenue@0 43 local TAB_OFFSET = 12
Nenue@0 44 local TAB_HEIGHT = 40
Nenue@0 45 local TAB_SPACING = 2
Nenue@5 46 local BORDER_UNASSIGNED = {0.2,0.2,0.2,1 }
Nenue@5 47 local BORDER_ASSIGNED = {0.5,0.5,0.5,1 }
Nenue@5 48 local BORDER_DYNAMIC = {1,1,0,1}
Nenue@5 49 local BORDER_PENDING = {1,0.5,0,1 }
Nenue@5 50 local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION
Nenue@5 51
Nenue@5 52
Nenue@5 53 --- Caps Lock derivatives
Nenue@5 54 local ACTION_SCRIPT = {
Nenue@5 55 ['mount'] = "/script C_MountJournal.SummonByID(%d)",
Nenue@5 56 ['macro'] = "%s",
Nenue@5 57 ['equipset'] = "/script UseEquipmentSet(%d)",
Nenue@5 58 ['spell'] = "/cast %s",
Nenue@5 59 ['petaction'] = "/cast %s",
Nenue@5 60 ['battlepet'] = SLASH_SUMMON_BATTLE_PET1 .. " %s",
Nenue@5 61 ['item'] = "/use %s"
Nenue@5 62 }
Nenue@5 63 local BUTTON_HEADERS = {
Nenue@5 64 ['spell'] = SPELLS,
Nenue@5 65 ['macro'] = MACRO,
Nenue@5 66 ['petaction'] = PET,
Nenue@5 67 ['mount'] = MOUNT,
Nenue@5 68 ['battlepet'] = BATTLEPET,
Nenue@5 69
Nenue@5 70
Nenue@5 71 [5] = PROFESSIONS_FIRST_AID,
Nenue@5 72 [7] = PROFESSIONS_COOKING,
Nenue@5 73 [9] = PROFESSIONS_FISHING,
Nenue@5 74 [10] = PROFESSIONS_ARCHAEOLOGY,
Nenue@5 75
Nenue@5 76 }
Nenue@5 77
Nenue@5 78 local professionMappings = {
Nenue@5 79 [5] = 3,
Nenue@5 80 [7] = 4,
Nenue@5 81 [9] = 5,
Nenue@5 82 [10] = 6
Nenue@5 83 }
Nenue@5 84
Nenue@0 85 local BINDING_MODE = {
Nenue@5 86 [BINDING_TYPE_GLOBAL] = 'Global Binds',
Nenue@0 87 [BINDING_TYPE_CHARACTER] = 'Character: %s',
Nenue@5 88 [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s'
Nenue@0 89 }
Nenue@5 90 local BINDING_DESCRIPTION = {
Nenue@5 91
Nenue@5 92 [BINDING_TYPE_GLOBAL] = 'The bindings are applied globally.',
Nenue@5 93 [BINDING_TYPE_CHARACTER] = 'Applied when you log onto this character.',
Nenue@5 94 [BINDING_TYPE_SPECIALIZATION] = 'Applied when you log onto this character and are that specialization.',
Nenue@5 95 }
Nenue@5 96
Nenue@0 97 local BINDING_SCHEME_COLOR = {
Nenue@5 98 [BINDING_TYPE_GLOBAL] = {0,.125,.5,.5},
Nenue@0 99 [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.5},
Nenue@5 100 [BINDING_TYPE_SPECIALIZATION] = {.25,0,0,0.5},
Nenue@0 101 }
Nenue@0 102 local BINDING_SCHEME_VERTEX = {
Nenue@5 103 [BINDING_TYPE_GLOBAL] = {0,.5,1,1},
Nenue@5 104 [BINDING_TYPE_CHARACTER] = {0,1,0,1},
Nenue@0 105 [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1},
Nenue@0 106 }
Nenue@0 107 local BINDING_SCHEME_TEXT = {
Nenue@5 108 [BINDING_TYPE_SPECIALIZATION] = {0, 1, 1},
Nenue@0 109 [BINDING_TYPE_CHARACTER] = {0, 1, 0},
Nenue@0 110 [BINDING_TYPE_GLOBAL] = {0, 1, 1}
Nenue@0 111 }
Nenue@0 112
Nenue@0 113
Nenue@0 114
Nenue@5 115 local loadedProfiles = {}
Nenue@5 116 -- Profiles ordered by precedance
Nenue@5 117 local priority = {}
Nenue@5 118 -- Button pointers
Nenue@5 119 local buttons = {}
Nenue@5 120 -- Backlog of changes
Nenue@5 121 local reverts = {}
Nenue@5 122 -- macro buttons used for mounts and other buttonable non-spells
Nenue@5 123 local macros = {}
Nenue@5 124 -- currently active non-blizzard keybinds
Nenue@5 125 local bindings = {}
Nenue@5 126 -- unselected talents
Nenue@5 127 local talentBindings = {}
Nenue@5 128 kb.inactiveTalentBindings = {}
Nenue@5 129 -- placeholder for the StaticPopup used for confirmations
Nenue@5 130 local confirmation
Nenue@5 131 -- header text
Nenue@5 132 local configHeaders = {}
Nenue@0 133
Nenue@0 134 local protected = {
Nenue@0 135 ['OPENCHATSLASH'] = true,
Nenue@0 136 ['OPENCHAT'] = true,
Nenue@0 137 }
Nenue@5 138
Nenue@5 139 --- Used to reflect the current working state
Nenue@5 140 local bindMode = 3
Nenue@5 141 local bindHeader, currentHeader = '', ''
Nenue@5 142 local configProfile, character, specialization, global, character_specialization
Nenue@5 143 local specID, specGlobalID, specName, specDesc, specTexture, characterHeader = 0, 0, 'SPEC_NAME', 'SPEC_DESCRIPTION', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME'
Nenue@5 144 local classHeader, className, classID = '', '', 0
Nenue@5 145 local numButtons = BINDS_PER_ROW * 8
Nenue@5 146 local bindsCommitted = true
Nenue@5 147 local forceButtonUpdate = false
Nenue@5 148
Nenue@5 149 --- Control handles
Nenue@0 150 local saveButton, restoreButton, clearButton
Nenue@0 151
Nenue@5 152 --- Cursor "pickup" actuators
Nenue@5 153 local PickupAction = {}
Nenue@5 154 PickupAction.spell = _G.PickupSpell
Nenue@5 155 PickupAction.macro = _G.PickupMacro
Nenue@5 156 PickupAction.item = _G.PickupItem
Nenue@5 157 PickupAction.mount = _G.C_MountJournal.Pickup
Nenue@5 158 local GetPickupValue = {}
Nenue@5 159 GetPickupValue.spell = function(self) return select(7, GetSpellInfo(self.actionID)) end
Nenue@5 160
Nenue@5 161 --- Returns conflicting assignment and binding profiles for use in displaying confirmations
Nenue@5 162 local IsCommandBound = function(self, command)
Nenue@5 163 local isAssigned, assignedBy = false, bindMode
Nenue@5 164 local isBound, boundBy = false, bindMode
Nenue@5 165
Nenue@5 166
Nenue@5 167 command = command or self.command
Nenue@5 168 for i = 1, #BINDING_MODE do
Nenue@0 169 local tier = priority[i]
Nenue@5 170 if i ~= bindMode then
Nenue@5 171
Nenue@5 172 if tier.commands[command] then
Nenue@5 173 isAssigned = true
Nenue@5 174 assignedBy = i
Nenue@5 175 end
Nenue@5 176 if tier.bound[command] then
Nenue@5 177 isBound = true
Nenue@5 178 boundBy = i
Nenue@5 179 end
Nenue@5 180
Nenue@5 181
Nenue@5 182 --print(' *', configHeaders[i], tier.commands[command], tier.bound[command])
Nenue@5 183
Nenue@5 184 if isAssigned and isBound then
Nenue@0 185 break
Nenue@0 186 end
Nenue@0 187 end
Nenue@5 188
Nenue@0 189 end
Nenue@5 190
Nenue@5 191 print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', bindMode .. ']', isAssigned, isBound, assignedBy, boundBy)
Nenue@5 192 return isAssigned, isBound, assignedBy, boundBy
Nenue@0 193 end
Nenue@0 194
Nenue@5 195 local talentSpellHardCodes = {
Nenue@5 196 [109248] = 'Binding Shot',
Nenue@5 197 }
Nenue@5 198
Nenue@0 199 --- Returns a value for use with Texture:SetDesaturated()
Nenue@0 200 local BindingIsLocked = function(key)
Nenue@0 201 local success = false
Nenue@0 202 for i = 1, bindMode-1 do
Nenue@0 203 local tier = priority[i]
Nenue@0 204 if tier.bindings[key] then
Nenue@0 205 success = true
Nenue@0 206 break
Nenue@0 207 end
Nenue@0 208 end
Nenue@0 209 return success
Nenue@0 210 end
Nenue@0 211
Nenue@0 212 --- Translates GetBindingKey() results into a printable string.
Nenue@0 213 local BindingString = function(...)
Nenue@0 214 local stack = {}
Nenue@0 215 for i = 1, select('#', ...) do
Nenue@0 216 local key = select(i, ...)
Nenue@5 217 stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ')
Nenue@0 218 end
Nenue@0 219
Nenue@0 220 if #stack >= 1 then
Nenue@0 221 return table.concat(stack, ',')
Nenue@0 222 else
Nenue@0 223 return nil
Nenue@0 224 end
Nenue@0 225 end
Nenue@0 226
Nenue@5 227 local restingAlpha = 0.7
Nenue@5 228 local fadeTime, fadeDelay = .30, 0.15
Nenue@5 229
Nenue@5 230 local portraitLayers = {}
Nenue@5 231 kb.UpdatePortraits = function()
Nenue@5 232 for i, layeredRegion in ipairs(portraitLayers) do
Nenue@5 233 SetPortraitTexture(layeredRegion , 'player')
Nenue@5 234 end
Nenue@5 235 end
Nenue@5 236
Nenue@5 237
Nenue@5 238
Nenue@5 239 local KeyButton_OnKeyDown = function(self, key)
Nenue@5 240 kb.StoreBinding(self, key)
Nenue@5 241 end
Nenue@5 242 local KeyButton_OnClick = function(self, click)
Nenue@5 243 print(self:GetName(), 'OnMouseDown', click)
Nenue@5 244 if click == 'LeftButton' then
Nenue@5 245 kb.DropToSlot(self)
Nenue@5 246 elseif click == 'RightButton' then
Nenue@5 247 kb.ReleaseSlot(self)
Nenue@5 248 else
Nenue@5 249 kb.StoreBinding(self, click:upper())
Nenue@5 250 end
Nenue@5 251 end
Nenue@5 252
Nenue@5 253 local KeyButton_OnDragStart = function(self)
Nenue@5 254 kb.PickupSlot(self)
Nenue@5 255 end
Nenue@5 256
Nenue@5 257 local KeyButton_OnReceiveDrag = function(self, ...)
Nenue@5 258 kb.DropToSlot(self)
Nenue@5 259 end
Nenue@5 260
Nenue@5 261
Nenue@5 262 local KeyBinder_OnUpdate = function(self, elapsed)
Nenue@5 263 self.elapsed = self.elapsed + elapsed
Nenue@5 264 self.throttle = self.throttle + elapsed
Nenue@5 265
Nenue@5 266 if (self.throttle >= 0.032) then
Nenue@5 267 self.throttle = 0
Nenue@5 268 else
Nenue@5 269 return
Nenue@5 270 end
Nenue@5 271
Nenue@5 272 local progress = 1
Nenue@5 273 if self.elapsed > fadeTime then
Nenue@5 274 self.elapsed = 0
Nenue@5 275 self.fadeStep = 0
Nenue@5 276 --self.statustext:SetText(nil)
Nenue@5 277 --self.bindingstext:SetText(nil)
Nenue@5 278 self:SetScript('OnUpdate', nil)
Nenue@5 279 else
Nenue@5 280 if self.elapsed < fadeDelay then
Nenue@5 281 progress = 0
Nenue@5 282 else
Nenue@5 283 self.fadeStep = self.fadeStep + 1
Nenue@5 284 progress = (self.elapsed - fadeDelay) /(fadeTime - fadeDelay)
Nenue@5 285 end
Nenue@5 286 --print(self.fadeStep, format('%.02f/%.02f', (self.elapsed - fadeDelay) ,(fadeTime - fadeDelay)) , progress)
Nenue@5 287 end
Nenue@5 288
Nenue@5 289 local alpha = 1 - progress * (1- restingAlpha)
Nenue@5 290 self.statustext:SetAlpha(alpha)
Nenue@5 291 self.bindingstext:SetAlpha(alpha)
Nenue@5 292 end
Nenue@5 293
Nenue@5 294 local KeyButton_OnUpdate = function(self)
Nenue@0 295 if not self.command then
Nenue@0 296 return
Nenue@0 297 end
Nenue@0 298
Nenue@0 299 if self:IsMouseOver() then
Nenue@5 300 kb.elapsed = 0
Nenue@0 301 if not self.active then
Nenue@0 302 -- only set this handler when the button is activated/mouseOver
Nenue@0 303 self.active = true
Nenue@5 304 self:SetScript('OnKeyDown', KeyButton_OnKeyDown)
Nenue@0 305
Nenue@5 306 kb.statustext:SetText(self.statusText .. ': '..self.actionName)
Nenue@5 307 kb.bindingstext:SetText(self.bindingText)
Nenue@5 308 kb.fadeStep = 0
Nenue@5 309 kb.throttle = 0
Nenue@5 310 kb:SetScript('OnUpdate', KeyBinder_OnUpdate)
Nenue@0 311
Nenue@0 312 end
Nenue@0 313 else
Nenue@0 314 if self.active then
Nenue@0 315 self.active = nil
Nenue@0 316 self:SetScript('OnKeyDown', nil)
Nenue@0 317 end
Nenue@0 318 end
Nenue@0 319 end
Nenue@0 320
Nenue@5 321 local KeyBinder_OnMouseWheel = function(self, delta)
Nenue@5 322 print(self, delta, self.scrollOffset, (self.scrollOffset <= 0))
Nenue@0 323
Nenue@5 324
Nenue@5 325 if IsControlKeyDown() then
Nenue@5 326 KEY_BUTTON_SIZE = KEY_BUTTON_SIZE - delta
Nenue@5 327 else
Nenue@5 328
Nenue@5 329
Nenue@5 330 if (delta > 0) and (self.scrollOffset <= 0) then
Nenue@5 331 return
Nenue@5 332 elseif delta < 0 and kb.scrollOffset >= 42 then
Nenue@5 333 return
Nenue@5 334 end
Nenue@5 335 kb.scrollOffset = ceil(kb.scrollOffset - (delta * BINDS_PER_ROW))
Nenue@5 336 end
Nenue@5 337
Nenue@5 338 kb.ui(true)
Nenue@5 339 end
Nenue@5 340
Nenue@5 341 local KeyBinder_OnHide = function()
Nenue@5 342 KeyBinderImportLog:Hide()
Nenue@5 343 end
Nenue@5 344
Nenue@5 345 local CloseButton_OnClick = function()
Nenue@5 346 db.showUI = false
Nenue@5 347 kb:Hide()
Nenue@5 348 end
Nenue@5 349 local CancelButton_OnClick = function()
Nenue@5 350 kb.RevertBindings()
Nenue@5 351 end
Nenue@5 352 local SaveButton_OnClick = function()
Nenue@5 353 kb.ConfirmBindings()
Nenue@5 354 end
Nenue@5 355
Nenue@5 356 local KeyBinder_Initialize = function()
Nenue@5 357 for i = 1, GetNumBindings() do
Nenue@5 358 local command = GetBinding(i)
Nenue@5 359 bindings[command] = true
Nenue@5 360 end
Nenue@5 361
Nenue@5 362 kb.scrollOffset = 0
Nenue@5 363 kb.tabAnchor = {'TOPLEFT', kb.profilebg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING}
Nenue@5 364 kb.tabGrowth = {'TOPLEFT', nil,'TOPRIGHT', BUTTON_SPACING, 0}
Nenue@5 365 kb.tabSize = {TAB_HEIGHT, TAB_HEIGHT }
Nenue@5 366 kb.UIPanelAnchor = {'TOPLEFT', kb.sourcesbg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING}
Nenue@5 367 kb.UIPanelGrowth = {'TOPLEFT', nil, 'BOTTOMLEFT', 0, -2 }
Nenue@5 368 kb.UIPanelSize = {84, 32 }
Nenue@5 369 kb.UIPanelIcon = {24, 32, 'LEFT', -12, 0}
Nenue@5 370 kb.controlsAnchor = {'BOTTOMLEFT', kb.footer, BUTTON_PADDING, BUTTON_PADDING }
Nenue@5 371 kb.controlsGrowth = {'BOTTOMLEFT', nil, 'BOTTOMRIGHT', BUTTON_SPACING, 0}
Nenue@5 372
Nenue@5 373 -- order of these is important
Nenue@5 374 kb:tab('KeyBinderGlobalTab',
Nenue@5 375 BINDING_MODE[BINDING_TYPE_GLOBAL] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_GLOBAL], "Interface\\ICONS\\item_azereansphere", {0.15,.85,.15,.85})
Nenue@5 376 kb:tab('KeyBinderCharacterTab',
Nenue@5 377 configHeaders[BINDING_TYPE_CHARACTER] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_CHARACTER], nil)
Nenue@5 378 kb:tab('KeyBinderSpecTab',
Nenue@5 379 configHeaders[BINDING_TYPE_SPECIALIZATION] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_SPECIALIZATION], specTexture)
Nenue@5 380 KeyBinderCharacterTab.icon:SetTexCoord(0.15,.85,.15,.85)
Nenue@5 381
Nenue@5 382
Nenue@5 383
Nenue@5 384 portraitLayers[1] = KeyBinderCharacterTab.icon
Nenue@5 385
Nenue@5 386 saveButton = kb:button('KeyBinderSaveButton', 'Save', 'Commit all changes.', SaveButton_OnClick)
Nenue@5 387 --restoreButton = kb:button('KeyBinderRestoreButton', 'Discard', 'Revert all changes.', CancelButton_OnClick)
Nenue@5 388 --clearButton = kb:button('KeyBinderClearButton', 'Clear Page', 'Release all buttons.', ResetButton_OnClick)
Nenue@5 389
Nenue@5 390 kb:uibutton(
Nenue@5 391 'KeyBinderSpellBookButton', 'SpellBook', nil,
Nenue@5 392 function() ToggleSpellBook(BOOKTYPE_SPELL) end,
Nenue@5 393 "Interface\\BUTTONS\\UI-MicroButton-Spellbook-Up", {0, 1, .4, 1})
Nenue@5 394 kb:uibutton(
Nenue@5 395 'KeyBinderTalentFrameButton', TALENTS, SPECIALIZATION,
Nenue@5 396 function() ToggleTalentFrame() end,
Nenue@5 397 "Interface\\BUTTONS\\UI-MicroButton-Talents-Up", {0, 1, .4, 1})
Nenue@5 398
Nenue@5 399 kb:uibutton(
Nenue@5 400 'KeyBinderMacroFrameButton', 'Macros', nil,
Nenue@5 401 function() if MacroFrame and MacroFrame:IsVisible() then
Nenue@5 402 HideUIPanel(MacroFrame)
Nenue@5 403 else
Nenue@5 404 ShowMacroFrame() end
Nenue@5 405 end,
Nenue@5 406 "Interface\\BUTTONS\\UI-MicroButton-Help-Up", {0, 1, .4, 1})
Nenue@5 407
Nenue@5 408 kb:uibutton(
Nenue@5 409 'KeyBinderInventoryButton', 'Bags', nil,
Nenue@5 410 function() OpenAllBags() end,
Nenue@5 411 "Interface\\BUTTONS\\UI-MicroButtonCharacter-Up", {0, 1, .4, 1})
Nenue@5 412
Nenue@5 413
Nenue@5 414
Nenue@5 415 kb.info:SetPoint('TOPLEFT', kb.UIPanels[1], 'BOTTOMLEFT', 0, -BUTTON_SPACING)
Nenue@5 416 HEADER_OFFSET = kb.UIPanels[1]:GetHeight() + BUTTON_PADDING
Nenue@5 417 + kb.info:GetHeight()
Nenue@5 418 FOOTER_OFFSET = saveButton:GetHeight() + BUTTON_PADDING
Nenue@5 419
Nenue@5 420 kb:SetScript('OnHide', KeyBinder_OnHide)
Nenue@5 421 kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel)
Nenue@5 422 kb.CloseButton:SetScript('OnClick', CloseButton_OnClick)
Nenue@5 423
Nenue@5 424 kb.UpdatePortraits()
Nenue@5 425 end
Nenue@5 426
Nenue@5 427 kb.DropToSlot = function(self)
Nenue@5 428
Nenue@5 429 print(self:GetName(),'|cFF0088FFreceived|r')
Nenue@5 430 local actionType, actionID, subType, subData = GetCursorInfo()
Nenue@5 431 print('GetCursorInfo', GetCursorInfo())
Nenue@5 432
Nenue@5 433
Nenue@5 434 if actionType then
Nenue@5 435
Nenue@5 436 if actionType == 'flyout' then
Nenue@5 437 ClearCursor()
Nenue@5 438 ResetCursor()
Nenue@5 439 return
Nenue@5 440 end
Nenue@5 441
Nenue@5 442
Nenue@5 443 local macroName, macroText
Nenue@5 444 local command, name, icon, _
Nenue@5 445 local pickupID, pickupBook
Nenue@5 446
Nenue@5 447 if actionType == 'spell' then
Nenue@5 448 actionID = subData
Nenue@5 449 name, _, icon = GetSpellInfo(actionID)
Nenue@5 450
Nenue@5 451 elseif actionType == 'macro' then
Nenue@5 452 name, icon = GetMacroInfo(actionID)
Nenue@5 453 actionID = name
Nenue@5 454 elseif actionType == 'petaction' then
Nenue@5 455 if not (CURSOR_SPELLSLOT and CURSOR_BOOKTYPE) then
Nenue@5 456
Nenue@5 457 ClearCursor()
Nenue@5 458 ResetCursor()
Nenue@0 459 end
Nenue@0 460
Nenue@5 461 local bookType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE)
Nenue@5 462 pickupID = CURSOR_SPELLSLOT
Nenue@5 463 pickupBook = CURSOR_BOOKTYPE
Nenue@5 464 name, _, icon = GetSpellInfo(spellID)
Nenue@5 465 actionID = name
Nenue@5 466
Nenue@5 467 elseif actionType == 'mount' then
Nenue@5 468 if subType == 0 then
Nenue@5 469 name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL)
Nenue@5 470 actionID = 0
Nenue@5 471 else
Nenue@5 472 name, _, icon = C_MountJournal.GetMountInfoByID(actionID)
Nenue@5 473 end
Nenue@5 474 elseif actionType == 'item' then
Nenue@5 475 name = GetItemInfo(actionID)
Nenue@5 476 icon = GetItemIcon(actionID)
Nenue@5 477 actionID = name
Nenue@5 478 elseif actionType == 'battlepet' then
Nenue@5 479
Nenue@5 480 local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = C_PetJournal.GetPetInfoByPetID(detail);
Nenue@5 481 name = customName or petName
Nenue@5 482 icon = petIcon
Nenue@5 483
Nenue@5 484 end
Nenue@5 485 macroName, macroText, command = kb.RegisterAction(actionType, actionID)
Nenue@5 486
Nenue@5 487
Nenue@5 488 local isAssigned, isBound, assignedBy, boundBy = IsCommandBound(self, command)
Nenue@5 489 if isAssigned then
Nenue@5 490 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"]
Nenue@5 491 popup.slot = self
Nenue@5 492 popup.text = "Currently assigned in |cFFFFFF00"..tostring(configHeaders[assignedBy]).."|r. Are you sure?"
Nenue@5 493 popup.oldProfile = assignedBy
Nenue@5 494 popup.args = {command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook }
Nenue@5 495 kb:SetScript('OnMouseWheel', nil) -- disable scrolling
Nenue@5 496 StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT')
Nenue@5 497 else
Nenue@5 498 kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook)
Nenue@5 499 kb.UpdateSlot(self)
Nenue@5 500 self.active = nil
Nenue@5 501 KeyButton_OnUpdate(self, 0)
Nenue@5 502 ClearCursor()
Nenue@5 503 ResetCursor()
Nenue@0 504 end
Nenue@0 505 end
Nenue@0 506 end
Nenue@0 507
Nenue@5 508 kb.PickupSlot = function(self)
Nenue@0 509 if not self.command then
Nenue@0 510 return
Nenue@0 511 end
Nenue@5 512 print(self.actionType)
Nenue@5 513 if self.actionType == 'spell' then
Nenue@5 514 -- It can't be picked up if SpellInfo(name) returns void
Nenue@5 515 local dummy = GetSpellInfo(self.actionName)
Nenue@5 516 if not dummy then
Nenue@5 517 return
Nenue@0 518 end
Nenue@5 519 elseif self.actionType == 'petaction' then
Nenue@5 520 PickupSpellBookItem(self.pickupSlot, self.pickupBook)
Nenue@5 521 end
Nenue@5 522 if PickupAction[self.actionType] then
Nenue@5 523 if GetPickupValue[self.actionType] then
Nenue@5 524 PickupAction[self.actionType](GetPickupValue[self.actionType](self))
Nenue@5 525 else
Nenue@5 526 PickupAction[self.actionType](self.actionID)
Nenue@0 527 end
Nenue@5 528 kb.ReleaseSlot(self)
Nenue@5 529 kb.UpdateSlot(self)
Nenue@0 530 end
Nenue@0 531 end
Nenue@0 532
Nenue@5 533
Nenue@5 534 --- Resolve the appropriate command and assign the corresponding secure state driver
Nenue@5 535 kb.RegisterAction = function(type, id)
Nenue@5 536
Nenue@5 537 if type == 'spell' then
Nenue@5 538
Nenue@5 539 id = GetSpellInfo(id)
Nenue@5 540 end
Nenue@5 541
Nenue@5 542 local macroText
Nenue@5 543 local macroName = type ..'_' .. id
Nenue@5 544
Nenue@5 545 if kb.ProfessionCache[id] then
Nenue@5 546 macroName = "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum
Nenue@5 547 macroText = "/cast " .. kb.ProfessionCache[id].spellName
Nenue@5 548 macros[macroName] = nil
Nenue@0 549 else
Nenue@5 550 macroName = macroName:gsub(' ', '')
Nenue@5 551 macroText = ACTION_SCRIPT[type]:format(id)
Nenue@0 552 end
Nenue@5 553
Nenue@5 554 local baseName, iterative = macroName, 1
Nenue@5 555 while (macros[macroName] and macros[macroName][1] ~= macroText) do
Nenue@5 556 print(' * cannot use|cFF00FF00', macroName, '|r"'.. (macros[macroName][1] or '') .. '"')
Nenue@5 557 macroName = baseName .. '_' .. iterative
Nenue@5 558 iterative = iterative + 1
Nenue@5 559 end
Nenue@5 560 if macroName ~= baseName then
Nenue@5 561 print(' * Creating|cFF00FF00', macroName)
Nenue@5 562 else
Nenue@5 563 print(' * Re-using|cFF00FF00', macroName)
Nenue@5 564 end
Nenue@5 565
Nenue@5 566 local command = 'CLICK KeyBinderMacro:'.. macroName
Nenue@5 567 macros[macroName] = {macroText, command }
Nenue@5 568 print('RegisterAction', command , macroText)
Nenue@5 569 if type == 'macro' then
Nenue@5 570 kb.LoadMacro(macroName)
Nenue@5 571 else
Nenue@5 572 kb.LoadAction(macroName, macroText, command)
Nenue@5 573 end
Nenue@5 574
Nenue@5 575
Nenue@5 576 return macroName, macroText, command
Nenue@0 577 end
Nenue@0 578
Nenue@5 579 kb.LoadMacro = function(macroName)
Nenue@5 580 KeyBinderMacro:SetAttribute('*macro-'..macroName, macros[macroName][1])
Nenue@5 581 return true
Nenue@5 582 end
Nenue@5 583
Nenue@5 584 kb.LoadAction = function(macroName)
Nenue@5 585 if not macros[macroName] then
Nenue@5 586 return false
Nenue@5 587 end
Nenue@5 588 KeyBinderMacro:SetAttribute('*macrotext-'..macroName, macros[macroName][1])
Nenue@5 589 return true
Nenue@5 590 end
Nenue@5 591
Nenue@5 592 local profressionsCache
Nenue@5 593
Nenue@5 594 kb.AcceptAssignment = function(self, ...)
Nenue@5 595 local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"]
Nenue@5 596 local source = loadedProfiles[popup.oldProfile]
Nenue@5 597 kb.SetSlot(popup.slot, unpack(popup.args))
Nenue@5 598 kb.UpdateSlot(popup.slot)
Nenue@5 599 kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) -- re-enable scrolling
Nenue@5 600 ClearCursor()
Nenue@5 601 ResetCursor()
Nenue@5 602 end
Nenue@5 603
Nenue@0 604
Nenue@0 605 --- Updates the current KeyBinding for the button's command
Nenue@5 606 kb.StoreBinding = function(self, key)
Nenue@0 607
Nenue@0 608 if not self.command then
Nenue@0 609 return
Nenue@0 610 end
Nenue@0 611
Nenue@0 612 if key:match('[RL]SHIFT') or key:match('[RL]ALT') or key:match('[RL]CTRL') then
Nenue@0 613 return
Nenue@0 614 end
Nenue@5 615 print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key)
Nenue@0 616
Nenue@5 617 if key == 'ESCAPE' then
Nenue@5 618 local keys = {GetBindingKey(self.command) }
Nenue@5 619 --print('detected', #keys, 'bindings')
Nenue@5 620 for i, key in pairs(keys) do
Nenue@5 621 --print('clearing', key)
Nenue@5 622 SetBinding(key, nil)
Nenue@5 623 SaveBindings(GetCurrentBindingSet())
Nenue@5 624 if configProfile.bindings[key] then
Nenue@5 625 kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[bindMode]))
Nenue@5 626 configProfile.bindings[key] = nil
Nenue@5 627 end
Nenue@5 628 if configProfile.talents[self.actionName] then
Nenue@5 629 configProfile.talents[self.actionName] = nil
Nenue@5 630 end
Nenue@5 631 bindings[self.actionType][self.actionID] = nil
Nenue@5 632 end
Nenue@5 633 if configProfile.bound[self.command] then
Nenue@5 634 configProfile.bound[self.command] = nil
Nenue@5 635 --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[bindMode]))
Nenue@5 636 end
Nenue@5 637
Nenue@5 638 bindsCommitted = false
Nenue@5 639 self.active = false
Nenue@5 640 else
Nenue@5 641
Nenue@5 642 local modifier = ''
Nenue@5 643 if IsAltKeyDown() then
Nenue@5 644 modifier = 'ALT-'
Nenue@5 645 end
Nenue@5 646 if IsControlKeyDown() then
Nenue@5 647 modifier = modifier.. 'CTRL-'
Nenue@5 648 end
Nenue@5 649 if IsShiftKeyDown() then
Nenue@5 650 modifier = modifier..'SHIFT-'
Nenue@5 651 end
Nenue@5 652
Nenue@5 653
Nenue@5 654 if self.command then
Nenue@5 655 self.binding = modifier..key
Nenue@5 656
Nenue@5 657 local previousKeys
Nenue@5 658 local previousAction = GetBindingAction(self.binding)
Nenue@5 659 local binding1, binding2, new1, new2
Nenue@5 660 print(type(previousAction), previousAction)
Nenue@5 661 if previousAction ~= "" and previousAction ~= self.command then
Nenue@5 662 if protected[previousAction] then
Nenue@5 663 -- bounce out if trying to use a protected key
Nenue@5 664 kb.statustext:SetText(BINDING_FAILED_PROTECTED:format(key, GetBindingAction(previousAction)))
Nenue@5 665 kb.bindingstext:SetText(nil)
Nenue@5 666 return
Nenue@5 667 else
Nenue@5 668 kb:print('Discarding keybind for', previousAction)
Nenue@5 669 -- todo: sort out retcon'd talent spells
Nenue@5 670 end
Nenue@5 671 end
Nenue@5 672
Nenue@5 673 self.pending = true
Nenue@5 674
Nenue@5 675 bindsCommitted = false
Nenue@5 676 SetBinding(self.binding, self.command)
Nenue@5 677 SaveBindings(GetCurrentBindingSet())
Nenue@5 678
Nenue@5 679 local talentInfo
Nenue@5 680 if self.actionType == 'spell' and kb.TalentCache[self.actionID] then
Nenue@5 681 print('conditional binding (talent = "'..self.actionName..'")')
Nenue@5 682 talentInfo = {self.macroName, self.actionName, self.actionType, self.actionID}
Nenue@5 683 local bindings = {GetBindingKey(self.command) }
Nenue@5 684 for i, key in ipairs(bindings) do
Nenue@5 685 tinsert(talentInfo, key)
Nenue@5 686 end
Nenue@5 687 end
Nenue@5 688
Nenue@5 689 for level, configProfile in ipairs(priority) do
Nenue@5 690 if (level == bindMode) then
Nenue@5 691 configProfile.bound[self.command] = true
Nenue@5 692 if talentInfo then
Nenue@5 693 configProfile.bindings[self.binding] = nil
Nenue@5 694 else
Nenue@5 695 configProfile.bindings[self.binding] = self.command
Nenue@5 696 end
Nenue@5 697 configProfile.talents[self.actionName] = talentInfo
Nenue@5 698 else
Nenue@5 699 configProfile.bindings[self.binding] = nil
Nenue@5 700 configProfile.bound[self.command] = nil
Nenue@5 701 configProfile.talents[self.actionName] = nil
Nenue@5 702 end
Nenue@5 703 if configProfile.talents[self.actionID] then
Nenue@5 704 configProfile.talents[self.actionID] = nil
Nenue@5 705 end
Nenue@5 706
Nenue@5 707 end
Nenue@5 708
Nenue@5 709
Nenue@5 710
Nenue@5 711 kb:print(BINDING_ASSIGNED:format(self.binding, self.actionName, configHeaders[bindMode]))
Nenue@5 712
Nenue@5 713 end
Nenue@0 714 end
Nenue@0 715
Nenue@5 716 kb.UpdateSlot(self, true)
Nenue@5 717 KeyBinderSaveButton:Enable()
Nenue@0 718
Nenue@0 719 end
Nenue@0 720
Nenue@0 721 --- Resets button command
Nenue@5 722 kb.ReleaseSlot = function(self)
Nenue@5 723 local slot = self:GetID()
Nenue@5 724
Nenue@5 725
Nenue@5 726 if configProfile.buttons[slot] then
Nenue@5 727 configProfile.buttons[slot] = nil
Nenue@5 728 end
Nenue@5 729 if self.command then
Nenue@5 730 configProfile.commands[self.command] = nil
Nenue@5 731 end
Nenue@5 732 if self.actionType == 'spell' and IsTalentSpell(self.actionName) then
Nenue@5 733 if configProfile.talents[self.actionID] then
Nenue@5 734 configProfile.talents[self.actionID] = nil
Nenue@5 735 end
Nenue@5 736 end
Nenue@5 737 local droppedKeys = {}
Nenue@5 738
Nenue@5 739 -- doing removal in second loop to avoid possible iterator shenanigans
Nenue@5 740 for k,v in pairs(configProfile.bindings) do
Nenue@5 741 if v == self.command then
Nenue@5 742 tinsert(droppedKeys, k)
Nenue@5 743 end
Nenue@5 744 end
Nenue@5 745 if #droppedKeys >=1 then
Nenue@5 746 for i, k in ipairs(droppedKeys) do
Nenue@5 747 configProfile.bindings[k] = nil
Nenue@5 748 end
Nenue@5 749 end
Nenue@5 750
Nenue@5 751 self.isAvailable = nil
Nenue@5 752 self.isDynamic = nil
Nenue@5 753 self.bindingText = nil
Nenue@5 754 self.statusText = nil
Nenue@0 755 self.command = nil
Nenue@5 756 self.actionType = nil
Nenue@5 757 self.actionID = nil
Nenue@0 758 self.actionName = nil
Nenue@5 759 self.pickupSlot = nil
Nenue@5 760 self.pickupBook = nil
Nenue@5 761 self.macroName = nil
Nenue@0 762 self.profile = nil
Nenue@0 763 self.icon:SetTexture(nil)
Nenue@0 764 self.border:SetColorTexture(unpack(BORDER_UNASSIGNED))
Nenue@0 765 self:EnableKeyboard(false)
Nenue@0 766 self:SetScript('OnKeyDown', nil)
Nenue@0 767 end
Nenue@0 768
Nenue@5 769 kb.SetSlot = function(self, command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook)
Nenue@5 770 local slot = self:GetID()
Nenue@5 771 local isDynamic, isAvailable
Nenue@0 772
Nenue@5 773 print('|cFFFFFF00SetSlot|r:', self:GetID())
Nenue@5 774 if command then
Nenue@0 775
Nenue@5 776 if actionType == 'spell' then
Nenue@5 777 local professionNum, spellNum = command:match("profession_(%d)_(%d)")
Nenue@0 778
Nenue@5 779 if (professionNum and spellNum) then
Nenue@5 780 isDynamic = 'profession'
Nenue@5 781 local cacheInfo = kb.ProfessionCache[professionNum..'_'..spellNum]
Nenue@5 782 if cacheInfo then
Nenue@5 783 isAvailable = true
Nenue@5 784 name = cacheInfo.spellName
Nenue@5 785 icon = cacheInfo.icon
Nenue@5 786 actionID = cacheInfo.spellID
Nenue@5 787 self.profIndex = cacheInfo.profIndex
Nenue@5 788 self.spellOffset = cacheInfo.spellOffset
Nenue@5 789 end
Nenue@5 790 print(' Special slot: |cFF00FFFFProfession|r', professionNum, spellNum, isDynamic, isAvailable)
Nenue@5 791
Nenue@5 792 self.professionNum = tonumber(professionNum)
Nenue@5 793 self.spellNum = tonumber(spellNum)
Nenue@5 794
Nenue@5 795 elseif kb.TalentCache[actionID] then
Nenue@5 796
Nenue@5 797 isDynamic = 'talent'
Nenue@5 798 isAvailable = GetSpellInfo(name)
Nenue@5 799 print(' Special slot: |cFFBBFF00talent|r', name, isAvailable)
Nenue@5 800 end
Nenue@5 801 if not actionID then
Nenue@5 802 actionID = select(7, GetSpellInfo(name))
Nenue@5 803 end
Nenue@5 804 elseif actionType == 'macro' then
Nenue@5 805 if not actionID then
Nenue@5 806 actionID = GetMacroIndexByName(name)
Nenue@5 807 end
Nenue@5 808 else
Nenue@5 809 --- Journal selections
Nenue@5 810 -- todo: consider using the deep end of blizzard action bar instead
Nenue@5 811 if not actionID then
Nenue@5 812 actionID = command:match("^KeyBinderMacro:(.+)")
Nenue@5 813 end
Nenue@0 814 end
Nenue@0 815
Nenue@5 816 if not macroName then
Nenue@5 817 local previousCommand = command
Nenue@5 818 macroName, macroText, command = kb.RegisterAction(actionType, actionID)
Nenue@0 819
Nenue@5 820 -- Clean up conflicting command entry for loaded buttons
Nenue@5 821 if macroName and command ~= previousCommand then
Nenue@5 822 print(' Repaired corruption in |cFFFFFF00'..currentHeader..'|r button #'.. self:GetID())
Nenue@5 823 configProfile.commands[previousCommand] = nil
Nenue@5 824 configProfile.bound[previousCommand] = nil
Nenue@5 825 end
Nenue@0 826 end
Nenue@0 827
Nenue@5 828 if actionType == 'petaction' then
Nenue@5 829 self.pickupSlot = pickupSlot
Nenue@5 830 self.pickupBook = pickupBook
Nenue@5 831 else
Nenue@5 832 self.pickupSlot = nil
Nenue@5 833 self.pickupBook = nil
Nenue@5 834 end
Nenue@5 835
Nenue@5 836 actionID = actionID or 0
Nenue@5 837 self:EnableKeyboard(true)
Nenue@5 838 print(' |cFF00FF00configProfile.buttons['..slot..'] |cFF00FFFF=|r |cFF00FFFF"'.. command.. '"|r |cFF00FF00"'.. name, '"|r |cFFFFFF00icon:'.. icon .. '|r |cFFFF8800"'.. actionType, '"|r |cFFFF0088id:'.. actionID ..'|r |cFF00FF00"'.. macroName .. '"|r')
Nenue@5 839 configProfile.buttons[slot] = {command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook}
Nenue@5 840
Nenue@5 841 -- Clean up conflicting entries for loaded button
Nenue@5 842 local previous = configProfile.commands[command]
Nenue@5 843 if previous ~= slot and buttons[previous] then
Nenue@5 844 kb.ReleaseSlot(buttons[previous])
Nenue@5 845 end
Nenue@5 846 configProfile.commands[command] = slot
Nenue@0 847 end
Nenue@0 848
Nenue@5 849 self.isAvailable = isAvailable
Nenue@5 850 self.isDynamic = isDynamic
Nenue@5 851
Nenue@5 852 self.macroText = macroText
Nenue@5 853 self.macroName = macroName
Nenue@5 854 self.actionType = actionType
Nenue@5 855 self.actionID = actionID
Nenue@0 856 self.actionName = name
Nenue@0 857 self.command = command
Nenue@0 858 self.icon:SetTexture(icon)
Nenue@5 859 self.profile = bindMode
Nenue@0 860 self:RegisterForDrag('LeftButton')
Nenue@0 861 end
Nenue@0 862
Nenue@0 863 --- Retrieves button at index; creates said button and instates any stored parameters
Nenue@5 864 local leftSlot, upSlot
Nenue@5 865 local buttonsDepth = 0
Nenue@5 866 kb.GetSlot = function(index)
Nenue@5 867
Nenue@5 868 local slot = index + kb.scrollOffset
Nenue@5 869
Nenue@0 870 if not buttons[index] then
Nenue@0 871 local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, kb, 'KeyButton')
Nenue@5 872 button:SetScript('OnClick', KeyButton_OnClick)
Nenue@5 873 button:SetScript('OnUpdate', KeyButton_OnUpdate)
Nenue@5 874 button:SetScript('OnDragStart', KeyButton_OnDragStart)
Nenue@5 875 button:SetScript('OnReceiveDrag', KeyButton_OnReceiveDrag)
Nenue@5 876 button:RegisterForClicks('AnyUp')
Nenue@0 877
Nenue@5 878
Nenue@5 879 local newRow = (mod(index, BINDS_PER_ROW) == 1)
Nenue@5 880
Nenue@5 881 if index == 1 then
Nenue@5 882 button:SetPoint('TOPLEFT', kb.bg, 'TOPLEFT', BUTTON_PADDING, - BUTTON_PADDING)
Nenue@5 883 upSlot = button
Nenue@5 884 buttonsDepth = KEY_BUTTON_SIZE + BUTTON_PADDING * 2
Nenue@5 885 elseif newRow then
Nenue@5 886 button:SetPoint('TOPLEFT', upSlot, 'BOTTOMLEFT', 0, -BUTTON_SPACING)
Nenue@5 887 upSlot = button
Nenue@5 888 buttonsDepth = buttonsDepth + KEY_BUTTON_SIZE + BUTTON_SPACING
Nenue@0 889 else
Nenue@5 890 button:SetPoint('TOPLEFT', leftSlot, 'TOPRIGHT', BUTTON_HSPACING, 0)
Nenue@0 891 end
Nenue@0 892
Nenue@0 893 button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE)
Nenue@0 894 button:Show()
Nenue@0 895 buttons[index] = button
Nenue@5 896 leftSlot = button
Nenue@0 897 end
Nenue@0 898 return buttons[index]
Nenue@0 899 end
Nenue@0 900
Nenue@0 901 --- Updates profile assignment and button contents
Nenue@5 902 kb.UpdateSlot = function(self, force)
Nenue@5 903 local slot = self:GetID()
Nenue@5 904
Nenue@5 905 if force then
Nenue@5 906 if configProfile.buttons[slot] then
Nenue@5 907 kb.SetSlot(self, unpack(configProfile.buttons[slot]))
Nenue@0 908 else
Nenue@5 909 kb.ReleaseSlot(self)
Nenue@0 910 end
Nenue@0 911 end
Nenue@0 912
Nenue@0 913 if self.command then
Nenue@5 914 print('['..slot..'] =', self.command, GetBindingKey(self.command))
Nenue@5 915
Nenue@0 916 if self.pending then
Nenue@0 917 self.border:SetColorTexture(unpack(BORDER_PENDING))
Nenue@5 918 elseif self.isDynamic then
Nenue@5 919 self.border:SetColorTexture(unpack(BORDER_DYNAMIC))
Nenue@0 920 else
Nenue@0 921 self.border:SetColorTexture(unpack(BORDER_ASSIGNED))
Nenue@0 922 end
Nenue@5 923
Nenue@5 924 if self.actionType == 'macro' then
Nenue@5 925 self.macro:Show()
Nenue@5 926 else
Nenue@5 927 self.macro:Hide()
Nenue@5 928 if self.actionType == 'spell' then
Nenue@5 929 local dummy = GetSpellInfo(self.actionName)
Nenue@5 930 if not dummy then
Nenue@5 931 self.icon:SetDesaturated(true)
Nenue@5 932 else
Nenue@5 933 self.icon:SetDesaturated(false)
Nenue@5 934 end
Nenue@5 935
Nenue@5 936 end
Nenue@5 937 end
Nenue@5 938
Nenue@5 939 if self.isDynamic then
Nenue@5 940 print('|cFFFFBB00UpdateSlot|r: ', self.isDynamic, self.isAvailable, self.actionID)
Nenue@5 941 end
Nenue@5 942
Nenue@5 943 if self.isDynamic == 'profession' then
Nenue@5 944 local profText = (self.spellNum == 1) and TRADE_SKILLS or (BUTTON_HEADERS[self.profIndex] or GetProfessionInfo(self.profIndex))
Nenue@5 945 if self.isAvailable then
Nenue@5 946 print(self.profIndex, 'spnum', type(self.spellNum), (self.spellNum == 1))
Nenue@5 947
Nenue@5 948 self.statusText = '|cFFFFFF00'..profText..'|r'
Nenue@5 949 self.bindingText = BindingString(GetBindingKey(self.command))
Nenue@5 950 else
Nenue@5 951 self.statusText = '|cFFFF4400'..profText..'|r'
Nenue@5 952 self.actionName = '(need to train profession #'..self.profNum..')'
Nenue@5 953 self.bindingText ='?'
Nenue@5 954 end
Nenue@5 955 elseif self.isDynamic == 'talent' then
Nenue@5 956
Nenue@5 957 self.statusText = '|cFF00FFFF'.. TALENT .. '|r'
Nenue@5 958 if self.isAvailable then
Nenue@5 959 self.bindingText = BindingString(GetBindingKey(self.command))
Nenue@5 960 else
Nenue@5 961 print(self.actionID, #kb.inactiveTalentBindings[self.actionID])
Nenue@5 962 self.bindingText= BindingString(unpack(kb.inactiveTalentBindings[self.actionID]))
Nenue@5 963 end
Nenue@5 964 else
Nenue@5 965 self.statusText = '|cFF00FF00'.. (BUTTON_HEADERS[self.actionType] and BUTTON_HEADERS[self.actionType] or self.actionType) .. '|r'
Nenue@5 966 self.bindingText = BindingString(GetBindingKey(self.command))
Nenue@5 967 end
Nenue@5 968
Nenue@5 969 local locked, layer = IsCommandBound(self)
Nenue@5 970 if locked then
Nenue@5 971 self.icon:SetAlpha(0.5)
Nenue@5 972 else
Nenue@5 973 self.icon:SetAlpha(1)
Nenue@5 974 end
Nenue@5 975
Nenue@5 976 if self.actionType == 'spell' then
Nenue@5 977 self.icon:SetTexture(GetSpellTexture(self.actionID))
Nenue@5 978 end
Nenue@5 979 end
Nenue@5 980
Nenue@5 981 if not self.isAvailable then
Nenue@5 982 self.bind:SetTextColor(0.7,0.7,0.7,1)
Nenue@0 983 else
Nenue@5 984 self.bind:SetTextColor(1,1,1,1)
Nenue@5 985 end
Nenue@5 986
Nenue@5 987 self.header:SetText(self.statusText)
Nenue@5 988 self.bind:SetText(self.bindingText)
Nenue@5 989 self.macro:SetText(self.macroName)
Nenue@5 990 self.details:SetText(self.actionName)
Nenue@5 991 end
Nenue@5 992
Nenue@5 993
Nenue@5 994 kb.ApplyTalentBinding = function(talentInfo, cache)
Nenue@5 995 for i = 5, #talentInfo do
Nenue@5 996 SetBinding(talentInfo[i], "CLICK KeyBinderMacro:".. talentInfo[1])
Nenue@5 997 tinsert(cache, talentInfo[i])
Nenue@0 998 end
Nenue@0 999 end
Nenue@5 1000 kb.CacheTalentBinding = function(talentInfo, cache)
Nenue@5 1001 local spellID = talentInfo[4]
Nenue@5 1002 kb.inactiveTalentBindings[spellID] = kb.inactiveTalentBindings[spellID] or {}
Nenue@5 1003 kb.inactiveTalentBindings[spellID] = {select(5,unpack(talentInfo)) }
Nenue@5 1004 cprint(spellID, unpack(kb.inactiveTalentBindings[spellID]))
Nenue@0 1005 end
Nenue@0 1006
Nenue@5 1007 kb.ApplyBinding = function(command, name, icon, actionType, actionID, macroName, macroText )
Nenue@5 1008
Nenue@5 1009 if actionType == 'macro' then
Nenue@5 1010 KeyBinderMacro:SetAttribute("*macro-"..macroName, actionID)
Nenue@5 1011 else
Nenue@5 1012 KeyBinderMacro:SetAttribute("*macrotext-"..macroName, macroText)
Nenue@5 1013 end
Nenue@5 1014 bindings[actionType] = bindings[actionType] or {}
Nenue@5 1015 bindings[actionType][actionID] = bindings[actionType][actionID] or {}
Nenue@5 1016 bindings[command] = bindings[actionType][actionID]
Nenue@5 1017 return bindings[actionType], actionID
Nenue@5 1018 end
Nenue@5 1019
Nenue@5 1020 kb.ApplyBindings = function (profile)
Nenue@5 1021 cprint('binding profile', profile)
Nenue@5 1022 for slot, data in pairs(profile.buttons) do
Nenue@5 1023 kb.ApplyBinding(unpack(data))
Nenue@5 1024 end
Nenue@5 1025
Nenue@5 1026 for key, command in pairs(profile.bindings) do
Nenue@5 1027
Nenue@5 1028 cprint('Bindings data registered', command, key)
Nenue@5 1029
Nenue@5 1030 --_G.print('HotKey','loading', key, command)
Nenue@5 1031 SetBinding(key, command)
Nenue@5 1032 if bindings[command] and not tContains(bindings[command], key) then
Nenue@5 1033 tinsert(bindings[command], key)
Nenue@5 1034 end
Nenue@5 1035 end
Nenue@5 1036
Nenue@5 1037 for spellName, talentInfo in pairs(profile.talents) do
Nenue@5 1038 local dummy = GetSpellInfo(spellName)
Nenue@5 1039 local func = kb.CacheTalentBinding
Nenue@5 1040 local dest = kb.inactiveTalentBindings
Nenue@5 1041 if dummy then
Nenue@5 1042 cprint('|cFFBBFF00Active:|r', dummy)
Nenue@5 1043 local macroName, spellName, actionType, actionID = unpack(talentInfo)
Nenue@5 1044 bindings[actionType] = bindings[actionType] or {}
Nenue@5 1045 bindings[actionType][actionID] = {}
Nenue@5 1046 func = kb.ApplyTalentBinding
Nenue@5 1047 dest = bindings[actionType][actionID]
Nenue@5 1048 else
Nenue@5 1049
Nenue@5 1050 cprint('|cFFFF4400Inactive:|r', talentInfo[2])
Nenue@5 1051 end
Nenue@5 1052 func(talentInfo, dest)
Nenue@5 1053 end
Nenue@5 1054
Nenue@5 1055 SaveBindings(GetCurrentBindingSet())
Nenue@5 1056 end
Nenue@5 1057
Nenue@5 1058 kb.ApplyAllBindings =function ()
Nenue@5 1059 table.wipe(kb.inactiveTalentBindings)
Nenue@5 1060
Nenue@5 1061 for i, profile in ipairs(priority) do
Nenue@5 1062 kb.ApplyBindings(profile)
Nenue@5 1063 end
Nenue@5 1064 -- do this after to ensure that profession binds are properly overridden
Nenue@5 1065 kb.UpdateProfessionInfo()
Nenue@5 1066 end
Nenue@5 1067
Nenue@5 1068 kb.Command = function(args, editor)
Nenue@5 1069 if args:match("import") then
Nenue@5 1070 kb.ImportCommmit(args)
Nenue@5 1071 return
Nenue@5 1072 elseif args:match("scan") then
Nenue@5 1073 kb.ImportScan(args)
Nenue@5 1074 kb.ui()
Nenue@5 1075 return
Nenue@5 1076 elseif args:match("load") then
Nenue@5 1077 kb:ApplyAllBindings()
Nenue@0 1078 return
Nenue@0 1079 end
Nenue@0 1080
Nenue@5 1081 if db.showUI then
Nenue@5 1082 db.showUI = false
Nenue@5 1083 kb:print('|cFFFFFF00KeyBinds|r trace, |cFFFF0000OFF|r.')
Nenue@5 1084 kb:Hide()
Nenue@5 1085 else
Nenue@1 1086 db.showUI = true
Nenue@5 1087 kb:print('|cFFFFFF00KeyBinds|r trace, |cFF00FF00ON|r.')
Nenue@5 1088 end
Nenue@5 1089 kb.ui(true)
Nenue@5 1090 end
Nenue@5 1091
Nenue@5 1092 kb.InitProfile = function(profile, prototype)
Nenue@5 1093 if not profile then
Nenue@5 1094 profile = {}
Nenue@5 1095 end
Nenue@5 1096 if prototype then
Nenue@5 1097 print('appplying prototype', prototype)
Nenue@5 1098 for k,v in pairs(prototype) do
Nenue@5 1099 if not profile[k] then
Nenue@5 1100 profile[k] = v
Nenue@5 1101 end
Nenue@5 1102 end
Nenue@0 1103 end
Nenue@0 1104
Nenue@5 1105 profile.bound = profile.bound or {}
Nenue@5 1106 profile.buttons = profile.buttons or {}
Nenue@5 1107 profile.commands = profile.commands or {}
Nenue@5 1108 profile.bindings = profile.bindings or {}
Nenue@5 1109 profile.macros = profile.macros or {}
Nenue@5 1110 profile.talents = profile.talents or {}
Nenue@5 1111 return profile
Nenue@5 1112 end
Nenue@5 1113
Nenue@5 1114 kb.ResetProfile = function(profile, prototype)
Nenue@5 1115 if profile == configProfile then
Nenue@5 1116 for i, button in pairs(buttons) do
Nenue@5 1117 kb.ReleaseSlot(button)
Nenue@5 1118 end
Nenue@5 1119 end
Nenue@5 1120 table.wipe(profile)
Nenue@5 1121 kb.InitProfile(profile, prototype)
Nenue@5 1122 end
Nenue@5 1123
Nenue@5 1124
Nenue@5 1125
Nenue@5 1126 --- Handles constructing spec profiles as they are selected
Nenue@5 1127
Nenue@5 1128
Nenue@5 1129 kb.TalentCache = {}
Nenue@5 1130
Nenue@5 1131 kb.UpdateSpecInfo = function()
Nenue@5 1132 specID = GetSpecialization()
Nenue@5 1133 specGlobalID, specName, specDesc , specTexture = GetSpecializationInfo(specID)
Nenue@5 1134 loadedProfiles[BINDING_TYPE_CHARACTER][specID] = kb.InitProfile(loadedProfiles[BINDING_TYPE_CHARACTER][specID], {
Nenue@5 1135 specID = specID})
Nenue@5 1136
Nenue@5 1137 configHeaders[BINDING_TYPE_SPECIALIZATION] = BINDING_MODE[BINDING_TYPE_SPECIALIZATION]:format(specName)
Nenue@5 1138 loadedProfiles[BINDING_TYPE_SPECIALIZATION] = loadedProfiles[BINDING_TYPE_CHARACTER][specID]
Nenue@5 1139 configProfile = loadedProfiles[bindMode]
Nenue@5 1140 print('|cFF00FF00bindMode:|r', bindMode)
Nenue@5 1141
Nenue@5 1142 priority = {loadedProfiles[BINDING_TYPE_GLOBAL], loadedProfiles[BINDING_TYPE_CHARACTER], loadedProfiles[BINDING_TYPE_SPECIALIZATION]}
Nenue@5 1143
Nenue@5 1144 print('|cFF00FF00current spec:|r', specID, 'of', GetNumSpecializations())
Nenue@5 1145 end
Nenue@5 1146
Nenue@5 1147 kb.UpdateTalentInfo = function()
Nenue@5 1148 if kb.talentsPushed then
Nenue@5 1149 return
Nenue@5 1150 end
Nenue@5 1151
Nenue@5 1152
Nenue@5 1153 table.wipe(kb.TalentCache)
Nenue@5 1154
Nenue@5 1155 for row =1, MAX_TALENT_TIERS do
Nenue@5 1156 for col = 1, NUM_TALENT_COLUMNS do
Nenue@5 1157 local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1)
Nenue@5 1158 local talentInfo = kb.TalentCache[spellID] or {}
Nenue@5 1159 talentInfo.row = 1
Nenue@5 1160 talentInfo.col = col
Nenue@5 1161 talentInfo.name = talentName
Nenue@5 1162 talentInfo.talentID = talentID
Nenue@5 1163 talentInfo.selected = selected
Nenue@5 1164 talentInfo.available = available
Nenue@5 1165 talentInfo.spellID = spellID
Nenue@5 1166 kb.TalentCache[spellID] = talentInfo
Nenue@5 1167 print('Talent ', row, col, spellID, talentName)
Nenue@5 1168 end
Nenue@5 1169 end
Nenue@5 1170 kb.talentsPushed = true
Nenue@5 1171 end
Nenue@5 1172
Nenue@5 1173
Nenue@5 1174 kb.ProfessionCache = {}
Nenue@5 1175 kb.UpdateProfessionInfo = function()
Nenue@5 1176 table.wipe(kb.ProfessionCache)
Nenue@5 1177 local profs = {GetProfessions() }
Nenue@5 1178 local primaryNum = 0
Nenue@5 1179 for i, index in ipairs(profs) do
Nenue@5 1180 local profName, texture, rank, maxRank, numSpells, spellOffset = GetProfessionInfo(index)
Nenue@5 1181 cprint(i, index, profName, numSpells, spellOffset)
Nenue@5 1182 if not professionMappings[index] then
Nenue@5 1183 primaryNum = primaryNum + 1
Nenue@5 1184 end
Nenue@5 1185 local profNum = professionMappings[index] or primaryNum
Nenue@5 1186
Nenue@5 1187
Nenue@5 1188 kb.ProfessionCache[profNum] = kb.ProfessionCache[i] or {}
Nenue@5 1189
Nenue@5 1190 for j = 1, numSpells do
Nenue@5 1191 local spellName, _, icon, _, _, _, spellID = GetSpellInfo(spellOffset+j, BOOKTYPE_PROFESSION)
Nenue@5 1192
Nenue@5 1193 local profInfo = {
Nenue@5 1194 spellName = spellName,
Nenue@5 1195 spellID = spellID,
Nenue@5 1196 icon = icon,
Nenue@5 1197 profOffset = i,
Nenue@5 1198 profIndex = index,
Nenue@5 1199 spellOffset = (spellOffset+j),
Nenue@5 1200 spellNum = j
Nenue@5 1201 }
Nenue@5 1202 KeyBinderMacro:SetAttribute("*macrotext-profession_"..i .. '_' ..j, "/cast ".. spellName)
Nenue@5 1203
Nenue@5 1204 kb.ProfessionCache[i .. '_' .. j] = profInfo
Nenue@5 1205 kb.ProfessionCache[spellName] = profInfo
Nenue@5 1206 kb.ProfessionCache[spellID] = profInfo
Nenue@5 1207 cprint(' |cFF0088FF['..i..']|r|cFFFF44BB['..spellOffset+i..']|r', spellName, "*macrotext-profession_"..i .. '_' ..j)
Nenue@5 1208 end
Nenue@5 1209
Nenue@5 1210 end
Nenue@5 1211
Nenue@5 1212 end
Nenue@5 1213
Nenue@5 1214 --- Obtains profile data or creates the necessary tables
Nenue@5 1215 kb.SelectProfileSet = function(name)
Nenue@5 1216
Nenue@5 1217 --- General info
Nenue@5 1218 classHeader, className, classID = UnitClass('player')
Nenue@5 1219 print('|cFF00FF00profile:|r', name)
Nenue@5 1220 print('|cFF00FF00class:|r', UnitClass('player'))
Nenue@5 1221
Nenue@5 1222 --- Global
Nenue@5 1223 bindMode = BINDING_TYPE_GLOBAL
Nenue@5 1224 kb.InitProfile(db)
Nenue@5 1225 loadedProfiles[BINDING_TYPE_GLOBAL] = db
Nenue@5 1226
Nenue@5 1227 --- Character
Nenue@5 1228 if name then
Nenue@5 1229 db[name] = kb.InitProfile(db[name],
Nenue@5 1230 {classHeader = classHeader, className = className, classID = classID})
Nenue@5 1231 loadedProfiles[BINDING_TYPE_CHARACTER] = db[name]
Nenue@5 1232 bindMode = BINDING_TYPE_CHARACTER
Nenue@5 1233 end
Nenue@5 1234
Nenue@5 1235 --- Mutable skills data
Nenue@5 1236 kb.UpdateSpecInfo()
Nenue@5 1237 kb.UpdateTalentInfo()
Nenue@5 1238
Nenue@5 1239 priority = {loadedProfiles[BINDING_TYPE_GLOBAL], loadedProfiles[BINDING_TYPE_CHARACTER], loadedProfiles[BINDING_TYPE_SPECIALIZATION]}
Nenue@5 1240 if db.bindMode and loadedProfiles[db.bindMode] then
Nenue@5 1241 bindMode = db.bindMode
Nenue@5 1242 end
Nenue@5 1243
Nenue@5 1244 db.bindMode = bindMode
Nenue@5 1245
Nenue@5 1246 if not BINDING_MODE[bindMode] then
Nenue@5 1247 bindMode = 3
Nenue@5 1248 db.bindMode = 3
Nenue@5 1249 print('overriding', bindMode)
Nenue@5 1250 end
Nenue@5 1251
Nenue@5 1252 print(BINDING_TYPE_GLOBAL)
Nenue@5 1253 configHeaders[BINDING_TYPE_GLOBAL] = BINDING_MODE[BINDING_TYPE_GLOBAL]
Nenue@5 1254 configHeaders[BINDING_TYPE_CHARACTER] = BINDING_MODE[BINDING_TYPE_CHARACTER]:format(UnitName('player', true))
Nenue@5 1255 configHeaders[BINDING_TYPE_SPECIALIZATION] = BINDING_MODE[BINDING_TYPE_SPECIALIZATION]:format(specName)
Nenue@5 1256
Nenue@5 1257
Nenue@5 1258 setmetatable(loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return configHeaders[BINDING_TYPE_GLOBAL] end})
Nenue@5 1259 setmetatable(loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return configHeaders[BINDING_TYPE_CHARACTER] end})
Nenue@5 1260 setmetatable(loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return configHeaders[BINDING_TYPE_SPECIALIZATION] end})
Nenue@5 1261
Nenue@5 1262 print('|cFF00FF00bindMode:|r', bindMode)
Nenue@5 1263 configProfile = loadedProfiles[bindMode]
Nenue@5 1264 end
Nenue@5 1265
Nenue@5 1266 local scrollCache = {}
Nenue@5 1267 kb.SelectTab = function(self)
Nenue@5 1268 scrollCache[bindMode] = kb.scrollOffset
Nenue@5 1269 bindMode = self:GetID()
Nenue@5 1270 configProfile = loadedProfiles[self:GetID()]
Nenue@5 1271 db.bindMode = self:GetID()
Nenue@5 1272 kb.scrollOffset = scrollCache[bindMode] or 0
Nenue@5 1273 kb.ui(true)
Nenue@5 1274 end
Nenue@5 1275
Nenue@5 1276 kb.RevertBindings = function()
Nenue@5 1277 -- todo: reversion code
Nenue@5 1278 end
Nenue@5 1279
Nenue@5 1280 kb.ConfirmBindings = function()
Nenue@5 1281 SaveBindings(GetCurrentBindingSet())
Nenue@5 1282 bindsCommitted = true
Nenue@5 1283 for i, button in ipairs(buttons) do
Nenue@5 1284 button.pending = false
Nenue@5 1285 end
Nenue@5 1286 kb.ApplyAllBindings()
Nenue@5 1287
Nenue@5 1288 kb.ui()
Nenue@5 1289 kb:print('Keybinds saved.')
Nenue@5 1290 end
Nenue@5 1291
Nenue@5 1292
Nenue@5 1293
Nenue@5 1294
Nenue@5 1295
Nenue@5 1296
Nenue@5 1297 --- push current information into living UI
Nenue@5 1298 kb.ui = function(force)
Nenue@5 1299 for i, module in ipairs(kb.modules) do
Nenue@5 1300 if module.ui then
Nenue@5 1301 module.ui(force)
Nenue@5 1302 end
Nenue@5 1303 end
Nenue@5 1304
Nenue@5 1305 if not db.showUI then
Nenue@5 1306 print('---end of refresh')
Nenue@5 1307 return
Nenue@5 1308 end
Nenue@0 1309 if not kb.loaded then
Nenue@5 1310 KeyBinder_Initialize()
Nenue@0 1311 kb.loaded = true
Nenue@0 1312 end
Nenue@0 1313 for i = 1, numButtons do
Nenue@5 1314 local button = kb.GetSlot(i)
Nenue@5 1315 button:SetID(i+kb.scrollOffset)
Nenue@5 1316 kb.UpdateSlot(button, force)
Nenue@0 1317 end
Nenue@0 1318
Nenue@0 1319 if bindsCommitted then
Nenue@0 1320 KeyBinderSaveButton:Disable()
Nenue@5 1321 --KeyBinderRestoreButton:Disable()
Nenue@0 1322 else
Nenue@0 1323 KeyBinderSaveButton:Enable()
Nenue@5 1324 --KeyBinderRestoreButton:Enable()
Nenue@0 1325 end
Nenue@0 1326
Nenue@5 1327 --- Frame Sizing
Nenue@5 1328 kb.profilebg:SetHeight(kb.tabSize[2] + BUTTON_PADDING * 2 + kb.profiletext:GetStringHeight())
Nenue@5 1329
Nenue@5 1330 kb.bg:SetWidth((KEY_BUTTON_SIZE + BUTTON_HSPACING + BUTTON_SPACING) * BINDS_PER_ROW + BUTTON_PADDING*2 - BUTTON_SPACING)
Nenue@0 1331 local numRows = numButtons/BINDS_PER_ROW
Nenue@5 1332
Nenue@5 1333 kb.bg:SetHeight((KEY_BUTTON_SIZE + BUTTON_SPACING) * numRows + BUTTON_PADDING*2 - BUTTON_SPACING)
Nenue@5 1334
Nenue@5 1335 kb:SetHeight(kb.headerbg:GetHeight() + kb.profilebg:GetHeight() + kb.bg:GetHeight() + kb.footer:GetHeight())
Nenue@5 1336 kb:SetWidth((kb.sourcesbg:GetWidth() +(BINDS_PER_ROW * (KEY_BUTTON_SIZE + BUTTON_HSPACING) + (BINDS_PER_ROW - 1) * BUTTON_SPACING + BUTTON_PADDING * 2) ))
Nenue@5 1337
Nenue@0 1338 kb.bg:SetColorTexture(unpack(BINDING_SCHEME_COLOR[bindMode]))
Nenue@0 1339 for i, tab in ipairs(kb.tabButtons) do
Nenue@5 1340 local border = tab:GetNormalTexture()
Nenue@0 1341 local tabTexture = "Interface\\Buttons\\UI-Quickslot2"
Nenue@0 1342 local left, top, right, bottom = -12, 12, 13, -13
Nenue@0 1343 if i == bindMode then
Nenue@0 1344 tabTexture = "Interface\\Buttons\\CheckButtonGlow"
Nenue@0 1345 left, top, right, bottom = -14, 14, 15, -15
Nenue@5 1346 tab.icon:SetDesaturated(false)
Nenue@5 1347 if tab.icon2 then tab.icon2:SetDesaturated(false) end
Nenue@5 1348 border:SetDesaturated(true)
Nenue@5 1349 border:SetVertexColor(1,1,1, 1)
Nenue@5 1350 else
Nenue@5 1351 tab.icon:SetDesaturated(true)
Nenue@5 1352 if tab.icon2 then tab.icon2:SetDesaturated(true) end
Nenue@5 1353 border:SetDesaturated(false)
Nenue@5 1354 border:SetVertexColor(1,1,1)
Nenue@0 1355 end
Nenue@5 1356 border:SetTexture(tabTexture)
Nenue@5 1357 border:SetPoint('TOPLEFT', tab, 'TOPLEFT', left, top)
Nenue@5 1358 border:SetPoint('BOTTOMRIGHT', tab, 'BOTTOMRIGHT', right, bottom)
Nenue@0 1359 end
Nenue@5 1360
Nenue@5 1361 KeyBinderSpecTab.icon:SetTexture(specTexture)
Nenue@5 1362
Nenue@5 1363 kb.profiletext:SetText(configHeaders[bindMode])
Nenue@5 1364 print(bindMode, configHeaders[bindMode], kb:GetSize())
Nenue@5 1365 print(kb:GetPoint(1))
Nenue@5 1366
Nenue@5 1367 kb:Show()
Nenue@5 1368
Nenue@5 1369 -- Reset this so talent cache can be rebuilt
Nenue@5 1370 kb.talentsPushed = nil
Nenue@0 1371 end
Nenue@0 1372
Nenue@5 1373 --- post ADDON_LOADED
Nenue@5 1374 kb.variables = function()
Nenue@5 1375 SkeletonKeyDB = SkeletonKeyDB or {spec = {}}
Nenue@5 1376 kb.db = SkeletonKeyDB
Nenue@5 1377 kb.playerName = UnitName('player')
Nenue@5 1378 kb.playerRealm = SelectedRealmName()
Nenue@5 1379 kb.profileName = kb.playerRealm .. '_' .. kb.playerName
Nenue@5 1380 db = kb.db
Nenue@5 1381
Nenue@5 1382 kb.SelectProfileSet(kb.profileName)
Nenue@5 1383 if not configProfile.imported then
Nenue@5 1384 kb.ImportScan()
Nenue@0 1385 end
Nenue@5 1386 kb.ApplyAllBindings()
Nenue@5 1387
Nenue@5 1388 kb.ui(true)
Nenue@0 1389 end
Nenue@0 1390
Nenue@1 1391
Nenue@5 1392 kb.wrap = function(module)
Nenue@5 1393 kb.modules = kb.modules or {}
Nenue@5 1394 tinsert(kb.modules, module)
Nenue@0 1395 end
Nenue@0 1396
Nenue@5 1397 -- Volatiles Access
Nenue@5 1398 kb.BindingIsLocked = BindingIsLocked
Nenue@5 1399 kb.BindingString = BindingString
Nenue@5 1400 kb.GetBindings = function() return bindings end
Nenue@5 1401 kb.GetButtons = function() return buttons end
Nenue@5 1402 kb.GetCharacterProfile = function () return loadedProfiles[BINDING_TYPE_CHARACTER] end
Nenue@5 1403 kb.GetGlobalProfile = function () return loadedProfiles[BINDING_TYPE_GLOBAL] end
Nenue@5 1404 kb.GetLooseTalents = function() return talentBindings end
Nenue@5 1405 kb.GetProfileStack = function() return priority end
Nenue@5 1406 kb.GetReverts = function() return reverts end
Nenue@5 1407 kb.GetSpecProfile = function () return loadedProfiles[BINDING_TYPE_SPECIALIZATION] end
Nenue@0 1408
Nenue@5 1409 --- Add to blizzard interfaces
Nenue@5 1410 StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = {
Nenue@5 1411 text = "Confirm moving an assigned command.",
Nenue@5 1412 button1 = OKAY,
Nenue@5 1413 button2 = CANCEL,
Nenue@5 1414 timeout = 0,
Nenue@5 1415 whileDead = 1,
Nenue@5 1416 showAlert = 1,
Nenue@5 1417 OnAccept = kb.AcceptAssignment,
Nenue@5 1418 OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end
Nenue@5 1419 }
Nenue@0 1420
Nenue@5 1421 SLASH_SKB1 = "/skb"
Nenue@5 1422 SLASH_SKB2 = "/skeletonkey"
Nenue@5 1423 SlashCmdList.SKB = kb.Command
Nenue@0 1424
Nenue@5 1425 -- This is needed to identify a spells that aren't reflected by GetCursorInfo()
Nenue@5 1426 hooksecurefunc("PickupSpellBookItem", function(slot, bookType)
Nenue@5 1427 print('|cFFFF4400PickupSpellBookItem(..', tostring(slot),', '..tostring(bookType)..')')
Nenue@5 1428 CURSOR_SPELLSLOT = slot
Nenue@5 1429 CURSOR_BOOKTYPE = bookType
Nenue@5 1430 end)
Nenue@0 1431
Nenue@5 1432 -- Pet actions
Nenue@5 1433 local isPickup
Nenue@5 1434 hooksecurefunc("PickupPetAction", function(slot, ...)
Nenue@5 1435 isPickup = GetCursorInfo()
Nenue@0 1436
Nenue@5 1437 CURSOR_PETACTION = isPickup and slot
Nenue@5 1438 print('|cFFFF4400PickupPetAction|r', isPickup, CURSOR_PETACTION)
Nenue@5 1439 end)