# HG changeset patch # User Nenue # Date 1469738756 14400 # Node ID f6d1c192afc69b908c4728a0bff3b59c821883aa # Parent 9ac29fe7745547834816cd63a00cca95801db509 Refactored file layout: - frame display logic in UI.lua - player data in Cache.lua - event responses in Events.lua a lot of local tables are now stored members of KeyBinder for that to work diff -r 9ac29fe77455 -r f6d1c192afc6 SkeletonKey/Cache.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/Cache.lua Thu Jul 28 16:45:56 2016 -0400 @@ -0,0 +1,107 @@ +-- KrakTool +-- Cache.lua +-- Created: 7/28/2016 3:28 PM +-- %file-revision% +-- Cached data regarding talent options, pet spells, etc. +local kb, print = LibStub('LibKraken').register(KeyBinder, 'PlayerInfo') + +local BINDING_TYPE_SPECIALIZATION = 3 +local BINDING_TYPE_CHARACTER = 2 +local BINDING_TYPE_GLOBAL = 1 +local professionMappings = { + [5] = 3, + [7] = 4, + [9] = 5, + [10] = 6 +} + +kb.TalentCache = {} +kb.ProfessionCache = {} +kb.PetCache = {} +kb.specInfo = {} +kb.UpdateSpecInfo = function() + kb.specInfo.id = GetSpecialization() + kb.specInfo.globalID, kb.specInfo.name, kb.specInfo.desc, kb.specInfo.texture = GetSpecializationInfo(kb.specInfo.id) + kb.loadedProfiles[BINDING_TYPE_CHARACTER][kb.specInfo.id] = kb.InitProfile(kb.loadedProfiles[BINDING_TYPE_CHARACTER][kb.specInfo.id], { + specID = kb.specInfo.id}) + + 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.profileOrder = {kb.loadedProfiles[BINDING_TYPE_GLOBAL], kb.loadedProfiles[BINDING_TYPE_CHARACTER], kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION]} + + print('|cFF00FF00current spec:|r', kb.specInfo.id, 'of', GetNumSpecializations()) +end + +kb.UpdateTalentInfo = function() + if kb.talentsPushed then + return + end + + + table.wipe(kb.TalentCache) + + for row =1, MAX_TALENT_TIERS do + for col = 1, NUM_TALENT_COLUMNS do + local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1) + local talentInfo = kb.TalentCache[spellID] or {} + talentInfo.row = 1 + talentInfo.col = col + talentInfo.name = talentName + talentInfo.talentID = talentID + talentInfo.selected = selected + talentInfo.available = available + talentInfo.spellID = spellID + kb.TalentCache[spellID] = talentInfo + print('Talent ', row, col, spellID, talentName) + end + end + kb.talentsPushed = true +end + +kb.UpdateProfessionInfo = function() + table.wipe(kb.ProfessionCache) + local profs = {GetProfessions() } + local primaryNum = 0 + for i, index in ipairs(profs) do + local profName, texture, rank, maxRank, numSpells, spellOffset = GetProfessionInfo(index) + print(i, index, profName, numSpells, spellOffset) + if not professionMappings[index] then + primaryNum = primaryNum + 1 + end + local profNum = professionMappings[index] or primaryNum + + + kb.ProfessionCache[profNum] = kb.ProfessionCache[i] or {} + + for j = 1, numSpells do + local spellName, _, icon, _, _, _, spellID = GetSpellInfo(spellOffset+j, BOOKTYPE_PROFESSION) + + local profInfo = { + spellName = spellName, + spellID = spellID, + icon = icon, + profOffset = i, + profIndex = index, + spellOffset = (spellOffset+j), + spellNum = j + } + KeyBinderKey:SetAttribute("*type-profession_"..i .. '_' ..j, "spell") + KeyBinderKey:SetAttribute("*spell-profession_"..i .. '_' ..j, spellName) + + kb.ProfessionCache[i .. '_' .. j] = profInfo + kb.ProfessionCache[spellName] = profInfo + kb.ProfessionCache[spellID] = profInfo + print(' |cFF0088FF['..i..']|r|cFFFF44BB['..spellOffset+i..']|r', spellName, "profession_"..i .. '_' ..j) + end + + end + +end + + +kb.UpdatePetInfo = function() + +end \ No newline at end of file diff -r 9ac29fe77455 -r f6d1c192afc6 SkeletonKey/Events.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/Events.lua Thu Jul 28 16:45:56 2016 -0400 @@ -0,0 +1,59 @@ +-- KrakTool +-- Events.lua +-- Created: 7/24/2016 11:10 PM +-- %file-revision% +-- Event handlers, and the init block that sets them up; nothing else should be here + +local kb = LibStub("LibKraken").register(KeyBinder) + +kb.init = function() + kb:RegisterEvent('PLAYER_ENTERING_WORLD') + kb:RegisterEvent('UPDATE_MACROS') + kb:RegisterUnitEvent('PLAYER_SPECIALIZATION_CHANGED', 'player', 'pet') + kb:RegisterUnitEvent('UNIT_PORTRAIT_UPDATE', 'player', 'pet') + kb:RegisterUnitEvent('TALENT_UPDATE', 'player', 'pet') + kb:RegisterEvent('PLAYER_REGEN_DISABLED') + kb:RegisterEvent('PLAYER_REGEN_ENABLED') +end + +kb.event = function(event, ...) + if kb[event] then + kb[event](kb, event, ...) + end +end + +kb.PLAYER_REGEN_DISABLED = function() + kb.ui() +end + +kb.UNIT_PORTRAIT_UPDATE = function() + SetPortraitTexture(KeyBinderCharacterTab.icon, 'player') +end + +kb.PLAYER_REGEN_ENABLED = function() + kb.ui() +end + +kb.PLAYER_SPECIALIZATION_CHANGED = function() + kb.UpdateSpecInfo() + kb.UpdateTalentInfo() + kb.ApplyAllBindings() + kb.ui(true) +end +kb.PLAYER_TALENT_UPDATE = function() + kb.UpdateTalentInfo() + kb.ApplyAllBindings() + kb.ui() +end +kb.ACTIONBAR_SLOT_CHANGED = function(self, event, slot) + kb.HotKeyText(slot) + return true +end + +kb.UNIT_PET = function(self, event, unit) + if unit ~= 'player' then + return + end + + kb.UpdatePetInfo() +end \ No newline at end of file diff -r 9ac29fe77455 -r f6d1c192afc6 SkeletonKey/HotKey.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/HotKey.lua Thu Jul 28 16:45:56 2016 -0400 @@ -0,0 +1,204 @@ +-- KrakTool +-- HotKey.lua +-- Created: 7/22/2016 10:28 PM +-- %file-revision% +-- Module for fixing actionbar hotkey text + +local kb, print = LibStub("LibKraken").register(KeyBinder, 'HotKey') +local hotkey = {} +local hotkeyText = {} +local blizHotKey = {} +local bindings + +-- frames obtained via post-load hooks, created by addons like Dominos or BarTender4 +local loadedFrames = {} +-- frames divided by update categories +local categoryFrames = {} +-- frames indexed by action slot ID (just the action bar, for... reasons) +local actionFrames = {} + +kb.wrap(hotkey) + +--- Used to determine which groups of action buttons need updating +local hotkeyEvents = { + ["UPDATE_BONUS_ACTIONBAR"] = {"bonus"}, + ["UPDATE_VEHICLE_ACTIONBAR"] = {"vehicle"}, + ["UPDATE_OVERRIDE_ACTIONBAR"] = {"override"}, + ["ACTIONBAR_PAGE_CHANGED"] = {"actionbar"}, + ["PLAYER_ENTERING_WORLD"] = {"world","all"}, + ["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) + hotkeyEvents[event] = {...} + hotkey[event] = hotkey.UpdateFromEvent +end + +hotkey.unwrapEvent = function(event) + if not kb[event] then + kb:UnregisterEvent(event) + end + hotkeyEvents[event] = nil + hotkey[event] = nil +end + +hotkey.ActionButton_Update = function(frame) + hotkey.wrap(function() + local actionType, actionID = GetActionInfo(frame.action) + hotkey.UpdateSkeletonKeyText(frame, actionType, actionID, HasAction(frame.action)) + end) +end + + +hotkey.RegisterFrame = function(frame) + --hotkey.wrap(function() + --print('ActionBarButtonEventsFrame_RegisterFrame(', frame:GetName(), frame.action, frame:IsVisible(), frame:IsShown()) + --end) + blizHotKey[frame] = frame.HotKey + loadedFrames[frame] = true +end + +hotkey.UpdateFromEvent = function(self, event, ...) + if hotkeyEvents[event] then + --print('call batch', event, ...) + for i, func in ipairs(hotkeyEvents[event]) do + + if hotkey[func] then + --print(' ', func) + hotkey[func](self, event, ...) + end + end + end + return true +end + +hotkey.variables = function() + bindings = kb.GetBindings() + for event, manifest in pairs(hotkeyEvents) do + kb:RegisterEvent(event) + hotkey[event] = hotkey.UpdateFromEvent + end + hotkey.wrapEvent('UNIT_PET', 'pet') +end + +hotkey.init = function() + hooksecurefunc("ActionBarButtonEventsFrame_RegisterFrame", hotkey.RegisterFrame) +end + +hotkey.world = function() + hotkeyEvents["UPDATE_BINDINGS"] = {"actionbar"} + hotkey.UPDATE_BINDINGS = hotkey.UpdateFromEvent + kb:RegisterEvent("UPDATE_BINDINGS") + + hotkey.player() + hotkey.pet() + + -- Set this after, since we already full-scanned buttons + hooksecurefunc("ActionButton_Update", hotkey.ActionButton_Update) +end + +-- requires all these arguments since non-actionbar buttons don't have all of said methods +hotkey.UpdateSkeletonKeyText = function(frame, actionType, actionID, hasAction) + if bindings[actionType] then + if actionType == 'macro' then + actionID = GetMacroInfo(actionID) + end + --print('|cFFFFFF00'..frame:GetName(), actionType, actionID, hasAction) + local binds = bindings[actionType][actionID] + if binds then + if hasAction and not frame.HotKey:IsVisible() then + if not hotkeyText[frame] then + hotkeyText[frame] = frame:CreateFontString('KeyBinderHotKeyText', 'OVERLAY') + hotkeyText[frame]:SetFont(frame.HotKey:GetFont()) + hotkeyText[frame]:SetTextColor(frame.HotKey:GetTextColor()) + hotkeyText[frame]:SetPoint('TOPRIGHT', frame.HotKey, 'TOPRIGHT') + end + + hotkeyText[frame]:SetText(kb.BindingString(unpack(binds))) + print('|cFF00FFFFUpdate text for', frame:GetName()) + print(unpack(binds)) + return + end + end + end + + if hotkeyText[frame] then + hotkeyText[frame]:SetText(nil) + --print('|cFFFF4400cleared text from', frame:GetName()) + end +end + +hotkey.actionbar = function() + if ActionBarButtonEventsFrame.frames then + for index, frame in ipairs(ActionBarButtonEventsFrame.frames) do + local actionType, actionID = GetActionInfo(frame.action) + hotkey.UpdateSkeletonKeyText(frame, actionType, actionID, HasAction(frame.action)) + end + end +end + +hotkey.actionslot = function(self, event, slot) + --print(event, slot) + --print(GetActionButtonForID(slot)) + hotkey.UpdateSkeletonKeyText(GetActionButtonForID(slot)) +end + +hotkey.player = function() + hotkey.actionbar() +end + + +hotkey.pet = function(self, event, arg1) + if event == 'UNIT_PET' and arg1 == 'player' then + if PetHasActionBar() and UnitIsVisible("pet") then + hotkey.wrapEvent('PET_UI_CLOSE', 'pet') + hotkey.wrapEvent('PET_BAR_UPDATE', 'pet') + else + hotkey.unwrapEvent('PET_UI_CLOSE') + hotkey.unwrapEvent('PET_BAR_UPDATE') + return + end + end + + for i=1, NUM_PET_ACTION_SLOTS, 1 do + local button = _G['PetActionButton'.. i] + --print(button:GetName()) + for k, v in pairs(button) do + --print(' ', k, type(v)) + end + end +end + + diff -r 9ac29fe77455 -r f6d1c192afc6 SkeletonKey/Import.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/Import.lua Thu Jul 28 16:45:56 2016 -0400 @@ -0,0 +1,209 @@ +-- KrakTool +-- Import.lua +-- Created: 7/10/2016 6:20 AM +-- %file-revision% +-- Tools for first-time setup and migration from other addons. + +local kb = LibStub("LibKraken").register(KeyBinder) +local print = DEVIAN_WORKSPACE and function(...) print('kbi', ...) end or function() end + + +local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 +local SUMMON_RANDOM_FAVORITE_MOUNT_SPELLNAME = "Summon Random Favorite Mount" +local results = {} +local importSet = setmetatable({}, {__tostring = function() return 'Global Bindings' end}) +kb.importTypes = {} + +local lineNumber = 0 +local usedBinds, usedKeys = {}, {} +local profileName = '' +local specProfile +local msg = function(...) return KeyBinderImportLog:AddMessage(...) end + +--- Core interfaces +kb.ImportScan = function() + -- hang onto this + SUMMON_RANDOM_FAVORITE_MOUNT_SPELLNAME = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) + + local hasAnyData = false + for addon, module in pairs(kb.importTypes) do + if IsAddOnLoaded(addon) then + local hasData = module.GetChanges(importSet) + if hasData then + kb:print("|cFFFFFF00"..addon.." is currently enabled.") + end + + hasAnyData = (hasData or hasAnyData) + end + end + if hasAnyData then + kb:print("You can use /skb import |cFF00FF00|r to attempt to copy settings related to this character. This will also disable that AddOn.") + end + + + kb.ui() + --KeyBinderImportLog:Show() + + return importSet +end + +kb.ImportCommmit = function(self, text) + kb.db.buttons = importSet.buttons + kb.db.bound = importSet.bound + kb.db.commands = importSet.commands + kb.db.bindings = importSet.bindings + kb.db.macros = importSet.macros + kb.db[profileName] = importSet[profileName] + kb.profile(profileName) + + + kb:ApplyAllBindings() + kb.ui() + kb:print('Imported settings applied! Note that you will need to change active specializations and run the command again to create their respective Char+Spec profiles.') +end + +--- Key Scan +kb.importTypes.KeyBinder = {} +kb.importTypes.BindPad = {} +local kbi = kb.importTypes.KeyBinder +local bp = kb.importTypes.BindPad + +--- BindPad import process +-- because bindpad doesn't store class info, it is not possible to discern the identity of primary/secondary + +local GetBindPadSlot = function(profile, slot, data) + local actionType = data.type:lower() + local command = data.action:gsub('CLICK BindPadKey:%s*', '') + local clickAction = command:match('BindPadMacro:%s*(.+)%s*$') + local macroName, macroText + if clickAction then + local clickType = 'spell' + if clickAction == SUMMON_RANDOM_FAVORITE_MOUNT_SPELLNAME then + clickType = 'mount' + clickAction = 0 + else + clickType = 'spell' + end + + macroName, macroText, command = kb.RegisterAction(nil, clickType, clickAction) + profile.macros[macroName] = {macroText, command} + end + print('[|cFF00FF00'.. data.type .. '|r] |cFFFF00FF' .. data.action .. '|r :: "' .. tostring(clickAction) .. '"') + + results[actionType] = (results[actionType] or 0) + 1 + profile.buttons[slot] = { + command, + command:gsub(data.type, ''), + data.texture + } + profile.commands[command] = slot + + if usedBinds[data.action] then + local key1, key2 = unpack(usedBinds[data.action]) + print('adding keybind |cFF00FFFF' .. command .. ' |cFF00FF00' .. (key1) .. ' |cFF00FF00' .. (key2 or '')) + profile.bindings[key1] = command + + if key2 then + profile.bindings[key2] = command + end + + usedBinds[data.action] = nil + + msg('|cFF00FFFF'..tostring(profile)..'|r '..slot..': ' .. '|cFF00FFFF' .. command .. '|r |cFF00FF00' .. (key1 or '') .. (key2 and ('|r, |cFF00FF00key2') or '') ) + else + print('|cFFFF4400no binding|r ' .. command) + end +end + +local GetBindPadProfile = function(profile, bp) + local bpnames = {'CharacterSpecificTab1', 'CharacterSpecificTab2', 'CharacterSpecificTab3'} -- won't need this ever again, let it fall into gc + + -- resolve spec ID + local specID = GetSpecialization() + local globalID = GetSpecializationInfo(GetSpecialization()) + local activeProfile + + -- setup string coercions for debugging + setmetatable(profile,{__tostring = function(t) return 'Character' end}) + if GetNumSpecGroups() > 1 then + local activeGroup = GetActiveSpecGroup() + activeProfile = bp.profileForTalentGroup[activeGroup] + profile[specID] = kb.InitProfile(profile[specID] or {}) + specProfile = profile[specID] + setmetatable(specProfile,{__tostring = function(t) return 'Spec #'..specID end}) + end + + print('-') + + results.spell = 0 + results.macro = 0 + results.click = 0 + results.item = 0 + + table.wipe(usedBinds) -- [action] = {key1, key2} + table.wipe(usedKeys) -- [key] = "action" + for id, bpProfile in ipairs(bp) do + + local slots = 0 + + if bpProfile.AllKeyBindings then + for binding, command in pairs(bpProfile.AllKeyBindings) do + -- each binding value + if not usedKeys[binding] then + usedKeys[binding] = command + end + + usedBinds[command] = usedBinds[command] or {} + tinsert(usedBinds[command], binding) + end + end + + + + for i, name in ipairs(bpnames) do + -- each tab + if bpProfile[name] then + for slot, data in pairs(bpProfile[name]) do + if type(data) == 'table' then + slots = slots + 1 + + + local profile = (id == activeProfile) and specProfile or profile + lineNumber = lineNumber + 1 + GetBindPadSlot(profile, slot, data) + + else + --print(type(data), slot, data) + end + end + end + end + end +end + + +bp.GetChanges = function(importSet) + -- ensure that subtables are there + kb.InitProfile(importSet) + if BindPadVars then + local globalSlots = 0 + for k,v in pairs(BindPadVars) do + --print(k, type(k)) + if type(k) == 'string' then + local realm, name = k:match("^PROFILE_([%S]+)_(%S+)$") + if realm == kb.playerRealm and name == kb.playerName then + profileName = realm .. '_' .. name + msg('Found character profile: |cFFFFFF00'.. tostring(realm) .. '|r-|cFF00FFFF'..tostring(name)..'|r') + importSet[profileName] = kb.InitProfile({}) + importSet[profileName].imported = true + GetBindPadProfile(importSet[profileName], v) + end + elseif type(k) == 'number' and type(v) == 'table' then + globalSlots = globalSlots + 1 + GetBindPadSlot(importSet, globalSlots, v) + end + end + end + + return results +end diff -r 9ac29fe77455 -r f6d1c192afc6 SkeletonKey/KeyBinds.lua --- a/SkeletonKey/KeyBinds.lua Tue Jul 26 19:29:44 2016 -0400 +++ b/SkeletonKey/KeyBinds.lua Thu Jul 28 16:45:56 2016 -0400 @@ -21,6 +21,7 @@ --- 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' @@ -30,24 +31,11 @@ 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 BINDS_PER_ROW = 2 -local BUTTON_HSPACING = 128 -local BUTTON_SPACING = 4 -local BUTTON_PADDING = 12 +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 -local KEY_BUTTON_SIZE = 48 -local MIN_BIND_SLOTS = 32 -local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544 -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 CURSOR_SPELLSLOT, CURSOR_BOOKTYPE, CURSOR_PETACTION --- Caps Lock derivatives @@ -60,20 +48,6 @@ ['battlepet'] = SLASH_SUMMON_BATTLE_PET1 .. " %s", ['item'] = "/use %s" } -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 professionMappings = { [5] = 3, @@ -82,40 +56,25 @@ [10] = 6 } -local BINDING_MODE = { +kb.configTitle = { [BINDING_TYPE_GLOBAL] = 'Global Binds', [BINDING_TYPE_CHARACTER] = 'Character: %s', [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s' } -local BINDING_DESCRIPTION = { - +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.', } -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} -} +kb.configHeaders = {} +kb.loadedProfiles = {} +kb.orderedProfiles = {} +kb.buttons = {} +kb.macros = {} -local loadedProfiles = {} --- Profiles ordered by precedance -local priority = {} --- Button pointers local buttons = {} -- Backlog of changes local reverts = {} @@ -128,8 +87,6 @@ kb.inactiveTalentBindings = {} -- placeholder for the StaticPopup used for confirmations local confirmation --- header text -local configHeaders = {} local protected = { ['OPENCHATSLASH'] = true, @@ -137,12 +94,9 @@ } --- Used to reflect the current working state -local bindMode = 3 local bindHeader, currentHeader = '', '' -local configProfile, character, specialization, global, character_specialization 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 numButtons = BINDS_PER_ROW * 8 local bindsCommitted = true local forceButtonUpdate = false @@ -159,15 +113,15 @@ GetPickupValue.spell = function(self) return select(7, GetSpellInfo(self.actionID)) end --- Returns conflicting assignment and binding profiles for use in displaying confirmations -local IsCommandBound = function(self, command) - local isAssigned, assignedBy = false, bindMode - local isBound, boundBy = false, bindMode +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, #BINDING_MODE do - local tier = priority[i] - if i ~= bindMode then + for i = 1, #kb.orderedProfiles do + local tier = kb.orderedProfiles[i] + if i ~= db.bindMode then if tier.commands[command] then isAssigned = true @@ -188,7 +142,7 @@ end - print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', bindMode .. ']', isAssigned, isBound, assignedBy, boundBy) + print('|cFFFFFF00IsCommandBound:|r', command:gsub(CLICK_KEYBINDER_MACRO, ''),'|r [profile:', db.bindMode .. ']', isAssigned, isBound, assignedBy, boundBy) return isAssigned, isBound, assignedBy, boundBy end @@ -197,10 +151,10 @@ } --- Returns a value for use with Texture:SetDesaturated() -local BindingIsLocked = function(key) +kb.BindingIsLocked = function(key) local success = false - for i = 1, bindMode-1 do - local tier = priority[i] + for i = 1, db.bindMode-1 do + local tier = kb.orderedProfiles[i] if tier.bindings[key] then success = true break @@ -210,7 +164,7 @@ end --- Translates GetBindingKey() results into a printable string. -local BindingString = function(...) +kb.BindingString = function(...) local stack = {} for i = 1, select('#', ...) do local key = select(i, ...) @@ -224,206 +178,9 @@ end end -local restingAlpha = 0.7 -local fadeTime, fadeDelay = .30, 0.15 -local portraitLayers = {} -kb.UpdatePortraits = function() - for i, layeredRegion in ipairs(portraitLayers) do - SetPortraitTexture(layeredRegion , 'player') - end -end - -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() - db.showUI = false - kb:Hide() -end -local CancelButton_OnClick = function() - kb.RevertBindings() -end -local SaveButton_OnClick = function() - kb.ConfirmBindings() -end - -local KeyBinder_Initialize = function() - for i = 1, GetNumBindings() do - local command = GetBinding(i) - bindings[command] = true - end - - 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', - BINDING_MODE[BINDING_TYPE_GLOBAL] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_GLOBAL], "Interface\\ICONS\\item_azereansphere", {0.15,.85,.15,.85}) - kb:tab('KeyBinderCharacterTab', - configHeaders[BINDING_TYPE_CHARACTER] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_CHARACTER], nil) - kb:tab('KeyBinderSpecTab', - configHeaders[BINDING_TYPE_SPECIALIZATION] .. '\n' .. BINDING_DESCRIPTION[BINDING_TYPE_SPECIALIZATION], specTexture) - KeyBinderCharacterTab.icon:SetTexCoord(0.15,.85,.15,.85) - - - - portraitLayers[1] = KeyBinderCharacterTab.icon - - saveButton = kb:button('KeyBinderSaveButton', 'Save', 'Commit all changes.', 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) - - kb.UpdatePortraits() -end - kb.DropToSlot = function(self) print(self:GetName(),'|cFF0088FFreceived|r') @@ -485,7 +242,7 @@ macroName, macroText, command = kb.RegisterAction(actionType, actionID) - local isAssigned, isBound, assignedBy, boundBy = IsCommandBound(self, command) + local isAssigned, isBound, assignedBy, boundBy = kb.IsCommandBound(self, command) if isAssigned then local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] popup.slot = self @@ -498,7 +255,6 @@ kb.SetSlot(self, command, name, icon, actionType, actionID, macroName, macroText, pickupID, pickupBook) kb.UpdateSlot(self) self.active = nil - KeyButton_OnUpdate(self, 0) ClearCursor() ResetCursor() end @@ -531,77 +287,38 @@ end ---- Resolve the appropriate command and assign the corresponding secure state driver +--- Resolve the appropriate command and macroText for the given action parameters kb.RegisterAction = function(type, id) + local macroText, macroName, command = '', '', '' if type == 'spell' then - - id = GetSpellInfo(id) + if kb.ProfessionCache[id] then + command = CLICK_KEYBINDER_KEY .. "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum + else + command = CLICK_KEYBINDER_KEY ..id + end + else + macroName = type .. ' ' .. id + macroText = ACTION_SCRIPT[type]:format(id) + 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 - local macroText - local macroName = type ..'_' .. id - - if kb.ProfessionCache[id] then - macroName = "profession_".. kb.ProfessionCache[id].profOffset .. '_' .. kb.ProfessionCache[id].spellNum - macroText = "/cast " .. kb.ProfessionCache[id].spellName - macros[macroName] = nil - else - macroName = macroName:gsub(' ', '') - macroText = ACTION_SCRIPT[type]:format(id) - end - - 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 - - local command = 'CLICK KeyBinderMacro:'.. macroName - macros[macroName] = {macroText, command } - print('RegisterAction', command , macroText) - if type == 'macro' then - kb.LoadMacro(macroName) - else - kb.LoadAction(macroName, macroText, command) - end - - + print('RegisterAction', type, id, '->', command , macroText) return macroName, macroText, command end -kb.LoadMacro = function(macroName) - KeyBinderMacro:SetAttribute('*macro-'..macroName, macros[macroName][1]) - return true -end - -kb.LoadAction = function(macroName) - if not macros[macroName] then - return false - end - KeyBinderMacro:SetAttribute('*macrotext-'..macroName, macros[macroName][1]) - return true -end - -local profressionsCache - -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 - - --- Updates the current KeyBinding for the button's command kb.StoreBinding = function(self, key) @@ -621,18 +338,18 @@ --print('clearing', key) SetBinding(key, nil) SaveBindings(GetCurrentBindingSet()) - if configProfile.bindings[key] then - kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[bindMode])) - configProfile.bindings[key] = nil + if kb.currentProfile.bindings[key] then + kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode])) + kb.currentProfile.bindings[key] = nil end - if configProfile.talents[self.actionName] then - configProfile.talents[self.actionName] = nil + if kb.currentProfile.talents[self.actionName] then + kb.currentProfile.talents[self.actionName] = nil end bindings[self.actionType][self.actionID] = nil end - if configProfile.bound[self.command] then - configProfile.bound[self.command] = nil - --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[bindMode])) + 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 @@ -686,29 +403,29 @@ end end - for level, configProfile in ipairs(priority) do - if (level == bindMode) then - configProfile.bound[self.command] = true + for level, profile in ipairs(kb.orderedProfiles) do + if (level == db.bindMode) then + profile.bound[self.command] = true if talentInfo then - configProfile.bindings[self.binding] = nil + profile.bindings[self.binding] = nil else - configProfile.bindings[self.binding] = self.command + profile.bindings[self.binding] = self.command end - configProfile.talents[self.actionName] = talentInfo + profile.talents[self.actionName] = talentInfo else - configProfile.bindings[self.binding] = nil - configProfile.bound[self.command] = nil - configProfile.talents[self.actionName] = nil + profile.bindings[self.binding] = nil + profile.bound[self.command] = nil + kb.currentProfile.talents[self.actionName] = nil end - if configProfile.talents[self.actionID] then - configProfile.talents[self.actionID] = nil + if kb.currentProfile.talents[self.actionID] then + kb.currentProfile.talents[self.actionID] = nil end end - kb:print(BINDING_ASSIGNED:format(self.binding, self.actionName, configHeaders[bindMode])) + kb:print(BINDING_ASSIGNED:format(self.binding, self.actionName, kb.configHeaders[db.bindMode])) end end @@ -718,295 +435,35 @@ end ---- Resets button command -kb.ReleaseSlot = function(self) - local slot = self:GetID() - - if configProfile.buttons[slot] then - configProfile.buttons[slot] = nil - end - if self.command then - configProfile.commands[self.command] = nil - end - if self.actionType == 'spell' and IsTalentSpell(self.actionName) then - if configProfile.talents[self.actionID] then - configProfile.talents[self.actionID] = nil - end - end - local droppedKeys = {} - - -- doing removal in second loop to avoid possible iterator shenanigans - for k,v in pairs(configProfile.bindings) do - if v == self.command then - tinsert(droppedKeys, k) - end - end - if #droppedKeys >=1 then - for i, k in ipairs(droppedKeys) do - configProfile.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) - - elseif kb.TalentCache[actionID] then - - isDynamic = 'talent' - isAvailable = GetSpellInfo(name) - print(' Special slot: |cFFBBFF00talent|r', name, isAvailable) - end - if not actionID then - actionID = select(7, GetSpellInfo(name)) - end - elseif actionType == 'macro' then - if not actionID then - actionID = GetMacroIndexByName(name) - end - else - --- Journal selections - -- todo: consider using the deep end of blizzard action bar instead - if not actionID then - actionID = command:match("^KeyBinderMacro:(.+)") - end - end - - if not macroName then - local previousCommand = command - macroName, macroText, command = kb.RegisterAction(actionType, actionID) - - -- Clean up conflicting command entry for loaded buttons - if macroName and command ~= previousCommand then - print(' Repaired corruption in |cFFFFFF00'..currentHeader..'|r button #'.. self:GetID()) - configProfile.commands[previousCommand] = nil - configProfile.bound[previousCommand] = nil - end - 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(' |cFF00FF00configProfile.buttons['..slot..'] |cFF00FFFF=|r |cFF00FFFF"'.. command.. '"|r |cFF00FF00"'.. name, '"|r |cFFFFFF00icon:'.. icon .. '|r |cFFFF8800"'.. actionType, '"|r |cFFFF0088id:'.. actionID ..'|r |cFF00FF00"'.. macroName .. '"|r') - configProfile.buttons[slot] = {command, name, icon, actionType, actionID, macroName, macroText, pickupSlot, pickupBook} - - -- Clean up conflicting entries for loaded button - local previous = configProfile.commands[command] - if previous ~= slot and buttons[previous] then - kb.ReleaseSlot(buttons[previous]) - end - configProfile.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 = bindMode - self:RegisterForDrag('LeftButton') -end - ---- Retrieves button at index; creates said button and instates any stored parameters -local leftSlot, upSlot -local buttonsDepth = 0 -kb.GetSlot = function(index) - - local slot = index + kb.scrollOffset - - if not 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() - buttons[index] = button - leftSlot = button - end - return buttons[index] -end - ---- Updates profile assignment and button contents -kb.UpdateSlot = function(self, force) - local slot = self:GetID() - - if force then - if configProfile.buttons[slot] then - kb.SetSlot(self, unpack(configProfile.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 = 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 = BindingString(GetBindingKey(self.command)) - else - print(self.actionID, #kb.inactiveTalentBindings[self.actionID]) - self.bindingText= BindingString(unpack(kb.inactiveTalentBindings[self.actionID])) - end - else - self.statusText = '|cFF00FF00'.. (BUTTON_HEADERS[self.actionType] and BUTTON_HEADERS[self.actionType] or self.actionType) .. '|r' - self.bindingText = BindingString(GetBindingKey(self.command)) - end - - local locked, layer = 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.macro:SetText(self.macroName) - self.details:SetText(self.actionName) -end - - +kb.inactiveTalentBindings = {} kb.ApplyTalentBinding = function(talentInfo, cache) for i = 5, #talentInfo do - SetBinding(talentInfo[i], "CLICK KeyBinderMacro:".. talentInfo[1]) + 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])) + --cprint(spellID, unpack(kb.inactiveTalentBindings[spellID])) end -kb.ApplyBinding = function(command, name, icon, actionType, actionID, macroName, macroText ) +kb.LoadBinding = function(command, name, icon, actionType, actionID, macroName, macroText ) - if actionType == 'macro' then + + + 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) @@ -1020,12 +477,12 @@ kb.ApplyBindings = function (profile) cprint('binding profile', profile) for slot, data in pairs(profile.buttons) do - kb.ApplyBinding(unpack(data)) + kb.LoadBinding(unpack(data)) end for key, command in pairs(profile.bindings) do - cprint('Bindings data registered', command, key) + cprint(' *', key, '->', command) --_G.print('HotKey','loading', key, command) SetBinding(key, command) @@ -1058,11 +515,22 @@ kb.ApplyAllBindings =function () table.wipe(kb.inactiveTalentBindings) - for i, profile in ipairs(priority) do + -- 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) @@ -1112,7 +580,7 @@ end kb.ResetProfile = function(profile, prototype) - if profile == configProfile then + if profile == kb.currentProfile then for i, button in pairs(buttons) do kb.ReleaseSlot(button) end @@ -1126,150 +594,59 @@ --- Handles constructing spec profiles as they are selected -kb.TalentCache = {} - -kb.UpdateSpecInfo = function() - specID = GetSpecialization() - specGlobalID, specName, specDesc , specTexture = GetSpecializationInfo(specID) - loadedProfiles[BINDING_TYPE_CHARACTER][specID] = kb.InitProfile(loadedProfiles[BINDING_TYPE_CHARACTER][specID], { - specID = specID}) - - configHeaders[BINDING_TYPE_SPECIALIZATION] = BINDING_MODE[BINDING_TYPE_SPECIALIZATION]:format(specName) - loadedProfiles[BINDING_TYPE_SPECIALIZATION] = loadedProfiles[BINDING_TYPE_CHARACTER][specID] - configProfile = loadedProfiles[bindMode] - print('|cFF00FF00bindMode:|r', bindMode) - - priority = {loadedProfiles[BINDING_TYPE_GLOBAL], loadedProfiles[BINDING_TYPE_CHARACTER], loadedProfiles[BINDING_TYPE_SPECIALIZATION]} - - print('|cFF00FF00current spec:|r', specID, 'of', GetNumSpecializations()) -end - -kb.UpdateTalentInfo = function() - if kb.talentsPushed then - return - end - - - table.wipe(kb.TalentCache) - - for row =1, MAX_TALENT_TIERS do - for col = 1, NUM_TALENT_COLUMNS do - local talentID, talentName, icon, selected, available, spellID = GetTalentInfo(row, col, 1) - local talentInfo = kb.TalentCache[spellID] or {} - talentInfo.row = 1 - talentInfo.col = col - talentInfo.name = talentName - talentInfo.talentID = talentID - talentInfo.selected = selected - talentInfo.available = available - talentInfo.spellID = spellID - kb.TalentCache[spellID] = talentInfo - print('Talent ', row, col, spellID, talentName) - end - end - kb.talentsPushed = true -end - - -kb.ProfessionCache = {} -kb.UpdateProfessionInfo = function() - table.wipe(kb.ProfessionCache) - local profs = {GetProfessions() } - local primaryNum = 0 - for i, index in ipairs(profs) do - local profName, texture, rank, maxRank, numSpells, spellOffset = GetProfessionInfo(index) - cprint(i, index, profName, numSpells, spellOffset) - if not professionMappings[index] then - primaryNum = primaryNum + 1 - end - local profNum = professionMappings[index] or primaryNum - - - kb.ProfessionCache[profNum] = kb.ProfessionCache[i] or {} - - for j = 1, numSpells do - local spellName, _, icon, _, _, _, spellID = GetSpellInfo(spellOffset+j, BOOKTYPE_PROFESSION) - - local profInfo = { - spellName = spellName, - spellID = spellID, - icon = icon, - profOffset = i, - profIndex = index, - spellOffset = (spellOffset+j), - spellNum = j - } - KeyBinderMacro:SetAttribute("*macrotext-profession_"..i .. '_' ..j, "/cast ".. spellName) - - kb.ProfessionCache[i .. '_' .. j] = profInfo - kb.ProfessionCache[spellName] = profInfo - kb.ProfessionCache[spellID] = profInfo - cprint(' |cFF0088FF['..i..']|r|cFFFF44BB['..spellOffset+i..']|r', spellName, "*macrotext-profession_"..i .. '_' ..j) - end - - end - -end - --- 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 - bindMode = BINDING_TYPE_GLOBAL + defaultMode = BINDING_TYPE_GLOBAL kb.InitProfile(db) - loadedProfiles[BINDING_TYPE_GLOBAL] = db + kb.loadedProfiles[BINDING_TYPE_GLOBAL] = db --- Character if name then db[name] = kb.InitProfile(db[name], {classHeader = classHeader, className = className, classID = classID}) - loadedProfiles[BINDING_TYPE_CHARACTER] = db[name] - bindMode = BINDING_TYPE_CHARACTER + kb.loadedProfiles[BINDING_TYPE_CHARACTER] = db[name] + defaultMode = BINDING_TYPE_CHARACTER end --- Mutable skills data kb.UpdateSpecInfo() kb.UpdateTalentInfo() - priority = {loadedProfiles[BINDING_TYPE_GLOBAL], loadedProfiles[BINDING_TYPE_CHARACTER], loadedProfiles[BINDING_TYPE_SPECIALIZATION]} - if db.bindMode and loadedProfiles[db.bindMode] then - bindMode = db.bindMode + 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 - db.bindMode = bindMode - - if not BINDING_MODE[bindMode] then - bindMode = 3 - db.bindMode = 3 - print('overriding', bindMode) - end print(BINDING_TYPE_GLOBAL) - configHeaders[BINDING_TYPE_GLOBAL] = BINDING_MODE[BINDING_TYPE_GLOBAL] - configHeaders[BINDING_TYPE_CHARACTER] = BINDING_MODE[BINDING_TYPE_CHARACTER]:format(UnitName('player', true)) - configHeaders[BINDING_TYPE_SPECIALIZATION] = BINDING_MODE[BINDING_TYPE_SPECIALIZATION]:format(specName) + 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(specName) - setmetatable(loadedProfiles[BINDING_TYPE_GLOBAL], {__tostring =function() return configHeaders[BINDING_TYPE_GLOBAL] end}) - setmetatable(loadedProfiles[BINDING_TYPE_CHARACTER], {__tostring =function() return configHeaders[BINDING_TYPE_CHARACTER] end}) - setmetatable(loadedProfiles[BINDING_TYPE_SPECIALIZATION], {__tostring =function() return configHeaders[BINDING_TYPE_SPECIALIZATION] end}) + 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', bindMode) - configProfile = loadedProfiles[bindMode] + print('|cFF00FF00bindMode:|r', db.bindMode) + kb.currentProfile = kb.loadedProfiles[db.bindMode] end local scrollCache = {} kb.SelectTab = function(self) - scrollCache[bindMode] = kb.scrollOffset - bindMode = self:GetID() - configProfile = loadedProfiles[self:GetID()] + scrollCache[db.bindMode] = kb.scrollOffset db.bindMode = self:GetID() - kb.scrollOffset = scrollCache[bindMode] or 0 + kb.currentProfile = kb.loadedProfiles[self:GetID()] + kb.scrollOffset = scrollCache[db.bindMode] or 0 kb.ui(true) end @@ -1292,84 +669,6 @@ - - ---- 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 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 - - if bindsCommitted then - KeyBinderSaveButton:Disable() - --KeyBinderRestoreButton:Disable() - else - KeyBinderSaveButton:Enable() - --KeyBinderRestoreButton:Enable() - 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[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 == 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(specTexture) - - kb.profiletext:SetText(configHeaders[bindMode]) - print(bindMode, configHeaders[bindMode], kb:GetSize()) - print(kb:GetPoint(1)) - - kb:Show() - - -- Reset this so talent cache can be rebuilt - kb.talentsPushed = nil -end - --- post ADDON_LOADED kb.variables = function() SkeletonKeyDB = SkeletonKeyDB or {spec = {}} @@ -1380,9 +679,10 @@ db = kb.db kb.SelectProfileSet(kb.profileName) - if not configProfile.imported then - kb.ImportScan() - end + -- todo: redo import checking + + + kb.ApplyAllBindings() kb.ui(true) @@ -1395,28 +695,14 @@ end -- Volatiles Access -kb.BindingIsLocked = BindingIsLocked -kb.BindingString = BindingString kb.GetBindings = function() return bindings end kb.GetButtons = function() return buttons end -kb.GetCharacterProfile = function () return loadedProfiles[BINDING_TYPE_CHARACTER] end -kb.GetGlobalProfile = function () return loadedProfiles[BINDING_TYPE_GLOBAL] 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.GetProfileStack = function() return priority end kb.GetReverts = function() return reverts end -kb.GetSpecProfile = function () return loadedProfiles[BINDING_TYPE_SPECIALIZATION] end +kb.GetSpecProfile = function () return kb.loadedProfiles[BINDING_TYPE_SPECIALIZATION] 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 -} SLASH_SKB1 = "/skb" SLASH_SKB2 = "/skeletonkey" diff -r 9ac29fe77455 -r f6d1c192afc6 SkeletonKey/KeyBinds.xml --- a/SkeletonKey/KeyBinds.xml Tue Jul 26 19:29:44 2016 -0400 +++ b/SkeletonKey/KeyBinds.xml Thu Jul 28 16:45:56 2016 -0400 @@ -1,12 +1,11 @@ +