annotate SkeletonKey/SkeletonKey.lua @ 15:32d64e42ec9b

- resolve pet bar actions for binding slots - detect type of petaction (can be spell, stance, or 'PETACTION') - keep track of displayed pet ability slots and update them alongside pet cache refreshes
author Nenue
date Fri, 29 Jul 2016 03:27:15 -0400
parents 82170735e67c
children cdd387d39137
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@5 19 local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end
Nenue@14 20 kb.L = setmetatable({}, {
Nenue@14 21 __call = function(t, k, ...) return format(t[k] or '', ...) end
Nenue@14 22 })
Nenue@14 23 local L = kb.L
Nenue@7 24
Nenue@5 25 --- Caps Lock literals
Nenue@5 26 local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:"
Nenue@6 27 local CLICK_KEYBINDER_KEY = "CLICK KeyBinderKey:"
Nenue@5 28 local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES"
Nenue@5 29 local FOOTER_OFFSET
Nenue@5 30 local HEADER_OFFSET
Nenue@14 31 L.BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).'
Nenue@14 32 L.BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.'
Nenue@14 33 L.BINDING_FAILED_PROTECTED = '|cFFFF4400Unable to use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400)|r'
Nenue@14 34
Nenue@14 35
Nenue@5 36 local BINDING_TYPE_SPECIALIZATION = 3
Nenue@5 37 local BINDING_TYPE_CHARACTER = 2
Nenue@5 38 local BINDING_TYPE_GLOBAL = 1
Nenue@5 39
Nenue@5 40
Nenue@5 41 --- Caps Lock derivatives
Nenue@5 42 local ACTION_SCRIPT = {
Nenue@5 43 ['mount'] = "/script C_MountJournal.SummonByID(%d)",
Nenue@5 44 ['macro'] = "%s",
Nenue@5 45 ['equipset'] = "/script UseEquipmentSet(%d)",
Nenue@5 46 ['spell'] = "/cast %s",
Nenue@5 47 ['petaction'] = "/cast %s",
Nenue@5 48 ['battlepet'] = SLASH_SUMMON_BATTLE_PET1 .. " %s",
Nenue@5 49 ['item'] = "/use %s"
Nenue@5 50 }
Nenue@5 51
Nenue@15 52
Nenue@15 53 local PETACTION_SCRIPT = {
Nenue@15 54 [PET_ACTION_MOVE_TO] = SLASH_PET_MOVE_TO1,
Nenue@15 55 [PET_ACTION_ATTACK] = SLASH_PET_ATTACK1,
Nenue@15 56 [PET_ACTION_FOLLOW] = SLASH_PET_FOLLOW1,
Nenue@15 57 [PET_ACTION_WAIT] = SLASH_PET_STAY1,
Nenue@15 58 [PET_MODE_AGGRESSIVE] = SLASH_PET_AGGRESSIVE1,
Nenue@15 59 [PET_MODE_DEFENSIVE] = SLASH_PET_DEFENSIVE1,
Nenue@15 60 [PET_MODE_PASSIVE] = SLASH_PET_PASSIVE1,
Nenue@15 61 [PET_MODE_ASSIST] = SLASH_PET_ASSIST1,
Nenue@15 62 }
Nenue@15 63
Nenue@5 64 local professionMappings = {
Nenue@5 65 [5] = 3,
Nenue@5 66 [7] = 4,
Nenue@5 67 [9] = 5,
Nenue@5 68 [10] = 6
Nenue@5 69 }
Nenue@6 70 kb.configTitle = {
Nenue@5 71 [BINDING_TYPE_GLOBAL] = 'Global Binds',
Nenue@0 72 [BINDING_TYPE_CHARACTER] = 'Character: %s',
Nenue@5 73 [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s'
Nenue@0 74 }
Nenue@6 75 kb.configDescription = {
Nenue@5 76 [BINDING_TYPE_GLOBAL] = 'The bindings are applied globally.',
Nenue@5 77 [BINDING_TYPE_CHARACTER] = 'Applied when you log onto this character.',
Nenue@5 78 [BINDING_TYPE_SPECIALIZATION] = 'Applied when you log onto this character and are that specialization.',
Nenue@5 79 }
Nenue@5 80
Nenue@0 81
Nenue@0 82
Nenue@14 83 kb.inactiveTalentBindings = {}
Nenue@6 84 kb.configHeaders = {}
Nenue@6 85 kb.loadedProfiles = {}
Nenue@6 86 kb.orderedProfiles = {}
Nenue@6 87 kb.buttons = {}
Nenue@6 88 kb.macros = {}
Nenue@15 89 kb.petFrames = {} -- pet data is slightly delayed, their buttons are indexed here so they can be refreshed
Nenue@15 90 kb.talentFrames = {}
Nenue@15 91 kb.professionFrames = {}
Nenue@0 92
Nenue@14 93 -- these are sent to plugin
Nenue@14 94
Nenue@14 95 local bindings = {}
Nenue@5 96 local macros = {}
Nenue@5 97 local talentBindings = {}
Nenue@0 98
Nenue@0 99 local protected = {
Nenue@0 100 ['OPENCHATSLASH'] = true,
Nenue@0 101 ['OPENCHAT'] = true,
Nenue@0 102 }
Nenue@5 103
Nenue@14 104
Nenue@14 105 local db
Nenue@5 106 local bindHeader, currentHeader = '', ''
Nenue@5 107 local specID, specGlobalID, specName, specDesc, specTexture, characterHeader = 0, 0, 'SPEC_NAME', 'SPEC_DESCRIPTION', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME'
Nenue@5 108 local classHeader, className, classID = '', '', 0
Nenue@5 109 local bindsCommitted = true
Nenue@5 110 local forceButtonUpdate = false
Nenue@5 111
Nenue@5 112 --- Control handles
Nenue@0 113 local saveButton, restoreButton, clearButton
Nenue@0 114
Nenue@5 115 --- Returns conflicting assignment and binding profiles for use in displaying confirmations
Nenue@6 116 kb.IsCommandBound = function(self, command)
Nenue@6 117 local isAssigned, assignedBy = false, db.bindMode
Nenue@6 118 local isBound, boundBy = false, db.bindMode
Nenue@5 119
Nenue@5 120
Nenue@5 121 command = command or self.command
Nenue@6 122 for i = 1, #kb.orderedProfiles do
Nenue@6 123 local tier = kb.orderedProfiles[i]
Nenue@6 124 if i ~= db.bindMode then
Nenue@5 125
Nenue@5 126 if tier.commands[command] then
Nenue@5 127 isAssigned = true
Nenue@5 128 assignedBy = i
Nenue@5 129 end
Nenue@5 130 if tier.bound[command] then
Nenue@5 131 isBound = true
Nenue@5 132 boundBy = i
Nenue@5 133 end
Nenue@5 134
Nenue@5 135
Nenue@5 136 --print(' *', configHeaders[i], tier.commands[command], tier.bound[command])
Nenue@5 137
Nenue@5 138 if isAssigned and isBound then
Nenue@0 139 break
Nenue@0 140 end
Nenue@0 141 end
Nenue@5 142
Nenue@0 143 end
Nenue@5 144
Nenue@6 145 print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', db.bindMode .. ']', isAssigned, isBound, assignedBy, boundBy)
Nenue@5 146 return isAssigned, isBound, assignedBy, boundBy
Nenue@0 147 end
Nenue@0 148
Nenue@5 149 local talentSpellHardCodes = {
Nenue@5 150 [109248] = 'Binding Shot',
Nenue@5 151 }
Nenue@5 152
Nenue@0 153 --- Returns a value for use with Texture:SetDesaturated()
Nenue@6 154 kb.BindingIsLocked = function(key)
Nenue@0 155 local success = false
Nenue@6 156 for i = 1, db.bindMode-1 do
Nenue@6 157 local tier = kb.orderedProfiles[i]
Nenue@0 158 if tier.bindings[key] then
Nenue@0 159 success = true
Nenue@0 160 break
Nenue@0 161 end
Nenue@0 162 end
Nenue@0 163 return success
Nenue@0 164 end
Nenue@0 165
Nenue@0 166 --- Translates GetBindingKey() results into a printable string.
Nenue@6 167 kb.BindingString = function(...)
Nenue@0 168 local stack = {}
Nenue@0 169 for i = 1, select('#', ...) do
Nenue@0 170 local key = select(i, ...)
Nenue@5 171 stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ')
Nenue@0 172 end
Nenue@0 173
Nenue@0 174 if #stack >= 1 then
Nenue@0 175 return table.concat(stack, ',')
Nenue@0 176 else
Nenue@0 177 return nil
Nenue@0 178 end
Nenue@0 179 end
Nenue@0 180
Nenue@5 181
Nenue@6 182 --- Resolve the appropriate command and macroText for the given action parameters
Nenue@13 183 kb.RegisterAction = function(type, id, name)
Nenue@6 184 local macroText, macroName, command = '', '', ''
Nenue@5 185
Nenue@5 186 if type == 'spell' then
Nenue@6 187 if kb.ProfessionCache[id] then
Nenue@6 188 command = CLICK_KEYBINDER_KEY .. "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum
Nenue@6 189 else
Nenue@13 190 command = CLICK_KEYBINDER_KEY ..name
Nenue@6 191 end
Nenue@6 192 else
Nenue@13 193 macroName = type .. ' ' .. name
Nenue@13 194 macroText = ACTION_SCRIPT[type]:format(name)
Nenue@6 195 local baseName, iterative = macroName, 1
Nenue@6 196 while (macros[macroName] and macros[macroName][1] ~= macroText) do
Nenue@6 197 print(' * cannot use|cFF00FF00', macroName, '|r"'.. (macros[macroName][1] or '') .. '"')
Nenue@6 198 macroName = baseName .. '_' .. iterative
Nenue@6 199 iterative = iterative + 1
Nenue@6 200 end
Nenue@6 201 if macroName ~= baseName then
Nenue@6 202 print(' * Creating|cFF00FF00', macroName)
Nenue@6 203 else
Nenue@6 204 print(' * Re-using|cFF00FF00', macroName)
Nenue@6 205 end
Nenue@6 206 command = 'CLICK KeyBinderMacro:'.. macroName
Nenue@6 207 macros[macroName] = {macroText, command }
Nenue@5 208 end
Nenue@5 209
Nenue@6 210 print('RegisterAction', type, id, '->', command , macroText)
Nenue@5 211 return macroName, macroText, command
Nenue@0 212 end
Nenue@0 213
Nenue@0 214 --- Updates the current KeyBinding for the button's command
Nenue@5 215 kb.StoreBinding = function(self, key)
Nenue@0 216
Nenue@0 217 if not self.command then
Nenue@0 218 return
Nenue@0 219 end
Nenue@0 220
Nenue@0 221 if key:match('[RL]SHIFT') or key:match('[RL]ALT') or key:match('[RL]CTRL') then
Nenue@0 222 return
Nenue@0 223 end
Nenue@5 224 print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key)
Nenue@0 225
Nenue@15 226 local modifier = ''
Nenue@15 227 if IsAltKeyDown() then
Nenue@15 228 modifier = 'ALT-'
Nenue@15 229 end
Nenue@15 230 if IsControlKeyDown() then
Nenue@15 231 modifier = modifier.. 'CTRL-'
Nenue@15 232 end
Nenue@15 233 if IsShiftKeyDown() then
Nenue@15 234 modifier = modifier..'SHIFT-'
Nenue@15 235 end
Nenue@15 236 local binding = modifier..key
Nenue@15 237
Nenue@5 238 if key == 'ESCAPE' then
Nenue@5 239 local keys = {GetBindingKey(self.command) }
Nenue@5 240 --print('detected', #keys, 'bindings')
Nenue@5 241 for i, key in pairs(keys) do
Nenue@5 242 --print('clearing', key)
Nenue@5 243 SetBinding(key, nil)
Nenue@5 244 SaveBindings(GetCurrentBindingSet())
Nenue@6 245 if kb.currentProfile.bindings[key] then
Nenue@14 246 kb:print(L('BINDING_REMOVED', self.actionName, kb.configHeaders[db.bindMode]))
Nenue@6 247 kb.currentProfile.bindings[key] = nil
Nenue@5 248 end
Nenue@6 249 if kb.currentProfile.talents[self.actionName] then
Nenue@6 250 kb.currentProfile.talents[self.actionName] = nil
Nenue@5 251 end
Nenue@5 252 bindings[self.actionType][self.actionID] = nil
Nenue@5 253 end
Nenue@6 254 if kb.currentProfile.bound[self.command] then
Nenue@6 255 kb.currentProfile.bound[self.command] = nil
Nenue@6 256 --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode]))
Nenue@5 257 end
Nenue@5 258
Nenue@5 259 bindsCommitted = false
Nenue@5 260 self.active = false
Nenue@5 261 else
Nenue@15 262 if kb.SystemBinds[binding] then
Nenue@15 263 kb.statustext:SetText(L('BINDING_FAILED_PROTECTED', key, kb.SystemBinds[binding]))
Nenue@15 264 return
Nenue@5 265 end
Nenue@5 266
Nenue@5 267
Nenue@5 268 if self.command then
Nenue@5 269
Nenue@5 270 local previousKeys
Nenue@15 271 local previousAction = GetBindingAction(binding)
Nenue@5 272 local binding1, binding2, new1, new2
Nenue@5 273 print(type(previousAction), previousAction)
Nenue@5 274 if previousAction ~= "" and previousAction ~= self.command then
Nenue@5 275 if protected[previousAction] then
Nenue@5 276 -- bounce out if trying to use a protected key
Nenue@15 277 kb.statustext:SetText(L('BINDING_FAILED_PROTECTED', key, GetBindingAction(binding)))
Nenue@5 278 kb.bindingstext:SetText(nil)
Nenue@5 279 return
Nenue@5 280 else
Nenue@5 281 kb:print('Discarding keybind for', previousAction)
Nenue@5 282 -- todo: sort out retcon'd talent spells
Nenue@5 283 end
Nenue@5 284 end
Nenue@5 285
Nenue@5 286 self.pending = true
Nenue@15 287 self.binding = binding
Nenue@5 288
Nenue@5 289 bindsCommitted = false
Nenue@5 290 SetBinding(self.binding, self.command)
Nenue@5 291 SaveBindings(GetCurrentBindingSet())
Nenue@5 292
Nenue@5 293 local talentInfo
Nenue@5 294 if self.actionType == 'spell' and kb.TalentCache[self.actionID] then
Nenue@5 295 print('conditional binding (talent = "'..self.actionName..'")')
Nenue@5 296 talentInfo = {self.macroName, self.actionName, self.actionType, self.actionID}
Nenue@5 297 local bindings = {GetBindingKey(self.command) }
Nenue@5 298 for i, key in ipairs(bindings) do
Nenue@5 299 tinsert(talentInfo, key)
Nenue@5 300 end
Nenue@5 301 end
Nenue@5 302
Nenue@6 303 for level, profile in ipairs(kb.orderedProfiles) do
Nenue@6 304 if (level == db.bindMode) then
Nenue@6 305 profile.bound[self.command] = true
Nenue@5 306 if talentInfo then
Nenue@6 307 profile.bindings[self.binding] = nil
Nenue@5 308 else
Nenue@6 309 profile.bindings[self.binding] = self.command
Nenue@5 310 end
Nenue@6 311 profile.talents[self.actionName] = talentInfo
Nenue@5 312 else
Nenue@6 313 profile.bindings[self.binding] = nil
Nenue@6 314 profile.bound[self.command] = nil
Nenue@6 315 kb.currentProfile.talents[self.actionName] = nil
Nenue@5 316 end
Nenue@6 317 if kb.currentProfile.talents[self.actionID] then
Nenue@6 318 kb.currentProfile.talents[self.actionID] = nil
Nenue@5 319 end
Nenue@5 320 end
Nenue@5 321
Nenue@14 322 kb:print(L('BINDING_ASSIGNED', self.binding, self.actionName, kb.configHeaders[db.bindMode]))
Nenue@5 323 end
Nenue@0 324 end
Nenue@5 325 kb.UpdateSlot(self, true)
Nenue@5 326 KeyBinderSaveButton:Enable()
Nenue@0 327 end
Nenue@0 328
Nenue@5 329
Nenue@6 330 kb.inactiveTalentBindings = {}
Nenue@5 331 kb.ApplyTalentBinding = function(talentInfo, cache)
Nenue@5 332 for i = 5, #talentInfo do
Nenue@6 333 local command = CLICK_KEYBINDER_KEY.. talentInfo[2]
Nenue@6 334 SetBinding(talentInfo[i], command)
Nenue@6 335 cprint(' **', talentInfo[i], '->', command)
Nenue@5 336 tinsert(cache, talentInfo[i])
Nenue@0 337 end
Nenue@0 338 end
Nenue@5 339 kb.CacheTalentBinding = function(talentInfo, cache)
Nenue@6 340
Nenue@5 341 local spellID = talentInfo[4]
Nenue@5 342 kb.inactiveTalentBindings[spellID] = kb.inactiveTalentBindings[spellID] or {}
Nenue@5 343 kb.inactiveTalentBindings[spellID] = {select(5,unpack(talentInfo)) }
Nenue@6 344 --cprint(spellID, unpack(kb.inactiveTalentBindings[spellID]))
Nenue@0 345 end
Nenue@0 346
Nenue@6 347 kb.LoadBinding = function(command, name, icon, actionType, actionID, macroName, macroText )
Nenue@5 348
Nenue@6 349 if actionType == 'spell' then
Nenue@6 350 KeyBinderKey:SetAttribute("*type-"..name, actionType)
Nenue@6 351 KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name)
Nenue@13 352
Nenue@6 353 elseif actionType == 'item' then
Nenue@6 354 KeyBinderKey:SetAttribute("*type-"..name, actionType)
Nenue@6 355 KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name)
Nenue@6 356 elseif actionType == 'macro' then
Nenue@5 357 KeyBinderMacro:SetAttribute("*macro-"..macroName, actionID)
Nenue@5 358 else
Nenue@5 359 KeyBinderMacro:SetAttribute("*macrotext-"..macroName, macroText)
Nenue@5 360 end
Nenue@13 361
Nenue@13 362 cprint('Loading binding', actionType, actionID)
Nenue@5 363 bindings[actionType] = bindings[actionType] or {}
Nenue@5 364 bindings[actionType][actionID] = bindings[actionType][actionID] or {}
Nenue@5 365 bindings[command] = bindings[actionType][actionID]
Nenue@5 366 return bindings[actionType], actionID
Nenue@5 367 end
Nenue@5 368
Nenue@5 369 kb.ApplyBindings = function (profile)
Nenue@5 370 cprint('binding profile', profile)
Nenue@5 371 for slot, data in pairs(profile.buttons) do
Nenue@6 372 kb.LoadBinding(unpack(data))
Nenue@5 373 end
Nenue@5 374
Nenue@5 375 for key, command in pairs(profile.bindings) do
Nenue@5 376
Nenue@6 377 cprint(' *', key, '->', command)
Nenue@5 378
Nenue@5 379 --_G.print('HotKey','loading', key, command)
Nenue@5 380 SetBinding(key, command)
Nenue@5 381 if bindings[command] and not tContains(bindings[command], key) then
Nenue@5 382 tinsert(bindings[command], key)
Nenue@5 383 end
Nenue@5 384 end
Nenue@5 385
Nenue@5 386 for spellName, talentInfo in pairs(profile.talents) do
Nenue@5 387 local dummy = GetSpellInfo(spellName)
Nenue@5 388 local func = kb.CacheTalentBinding
Nenue@5 389 local dest = kb.inactiveTalentBindings
Nenue@5 390 if dummy then
Nenue@5 391 cprint('|cFFBBFF00Active:|r', dummy)
Nenue@5 392 local macroName, spellName, actionType, actionID = unpack(talentInfo)
Nenue@5 393 bindings[actionType] = bindings[actionType] or {}
Nenue@5 394 bindings[actionType][actionID] = {}
Nenue@5 395 func = kb.ApplyTalentBinding
Nenue@5 396 dest = bindings[actionType][actionID]
Nenue@5 397 else
Nenue@5 398
Nenue@5 399 cprint('|cFFFF4400Inactive:|r', talentInfo[2])
Nenue@5 400 end
Nenue@5 401 func(talentInfo, dest)
Nenue@5 402 end
Nenue@5 403
Nenue@5 404 SaveBindings(GetCurrentBindingSet())
Nenue@5 405 end
Nenue@5 406
Nenue@5 407 kb.ApplyAllBindings =function ()
Nenue@5 408 table.wipe(kb.inactiveTalentBindings)
Nenue@5 409
Nenue@15 410
Nenue@6 411 -- reflect action key settings
Nenue@6 412 if GetCVarBool("ActionButtonUseKeyDown") then
Nenue@6 413 KeyBinderMacro:RegisterForClicks("AnyDown")
Nenue@6 414 KeyBinderKey:RegisterForClicks("AnyDown")
Nenue@6 415 else
Nenue@6 416 KeyBinderMacro:RegisterForClicks("AnyUp")
Nenue@6 417 KeyBinderKey:RegisterForClicks("AnyUp")
Nenue@6 418 end
Nenue@6 419
Nenue@6 420 for i, profile in ipairs(kb.orderedProfiles) do
Nenue@5 421 kb.ApplyBindings(profile)
Nenue@5 422 end
Nenue@5 423 -- do this after to ensure that profession binds are properly overridden
Nenue@5 424 kb.UpdateProfessionInfo()
Nenue@6 425
Nenue@6 426
Nenue@5 427 end
Nenue@5 428
Nenue@5 429 kb.Command = function(args, editor)
Nenue@5 430 if args:match("import") then
Nenue@5 431 kb.ImportCommmit(args)
Nenue@5 432 return
Nenue@5 433 elseif args:match("scan") then
Nenue@5 434 kb.ImportScan(args)
Nenue@5 435 kb.ui()
Nenue@5 436 return
Nenue@5 437 elseif args:match("load") then
Nenue@5 438 kb:ApplyAllBindings()
Nenue@0 439 return
Nenue@0 440 end
Nenue@0 441
Nenue@5 442 if db.showUI then
Nenue@5 443 db.showUI = false
Nenue@5 444 kb:print('|cFFFFFF00KeyBinds|r trace, |cFFFF0000OFF|r.')
Nenue@5 445 kb:Hide()
Nenue@5 446 else
Nenue@1 447 db.showUI = true
Nenue@5 448 kb:print('|cFFFFFF00KeyBinds|r trace, |cFF00FF00ON|r.')
Nenue@5 449 end
Nenue@5 450 kb.ui(true)
Nenue@5 451 end
Nenue@5 452
Nenue@5 453 kb.InitProfile = function(profile, prototype)
Nenue@5 454 if not profile then
Nenue@5 455 profile = {}
Nenue@5 456 end
Nenue@5 457 if prototype then
Nenue@5 458 print('appplying prototype', prototype)
Nenue@5 459 for k,v in pairs(prototype) do
Nenue@5 460 if not profile[k] then
Nenue@5 461 profile[k] = v
Nenue@5 462 end
Nenue@5 463 end
Nenue@0 464 end
Nenue@0 465
Nenue@5 466 profile.bound = profile.bound or {}
Nenue@5 467 profile.buttons = profile.buttons or {}
Nenue@5 468 profile.commands = profile.commands or {}
Nenue@5 469 profile.bindings = profile.bindings or {}
Nenue@5 470 profile.macros = profile.macros or {}
Nenue@5 471 profile.talents = profile.talents or {}
Nenue@5 472 return profile
Nenue@5 473 end
Nenue@5 474
Nenue@5 475 kb.ResetProfile = function(profile, prototype)
Nenue@6 476 if profile == kb.currentProfile then
Nenue@5 477 for i, button in pairs(buttons) do
Nenue@5 478 kb.ReleaseSlot(button)
Nenue@5 479 end
Nenue@5 480 end
Nenue@5 481 table.wipe(profile)
Nenue@5 482 kb.InitProfile(profile, prototype)
Nenue@5 483 end
Nenue@5 484
Nenue@5 485
Nenue@5 486
Nenue@5 487 --- Handles constructing spec profiles as they are selected
Nenue@5 488
Nenue@5 489
Nenue@5 490 --- Obtains profile data or creates the necessary tables
Nenue@5 491 kb.SelectProfileSet = function(name)
Nenue@5 492
Nenue@6 493 local defaultMode
Nenue@5 494 --- General info
Nenue@5 495 classHeader, className, classID = UnitClass('player')
Nenue@5 496 print('|cFF00FF00profile:|r', name)
Nenue@5 497 print('|cFF00FF00class:|r', UnitClass('player'))
Nenue@5 498
Nenue@5 499 --- Global
Nenue@6 500 defaultMode = BINDING_TYPE_GLOBAL
Nenue@5 501 kb.InitProfile(db)
Nenue@6 502 kb.loadedProfiles[BINDING_TYPE_GLOBAL] = db
Nenue@5 503
Nenue@5 504 --- Character
Nenue@5 505 if name then
Nenue@5 506 db[name] = kb.InitProfile(db[name],
Nenue@5 507 {classHeader = classHeader, className = className, classID = classID})
Nenue@6 508 kb.loadedProfiles[BINDING_TYPE_CHARACTER] = db[name]
Nenue@6 509 defaultMode = BINDING_TYPE_CHARACTER
Nenue@5 510 end
Nenue@5 511
Nenue@5 512 --- Mutable skills data
Nenue@5 513 kb.UpdateSpecInfo()
Nenue@5 514 kb.UpdateTalentInfo()
Nenue@5 515
Nenue@6 516 kb.orderedProfiles = {kb.loadedProfiles[BINDING_TYPE_GLOBAL], kb.loadedProfiles[BINDING_TYPE_CHARACTER], kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION]}
Nenue@15 517 if (not db.bindMode) or (not kb.configTitle[db.bindMode]) then
Nenue@6 518 print('fixing bad bindMode value, was', db.bindMode)
Nenue@6 519 db.bindMode = defaultMode
Nenue@5 520 end
Nenue@5 521
Nenue@5 522
Nenue@5 523 print(BINDING_TYPE_GLOBAL)
Nenue@6 524 kb.configHeaders[BINDING_TYPE_GLOBAL] = kb.configTitle[BINDING_TYPE_GLOBAL]
Nenue@6 525 kb.configHeaders[BINDING_TYPE_CHARACTER] = kb.configTitle[BINDING_TYPE_CHARACTER]:format(UnitName('player', true))
Nenue@10 526 kb.configHeaders[BINDING_TYPE_SPECIALIZATION] = kb.configTitle[BINDING_TYPE_SPECIALIZATION]:format(kb.specInfo.name)
Nenue@5 527
Nenue@5 528
Nenue@6 529 setmetatable(kb.loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return kb.configHeaders[BINDING_TYPE_GLOBAL] end})
Nenue@6 530 setmetatable(kb.loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return kb.configHeaders[BINDING_TYPE_CHARACTER] end})
Nenue@6 531 setmetatable(kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return kb.configHeaders[BINDING_TYPE_SPECIALIZATION] end})
Nenue@5 532
Nenue@6 533 print('|cFF00FF00bindMode:|r', db.bindMode)
Nenue@6 534 kb.currentProfile = kb.loadedProfiles[db.bindMode]
Nenue@5 535 end
Nenue@5 536
Nenue@5 537 local scrollCache = {}
Nenue@5 538 kb.SelectTab = function(self)
Nenue@6 539 scrollCache[db.bindMode] = kb.scrollOffset
Nenue@5 540 db.bindMode = self:GetID()
Nenue@6 541 kb.currentProfile = kb.loadedProfiles[self:GetID()]
Nenue@6 542 kb.scrollOffset = scrollCache[db.bindMode] or 0
Nenue@5 543 kb.ui(true)
Nenue@5 544 end
Nenue@5 545
Nenue@5 546 kb.RevertBindings = function()
Nenue@5 547 -- todo: reversion code
Nenue@5 548 end
Nenue@5 549
Nenue@5 550 kb.ConfirmBindings = function()
Nenue@5 551 kb.ApplyAllBindings()
Nenue@5 552 kb.ui()
Nenue@5 553 end
Nenue@5 554
Nenue@5 555
Nenue@5 556
Nenue@5 557
Nenue@5 558 --- post ADDON_LOADED
Nenue@5 559 kb.variables = function()
Nenue@5 560 SkeletonKeyDB = SkeletonKeyDB or {spec = {}}
Nenue@5 561 kb.db = SkeletonKeyDB
Nenue@5 562 kb.playerName = UnitName('player')
Nenue@5 563 kb.playerRealm = SelectedRealmName()
Nenue@5 564 kb.profileName = kb.playerRealm .. '_' .. kb.playerName
Nenue@5 565 db = kb.db
Nenue@5 566
Nenue@5 567 kb.SelectProfileSet(kb.profileName)
Nenue@6 568 -- todo: redo import checking
Nenue@6 569
Nenue@15 570 kb.UpdateSystemBinds()
Nenue@5 571 kb.ApplyAllBindings()
Nenue@5 572
Nenue@5 573 kb.ui(true)
Nenue@0 574 end
Nenue@0 575
Nenue@1 576
Nenue@5 577 kb.wrap = function(module)
Nenue@5 578 kb.modules = kb.modules or {}
Nenue@5 579 tinsert(kb.modules, module)
Nenue@0 580 end
Nenue@0 581
Nenue@5 582 -- Volatiles Access
Nenue@5 583 kb.GetBindings = function() return bindings end
Nenue@5 584 kb.GetButtons = function() return buttons end
Nenue@6 585 kb.GetCharacterProfile = function () return kb.loadedProfiles[BINDING_TYPE_CHARACTER] end
Nenue@6 586 kb.GetGlobalProfile = function () return kb.loadedProfiles[BINDING_TYPE_GLOBAL] end
Nenue@5 587 kb.GetLooseTalents = function() return talentBindings end
Nenue@5 588 kb.GetReverts = function() return reverts end
Nenue@6 589 kb.GetSpecProfile = function () return kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] end
Nenue@0 590
Nenue@0 591
Nenue@5 592 SLASH_SKB1 = "/skb"
Nenue@5 593 SLASH_SKB2 = "/skeletonkey"
Nenue@5 594 SlashCmdList.SKB = kb.Command