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