Mercurial > wow > skeletonkey
changeset 14:82170735e67c
- move co-routine handler to general lib
- slightly better handling of pet actions
author | Nenue |
---|---|
date | Thu, 28 Jul 2016 23:58:53 -0400 |
parents | eeec4a600064 |
children | 32d64e42ec9b |
files | LibKraken/LibKraken-1.0.lua SkeletonKey/BindingsUI.lua SkeletonKey/Cache.lua SkeletonKey/HotKey.lua SkeletonKey/KeyBinds.lua SkeletonKey/KeySlot.lua SkeletonKey/SkeletonKey.lua SkeletonKey/SkeletonKey.toc SkeletonKey/UI.lua |
diffstat | 9 files changed, 1381 insertions(+), 1347 deletions(-) [+] |
line wrap: on
line diff
--- a/LibKraken/LibKraken-1.0.lua Thu Jul 28 18:20:32 2016 -0400 +++ b/LibKraken/LibKraken-1.0.lua Thu Jul 28 23:58:53 2016 -0400 @@ -237,7 +237,7 @@ end end - return addon, (DEVIAN_WORKSPACE and function(...) _G.print(name, ...) end or function() end) + return addon, (DEVIAN_WORKSPACE and function(...) _G.print(name, ...) end or function() end), KT.wrap end @@ -360,6 +360,35 @@ return button end +--- Co-routine Handler kajigger +do + local tickerQueue = {} + local ticker + local instant = false + KT.tick = function() + + if #tickerQueue == 0 then + ticker:Cancel() + ticker = nil + end + local func = tremove(tickerQueue, 1) + if func then + --print('#', #tickerQueue) + func() + end + end + + KT.wrap = function(f) + if not ticker then + --print('create ticker') + ticker = C_Timer.NewTicker(.001, KT.tick) + end + tinsert(tickerQueue, f) + + return #tickerQueue + + end +end KT.handler:RegisterEvent('ADDON_LOADED') KT.handler:RegisterEvent('PLAYER_LOGIN')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/BindingsUI.lua Thu Jul 28 23:58:53 2016 -0400 @@ -0,0 +1,345 @@ +-- KrakTool +-- BindingsUI.lua +-- Created: 7/28/2016 3:39 PM +-- %file-revision% +-- + +local kb, print = LibStub("LibKraken").register(KeyBinder, 'KeySlot') +local BINDS_PER_ROW = 2 +local BUTTON_HSPACING = 128 +local BUTTON_SPACING = 4 +local BUTTON_PADDING = 12 +local BINDING_TYPE_SPECIALIZATION = 3 +local BINDING_TYPE_CHARACTER = 2 +local BINDING_TYPE_GLOBAL = 1 +local KEY_BUTTON_SIZE = 48 +local MIN_BIND_SLOTS = 32 +local TAB_OFFSET = 12 +local TAB_HEIGHT = 40 +local TAB_SPACING = 2 + +local BINDING_SCHEME_COLOR = { + [BINDING_TYPE_GLOBAL] = {0,.125,.5,.5}, + [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.5}, + [BINDING_TYPE_SPECIALIZATION] = {.25,0,0,0.5}, +} +local BINDING_SCHEME_VERTEX = { + [BINDING_TYPE_GLOBAL] = {0,.5,1,1}, + [BINDING_TYPE_CHARACTER] = {0,1,0,1}, + [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1}, +} +local BINDING_SCHEME_TEXT = { + [BINDING_TYPE_SPECIALIZATION] = {0, 1, 1}, + [BINDING_TYPE_CHARACTER] = {0, 1, 0}, + [BINDING_TYPE_GLOBAL] = {0, 1, 1} +} + +local restingAlpha = 0.7 +local fadeTime, fadeDelay = .30, 0.15 +local numButtons = BINDS_PER_ROW * 8 +local saveButton +local KeyButton_OnKeyDown = function(self, key) + kb.StoreBinding(self, key) +end +local KeyButton_OnClick = function(self, click) + print(self:GetName(), 'OnMouseDown', click) + if click == 'LeftButton' then + kb.DropToSlot(self) + elseif click == 'RightButton' then + kb.ReleaseSlot(self) + else + kb.StoreBinding(self, click:upper()) + end +end + +local KeyButton_OnDragStart = function(self) + kb.PickupSlot(self) +end + +local KeyButton_OnReceiveDrag = function(self, ...) + kb.DropToSlot(self) +end + + +local KeyBinder_OnUpdate = function(self, elapsed) + self.elapsed = self.elapsed + elapsed + self.throttle = self.throttle + elapsed + + if (self.throttle >= 0.032) then + self.throttle = 0 + else + return + end + + local progress = 1 + if self.elapsed > fadeTime then + self.elapsed = 0 + self.fadeStep = 0 + --self.statustext:SetText(nil) + --self.bindingstext:SetText(nil) + self:SetScript('OnUpdate', nil) + else + if self.elapsed < fadeDelay then + progress = 0 + else + self.fadeStep = self.fadeStep + 1 + progress = (self.elapsed - fadeDelay) /(fadeTime - fadeDelay) + end + --print(self.fadeStep, format('%.02f/%.02f', (self.elapsed - fadeDelay) ,(fadeTime - fadeDelay)) , progress) + end + + local alpha = 1 - progress * (1- restingAlpha) + self.statustext:SetAlpha(alpha) + self.bindingstext:SetAlpha(alpha) +end + +local KeyButton_OnUpdate = function(self) + if not self.command then + return + end + + if self:IsMouseOver() then + kb.elapsed = 0 + if not self.active then + -- only set this handler when the button is activated/mouseOver + self.active = true + self:SetScript('OnKeyDown', KeyButton_OnKeyDown) + + kb.statustext:SetText(self.statusText .. ': '..self.actionName) + kb.bindingstext:SetText(self.bindingText) + kb.fadeStep = 0 + kb.throttle = 0 + kb:SetScript('OnUpdate', KeyBinder_OnUpdate) + + end + else + if self.active then + self.active = nil + self:SetScript('OnKeyDown', nil) + end + end +end + +local KeyBinder_OnMouseWheel = function(self, delta) + print(self, delta, self.scrollOffset, (self.scrollOffset <= 0)) + + + if IsControlKeyDown() then + KEY_BUTTON_SIZE = KEY_BUTTON_SIZE - delta + else + + + if (delta > 0) and (self.scrollOffset <= 0) then + return + elseif delta < 0 and kb.scrollOffset >= 42 then + return + end + kb.scrollOffset = ceil(kb.scrollOffset - (delta * BINDS_PER_ROW)) + end + + kb.ui(true) +end + +local KeyBinder_OnHide = function() + KeyBinderImportLog:Hide() +end + +local CloseButton_OnClick = function() + kb.db.showUI = false + kb:Hide() +end +local CancelButton_OnClick = function() + kb.RevertBindings() +end +local SaveButton_OnClick = function() + kb.ConfirmBindings() +end + +local KeyBinder_Initialize = function() + + + kb.scrollOffset = 0 + kb.tabAnchor = {'TOPLEFT', kb.profilebg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING} + kb.tabGrowth = {'TOPLEFT', nil,'TOPRIGHT', BUTTON_SPACING, 0} + kb.tabSize = {TAB_HEIGHT, TAB_HEIGHT } + kb.UIPanelAnchor = {'TOPLEFT', kb.sourcesbg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING} + kb.UIPanelGrowth = {'TOPLEFT', nil, 'BOTTOMLEFT', 0, -2 } + kb.UIPanelSize = {84, 32 } + kb.UIPanelIcon = {24, 32, 'LEFT', -12, 0} + kb.controlsAnchor = {'BOTTOMLEFT', kb.footer, BUTTON_PADDING, BUTTON_PADDING } + kb.controlsGrowth = {'BOTTOMLEFT', nil, 'BOTTOMRIGHT', BUTTON_SPACING, 0} + + -- order of these is important + kb:tab('KeyBinderGlobalTab', + kb.configTitle[BINDING_TYPE_GLOBAL] .. '\n' .. kb.configDescription[BINDING_TYPE_GLOBAL], "Interface\\ICONS\\item_azereansphere", {0.15,.85,.15,.85}) + kb:tab('KeyBinderCharacterTab', + kb.configHeaders[BINDING_TYPE_CHARACTER] .. '\n' .. kb.configDescription[BINDING_TYPE_CHARACTER], nil) + kb:tab('KeyBinderSpecTab', + kb.configHeaders[BINDING_TYPE_SPECIALIZATION] .. '\n' .. kb.configDescription[BINDING_TYPE_SPECIALIZATION], kb.specInfo.texture) + KeyBinderCharacterTab.icon:SetTexCoord(0.15,.85,.15,.85) + + + + --portraitLayers[1] = KeyBinderCharacterTab.icon + + saveButton = kb:button('KeyBinderSaveButton', 'Refresh', 'Reload current bindings and refresh panel.', SaveButton_OnClick) + --restoreButton = kb:button('KeyBinderRestoreButton', 'Discard', 'Revert all changes.', CancelButton_OnClick) + --clearButton = kb:button('KeyBinderClearButton', 'Clear Page', 'Release all buttons.', ResetButton_OnClick) + + kb:uibutton( + 'KeyBinderSpellBookButton', 'SpellBook', nil, + function() ToggleSpellBook(BOOKTYPE_SPELL) end, + "Interface\\BUTTONS\\UI-MicroButton-Spellbook-Up", {0, 1, .4, 1}) + kb:uibutton( + 'KeyBinderTalentFrameButton', TALENTS, SPECIALIZATION, + function() ToggleTalentFrame() end, + "Interface\\BUTTONS\\UI-MicroButton-Talents-Up", {0, 1, .4, 1}) + + kb:uibutton( + 'KeyBinderMacroFrameButton', 'Macros', nil, + function() if MacroFrame and MacroFrame:IsVisible() then + HideUIPanel(MacroFrame) + else + ShowMacroFrame() end + end, + "Interface\\BUTTONS\\UI-MicroButton-Help-Up", {0, 1, .4, 1}) + + kb:uibutton( + 'KeyBinderInventoryButton', 'Bags', nil, + function() OpenAllBags() end, + "Interface\\BUTTONS\\UI-MicroButtonCharacter-Up", {0, 1, .4, 1}) + + + + kb.info:SetPoint('TOPLEFT', kb.UIPanels[1], 'BOTTOMLEFT', 0, -BUTTON_SPACING) + HEADER_OFFSET = kb.UIPanels[1]:GetHeight() + BUTTON_PADDING + + kb.info:GetHeight() + FOOTER_OFFSET = saveButton:GetHeight() + BUTTON_PADDING + + kb:SetScript('OnHide', KeyBinder_OnHide) + kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) + kb.CloseButton:SetScript('OnClick', CloseButton_OnClick) + +end + + +--- Retrieves button at index; creates said button and instates any stored parameters +do + local leftSlot, upSlot + local buttonsDepth = 0 + kb.GetSlot = function(index) + + local slot = index + kb.scrollOffset + + if not kb.buttons[index] then + local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, kb, 'KeyButton') + button:SetScript('OnClick', KeyButton_OnClick) + button:SetScript('OnUpdate', KeyButton_OnUpdate) + button:SetScript('OnDragStart', KeyButton_OnDragStart) + button:SetScript('OnReceiveDrag', KeyButton_OnReceiveDrag) + button:RegisterForClicks('AnyUp') + + + local newRow = (mod(index, BINDS_PER_ROW) == 1) + + if index == 1 then + button:SetPoint('TOPLEFT', kb.bg, 'TOPLEFT', BUTTON_PADDING, - BUTTON_PADDING) + upSlot = button + buttonsDepth = KEY_BUTTON_SIZE + BUTTON_PADDING * 2 + elseif newRow then + button:SetPoint('TOPLEFT', upSlot, 'BOTTOMLEFT', 0, -BUTTON_SPACING) + upSlot = button + buttonsDepth = buttonsDepth + KEY_BUTTON_SIZE + BUTTON_SPACING + else + button:SetPoint('TOPLEFT', leftSlot, 'TOPRIGHT', BUTTON_HSPACING, 0) + end + + button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE) + button:Show() + kb.buttons[index] = button + leftSlot = button + end + return kb.buttons[index] + end +end + + +--- push current information into living UI +kb.ui = function(force) + for i, module in ipairs(kb.modules) do + if module.ui then + module.ui(force) + end + end + + if not kb.db.showUI then + print('---end of refresh') + return + end + if not kb.loaded then + KeyBinder_Initialize() + kb.loaded = true + end + for i = 1, numButtons do + local button = kb.GetSlot(i) + button:SetID(i+kb.scrollOffset) + kb.UpdateSlot(button, force) + end + + + --- Frame Sizing + kb.profilebg:SetHeight(kb.tabSize[2] + BUTTON_PADDING * 2 + kb.profiletext:GetStringHeight()) + + kb.bg:SetWidth((KEY_BUTTON_SIZE + BUTTON_HSPACING + BUTTON_SPACING) * BINDS_PER_ROW + BUTTON_PADDING*2 - BUTTON_SPACING) + local numRows = numButtons/BINDS_PER_ROW + + kb.bg:SetHeight((KEY_BUTTON_SIZE + BUTTON_SPACING) * numRows + BUTTON_PADDING*2 - BUTTON_SPACING) + + kb:SetHeight(kb.headerbg:GetHeight() + kb.profilebg:GetHeight() + kb.bg:GetHeight() + kb.footer:GetHeight()) + kb:SetWidth((kb.sourcesbg:GetWidth() +(BINDS_PER_ROW * (KEY_BUTTON_SIZE + BUTTON_HSPACING) + (BINDS_PER_ROW - 1) * BUTTON_SPACING + BUTTON_PADDING * 2) )) + + kb.bg:SetColorTexture(unpack(BINDING_SCHEME_COLOR[kb.db.bindMode])) + for i, tab in ipairs(kb.tabButtons) do + local border = tab:GetNormalTexture() + local tabTexture = "Interface\\Buttons\\UI-Quickslot2" + local left, top, right, bottom = -12, 12, 13, -13 + if i == kb.db.bindMode then + tabTexture = "Interface\\Buttons\\CheckButtonGlow" + left, top, right, bottom = -14, 14, 15, -15 + tab.icon:SetDesaturated(false) + if tab.icon2 then tab.icon2:SetDesaturated(false) end + border:SetDesaturated(true) + border:SetVertexColor(1,1,1, 1) + else + tab.icon:SetDesaturated(true) + if tab.icon2 then tab.icon2:SetDesaturated(true) end + border:SetDesaturated(false) + border:SetVertexColor(1,1,1) + end + border:SetTexture(tabTexture) + border:SetPoint('TOPLEFT', tab, 'TOPLEFT', left, top) + border:SetPoint('BOTTOMRIGHT', tab, 'BOTTOMRIGHT', right, bottom) + end + + KeyBinderSpecTab.icon:SetTexture(kb.specInfo.texture) + SetPortraitTexture(KeyBinderCharacterTab.icon, 'player') + + kb.profiletext:SetText(kb.configHeaders[kb.db.bindMode]) + print(kb.db.bindMode, kb.configHeaders[kb.db.bindMode], kb:GetSize()) + print(kb:GetPoint(1)) + + kb:Show() + + -- Reset this so talent cache can be rebuilt + kb.talentsPushed = nil +end + +kb.AcceptAssignment = function(self, ...) + local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] + local source = loadedProfiles[popup.oldProfile] + kb.SetSlot(popup.slot, unpack(popup.args)) + kb.UpdateSlot(popup.slot) + kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) -- re-enable scrolling + ClearCursor() + ResetCursor() +end
--- a/SkeletonKey/Cache.lua Thu Jul 28 18:20:32 2016 -0400 +++ b/SkeletonKey/Cache.lua Thu Jul 28 23:58:53 2016 -0400 @@ -27,8 +27,8 @@ kb.configHeaders[BINDING_TYPE_SPECIALIZATION] = kb.configTitle[BINDING_TYPE_SPECIALIZATION]:format(kb.specInfo.name) kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] = kb.loadedProfiles[BINDING_TYPE_CHARACTER][kb.specInfo.id] - kb.currentProfile = kb.loadedProfiles[kb.bindMode] - print('|cFF00FF00bindMode:|r', kb.bindMode) + kb.currentProfile = kb.loadedProfiles[kb.db.bindMode] + print('|cFF00FF00bindMode:|r', kb.db.bindMode) kb.profileOrder = {kb.loadedProfiles[BINDING_TYPE_GLOBAL], kb.loadedProfiles[BINDING_TYPE_CHARACTER], kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION]}
--- a/SkeletonKey/HotKey.lua Thu Jul 28 18:20:32 2016 -0400 +++ b/SkeletonKey/HotKey.lua Thu Jul 28 23:58:53 2016 -0400 @@ -4,7 +4,7 @@ -- %file-revision% -- Module for fixing actionbar hotkey text -local kb, print = LibStub("LibKraken").register(KeyBinder, 'HotKey') +local kb, print, wrap = LibStub("LibKraken").register(KeyBinder, 'HotKey') local hotkey = {} local hotkeyText = {} local blizHotKey = {} @@ -29,36 +29,6 @@ ["PET_UI_UPDATE"] = {"pet"}, } -do - local tickerQueue = {} - local ticker - local instant = false - hotkey.tick = function() - - if #tickerQueue == 0 then - instant = true - return - else - instant = false - end - local func = tremove(tickerQueue, 1) - if func then - --print('#', #tickerQueue) - func() - end - end - hotkey.wrap = function(f) - if not ticker then - --print('create ticker') - ticker = C_Timer.NewTicker(0, hotkey.tick) - end - if instant then - f() - else - tinsert(tickerQueue, f) - end - end -end hotkey.wrapEvent = function(event, ...) kb:RegisterEvent(event) @@ -75,7 +45,7 @@ end hotkey.ActionButton_Update = function(frame) - hotkey.wrap(function() + wrap(function() local actionType, actionID = GetActionInfo(frame.action) hotkey.UpdateSkeletonKeyText(frame, actionType, actionID, HasAction(frame.action)) end) @@ -83,7 +53,7 @@ hotkey.RegisterFrame = function(frame) - --hotkey.wrap(function() + --wrap(function() --print('ActionBarButtonEventsFrame_RegisterFrame(', frame:GetName(), frame.action, frame:IsVisible(), frame:IsShown()) --end) blizHotKey[frame] = frame.HotKey
--- a/SkeletonKey/KeyBinds.lua Thu Jul 28 18:20:32 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,719 +0,0 @@ --------------------------------------------- --- SkeletonKey --- Krakyn-Mal'Ganis --- @project-revision@ @project-hash@ --- @file-revision@ @file-hash@ --- Created: 6/16/2016 3:47 AM --------------------------------------------- --- kb --- .StoreBinding(button, key) bind current keystroke to command --- .GetSlot(index) return display slot --- .SetSlot(button, command, name, icon) assign display slot --- .ReleaseSlot(button) clear button command --- .UpdateSlot(button) update button contents --- .SelectProfile(name) set profile character --- .ApplyBindings(bindings) walk table with SetBinding() - -local _ -local kb, print = LibStub("LibKraken").register(KeyBinder) -local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end - - ---- Caps Lock literals -local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:" -local CLICK_KEYBINDER_KEY = "CLICK KeyBinderKey:" -local BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).' -local BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.' -local BINDING_FAILED_PROTECTED = '|cFFFF4400Unable to use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400)|r' -local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES" -local FOOTER_OFFSET -local HEADER_OFFSET -local HELP_1 = "Drag and drop spells/items from your inventory, spellbook, or collections panels." -local HELP_2 = "While the cursor is above an icon, up to two key combinations will be bound to that action." -local HELP_3 = "If that key used for a client binding (e.g. game menu), a confirmation popup will appear before making the change." -local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 -local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION -local BINDING_TYPE_SPECIALIZATION = 3 -local BINDING_TYPE_CHARACTER = 2 -local BINDING_TYPE_GLOBAL = 1 - - ---- Caps Lock derivatives -local ACTION_SCRIPT = { - ['mount'] = "/script C_MountJournal.SummonByID(%d)", - ['macro'] = "%s", - ['equipset'] = "/script UseEquipmentSet(%d)", - ['spell'] = "/cast %s", - ['petaction'] = "/cast %s", - ['battlepet'] = SLASH_SUMMON_BATTLE_PET1 .. " %s", - ['item'] = "/use %s" -} - -local professionMappings = { - [5] = 3, - [7] = 4, - [9] = 5, - [10] = 6 -} - -kb.configTitle = { - [BINDING_TYPE_GLOBAL] = 'Global Binds', - [BINDING_TYPE_CHARACTER] = 'Character: %s', - [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s' -} -kb.configDescription = { - [BINDING_TYPE_GLOBAL] = 'The bindings are applied globally.', - [BINDING_TYPE_CHARACTER] = 'Applied when you log onto this character.', - [BINDING_TYPE_SPECIALIZATION] = 'Applied when you log onto this character and are that specialization.', -} - - - -kb.configHeaders = {} -kb.loadedProfiles = {} -kb.orderedProfiles = {} -kb.buttons = {} -kb.macros = {} - -local buttons = {} --- Backlog of changes -local reverts = {} --- macro buttons used for mounts and other buttonable non-spells -local macros = {} --- currently active non-blizzard keybinds -local bindings = {} --- unselected talents -local talentBindings = {} -kb.inactiveTalentBindings = {} --- placeholder for the StaticPopup used for confirmations -local confirmation --- savedvars, pulled a lot here -local db - -local protected = { - ['OPENCHATSLASH'] = true, - ['OPENCHAT'] = true, -} - ---- Used to reflect the current working state -local bindHeader, currentHeader = '', '' -local specID, specGlobalID, specName, specDesc, specTexture, characterHeader = 0, 0, 'SPEC_NAME', 'SPEC_DESCRIPTION', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME' -local classHeader, className, classID = '', '', 0 -local bindsCommitted = true -local forceButtonUpdate = false - ---- Control handles -local saveButton, restoreButton, clearButton - ---- Cursor "pickup" actuators -local PickupAction = {} -PickupAction.spell = _G.PickupSpell -PickupAction.macro = _G.PickupMacro -PickupAction.item = _G.PickupItem -PickupAction.mount = _G.C_MountJournal.Pickup -local GetPickupValue = {} -GetPickupValue.spell = function(self) return select(7, GetSpellInfo(self.actionID)) end - ---- Returns conflicting assignment and binding profiles for use in displaying confirmations -kb.IsCommandBound = function(self, command) - local isAssigned, assignedBy = false, db.bindMode - local isBound, boundBy = false, db.bindMode - - - command = command or self.command - for i = 1, #kb.orderedProfiles do - local tier = kb.orderedProfiles[i] - if i ~= db.bindMode then - - if tier.commands[command] then - isAssigned = true - assignedBy = i - end - if tier.bound[command] then - isBound = true - boundBy = i - end - - - --print(' *', configHeaders[i], tier.commands[command], tier.bound[command]) - - if isAssigned and isBound then - break - end - end - - end - - print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', db.bindMode .. ']', isAssigned, isBound, assignedBy, boundBy) - return isAssigned, isBound, assignedBy, boundBy -end - -local talentSpellHardCodes = { - [109248] = 'Binding Shot', -} - ---- Returns a value for use with Texture:SetDesaturated() -kb.BindingIsLocked = function(key) - local success = false - for i = 1, db.bindMode-1 do - local tier = kb.orderedProfiles[i] - if tier.bindings[key] then - success = true - break - end - end - return success -end - ---- Translates GetBindingKey() results into a printable string. -kb.BindingString = function(...) - local stack = {} - for i = 1, select('#', ...) do - local key = select(i, ...) - stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ') - end - - if #stack >= 1 then - return table.concat(stack, ',') - else - return nil - end -end - -kb.DropToSlot = function(self) - print(self:GetName(),'|cFF0088FFreceived|r') - local actionType, actionID, subType, subData = GetCursorInfo() - print('GetCursorInfo', GetCursorInfo()) - if actionType then - - if actionType == 'flyout' then - ClearCursor() - ResetCursor() - return - end - - - local macroName, macroText - local command, name, icon, _ - local pickupID, pickupBook - - if actionType == 'spell' then - actionID = subData - name, _, icon = GetSpellInfo(actionID) - - elseif actionType == 'macro' then - name, icon = GetMacroInfo(actionID) - elseif actionType == 'petaction' then - if not (CURSOR_SPELLSLOT and CURSOR_BOOKTYPE) then - - ClearCursor() - ResetCursor() - end - - local bookType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE) - pickupID = CURSOR_SPELLSLOT - pickupBook = CURSOR_BOOKTYPE - name, _, icon = GetSpellInfo(spellID) - elseif actionType == 'mount' then - if subType == 0 then - name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) - actionID = 0 - else - name, _, icon = C_MountJournal.GetMountInfoByID(actionID) - end - elseif actionType == 'item' then - name = GetItemInfo(actionID) - icon = GetItemIcon(actionID) - actionID = name - elseif actionType == 'battlepet' then - - local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = C_PetJournal.GetPetInfoByPetID(detail); - name = customName or petName - icon = petIcon - - end - macroName, macroText, command = kb.RegisterAction(actionType, actionID, name) - - - local isAssigned, isBound, assignedBy, boundBy = kb.IsCommandBound(self, command) - if isAssigned then - local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] - popup.slot = self - popup.text = "Currently assigned in |cFFFFFF00"..tostring(kb.configHeaders[assignedBy]).."|r. Are you sure?" - popup.oldProfile = assignedBy - popup.args = {command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook } - kb:SetScript('OnMouseWheel', nil) -- disable scrolling - StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT') - else - kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook) - kb.UpdateSlot(self) - self.active = nil - ClearCursor() - ResetCursor() - end - end -end - -kb.PickupSlot = function(self) - if not self.command then - return - end - print(self.actionType) - if self.actionType == 'spell' then - -- It can't be picked up if SpellInfo(name) returns void - local dummy = GetSpellInfo(self.actionName) - if not dummy then - return - end - elseif self.actionType == 'petaction' then - PickupSpellBookItem(self.pickupSlot, self.pickupBook) - end - if PickupAction[self.actionType] then - if GetPickupValue[self.actionType] then - PickupAction[self.actionType](GetPickupValue[self.actionType](self)) - else - PickupAction[self.actionType](self.actionID) - end - kb.ReleaseSlot(self) - kb.UpdateSlot(self) - end -end - - ---- Resolve the appropriate command and macroText for the given action parameters -kb.RegisterAction = function(type, id, name) - local macroText, macroName, command = '', '', '' - - if type == 'spell' then - if kb.ProfessionCache[id] then - command = CLICK_KEYBINDER_KEY .. "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum - else - command = CLICK_KEYBINDER_KEY ..name - end - else - macroName = type .. ' ' .. name - macroText = ACTION_SCRIPT[type]:format(name) - local baseName, iterative = macroName, 1 - while (macros[macroName] and macros[macroName][1] ~= macroText) do - print(' * cannot use|cFF00FF00', macroName, '|r"'.. (macros[macroName][1] or '') .. '"') - macroName = baseName .. '_' .. iterative - iterative = iterative + 1 - end - if macroName ~= baseName then - print(' * Creating|cFF00FF00', macroName) - else - print(' * Re-using|cFF00FF00', macroName) - end - command = 'CLICK KeyBinderMacro:'.. macroName - macros[macroName] = {macroText, command } - end - - print('RegisterAction', type, id, '->', command , macroText) - return macroName, macroText, command -end - ---- Updates the current KeyBinding for the button's command -kb.StoreBinding = function(self, key) - - if not self.command then - return - end - - if key:match('[RL]SHIFT') or key:match('[RL]ALT') or key:match('[RL]CTRL') then - return - end - print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key) - - if key == 'ESCAPE' then - local keys = {GetBindingKey(self.command) } - --print('detected', #keys, 'bindings') - for i, key in pairs(keys) do - --print('clearing', key) - SetBinding(key, nil) - SaveBindings(GetCurrentBindingSet()) - if kb.currentProfile.bindings[key] then - kb:print(BINDING_REMOVED:format(self.actionName, kb.configHeaders[db.bindMode])) - kb.currentProfile.bindings[key] = nil - end - if kb.currentProfile.talents[self.actionName] then - kb.currentProfile.talents[self.actionName] = nil - end - bindings[self.actionType][self.actionID] = nil - end - if kb.currentProfile.bound[self.command] then - kb.currentProfile.bound[self.command] = nil - --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode])) - end - - bindsCommitted = false - self.active = false - else - - local modifier = '' - if IsAltKeyDown() then - modifier = 'ALT-' - end - if IsControlKeyDown() then - modifier = modifier.. 'CTRL-' - end - if IsShiftKeyDown() then - modifier = modifier..'SHIFT-' - end - - - if self.command then - self.binding = modifier..key - - local previousKeys - local previousAction = GetBindingAction(self.binding) - local binding1, binding2, new1, new2 - print(type(previousAction), previousAction) - if previousAction ~= "" and previousAction ~= self.command then - if protected[previousAction] then - -- bounce out if trying to use a protected key - kb.statustext:SetText(BINDING_FAILED_PROTECTED:format(key, GetBindingAction(previousAction))) - kb.bindingstext:SetText(nil) - return - else - kb:print('Discarding keybind for', previousAction) - -- todo: sort out retcon'd talent spells - end - end - - self.pending = true - - bindsCommitted = false - SetBinding(self.binding, self.command) - SaveBindings(GetCurrentBindingSet()) - - local talentInfo - if self.actionType == 'spell' and kb.TalentCache[self.actionID] then - print('conditional binding (talent = "'..self.actionName..'")') - talentInfo = {self.macroName, self.actionName, self.actionType, self.actionID} - local bindings = {GetBindingKey(self.command) } - for i, key in ipairs(bindings) do - tinsert(talentInfo, key) - end - end - - for level, profile in ipairs(kb.orderedProfiles) do - if (level == db.bindMode) then - profile.bound[self.command] = true - if talentInfo then - profile.bindings[self.binding] = nil - else - profile.bindings[self.binding] = self.command - end - profile.talents[self.actionName] = talentInfo - else - profile.bindings[self.binding] = nil - profile.bound[self.command] = nil - kb.currentProfile.talents[self.actionName] = nil - end - if kb.currentProfile.talents[self.actionID] then - kb.currentProfile.talents[self.actionID] = nil - end - - end - - - - kb:print(BINDING_ASSIGNED:format(self.binding, self.actionName, kb.configHeaders[db.bindMode])) - - end - end - - kb.UpdateSlot(self, true) - KeyBinderSaveButton:Enable() - -end - - -kb.inactiveTalentBindings = {} -kb.ApplyTalentBinding = function(talentInfo, cache) - for i = 5, #talentInfo do - local command = CLICK_KEYBINDER_KEY.. talentInfo[2] - SetBinding(talentInfo[i], command) - cprint(' **', talentInfo[i], '->', command) - tinsert(cache, talentInfo[i]) - end -end -kb.CacheTalentBinding = function(talentInfo, cache) - - local spellID = talentInfo[4] - kb.inactiveTalentBindings[spellID] = kb.inactiveTalentBindings[spellID] or {} - kb.inactiveTalentBindings[spellID] = {select(5,unpack(talentInfo)) } - --cprint(spellID, unpack(kb.inactiveTalentBindings[spellID])) -end - -kb.LoadBinding = function(command, name, icon, actionType, actionID, macroName, macroText ) - - if actionType == 'spell' then - KeyBinderKey:SetAttribute("*type-"..name, actionType) - KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name) - - elseif actionType == 'item' then - KeyBinderKey:SetAttribute("*type-"..name, actionType) - KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name) - elseif actionType == 'macro' then - KeyBinderMacro:SetAttribute("*macro-"..macroName, actionID) - else - KeyBinderMacro:SetAttribute("*macrotext-"..macroName, macroText) - end - - cprint('Loading binding', actionType, actionID) - bindings[actionType] = bindings[actionType] or {} - bindings[actionType][actionID] = bindings[actionType][actionID] or {} - bindings[command] = bindings[actionType][actionID] - return bindings[actionType], actionID -end - -kb.ApplyBindings = function (profile) - cprint('binding profile', profile) - for slot, data in pairs(profile.buttons) do - kb.LoadBinding(unpack(data)) - end - - for key, command in pairs(profile.bindings) do - - cprint(' *', key, '->', command) - - --_G.print('HotKey','loading', key, command) - SetBinding(key, command) - if bindings[command] and not tContains(bindings[command], key) then - tinsert(bindings[command], key) - end - end - - for spellName, talentInfo in pairs(profile.talents) do - local dummy = GetSpellInfo(spellName) - local func = kb.CacheTalentBinding - local dest = kb.inactiveTalentBindings - if dummy then - cprint('|cFFBBFF00Active:|r', dummy) - local macroName, spellName, actionType, actionID = unpack(talentInfo) - bindings[actionType] = bindings[actionType] or {} - bindings[actionType][actionID] = {} - func = kb.ApplyTalentBinding - dest = bindings[actionType][actionID] - else - - cprint('|cFFFF4400Inactive:|r', talentInfo[2]) - end - func(talentInfo, dest) - end - - SaveBindings(GetCurrentBindingSet()) -end - -kb.ApplyAllBindings =function () - table.wipe(kb.inactiveTalentBindings) - - -- reflect action key settings - if GetCVarBool("ActionButtonUseKeyDown") then - KeyBinderMacro:RegisterForClicks("AnyDown") - KeyBinderKey:RegisterForClicks("AnyDown") - else - KeyBinderMacro:RegisterForClicks("AnyUp") - KeyBinderKey:RegisterForClicks("AnyUp") - end - - for i, profile in ipairs(kb.orderedProfiles) do - kb.ApplyBindings(profile) - end - -- do this after to ensure that profession binds are properly overridden - kb.UpdateProfessionInfo() - - -end - -kb.Command = function(args, editor) - if args:match("import") then - kb.ImportCommmit(args) - return - elseif args:match("scan") then - kb.ImportScan(args) - kb.ui() - return - elseif args:match("load") then - kb:ApplyAllBindings() - return - end - - if db.showUI then - db.showUI = false - kb:print('|cFFFFFF00KeyBinds|r trace, |cFFFF0000OFF|r.') - kb:Hide() - else - db.showUI = true - kb:print('|cFFFFFF00KeyBinds|r trace, |cFF00FF00ON|r.') - end - kb.ui(true) -end - -kb.InitProfile = function(profile, prototype) - if not profile then - profile = {} - end - if prototype then - print('appplying prototype', prototype) - for k,v in pairs(prototype) do - if not profile[k] then - profile[k] = v - end - end - end - - profile.bound = profile.bound or {} - profile.buttons = profile.buttons or {} - profile.commands = profile.commands or {} - profile.bindings = profile.bindings or {} - profile.macros = profile.macros or {} - profile.talents = profile.talents or {} - return profile -end - -kb.ResetProfile = function(profile, prototype) - if profile == kb.currentProfile then - for i, button in pairs(buttons) do - kb.ReleaseSlot(button) - end - end - table.wipe(profile) - kb.InitProfile(profile, prototype) -end - - - ---- Handles constructing spec profiles as they are selected - - ---- Obtains profile data or creates the necessary tables -kb.SelectProfileSet = function(name) - - local defaultMode - --- General info - classHeader, className, classID = UnitClass('player') - print('|cFF00FF00profile:|r', name) - print('|cFF00FF00class:|r', UnitClass('player')) - - --- Global - defaultMode = BINDING_TYPE_GLOBAL - kb.InitProfile(db) - kb.loadedProfiles[BINDING_TYPE_GLOBAL] = db - - --- Character - if name then - db[name] = kb.InitProfile(db[name], - {classHeader = classHeader, className = className, classID = classID}) - kb.loadedProfiles[BINDING_TYPE_CHARACTER] = db[name] - defaultMode = BINDING_TYPE_CHARACTER - end - - --- Mutable skills data - kb.UpdateSpecInfo() - kb.UpdateTalentInfo() - - kb.orderedProfiles = {kb.loadedProfiles[BINDING_TYPE_GLOBAL], kb.loadedProfiles[BINDING_TYPE_CHARACTER], kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION]} - if db.bindMode and (not kb.configTitle[db.bindMode]) then - print('fixing bad bindMode value, was', db.bindMode) - db.bindMode = defaultMode - end - - - print(BINDING_TYPE_GLOBAL) - kb.configHeaders[BINDING_TYPE_GLOBAL] = kb.configTitle[BINDING_TYPE_GLOBAL] - kb.configHeaders[BINDING_TYPE_CHARACTER] = kb.configTitle[BINDING_TYPE_CHARACTER]:format(UnitName('player', true)) - kb.configHeaders[BINDING_TYPE_SPECIALIZATION] = kb.configTitle[BINDING_TYPE_SPECIALIZATION]:format(kb.specInfo.name) - - - setmetatable(kb.loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return kb.configHeaders[BINDING_TYPE_GLOBAL] end}) - setmetatable(kb.loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return kb.configHeaders[BINDING_TYPE_CHARACTER] end}) - setmetatable(kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return kb.configHeaders[BINDING_TYPE_SPECIALIZATION] end}) - - print('|cFF00FF00bindMode:|r', db.bindMode) - kb.currentProfile = kb.loadedProfiles[db.bindMode] -end - -local scrollCache = {} -kb.SelectTab = function(self) - scrollCache[db.bindMode] = kb.scrollOffset - db.bindMode = self:GetID() - kb.currentProfile = kb.loadedProfiles[self:GetID()] - kb.scrollOffset = scrollCache[db.bindMode] or 0 - kb.ui(true) -end - -kb.RevertBindings = function() - -- todo: reversion code -end - -kb.ConfirmBindings = function() - SaveBindings(GetCurrentBindingSet()) - bindsCommitted = true - for i, button in ipairs(buttons) do - button.pending = false - end - kb.ApplyAllBindings() - - kb.ui() - kb:print('Keybinds saved.') -end - - - - ---- post ADDON_LOADED -kb.variables = function() - SkeletonKeyDB = SkeletonKeyDB or {spec = {}} - kb.db = SkeletonKeyDB - kb.playerName = UnitName('player') - kb.playerRealm = SelectedRealmName() - kb.profileName = kb.playerRealm .. '_' .. kb.playerName - db = kb.db - - kb.SelectProfileSet(kb.profileName) - -- todo: redo import checking - - - - kb.ApplyAllBindings() - - kb.ui(true) -end - - -kb.wrap = function(module) - kb.modules = kb.modules or {} - tinsert(kb.modules, module) -end - --- Volatiles Access -kb.GetBindings = function() return bindings end -kb.GetButtons = function() return buttons end -kb.GetCharacterProfile = function () return kb.loadedProfiles[BINDING_TYPE_CHARACTER] end -kb.GetGlobalProfile = function () return kb.loadedProfiles[BINDING_TYPE_GLOBAL] end -kb.GetLooseTalents = function() return talentBindings end -kb.GetReverts = function() return reverts end -kb.GetSpecProfile = function () return kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] end - - -SLASH_SKB1 = "/skb" -SLASH_SKB2 = "/skeletonkey" -SlashCmdList.SKB = kb.Command - --- This is needed to identify a spells that aren't reflected by GetCursorInfo() -hooksecurefunc("PickupSpellBookItem", function(slot, bookType) - print('|cFFFF4400PickupSpellBookItem(..', tostring(slot),', '..tostring(bookType)..')') - CURSOR_SPELLSLOT = slot - CURSOR_BOOKTYPE = bookType -end) - --- Pet actions -local isPickup -hooksecurefunc("PickupPetAction", function(slot, ...) - isPickup = GetCursorInfo() - - CURSOR_PETACTION = isPickup and slot - print('|cFFFF4400PickupPetAction|r', isPickup, CURSOR_PETACTION) -end) \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/KeySlot.lua Thu Jul 28 23:58:53 2016 -0400 @@ -0,0 +1,416 @@ +-- SkeletonKey +-- KeySlot.lua +-- Created: 7/28/2016 11:26 PM +-- %file-revision% +-- All the internal slot logic is kept here + +local kb, print = LibStub('LibKraken').register(KeyBinder, 'Slot') +local CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION +local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 +local BORDER_UNASSIGNED = {0.2,0.2,0.2,1 } +local BORDER_ASSIGNED = {0.5,0.5,0.5,1 } +local BORDER_DYNAMIC = {1,1,0,1} +local BORDER_PENDING = {1,0.5,0,1 } + +local BUTTON_HEADERS = { + ['spell'] = SPELLS, + ['macro'] = MACRO, + ['petaction'] = PET, + ['mount'] = MOUNT, + ['battlepet'] = BATTLEPET, + + + [5] = PROFESSIONS_FIRST_AID, + [7] = PROFESSIONS_COOKING, + [9] = PROFESSIONS_FISHING, + [10] = PROFESSIONS_ARCHAEOLOGY, + +} + +-- This is needed to identify a spells that aren't reflected by GetCursorInfo() +hooksecurefunc("PickupSpellBookItem", function(slot, bookType) + print('|cFFFF4400PickupSpellBookItem(..', tostring(slot),', '..tostring(bookType)..')') + CURSOR_SPELLSLOT = slot + CURSOR_BOOKTYPE = bookType +end) + +do +-- Pet actions + local isPickup + hooksecurefunc("PickupPetAction", function(slot, ...) + isPickup = GetCursorInfo() + + CURSOR_PETACTION = isPickup and slot + print('|cFFFF4400PickupPetAction|r', isPickup, CURSOR_PETACTION) + end) +end + + +kb.DropToSlot = function(self) + print(self:GetName(),'|cFF0088FFreceived|r') + local actionType, actionID, subType, subData = GetCursorInfo() + print('GetCursorInfo', GetCursorInfo()) + if actionType then + + if actionType == 'flyout' then + ClearCursor() + ResetCursor() + return + end + + + local macroName, macroText + local command, name, icon, _ + local pickupID, pickupBook + + if actionType == 'spell' then + actionID = subData + name, _, icon = GetSpellInfo(actionID) + + elseif actionType == 'macro' then + name, icon = GetMacroInfo(actionID) + elseif actionType == 'petaction' then + if not (CURSOR_SPELLSLOT and CURSOR_BOOKTYPE) then + + ClearCursor() + ResetCursor() + end + + local bookType, spellID = GetSpellBookItemInfo(CURSOR_SPELLSLOT, CURSOR_BOOKTYPE) + actionID = spellID + pickupID = CURSOR_SPELLSLOT + pickupBook = CURSOR_BOOKTYPE + name, _, icon = GetSpellInfo(spellID) + elseif actionType == 'mount' then + if subType == 0 then + name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) + actionID = 0 + else + name, _, icon = C_MountJournal.GetMountInfoByID(actionID) + end + elseif actionType == 'item' then + name = GetItemInfo(actionID) + icon = GetItemIcon(actionID) + actionID = name + elseif actionType == 'battlepet' then + + local speciesID, customName, level, xp, maxXp, displayID, isFavorite, petName, petIcon, petType, creatureID = C_PetJournal.GetPetInfoByPetID(detail); + name = customName or petName + icon = petIcon + + end + macroName, macroText, command = kb.RegisterAction(actionType, actionID, name) + + + local isAssigned, isBound, assignedBy, boundBy = kb.IsCommandBound(self, command) + if isAssigned then + local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] + popup.slot = self + popup.text = "Currently assigned in |cFFFFFF00"..tostring(kb.configHeaders[assignedBy]).."|r. Are you sure?" + popup.oldProfile = assignedBy + popup.args = {command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook } + kb:SetScript('OnMouseWheel', nil) -- disable scrolling + StaticPopup_Show('SKELETONKEY_CONFIRM_ASSIGN_SLOT') + else + kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook) + kb.UpdateSlot(self) + self.active = nil + ClearCursor() + ResetCursor() + end + end +end + + +do + local PickupAction = { + spell = _G.PickupSpell, + petaction = _G.PickupSpellBookItem, + macro = _G.PickupMacro, + item = _G.PickupItem, + mount = _G.C_MountJournal.Pickup + } + local GetPickupValue = { + spell = function(self) return select(7, GetSpellInfo(self.actionID)) end, + petaction = function(self) return self.pickupSlot, self.pickupBook end, + } + kb.PickupSlot = function(self) + if not self.command then + return + end + print(self.actionType) + if self.actionType == 'spell' then + -- It can't be picked up if SpellInfo(name) returns void + local dummy = GetSpellInfo(self.actionName) + if not dummy then + return + end + end + if PickupAction[self.actionType] then + if GetPickupValue[self.actionType] then + PickupAction[self.actionType](GetPickupValue[self.actionType](self)) + else + PickupAction[self.actionType](self.actionID) + end + kb.ReleaseSlot(self) + kb.UpdateSlot(self) + end + end +end + + + +--- Updates profile assignment and button contents +kb.UpdateSlot = function(self, force) + local slot = self:GetID() + + if force then + if kb.currentProfile.buttons[slot] then + kb.SetSlot(self, unpack(kb.currentProfile.buttons[slot])) + else + kb.ReleaseSlot(self) + end + end + + if self.command then + print('['..slot..'] =', self.command, GetBindingKey(self.command)) + + if self.pending then + self.border:SetColorTexture(unpack(BORDER_PENDING)) + elseif self.isDynamic then + self.border:SetColorTexture(unpack(BORDER_DYNAMIC)) + else + self.border:SetColorTexture(unpack(BORDER_ASSIGNED)) + end + + if self.actionType == 'macro' then + self.macro:Show() + else + self.macro:Hide() + if self.actionType == 'spell' then + local dummy = GetSpellInfo(self.actionName) + if not dummy then + self.icon:SetDesaturated(true) + else + self.icon:SetDesaturated(false) + end + + end + end + + if self.isDynamic then + print('|cFFFFBB00UpdateSlot|r: ', self.isDynamic, self.isAvailable, self.actionID) + end + + if self.isDynamic == 'profession' then + local profText = (self.spellNum == 1) and TRADE_SKILLS or (BUTTON_HEADERS[self.profIndex] or GetProfessionInfo(self.profIndex)) + if self.isAvailable then + print(self.profIndex, 'spnum', type(self.spellNum), (self.spellNum == 1)) + + self.statusText = '|cFFFFFF00'..profText..'|r' + self.bindingText = kb.BindingString(GetBindingKey(self.command)) + else + self.statusText = '|cFFFF4400'..profText..'|r' + self.actionName = '(need to train profession #'..self.profNum..')' + self.bindingText ='?' + end + elseif self.isDynamic == 'talent' then + + self.statusText = '|cFF00FFFF'.. TALENT .. '|r' + if self.isAvailable then + self.bindingText = kb.BindingString(GetBindingKey(self.command)) + else + if kb.inactiveTalentBindings[self.actionID] then + print(self.actionID, #kb.inactiveTalentBindings[self.actionID]) + self.bindingText= kb.BindingString(unpack(kb.inactiveTalentBindings[self.actionID])) + end + + end + else + self.statusText = '|cFF00FF00'.. (BUTTON_HEADERS[self.actionType] and BUTTON_HEADERS[self.actionType] or self.actionType) .. '|r' + self.bindingText = kb.BindingString(GetBindingKey(self.command)) + end + + local locked, layer = kb.IsCommandBound(self) + if locked then + self.icon:SetAlpha(0.5) + else + self.icon:SetAlpha(1) + end + + if self.actionType == 'spell' then + self.icon:SetTexture(GetSpellTexture(self.actionID)) + end + end + + if not self.isAvailable then + self.bind:SetTextColor(0.7,0.7,0.7,1) + else + self.bind:SetTextColor(1,1,1,1) + end + + self.header:SetText(self.statusText) + self.bind:SetText(self.bindingText) + self.details:SetText(self.actionName) +end + +--- Resets button command +kb.ReleaseSlot = function(self) + local slot = self:GetID() + + + if kb.currentProfile.buttons[slot] then + kb.currentProfile.buttons[slot] = nil + end + if self.command then + kb.currentProfile.commands[self.command] = nil + end + if self.actionType == 'spell' and IsTalentSpell(self.actionName) then + if kb.currentProfile.talents[self.actionID] then + kb.currentProfile.talents[self.actionID] = nil + end + end + local droppedKeys = {} + + -- doing removal in second loop to avoid possible iterator shenanigans + for k,v in pairs(kb.currentProfile.bindings) do + if v == self.command then + tinsert(droppedKeys, k) + end + end + if #droppedKeys >=1 then + for i, k in ipairs(droppedKeys) do + kb.currentProfile.bindings[k] = nil + end + end + + self.isAvailable = nil + self.isDynamic = nil + self.bindingText = nil + self.statusText = nil + self.command = nil + self.actionType = nil + self.actionID = nil + self.actionName = nil + self.pickupSlot = nil + self.pickupBook = nil + self.macroName = nil + self.profile = nil + self.icon:SetTexture(nil) + self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) + self:EnableKeyboard(false) + self:SetScript('OnKeyDown', nil) +end + +kb.SetSlot = function(self, command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook) + local slot = self:GetID() + local isDynamic, isAvailable + + print('|cFFFFFF00SetSlot|r:', self:GetID()) + if command then + + if actionType == 'spell' then + local professionNum, spellNum = command:match("profession_(%d)_(%d)") + + if (professionNum and spellNum) then + isDynamic = 'profession' + local cacheInfo = kb.ProfessionCache[professionNum..'_'..spellNum] + if cacheInfo then + isAvailable = true + name = cacheInfo.spellName + icon = cacheInfo.icon + actionID = cacheInfo.spellID + self.profIndex = cacheInfo.profIndex + self.spellOffset = cacheInfo.spellOffset + end + print(' Special slot: |cFF00FFFFProfession|r', professionNum, spellNum, isDynamic, isAvailable) + + self.professionNum = tonumber(professionNum) + self.spellNum = tonumber(spellNum) + + else + if kb.TalentCache[actionID] then + isDynamic = 'talent' + print(' Special slot: |cFFBBFF00talent|r', name, isAvailable) + end + + isAvailable = GetSpellInfo(name) + end + elseif actionType == 'macro' then + if not actionID then + actionID = GetMacroIndexByName(name) + end + isAvailable = true + else + --- Journal selections + -- todo: consider using the deep end of blizzard action bar instead + if not actionID then + actionID = command:match("^KeyBinderMacro:(.+)") + end + isAvailable = true + end + + if isAvailable then + local oldCommand = command + macroName, macroText, command = kb.RegisterAction(actionType, actionID, name) + if oldCommand ~= command then + print('|cFFFF4400fixing command string', actionType, actionID, name) + kb.currentProfile.bound[oldCommand] = nil + kb.currentProfile.bound[command] = slot + for k,v in pairs(kb.currentProfile.bindings) do + if v == oldCommand then + kb.currentProfile.bindings[k] = command + end + end + end + kb.LoadBinding(command, name, icon, actionType, actionID, macroName, macroText) + end + + if actionType == 'petaction' then + self.pickupSlot = pickupSlot + self.pickupBook = pickupBook + else + self.pickupSlot = nil + self.pickupBook = nil + end + + actionID = actionID or 0 + self:EnableKeyboard(true) + print(' |cFF00FF00kb.currentProfile.buttons['..slot..'] |cFF00FFFF=|r |cFF00FFFF"'.. command.. '"|r |cFF00FF00"'.. name, '"|r |cFFFFFF00icon:'.. icon .. '|r |cFFFF8800"'.. actionType, '"|r |cFFFF0088id:'.. actionID ..'|r |cFF00FF00"'.. macroName .. '"|r') + kb.currentProfile.buttons[slot] = {command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook} + + -- Clean up conflicting entries for loaded button + local previous = kb.currentProfile.commands[command] + if previous ~= slot and kb.buttons[previous] then + kb.ReleaseSlot(kb.buttons[previous]) + end + kb.currentProfile.commands[command] = slot + end + + self.isAvailable = isAvailable + self.isDynamic = isDynamic + + self.macroText = macroText + self.macroName = macroName + self.actionType = actionType + self.actionID = actionID + self.actionName = name + self.command = command + self.icon:SetTexture(icon) + self.profile = kb.db.bindMode + self:RegisterForDrag('LeftButton') +end + + + +--- Add to blizzard interfaces +StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = { + text = "Confirm moving an assigned command.", + button1 = OKAY, + button2 = CANCEL, + timeout = 0, + whileDead = 1, + showAlert = 1, + OnAccept = kb.AcceptAssignment, + OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/SkeletonKey.lua Thu Jul 28 23:58:53 2016 -0400 @@ -0,0 +1,581 @@ +-------------------------------------------- +-- SkeletonKey +-- Krakyn-Mal'Ganis +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 6/16/2016 3:47 AM +-------------------------------------------- +-- kb +-- .StoreBinding(button, key) bind current keystroke to command +-- .GetSlot(index) return display slot +-- .SetSlot(button, command, name, icon) assign display slot +-- .ReleaseSlot(button) clear button command +-- .UpdateSlot(button) update button contents +-- .SelectProfile(name) set profile character +-- .ApplyBindings(bindings) walk table with SetBinding() + +local _ +local kb, print = LibStub("LibKraken").register(KeyBinder) +local cprint = DEVIAN_WORKSPACE and function(...) _G.print('Cfg', ...) end or function() end +kb.L = setmetatable({}, { + __call = function(t, k, ...) return format(t[k] or '', ...) end +}) +local L = kb.L + +--- Caps Lock literals +local CLICK_KEYBINDER_MACRO = "CLICK KeyBinderMacro:" +local CLICK_KEYBINDER_KEY = "CLICK KeyBinderKey:" +local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES" +local FOOTER_OFFSET +local HEADER_OFFSET +L.BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).' +L.BINDING_REMOVED = '|cFFFFFF00%s|r (|cFF00FFFF%s|r) unbound.' +L.BINDING_FAILED_PROTECTED = '|cFFFF4400Unable to use |r|cFF00FF00%s|r|cFFFF4400 (currently |cFFFFFF00%s|r|cFFFF4400)|r' + + +local BINDING_TYPE_SPECIALIZATION = 3 +local BINDING_TYPE_CHARACTER = 2 +local BINDING_TYPE_GLOBAL = 1 + + +--- Caps Lock derivatives +local ACTION_SCRIPT = { + ['mount'] = "/script C_MountJournal.SummonByID(%d)", + ['macro'] = "%s", + ['equipset'] = "/script UseEquipmentSet(%d)", + ['spell'] = "/cast %s", + ['petaction'] = "/cast %s", + ['battlepet'] = SLASH_SUMMON_BATTLE_PET1 .. " %s", + ['item'] = "/use %s" +} + +local professionMappings = { + [5] = 3, + [7] = 4, + [9] = 5, + [10] = 6 +} +kb.configTitle = { + [BINDING_TYPE_GLOBAL] = 'Global Binds', + [BINDING_TYPE_CHARACTER] = 'Character: %s', + [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s' +} +kb.configDescription = { + [BINDING_TYPE_GLOBAL] = 'The bindings are applied globally.', + [BINDING_TYPE_CHARACTER] = 'Applied when you log onto this character.', + [BINDING_TYPE_SPECIALIZATION] = 'Applied when you log onto this character and are that specialization.', +} + + + +kb.inactiveTalentBindings = {} +kb.configHeaders = {} +kb.loadedProfiles = {} +kb.orderedProfiles = {} +kb.buttons = {} +kb.macros = {} + +-- these are sent to plugin + +local bindings = {} +local macros = {} +local talentBindings = {} + +local protected = { + ['OPENCHATSLASH'] = true, + ['OPENCHAT'] = true, +} + + +local db +local bindHeader, currentHeader = '', '' +local specID, specGlobalID, specName, specDesc, specTexture, characterHeader = 0, 0, 'SPEC_NAME', 'SPEC_DESCRIPTION', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME' +local classHeader, className, classID = '', '', 0 +local bindsCommitted = true +local forceButtonUpdate = false + +--- Control handles +local saveButton, restoreButton, clearButton + +--- Returns conflicting assignment and binding profiles for use in displaying confirmations +kb.IsCommandBound = function(self, command) + local isAssigned, assignedBy = false, db.bindMode + local isBound, boundBy = false, db.bindMode + + + command = command or self.command + for i = 1, #kb.orderedProfiles do + local tier = kb.orderedProfiles[i] + if i ~= db.bindMode then + + if tier.commands[command] then + isAssigned = true + assignedBy = i + end + if tier.bound[command] then + isBound = true + boundBy = i + end + + + --print(' *', configHeaders[i], tier.commands[command], tier.bound[command]) + + if isAssigned and isBound then + break + end + end + + end + + print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', db.bindMode .. ']', isAssigned, isBound, assignedBy, boundBy) + return isAssigned, isBound, assignedBy, boundBy +end + +local talentSpellHardCodes = { + [109248] = 'Binding Shot', +} + +--- Returns a value for use with Texture:SetDesaturated() +kb.BindingIsLocked = function(key) + local success = false + for i = 1, db.bindMode-1 do + local tier = kb.orderedProfiles[i] + if tier.bindings[key] then + success = true + break + end + end + return success +end + +--- Translates GetBindingKey() results into a printable string. +kb.BindingString = function(...) + local stack = {} + for i = 1, select('#', ...) do + local key = select(i, ...) + stack[i] = key:gsub('SHIFT', 's'):gsub('ALT', 'a'):gsub('CTRL', 'c'):gsub('SPACE', 'Sp'):gsub('BUTTON', 'M '):gsub('NUMPAD', '# ') + end + + if #stack >= 1 then + return table.concat(stack, ',') + else + return nil + end +end + + +--- Resolve the appropriate command and macroText for the given action parameters +kb.RegisterAction = function(type, id, name) + local macroText, macroName, command = '', '', '' + + if type == 'spell' then + if kb.ProfessionCache[id] then + command = CLICK_KEYBINDER_KEY .. "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum + else + command = CLICK_KEYBINDER_KEY ..name + end + else + macroName = type .. ' ' .. name + macroText = ACTION_SCRIPT[type]:format(name) + local baseName, iterative = macroName, 1 + while (macros[macroName] and macros[macroName][1] ~= macroText) do + print(' * cannot use|cFF00FF00', macroName, '|r"'.. (macros[macroName][1] or '') .. '"') + macroName = baseName .. '_' .. iterative + iterative = iterative + 1 + end + if macroName ~= baseName then + print(' * Creating|cFF00FF00', macroName) + else + print(' * Re-using|cFF00FF00', macroName) + end + command = 'CLICK KeyBinderMacro:'.. macroName + macros[macroName] = {macroText, command } + end + + print('RegisterAction', type, id, '->', command , macroText) + return macroName, macroText, command +end + +--- Updates the current KeyBinding for the button's command +kb.StoreBinding = function(self, key) + + if not self.command then + return + end + + if key:match('[RL]SHIFT') or key:match('[RL]ALT') or key:match('[RL]CTRL') then + return + end + print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key) + + if key == 'ESCAPE' then + local keys = {GetBindingKey(self.command) } + --print('detected', #keys, 'bindings') + for i, key in pairs(keys) do + --print('clearing', key) + SetBinding(key, nil) + SaveBindings(GetCurrentBindingSet()) + if kb.currentProfile.bindings[key] then + kb:print(L('BINDING_REMOVED', self.actionName, kb.configHeaders[db.bindMode])) + kb.currentProfile.bindings[key] = nil + end + if kb.currentProfile.talents[self.actionName] then + kb.currentProfile.talents[self.actionName] = nil + end + bindings[self.actionType][self.actionID] = nil + end + if kb.currentProfile.bound[self.command] then + kb.currentProfile.bound[self.command] = nil + --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode])) + end + + bindsCommitted = false + self.active = false + else + + local modifier = '' + if IsAltKeyDown() then + modifier = 'ALT-' + end + if IsControlKeyDown() then + modifier = modifier.. 'CTRL-' + end + if IsShiftKeyDown() then + modifier = modifier..'SHIFT-' + end + + + if self.command then + self.binding = modifier..key + + local previousKeys + local previousAction = GetBindingAction(self.binding) + local binding1, binding2, new1, new2 + print(type(previousAction), previousAction) + if previousAction ~= "" and previousAction ~= self.command then + if protected[previousAction] then + -- bounce out if trying to use a protected key + kb.statustext:SetText(L('BINDING_FAILED_PROTECTED', key, GetBindingAction(previousAction))) + kb.bindingstext:SetText(nil) + return + else + kb:print('Discarding keybind for', previousAction) + -- todo: sort out retcon'd talent spells + end + end + + self.pending = true + + bindsCommitted = false + SetBinding(self.binding, self.command) + SaveBindings(GetCurrentBindingSet()) + + local talentInfo + if self.actionType == 'spell' and kb.TalentCache[self.actionID] then + print('conditional binding (talent = "'..self.actionName..'")') + talentInfo = {self.macroName, self.actionName, self.actionType, self.actionID} + local bindings = {GetBindingKey(self.command) } + for i, key in ipairs(bindings) do + tinsert(talentInfo, key) + end + end + + for level, profile in ipairs(kb.orderedProfiles) do + if (level == db.bindMode) then + profile.bound[self.command] = true + if talentInfo then + profile.bindings[self.binding] = nil + else + profile.bindings[self.binding] = self.command + end + profile.talents[self.actionName] = talentInfo + else + profile.bindings[self.binding] = nil + profile.bound[self.command] = nil + kb.currentProfile.talents[self.actionName] = nil + end + if kb.currentProfile.talents[self.actionID] then + kb.currentProfile.talents[self.actionID] = nil + end + end + + kb:print(L('BINDING_ASSIGNED', self.binding, self.actionName, kb.configHeaders[db.bindMode])) + end + end + kb.UpdateSlot(self, true) + KeyBinderSaveButton:Enable() +end + + +kb.inactiveTalentBindings = {} +kb.ApplyTalentBinding = function(talentInfo, cache) + for i = 5, #talentInfo do + local command = CLICK_KEYBINDER_KEY.. talentInfo[2] + SetBinding(talentInfo[i], command) + cprint(' **', talentInfo[i], '->', command) + tinsert(cache, talentInfo[i]) + end +end +kb.CacheTalentBinding = function(talentInfo, cache) + + local spellID = talentInfo[4] + kb.inactiveTalentBindings[spellID] = kb.inactiveTalentBindings[spellID] or {} + kb.inactiveTalentBindings[spellID] = {select(5,unpack(talentInfo)) } + --cprint(spellID, unpack(kb.inactiveTalentBindings[spellID])) +end + +kb.LoadBinding = function(command, name, icon, actionType, actionID, macroName, macroText ) + + if actionType == 'spell' then + KeyBinderKey:SetAttribute("*type-"..name, actionType) + KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name) + + elseif actionType == 'item' then + KeyBinderKey:SetAttribute("*type-"..name, actionType) + KeyBinderKey:SetAttribute("*"..actionType.."-"..name, name) + elseif actionType == 'macro' then + KeyBinderMacro:SetAttribute("*macro-"..macroName, actionID) + else + KeyBinderMacro:SetAttribute("*macrotext-"..macroName, macroText) + end + + cprint('Loading binding', actionType, actionID) + bindings[actionType] = bindings[actionType] or {} + bindings[actionType][actionID] = bindings[actionType][actionID] or {} + bindings[command] = bindings[actionType][actionID] + return bindings[actionType], actionID +end + +kb.ApplyBindings = function (profile) + cprint('binding profile', profile) + for slot, data in pairs(profile.buttons) do + kb.LoadBinding(unpack(data)) + end + + for key, command in pairs(profile.bindings) do + + cprint(' *', key, '->', command) + + --_G.print('HotKey','loading', key, command) + SetBinding(key, command) + if bindings[command] and not tContains(bindings[command], key) then + tinsert(bindings[command], key) + end + end + + for spellName, talentInfo in pairs(profile.talents) do + local dummy = GetSpellInfo(spellName) + local func = kb.CacheTalentBinding + local dest = kb.inactiveTalentBindings + if dummy then + cprint('|cFFBBFF00Active:|r', dummy) + local macroName, spellName, actionType, actionID = unpack(talentInfo) + bindings[actionType] = bindings[actionType] or {} + bindings[actionType][actionID] = {} + func = kb.ApplyTalentBinding + dest = bindings[actionType][actionID] + else + + cprint('|cFFFF4400Inactive:|r', talentInfo[2]) + end + func(talentInfo, dest) + end + + SaveBindings(GetCurrentBindingSet()) +end + +kb.ApplyAllBindings =function () + table.wipe(kb.inactiveTalentBindings) + + -- reflect action key settings + if GetCVarBool("ActionButtonUseKeyDown") then + KeyBinderMacro:RegisterForClicks("AnyDown") + KeyBinderKey:RegisterForClicks("AnyDown") + else + KeyBinderMacro:RegisterForClicks("AnyUp") + KeyBinderKey:RegisterForClicks("AnyUp") + end + + for i, profile in ipairs(kb.orderedProfiles) do + kb.ApplyBindings(profile) + end + -- do this after to ensure that profession binds are properly overridden + kb.UpdateProfessionInfo() + + +end + +kb.Command = function(args, editor) + if args:match("import") then + kb.ImportCommmit(args) + return + elseif args:match("scan") then + kb.ImportScan(args) + kb.ui() + return + elseif args:match("load") then + kb:ApplyAllBindings() + return + end + + if db.showUI then + db.showUI = false + kb:print('|cFFFFFF00KeyBinds|r trace, |cFFFF0000OFF|r.') + kb:Hide() + else + db.showUI = true + kb:print('|cFFFFFF00KeyBinds|r trace, |cFF00FF00ON|r.') + end + kb.ui(true) +end + +kb.InitProfile = function(profile, prototype) + if not profile then + profile = {} + end + if prototype then + print('appplying prototype', prototype) + for k,v in pairs(prototype) do + if not profile[k] then + profile[k] = v + end + end + end + + profile.bound = profile.bound or {} + profile.buttons = profile.buttons or {} + profile.commands = profile.commands or {} + profile.bindings = profile.bindings or {} + profile.macros = profile.macros or {} + profile.talents = profile.talents or {} + return profile +end + +kb.ResetProfile = function(profile, prototype) + if profile == kb.currentProfile then + for i, button in pairs(buttons) do + kb.ReleaseSlot(button) + end + end + table.wipe(profile) + kb.InitProfile(profile, prototype) +end + + + +--- Handles constructing spec profiles as they are selected + + +--- Obtains profile data or creates the necessary tables +kb.SelectProfileSet = function(name) + + local defaultMode + --- General info + classHeader, className, classID = UnitClass('player') + print('|cFF00FF00profile:|r', name) + print('|cFF00FF00class:|r', UnitClass('player')) + + --- Global + defaultMode = BINDING_TYPE_GLOBAL + kb.InitProfile(db) + kb.loadedProfiles[BINDING_TYPE_GLOBAL] = db + + --- Character + if name then + db[name] = kb.InitProfile(db[name], + {classHeader = classHeader, className = className, classID = classID}) + kb.loadedProfiles[BINDING_TYPE_CHARACTER] = db[name] + defaultMode = BINDING_TYPE_CHARACTER + end + + --- Mutable skills data + kb.UpdateSpecInfo() + kb.UpdateTalentInfo() + + kb.orderedProfiles = {kb.loadedProfiles[BINDING_TYPE_GLOBAL], kb.loadedProfiles[BINDING_TYPE_CHARACTER], kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION]} + if db.bindMode and (not kb.configTitle[db.bindMode]) then + print('fixing bad bindMode value, was', db.bindMode) + db.bindMode = defaultMode + end + + + print(BINDING_TYPE_GLOBAL) + kb.configHeaders[BINDING_TYPE_GLOBAL] = kb.configTitle[BINDING_TYPE_GLOBAL] + kb.configHeaders[BINDING_TYPE_CHARACTER] = kb.configTitle[BINDING_TYPE_CHARACTER]:format(UnitName('player', true)) + kb.configHeaders[BINDING_TYPE_SPECIALIZATION] = kb.configTitle[BINDING_TYPE_SPECIALIZATION]:format(kb.specInfo.name) + + + setmetatable(kb.loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return kb.configHeaders[BINDING_TYPE_GLOBAL] end}) + setmetatable(kb.loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return kb.configHeaders[BINDING_TYPE_CHARACTER] end}) + setmetatable(kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return kb.configHeaders[BINDING_TYPE_SPECIALIZATION] end}) + + print('|cFF00FF00bindMode:|r', db.bindMode) + kb.currentProfile = kb.loadedProfiles[db.bindMode] +end + +local scrollCache = {} +kb.SelectTab = function(self) + scrollCache[db.bindMode] = kb.scrollOffset + db.bindMode = self:GetID() + kb.currentProfile = kb.loadedProfiles[self:GetID()] + kb.scrollOffset = scrollCache[db.bindMode] or 0 + kb.ui(true) +end + +kb.RevertBindings = function() + -- todo: reversion code +end + +kb.ConfirmBindings = function() + SaveBindings(GetCurrentBindingSet()) + bindsCommitted = true + for i, button in ipairs(buttons) do + button.pending = false + end + kb.ApplyAllBindings() + + kb.ui() + kb:print('Keybinds saved.') +end + + + + +--- post ADDON_LOADED +kb.variables = function() + SkeletonKeyDB = SkeletonKeyDB or {spec = {}} + kb.db = SkeletonKeyDB + kb.playerName = UnitName('player') + kb.playerRealm = SelectedRealmName() + kb.profileName = kb.playerRealm .. '_' .. kb.playerName + db = kb.db + + kb.SelectProfileSet(kb.profileName) + -- todo: redo import checking + + + + kb.ApplyAllBindings() + + kb.ui(true) +end + + +kb.wrap = function(module) + kb.modules = kb.modules or {} + tinsert(kb.modules, module) +end + +-- Volatiles Access +kb.GetBindings = function() return bindings end +kb.GetButtons = function() return buttons end +kb.GetCharacterProfile = function () return kb.loadedProfiles[BINDING_TYPE_CHARACTER] end +kb.GetGlobalProfile = function () return kb.loadedProfiles[BINDING_TYPE_GLOBAL] end +kb.GetLooseTalents = function() return talentBindings end +kb.GetReverts = function() return reverts end +kb.GetSpecProfile = function () return kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] end + + +SLASH_SKB1 = "/skb" +SLASH_SKB2 = "/skeletonkey" +SlashCmdList.SKB = kb.Command
--- a/SkeletonKey/SkeletonKey.toc Thu Jul 28 18:20:32 2016 -0400 +++ b/SkeletonKey/SkeletonKey.toc Thu Jul 28 23:58:53 2016 -0400 @@ -12,9 +12,11 @@ LibStub\LibStub.lua libKT-1.0\libKT-1.0.xml KeyBinds.xml -KeyBinds.lua +SkeletonKey.lua Cache.lua -UI.lua +BindingsUI.lua +KeySlot.lua + Events.lua HotKey.lua
--- a/SkeletonKey/UI.lua Thu Jul 28 18:20:32 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,616 +0,0 @@ --- KrakTool --- UI.lua --- Created: 7/28/2016 3:39 PM --- %file-revision% --- - -local kb, print = LibStub("LibKraken").register(KeyBinder, 'KeySlot') -local BINDS_PER_ROW = 2 -local BUTTON_HSPACING = 128 -local BUTTON_SPACING = 4 -local BUTTON_PADDING = 12 -local BINDING_TYPE_SPECIALIZATION = 3 -local BINDING_TYPE_CHARACTER = 2 -local BINDING_TYPE_GLOBAL = 1 -local KEY_BUTTON_SIZE = 48 -local MIN_BIND_SLOTS = 32 -local TAB_OFFSET = 12 -local TAB_HEIGHT = 40 -local TAB_SPACING = 2 -local BORDER_UNASSIGNED = {0.2,0.2,0.2,1 } -local BORDER_ASSIGNED = {0.5,0.5,0.5,1 } -local BORDER_DYNAMIC = {1,1,0,1} -local BORDER_PENDING = {1,0.5,0,1 } - -local BUTTON_HEADERS = { - ['spell'] = SPELLS, - ['macro'] = MACRO, - ['petaction'] = PET, - ['mount'] = MOUNT, - ['battlepet'] = BATTLEPET, - - - [5] = PROFESSIONS_FIRST_AID, - [7] = PROFESSIONS_COOKING, - [9] = PROFESSIONS_FISHING, - [10] = PROFESSIONS_ARCHAEOLOGY, - -} - -local BINDING_SCHEME_COLOR = { - [BINDING_TYPE_GLOBAL] = {0,.125,.5,.5}, - [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.5}, - [BINDING_TYPE_SPECIALIZATION] = {.25,0,0,0.5}, -} -local BINDING_SCHEME_VERTEX = { - [BINDING_TYPE_GLOBAL] = {0,.5,1,1}, - [BINDING_TYPE_CHARACTER] = {0,1,0,1}, - [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1}, -} -local BINDING_SCHEME_TEXT = { - [BINDING_TYPE_SPECIALIZATION] = {0, 1, 1}, - [BINDING_TYPE_CHARACTER] = {0, 1, 0}, - [BINDING_TYPE_GLOBAL] = {0, 1, 1} -} - -local restingAlpha = 0.7 -local fadeTime, fadeDelay = .30, 0.15 -local numButtons = BINDS_PER_ROW * 8 -local saveButton -local KeyButton_OnKeyDown = function(self, key) - kb.StoreBinding(self, key) -end -local KeyButton_OnClick = function(self, click) - print(self:GetName(), 'OnMouseDown', click) - if click == 'LeftButton' then - kb.DropToSlot(self) - elseif click == 'RightButton' then - kb.ReleaseSlot(self) - else - kb.StoreBinding(self, click:upper()) - end -end - -local KeyButton_OnDragStart = function(self) - kb.PickupSlot(self) -end - -local KeyButton_OnReceiveDrag = function(self, ...) - kb.DropToSlot(self) -end - - -local KeyBinder_OnUpdate = function(self, elapsed) - self.elapsed = self.elapsed + elapsed - self.throttle = self.throttle + elapsed - - if (self.throttle >= 0.032) then - self.throttle = 0 - else - return - end - - local progress = 1 - if self.elapsed > fadeTime then - self.elapsed = 0 - self.fadeStep = 0 - --self.statustext:SetText(nil) - --self.bindingstext:SetText(nil) - self:SetScript('OnUpdate', nil) - else - if self.elapsed < fadeDelay then - progress = 0 - else - self.fadeStep = self.fadeStep + 1 - progress = (self.elapsed - fadeDelay) /(fadeTime - fadeDelay) - end - --print(self.fadeStep, format('%.02f/%.02f', (self.elapsed - fadeDelay) ,(fadeTime - fadeDelay)) , progress) - end - - local alpha = 1 - progress * (1- restingAlpha) - self.statustext:SetAlpha(alpha) - self.bindingstext:SetAlpha(alpha) -end - -local KeyButton_OnUpdate = function(self) - if not self.command then - return - end - - if self:IsMouseOver() then - kb.elapsed = 0 - if not self.active then - -- only set this handler when the button is activated/mouseOver - self.active = true - self:SetScript('OnKeyDown', KeyButton_OnKeyDown) - - kb.statustext:SetText(self.statusText .. ': '..self.actionName) - kb.bindingstext:SetText(self.bindingText) - kb.fadeStep = 0 - kb.throttle = 0 - kb:SetScript('OnUpdate', KeyBinder_OnUpdate) - - end - else - if self.active then - self.active = nil - self:SetScript('OnKeyDown', nil) - end - end -end - -local KeyBinder_OnMouseWheel = function(self, delta) - print(self, delta, self.scrollOffset, (self.scrollOffset <= 0)) - - - if IsControlKeyDown() then - KEY_BUTTON_SIZE = KEY_BUTTON_SIZE - delta - else - - - if (delta > 0) and (self.scrollOffset <= 0) then - return - elseif delta < 0 and kb.scrollOffset >= 42 then - return - end - kb.scrollOffset = ceil(kb.scrollOffset - (delta * BINDS_PER_ROW)) - end - - kb.ui(true) -end - -local KeyBinder_OnHide = function() - KeyBinderImportLog:Hide() -end - -local CloseButton_OnClick = function() - kb.db.showUI = false - kb:Hide() -end -local CancelButton_OnClick = function() - kb.RevertBindings() -end -local SaveButton_OnClick = function() - kb.ConfirmBindings() -end - -local KeyBinder_Initialize = function() - - - kb.scrollOffset = 0 - kb.tabAnchor = {'TOPLEFT', kb.profilebg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING} - kb.tabGrowth = {'TOPLEFT', nil,'TOPRIGHT', BUTTON_SPACING, 0} - kb.tabSize = {TAB_HEIGHT, TAB_HEIGHT } - kb.UIPanelAnchor = {'TOPLEFT', kb.sourcesbg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING} - kb.UIPanelGrowth = {'TOPLEFT', nil, 'BOTTOMLEFT', 0, -2 } - kb.UIPanelSize = {84, 32 } - kb.UIPanelIcon = {24, 32, 'LEFT', -12, 0} - kb.controlsAnchor = {'BOTTOMLEFT', kb.footer, BUTTON_PADDING, BUTTON_PADDING } - kb.controlsGrowth = {'BOTTOMLEFT', nil, 'BOTTOMRIGHT', BUTTON_SPACING, 0} - - -- order of these is important - kb:tab('KeyBinderGlobalTab', - kb.configTitle[BINDING_TYPE_GLOBAL] .. '\n' .. kb.configDescription[BINDING_TYPE_GLOBAL], "Interface\\ICONS\\item_azereansphere", {0.15,.85,.15,.85}) - kb:tab('KeyBinderCharacterTab', - kb.configHeaders[BINDING_TYPE_CHARACTER] .. '\n' .. kb.configDescription[BINDING_TYPE_CHARACTER], nil) - kb:tab('KeyBinderSpecTab', - kb.configHeaders[BINDING_TYPE_SPECIALIZATION] .. '\n' .. kb.configDescription[BINDING_TYPE_SPECIALIZATION], kb.specInfo.texture) - KeyBinderCharacterTab.icon:SetTexCoord(0.15,.85,.15,.85) - - - - --portraitLayers[1] = KeyBinderCharacterTab.icon - - saveButton = kb:button('KeyBinderSaveButton', 'Refresh', 'Reload current bindings and refresh panel.', SaveButton_OnClick) - --restoreButton = kb:button('KeyBinderRestoreButton', 'Discard', 'Revert all changes.', CancelButton_OnClick) - --clearButton = kb:button('KeyBinderClearButton', 'Clear Page', 'Release all buttons.', ResetButton_OnClick) - - kb:uibutton( - 'KeyBinderSpellBookButton', 'SpellBook', nil, - function() ToggleSpellBook(BOOKTYPE_SPELL) end, - "Interface\\BUTTONS\\UI-MicroButton-Spellbook-Up", {0, 1, .4, 1}) - kb:uibutton( - 'KeyBinderTalentFrameButton', TALENTS, SPECIALIZATION, - function() ToggleTalentFrame() end, - "Interface\\BUTTONS\\UI-MicroButton-Talents-Up", {0, 1, .4, 1}) - - kb:uibutton( - 'KeyBinderMacroFrameButton', 'Macros', nil, - function() if MacroFrame and MacroFrame:IsVisible() then - HideUIPanel(MacroFrame) - else - ShowMacroFrame() end - end, - "Interface\\BUTTONS\\UI-MicroButton-Help-Up", {0, 1, .4, 1}) - - kb:uibutton( - 'KeyBinderInventoryButton', 'Bags', nil, - function() OpenAllBags() end, - "Interface\\BUTTONS\\UI-MicroButtonCharacter-Up", {0, 1, .4, 1}) - - - - kb.info:SetPoint('TOPLEFT', kb.UIPanels[1], 'BOTTOMLEFT', 0, -BUTTON_SPACING) - HEADER_OFFSET = kb.UIPanels[1]:GetHeight() + BUTTON_PADDING - + kb.info:GetHeight() - FOOTER_OFFSET = saveButton:GetHeight() + BUTTON_PADDING - - kb:SetScript('OnHide', KeyBinder_OnHide) - kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) - kb.CloseButton:SetScript('OnClick', CloseButton_OnClick) - -end - ---- Resets button command -kb.ReleaseSlot = function(self) - local slot = self:GetID() - - - if kb.currentProfile.buttons[slot] then - kb.currentProfile.buttons[slot] = nil - end - if self.command then - kb.currentProfile.commands[self.command] = nil - end - if self.actionType == 'spell' and IsTalentSpell(self.actionName) then - if kb.currentProfile.talents[self.actionID] then - kb.currentProfile.talents[self.actionID] = nil - end - end - local droppedKeys = {} - - -- doing removal in second loop to avoid possible iterator shenanigans - for k,v in pairs(kb.currentProfile.bindings) do - if v == self.command then - tinsert(droppedKeys, k) - end - end - if #droppedKeys >=1 then - for i, k in ipairs(droppedKeys) do - kb.currentProfile.bindings[k] = nil - end - end - - self.isAvailable = nil - self.isDynamic = nil - self.bindingText = nil - self.statusText = nil - self.command = nil - self.actionType = nil - self.actionID = nil - self.actionName = nil - self.pickupSlot = nil - self.pickupBook = nil - self.macroName = nil - self.profile = nil - self.icon:SetTexture(nil) - self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) - self:EnableKeyboard(false) - self:SetScript('OnKeyDown', nil) -end - -kb.SetSlot = function(self, command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook) - local slot = self:GetID() - local isDynamic, isAvailable - - print('|cFFFFFF00SetSlot|r:', self:GetID()) - if command then - - if actionType == 'spell' then - local professionNum, spellNum = command:match("profession_(%d)_(%d)") - - if (professionNum and spellNum) then - isDynamic = 'profession' - local cacheInfo = kb.ProfessionCache[professionNum..'_'..spellNum] - if cacheInfo then - isAvailable = true - name = cacheInfo.spellName - icon = cacheInfo.icon - actionID = cacheInfo.spellID - self.profIndex = cacheInfo.profIndex - self.spellOffset = cacheInfo.spellOffset - end - print(' Special slot: |cFF00FFFFProfession|r', professionNum, spellNum, isDynamic, isAvailable) - - self.professionNum = tonumber(professionNum) - self.spellNum = tonumber(spellNum) - - else - if kb.TalentCache[actionID] then - isDynamic = 'talent' - print(' Special slot: |cFFBBFF00talent|r', name, isAvailable) - end - - isAvailable = GetSpellInfo(name) - end - elseif actionType == 'macro' then - if not actionID then - actionID = GetMacroIndexByName(name) - end - isAvailable = true - else - --- Journal selections - -- todo: consider using the deep end of blizzard action bar instead - if not actionID then - actionID = command:match("^KeyBinderMacro:(.+)") - end - isAvailable = true - end - - if isAvailable then - local oldCommand = command - macroName, macroText, command = kb.RegisterAction(actionType, actionID, name) - if oldCommand ~= command then - print('|cFFFF4400fixing command string', actionType, actionID, name) - kb.currentProfile.bound[oldCommand] = nil - kb.currentProfile.bound[command] = slot - for k,v in pairs(kb.currentProfile.bindings) do - if v == oldCommand then - kb.currentProfile.bindings[k] = command - end - end - end - kb.LoadBinding(command, name, icon, actionType, actionID, macroName, macroText) - end - - if actionType == 'petaction' then - self.pickupSlot = pickupSlot - self.pickupBook = pickupBook - else - self.pickupSlot = nil - self.pickupBook = nil - end - - actionID = actionID or 0 - self:EnableKeyboard(true) - print(' |cFF00FF00kb.currentProfile.buttons['..slot..'] |cFF00FFFF=|r |cFF00FFFF"'.. command.. '"|r |cFF00FF00"'.. name, '"|r |cFFFFFF00icon:'.. icon .. '|r |cFFFF8800"'.. actionType, '"|r |cFFFF0088id:'.. actionID ..'|r |cFF00FF00"'.. macroName .. '"|r') - kb.currentProfile.buttons[slot] = {command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook} - - -- Clean up conflicting entries for loaded button - local previous = kb.currentProfile.commands[command] - if previous ~= slot and kb.buttons[previous] then - kb.ReleaseSlot(kb.buttons[previous]) - end - kb.currentProfile.commands[command] = slot - end - - self.isAvailable = isAvailable - self.isDynamic = isDynamic - - self.macroText = macroText - self.macroName = macroName - self.actionType = actionType - self.actionID = actionID - self.actionName = name - self.command = command - self.icon:SetTexture(icon) - self.profile = kb.db.bindMode - self:RegisterForDrag('LeftButton') -end - ---- Retrieves button at index; creates said button and instates any stored parameters -do - local leftSlot, upSlot - local buttonsDepth = 0 - kb.GetSlot = function(index) - - local slot = index + kb.scrollOffset - - if not kb.buttons[index] then - local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, kb, 'KeyButton') - button:SetScript('OnClick', KeyButton_OnClick) - button:SetScript('OnUpdate', KeyButton_OnUpdate) - button:SetScript('OnDragStart', KeyButton_OnDragStart) - button:SetScript('OnReceiveDrag', KeyButton_OnReceiveDrag) - button:RegisterForClicks('AnyUp') - - - local newRow = (mod(index, BINDS_PER_ROW) == 1) - - if index == 1 then - button:SetPoint('TOPLEFT', kb.bg, 'TOPLEFT', BUTTON_PADDING, - BUTTON_PADDING) - upSlot = button - buttonsDepth = KEY_BUTTON_SIZE + BUTTON_PADDING * 2 - elseif newRow then - button:SetPoint('TOPLEFT', upSlot, 'BOTTOMLEFT', 0, -BUTTON_SPACING) - upSlot = button - buttonsDepth = buttonsDepth + KEY_BUTTON_SIZE + BUTTON_SPACING - else - button:SetPoint('TOPLEFT', leftSlot, 'TOPRIGHT', BUTTON_HSPACING, 0) - end - - button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE) - button:Show() - kb.buttons[index] = button - leftSlot = button - end - return kb.buttons[index] - end -end - ---- Updates profile assignment and button contents -kb.UpdateSlot = function(self, force) - local slot = self:GetID() - - if force then - if kb.currentProfile.buttons[slot] then - kb.SetSlot(self, unpack(kb.currentProfile.buttons[slot])) - else - kb.ReleaseSlot(self) - end - end - - if self.command then - print('['..slot..'] =', self.command, GetBindingKey(self.command)) - - if self.pending then - self.border:SetColorTexture(unpack(BORDER_PENDING)) - elseif self.isDynamic then - self.border:SetColorTexture(unpack(BORDER_DYNAMIC)) - else - self.border:SetColorTexture(unpack(BORDER_ASSIGNED)) - end - - if self.actionType == 'macro' then - self.macro:Show() - else - self.macro:Hide() - if self.actionType == 'spell' then - local dummy = GetSpellInfo(self.actionName) - if not dummy then - self.icon:SetDesaturated(true) - else - self.icon:SetDesaturated(false) - end - - end - end - - if self.isDynamic then - print('|cFFFFBB00UpdateSlot|r: ', self.isDynamic, self.isAvailable, self.actionID) - end - - if self.isDynamic == 'profession' then - local profText = (self.spellNum == 1) and TRADE_SKILLS or (BUTTON_HEADERS[self.profIndex] or GetProfessionInfo(self.profIndex)) - if self.isAvailable then - print(self.profIndex, 'spnum', type(self.spellNum), (self.spellNum == 1)) - - self.statusText = '|cFFFFFF00'..profText..'|r' - self.bindingText = kb.BindingString(GetBindingKey(self.command)) - else - self.statusText = '|cFFFF4400'..profText..'|r' - self.actionName = '(need to train profession #'..self.profNum..')' - self.bindingText ='?' - end - elseif self.isDynamic == 'talent' then - - self.statusText = '|cFF00FFFF'.. TALENT .. '|r' - if self.isAvailable then - self.bindingText = kb.BindingString(GetBindingKey(self.command)) - else - if kb.inactiveTalentBindings[self.actionID] then - print(self.actionID, #kb.inactiveTalentBindings[self.actionID]) - self.bindingText= kb.BindingString(unpack(kb.inactiveTalentBindings[self.actionID])) - end - - end - else - self.statusText = '|cFF00FF00'.. (BUTTON_HEADERS[self.actionType] and BUTTON_HEADERS[self.actionType] or self.actionType) .. '|r' - self.bindingText = kb.BindingString(GetBindingKey(self.command)) - end - - local locked, layer = kb.IsCommandBound(self) - if locked then - self.icon:SetAlpha(0.5) - else - self.icon:SetAlpha(1) - end - - if self.actionType == 'spell' then - self.icon:SetTexture(GetSpellTexture(self.actionID)) - end - end - - if not self.isAvailable then - self.bind:SetTextColor(0.7,0.7,0.7,1) - else - self.bind:SetTextColor(1,1,1,1) - end - - self.header:SetText(self.statusText) - self.bind:SetText(self.bindingText) - self.details:SetText(self.actionName) -end - ---- push current information into living UI -kb.ui = function(force) - for i, module in ipairs(kb.modules) do - if module.ui then - module.ui(force) - end - end - - if not kb.db.showUI then - print('---end of refresh') - return - end - if not kb.loaded then - KeyBinder_Initialize() - kb.loaded = true - end - for i = 1, numButtons do - local button = kb.GetSlot(i) - button:SetID(i+kb.scrollOffset) - kb.UpdateSlot(button, force) - end - - - --- Frame Sizing - kb.profilebg:SetHeight(kb.tabSize[2] + BUTTON_PADDING * 2 + kb.profiletext:GetStringHeight()) - - kb.bg:SetWidth((KEY_BUTTON_SIZE + BUTTON_HSPACING + BUTTON_SPACING) * BINDS_PER_ROW + BUTTON_PADDING*2 - BUTTON_SPACING) - local numRows = numButtons/BINDS_PER_ROW - - kb.bg:SetHeight((KEY_BUTTON_SIZE + BUTTON_SPACING) * numRows + BUTTON_PADDING*2 - BUTTON_SPACING) - - kb:SetHeight(kb.headerbg:GetHeight() + kb.profilebg:GetHeight() + kb.bg:GetHeight() + kb.footer:GetHeight()) - kb:SetWidth((kb.sourcesbg:GetWidth() +(BINDS_PER_ROW * (KEY_BUTTON_SIZE + BUTTON_HSPACING) + (BINDS_PER_ROW - 1) * BUTTON_SPACING + BUTTON_PADDING * 2) )) - - kb.bg:SetColorTexture(unpack(BINDING_SCHEME_COLOR[kb.db.bindMode])) - for i, tab in ipairs(kb.tabButtons) do - local border = tab:GetNormalTexture() - local tabTexture = "Interface\\Buttons\\UI-Quickslot2" - local left, top, right, bottom = -12, 12, 13, -13 - if i == kb.db.bindMode then - tabTexture = "Interface\\Buttons\\CheckButtonGlow" - left, top, right, bottom = -14, 14, 15, -15 - tab.icon:SetDesaturated(false) - if tab.icon2 then tab.icon2:SetDesaturated(false) end - border:SetDesaturated(true) - border:SetVertexColor(1,1,1, 1) - else - tab.icon:SetDesaturated(true) - if tab.icon2 then tab.icon2:SetDesaturated(true) end - border:SetDesaturated(false) - border:SetVertexColor(1,1,1) - end - border:SetTexture(tabTexture) - border:SetPoint('TOPLEFT', tab, 'TOPLEFT', left, top) - border:SetPoint('BOTTOMRIGHT', tab, 'BOTTOMRIGHT', right, bottom) - end - - KeyBinderSpecTab.icon:SetTexture(kb.specInfo.texture) - SetPortraitTexture(KeyBinderCharacterTab.icon, 'player') - - kb.profiletext:SetText(kb.configHeaders[kb.db.bindMode]) - print(kb.db.bindMode, kb.configHeaders[kb.db.bindMode], kb:GetSize()) - print(kb:GetPoint(1)) - - kb:Show() - - -- Reset this so talent cache can be rebuilt - kb.talentsPushed = nil -end - -kb.AcceptAssignment = function(self, ...) - local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] - local source = loadedProfiles[popup.oldProfile] - kb.SetSlot(popup.slot, unpack(popup.args)) - kb.UpdateSlot(popup.slot) - kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) -- re-enable scrolling - ClearCursor() - ResetCursor() -end - - ---- Add to blizzard interfaces -StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = { - text = "Confirm moving an assigned command.", - button1 = OKAY, - button2 = CANCEL, - timeout = 0, - whileDead = 1, - showAlert = 1, - OnAccept = kb.AcceptAssignment, - OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end -} \ No newline at end of file