annotate SkeletonKey/SkeletonKey.lua @ 42:c77b355a0366

Added tag v7.0.3-10-release for changeset 0877063fd03b
author Nenue
date Tue, 16 Aug 2016 11:34:46 -0400
parents 73df13211b22
children 1aba8a6fd4a9
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@14 19 kb.L = setmetatable({}, {
Nenue@17 20 __call = function(t, k, ...) return format(t[k] or k, ...) end
Nenue@14 21 })
Nenue@14 22 local L = kb.L
Nenue@7 23
Nenue@5 24 --- Caps Lock literals
Nenue@5 25 local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES"
Nenue@14 26 L.BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).'
Nenue@14 27 L.BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.'
Nenue@14 28 L.BINDING_FAILED_PROTECTED = '|cFFFF4400Unable to use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400)|r'
Nenue@14 29
Nenue@14 30
Nenue@5 31 local BINDING_TYPE_SPECIALIZATION = 3
Nenue@5 32 local BINDING_TYPE_CHARACTER = 2
Nenue@5 33 local BINDING_TYPE_GLOBAL = 1
Nenue@6 34 kb.configTitle = {
Nenue@17 35 [BINDING_TYPE_GLOBAL] = L('Global Binds'),
Nenue@17 36 [BINDING_TYPE_CHARACTER] = L('Character: %%s'),
Nenue@17 37 [BINDING_TYPE_SPECIALIZATION] = L('Specialization: %%s')
Nenue@0 38 }
Nenue@6 39 kb.configDescription = {
Nenue@17 40 [BINDING_TYPE_GLOBAL] = L('The bindings are applied globally.'),
Nenue@17 41 [BINDING_TYPE_CHARACTER] = L('Applied when you log onto this character.'),
Nenue@17 42 [BINDING_TYPE_SPECIALIZATION] = L('Applied when you select this specialization.'),
Nenue@5 43 }
Nenue@5 44
Nenue@27 45 kb.ChangedBindings = {}
Nenue@19 46 kb.SystemBindings = {}
Nenue@19 47 kb.ActionTypes = {}
Nenue@19 48 kb.TalentBindings = {}
Nenue@27 49 kb.PetCache = {
Nenue@27 50 spell = {},
Nenue@27 51 spellslot = {},
Nenue@27 52 action = {},
Nenue@27 53 special = {},
Nenue@27 54 subtext = {}
Nenue@27 55 }
Nenue@27 56 kb.TalentCache = {}
Nenue@27 57 kb.ProfessionCache = {}
Nenue@27 58 kb.pendingCalls = {}
Nenue@27 59 kb.pendingAttributes = {}
Nenue@0 60
Nenue@6 61 kb.configHeaders = {}
Nenue@6 62 kb.loadedProfiles = {}
Nenue@6 63 kb.orderedProfiles = {}
Nenue@6 64 kb.buttons = {}
Nenue@6 65 kb.macros = {}
Nenue@17 66 kb.bindings = {}
Nenue@15 67 kb.petFrames = {} -- pet data is slightly delayed, their buttons are indexed here so they can be refreshed
Nenue@15 68 kb.talentFrames = {}
Nenue@15 69 kb.professionFrames = {}
Nenue@0 70
Nenue@14 71 -- these are sent to plugin
Nenue@14 72
Nenue@14 73
Nenue@14 74 local db
Nenue@5 75 local bindHeader, currentHeader = '', ''
Nenue@5 76 local specID, specGlobalID, specName, specDesc, specTexture, characterHeader = 0, 0, 'SPEC_NAME', 'SPEC_DESCRIPTION', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME'
Nenue@5 77 local classHeader, className, classID = '', '', 0
Nenue@5 78 local bindsCommitted = true
Nenue@5 79 local forceButtonUpdate = false
Nenue@5 80
Nenue@5 81 --- Control handles
Nenue@0 82 local saveButton, restoreButton, clearButton
Nenue@0 83
Nenue@5 84 --- Returns conflicting assignment and binding profiles for use in displaying confirmations
Nenue@6 85 kb.IsCommandBound = function(self, command)
Nenue@6 86 local isAssigned, assignedBy = false, db.bindMode
Nenue@6 87 local isBound, boundBy = false, db.bindMode
Nenue@5 88 command = command or self.command
Nenue@6 89 for i = 1, #kb.orderedProfiles do
Nenue@6 90 local tier = kb.orderedProfiles[i]
Nenue@6 91 if i ~= db.bindMode then
Nenue@5 92
Nenue@5 93 if tier.commands[command] then
Nenue@5 94 isAssigned = true
Nenue@5 95 assignedBy = i
Nenue@5 96 end
Nenue@5 97 if tier.bound[command] then
Nenue@5 98 isBound = true
Nenue@5 99 boundBy = i
Nenue@5 100 end
Nenue@5 101
Nenue@5 102
Nenue@5 103 --print(' *', configHeaders[i], tier.commands[command], tier.bound[command])
Nenue@5 104
Nenue@5 105 if isAssigned and isBound then
Nenue@0 106 break
Nenue@0 107 end
Nenue@0 108 end
Nenue@5 109
Nenue@0 110 end
Nenue@5 111
Nenue@17 112 print('|cFFFFFF00IsCommandBound:|r', command,'|r [profile:', db.bindMode .. ']', isAssigned, isBound, assignedBy, boundBy)
Nenue@5 113 return isAssigned, isBound, assignedBy, boundBy
Nenue@0 114 end
Nenue@0 115
Nenue@5 116 local talentSpellHardCodes = {
Nenue@5 117 [109248] = 'Binding Shot',
Nenue@5 118 }
Nenue@5 119
Nenue@0 120 --- Returns a value for use with Texture:SetDesaturated()
Nenue@6 121 kb.BindingIsLocked = function(key)
Nenue@0 122 local success = false
Nenue@6 123 for i = 1, db.bindMode-1 do
Nenue@6 124 local tier = kb.orderedProfiles[i]
Nenue@0 125 if tier.bindings[key] then
Nenue@0 126 success = true
Nenue@0 127 break
Nenue@0 128 end
Nenue@0 129 end
Nenue@0 130 return success
Nenue@0 131 end
Nenue@0 132
Nenue@0 133 --- Translates GetBindingKey() results into a printable string.
Nenue@6 134 kb.BindingString = function(...)
Nenue@0 135 local stack = {}
Nenue@0 136 for i = 1, select('#', ...) do
Nenue@0 137 local key = select(i, ...)
Nenue@5 138 stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ')
Nenue@0 139 end
Nenue@0 140
Nenue@0 141 if #stack >= 1 then
Nenue@0 142 return table.concat(stack, ',')
Nenue@0 143 else
Nenue@0 144 return nil
Nenue@0 145 end
Nenue@0 146 end
Nenue@0 147
Nenue@5 148
Nenue@5 149
Nenue@5 150
Nenue@0 151
Nenue@5 152 kb.Command = function(args, editor)
Nenue@5 153 if args:match("import") then
Nenue@5 154 kb.ImportCommmit(args)
Nenue@5 155 return
Nenue@5 156 elseif args:match("scan") then
Nenue@5 157 kb.ImportScan(args)
Nenue@5 158 kb.ui()
Nenue@5 159 return
Nenue@5 160 elseif args:match("load") then
Nenue@5 161 kb:ApplyAllBindings()
Nenue@0 162 return
Nenue@0 163 end
Nenue@0 164
Nenue@5 165 if db.showUI then
Nenue@5 166 db.showUI = false
Nenue@5 167 kb:print('|cFFFFFF00KeyBinds|r trace, |cFFFF0000OFF|r.')
Nenue@5 168 kb:Hide()
Nenue@5 169 else
Nenue@1 170 db.showUI = true
Nenue@5 171 kb:print('|cFFFFFF00KeyBinds|r trace, |cFF00FF00ON|r.')
Nenue@5 172 end
Nenue@5 173 kb.ui(true)
Nenue@5 174 end
Nenue@5 175
Nenue@5 176 kb.InitProfile = function(profile, prototype)
Nenue@5 177 if not profile then
Nenue@5 178 profile = {}
Nenue@5 179 end
Nenue@5 180 if prototype then
Nenue@5 181 print('appplying prototype', prototype)
Nenue@5 182 for k,v in pairs(prototype) do
Nenue@5 183 if not profile[k] then
Nenue@5 184 profile[k] = v
Nenue@5 185 end
Nenue@5 186 end
Nenue@0 187 end
Nenue@0 188
Nenue@5 189 profile.bound = profile.bound or {}
Nenue@5 190 profile.buttons = profile.buttons or {}
Nenue@5 191 profile.commands = profile.commands or {}
Nenue@5 192 profile.bindings = profile.bindings or {}
Nenue@5 193 profile.macros = profile.macros or {}
Nenue@5 194 profile.talents = profile.talents or {}
Nenue@5 195 return profile
Nenue@5 196 end
Nenue@5 197
Nenue@5 198 kb.ResetProfile = function(profile, prototype)
Nenue@6 199 if profile == kb.currentProfile then
Nenue@5 200 for i, button in pairs(buttons) do
Nenue@5 201 kb.ReleaseSlot(button)
Nenue@5 202 end
Nenue@5 203 end
Nenue@5 204 table.wipe(profile)
Nenue@5 205 kb.InitProfile(profile, prototype)
Nenue@5 206 end
Nenue@5 207
Nenue@5 208
Nenue@5 209
Nenue@5 210 --- Handles constructing spec profiles as they are selected
Nenue@5 211
Nenue@5 212
Nenue@5 213 --- Obtains profile data or creates the necessary tables
Nenue@5 214 kb.SelectProfileSet = function(name)
Nenue@5 215
Nenue@6 216 local defaultMode
Nenue@5 217 --- General info
Nenue@5 218 classHeader, className, classID = UnitClass('player')
Nenue@5 219 print('|cFF00FF00profile:|r', name)
Nenue@5 220 print('|cFF00FF00class:|r', UnitClass('player'))
Nenue@5 221
Nenue@6 222 defaultMode = BINDING_TYPE_GLOBAL
Nenue@17 223 if db[name] then
Nenue@6 224 defaultMode = BINDING_TYPE_CHARACTER
Nenue@17 225 if db[name][kb.specInfo.id] then
Nenue@17 226 defaultMode = BINDING_TYPE_SPECIALIZATION
Nenue@17 227 end
Nenue@5 228 end
Nenue@5 229
Nenue@17 230 db[name] = kb.InitProfile(db[name],
Nenue@17 231 {
Nenue@17 232 classHeader = classHeader,
Nenue@17 233 className = className,
Nenue@17 234 classID = classID
Nenue@17 235 })
Nenue@17 236 db[name][kb.specInfo.id] = kb.InitProfile(db[name][kb.specInfo.id],
Nenue@17 237 {
Nenue@17 238 specID = kb.specInfo.id,
Nenue@17 239 specName = kb.specInfo.name
Nenue@17 240 })
Nenue@5 241
Nenue@17 242 kb.loadedProfiles[BINDING_TYPE_GLOBAL] = db
Nenue@17 243 kb.loadedProfiles[BINDING_TYPE_CHARACTER] = db[name]
Nenue@17 244 kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] = db[name][kb.specInfo.id]
Nenue@17 245 kb.orderedProfiles = {db, db[name], db[name][kb.specInfo.id]}
Nenue@17 246
Nenue@15 247 if (not db.bindMode) or (not kb.configTitle[db.bindMode]) then
Nenue@6 248 print('fixing bad bindMode value, was', db.bindMode)
Nenue@6 249 db.bindMode = defaultMode
Nenue@5 250 end
Nenue@5 251
Nenue@5 252
Nenue@5 253 print(BINDING_TYPE_GLOBAL)
Nenue@6 254 kb.configHeaders[BINDING_TYPE_GLOBAL] = kb.configTitle[BINDING_TYPE_GLOBAL]
Nenue@6 255 kb.configHeaders[BINDING_TYPE_CHARACTER] = kb.configTitle[BINDING_TYPE_CHARACTER]:format(UnitName('player', true))
Nenue@10 256 kb.configHeaders[BINDING_TYPE_SPECIALIZATION] = kb.configTitle[BINDING_TYPE_SPECIALIZATION]:format(kb.specInfo.name)
Nenue@5 257
Nenue@5 258
Nenue@6 259 setmetatable(kb.loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return kb.configHeaders[BINDING_TYPE_GLOBAL] end})
Nenue@6 260 setmetatable(kb.loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return kb.configHeaders[BINDING_TYPE_CHARACTER] end})
Nenue@6 261 setmetatable(kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return kb.configHeaders[BINDING_TYPE_SPECIALIZATION] end})
Nenue@5 262
Nenue@6 263 print('|cFF00FF00bindMode:|r', db.bindMode)
Nenue@6 264 kb.currentProfile = kb.loadedProfiles[db.bindMode]
Nenue@17 265 kb.currentHeader = kb.configHeaders[db.bindMode]
Nenue@5 266 end
Nenue@5 267
Nenue@5 268 local scrollCache = {}
Nenue@5 269 kb.SelectTab = function(self)
Nenue@6 270 scrollCache[db.bindMode] = kb.scrollOffset
Nenue@5 271 db.bindMode = self:GetID()
Nenue@6 272 kb.currentProfile = kb.loadedProfiles[self:GetID()]
Nenue@17 273 kb.currentHeader = kb.configHeaders[db.bindMode]
Nenue@6 274 kb.scrollOffset = scrollCache[db.bindMode] or 0
Nenue@5 275 kb.ui(true)
Nenue@5 276 end
Nenue@5 277
Nenue@5 278 kb.RevertBindings = function()
Nenue@5 279 -- todo: reversion code
Nenue@5 280 end
Nenue@5 281
Nenue@5 282 kb.ConfirmBindings = function()
Nenue@5 283 kb.ApplyAllBindings()
Nenue@5 284 kb.ui()
Nenue@5 285 end
Nenue@5 286
Nenue@5 287
Nenue@5 288
Nenue@5 289
Nenue@5 290 --- post ADDON_LOADED
Nenue@5 291 kb.variables = function()
Nenue@17 292 SkeletonKeyDB = kb.InitProfile(SkeletonKeyDB, {})
Nenue@5 293 kb.db = SkeletonKeyDB
Nenue@5 294 kb.playerName = UnitName('player')
Nenue@5 295 kb.playerRealm = SelectedRealmName()
Nenue@5 296 kb.profileName = kb.playerRealm .. '_' .. kb.playerName
Nenue@5 297 db = kb.db
Nenue@5 298
Nenue@17 299 kb.UpdateSpecInfo()
Nenue@17 300 kb.UpdateTalentInfo()
Nenue@5 301 kb.SelectProfileSet(kb.profileName)
Nenue@6 302 -- todo: redo import checking
Nenue@6 303
Nenue@15 304 kb.UpdateSystemBinds()
Nenue@5 305 kb.ApplyAllBindings()
Nenue@5 306
Nenue@27 307 if not InCombatLockdown() then
Nenue@27 308 kb.CreateHooks()
Nenue@27 309 else
Nenue@27 310 kb:print('Some functionality will not load until breaking combat.')
Nenue@27 311 tinsert(kb.pendingCalls, kb.CreateHooks)
Nenue@27 312 end
Nenue@27 313
Nenue@27 314
Nenue@5 315 kb.ui(true)
Nenue@0 316 end
Nenue@0 317
Nenue@1 318
Nenue@5 319 kb.wrap = function(module)
Nenue@5 320 kb.modules = kb.modules or {}
Nenue@5 321 tinsert(kb.modules, module)
Nenue@0 322 end
Nenue@0 323
Nenue@5 324 -- Volatiles Access
Nenue@17 325 kb.GetBindings = function() return kb.bindings end
Nenue@17 326 kb.GetButtons = function() return kb.buttons end
Nenue@6 327 kb.GetCharacterProfile = function () return kb.loadedProfiles[BINDING_TYPE_CHARACTER] end
Nenue@6 328 kb.GetGlobalProfile = function () return kb.loadedProfiles[BINDING_TYPE_GLOBAL] end
Nenue@6 329 kb.GetSpecProfile = function () return kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] end
Nenue@0 330
Nenue@0 331
Nenue@5 332 SLASH_SKB1 = "/skb"
Nenue@5 333 SLASH_SKB2 = "/skeletonkey"
Nenue@5 334 SlashCmdList.SKB = kb.Command