# HG changeset patch # User Nenue # Date 1466418911 14400 # Node ID 69e828f4238a334dd85fad79855f73a977f61afa Initial Commit diff -r 000000000000 -r 69e828f4238a SkeletonKey/KeyBinds.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/KeyBinds.lua Mon Jun 20 06:35:11 2016 -0400 @@ -0,0 +1,776 @@ +-------------------------------------------- +-- KrakTool +-- Nick +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 6/16/2016 3:47 AM +-------------------------------------------- +-- kb +-- .bind(button, key) bind current keystroke to command +-- .assign(button, command, name, icon) set button command +-- .release(button) clear button command +-- .refresh(button) update button contents +-- .ui() invoke interface +-- .profile(name) set profile character +-- .loadbinds(bindings) walk table with SetBinding() + +local kb = KeyBinder +local KT = select(2,...) +KT.register(KeyBinder) +local MIN_BIND_SLOTS = 32 +local BINDS_PER_ROW = 8 +local KEY_BUTTON_SIZE = 40 +local TAB_OFFSET = 12 +local TAB_HEIGHT = 40 +local TAB_SPACING = 2 +local BUTTON_SPACING = 4 +local BUTTON_PADDING = 12 +local HEADER_OFFSET +local FOOTER_OFFSET +local SUMMON_RANDOM_FAVORITE_MOUNT_SPELL = 150544; +local BINDING_TYPE_SPECIALIZATION = 3 +local BINDING_TYPE_CHARACTER = 2 +local BINDING_TYPE_GLOBAL = 1 +local BINDING_ASSIGNED = '|cFF00FF00%s|r assigned to |cFFFFFF00%s|r (%s).' +local BINDING_FAILED_PROTECTED = '|cFF00FF00%s|r used by |cFFFFFF00%s|r!' +local BINDING_MODE = { + [BINDING_TYPE_SPECIALIZATION] = 'Specialization: %s', + [BINDING_TYPE_CHARACTER] = 'Character: %s', + [BINDING_TYPE_GLOBAL] = 'Global Binds' +} +local BINDING_SCHEME_COLOR = { + [BINDING_TYPE_SPECIALIZATION] = {0,0,0,0.5}, + [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.5}, + [BINDING_TYPE_GLOBAL] = {0,.125,.5,.5} +} +local BINDING_SCHEME_VERTEX = { + + [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1}, + [BINDING_TYPE_CHARACTER] = {0,1,0,1}, + [BINDING_TYPE_GLOBAL] = {0,.5,1,1} +} + +local BINDING_SCHEME_TEXT = { + [BINDING_TYPE_SPECIALIZATION] = {1, 1, 0}, + [BINDING_TYPE_CHARACTER] = {0, 1, 0}, + [BINDING_TYPE_GLOBAL] = {0, 1, 1} +} +local ACTION_SCRIPT = { + ['mount'] = "/script C_MountJournal.SummonByID(%d)", + ['equipset'] = "/script UseEquipmentSet(%d)", +} + +local COMMAND_SPELL = "^SPELL (%S.+)" +local COMMAND_MACRO = "^MACRO (%S.+)" +local COMMAND_ITEM = "^ITEM (%S.+)" +local COMMAND_MOUNT = "^CLICK KeyBinderMacro:mount(%d+)" +local COMMAND_EQUIPSET = "^CLICK KeyBinderMacro:equipset(%d+)" + +local PICKUP_TYPES = { + [COMMAND_SPELL] = PickupSpell, + [COMMAND_MACRO] = PickupMacro, + [COMMAND_ITEM] = PickupItem, + [COMMAND_MOUNT] = C_MountJournal.Pickup, + [COMMAND_EQUIPSET] = PickupEquipmentSet +} +local PICKUP_VALUES = { + [COMMAND_SPELL] = function(name) return select(7, GetSpellInfo(name)) end +} +local CLASS_ICON_TEXTURE = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES" +local BORDER_UNASSIGNED = {0.2,0.2,0.2,1 } +local BORDER_ASSIGNED = {0.5,0.5,0.5,1 } +local BORDER_PENDING = {1,0.5,0,1 } + + + +local bindMode = 3 -- not to be confused with db.bindMode which is boolean +local bindHeader = '' +local specHeader, specTexture, characterHeader = 'SPEC_NAME', 'Interface\\ICONS\\INV_Misc_QuestionMark', 'PLAYER_NAME' +local bindsCommitted = true + +local profile +local character +local specialization +local global +local priority = {} +local numButtons = BINDS_PER_ROW * 4 +local buttons = {} +local reverts = {} +local KeyButton = {} -- collection of KeyButton template handlers +local Action = {} -- collection of special action buttons for special binds +local protected = { + ['OPENCHATSLASH'] = true, + ['OPENCHAT'] = true, +} +local saveButton, restoreButton, clearButton + +--- Returns a value for use with Texture:SetDesaturated() +local CommandIsLocked = function(self) + print('command check: 1-'..(bindMode-1)) + local desaturated, layer = false, 3 + for i = 1, bindMode-1 do + local tier = priority[i] + local existing = tier.commands[self.command] + print(' ', i, tier.commands[self.command]) + if existing then + if self:GetID() ~= existing then + -- sanitize bad data + tier.commands[self.command] = nil + else + layer = i + desaturated = true + break + end + end + end + return desaturated, layer +end + +--- Returns a value for use with Texture:SetDesaturated() +local BindingIsLocked = function(key) + local success = false + for i = 1, bindMode-1 do + local tier = priority[i] + if tier.bindings[key] then + success = true + break + end + end + return success +end + +--- Translates GetBindingKey() results into a printable string. +local 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') + end + + if #stack >= 1 then + return table.concat(stack, ',') + else + return nil + end +end + +--- This keeps our KeyDown handler from getting stuck with game controls +KeyButton.OnUpdate = function(self) + if not self.command then + return + end + + if self:IsMouseOver() then + if not self.active then + -- only set this handler when the button is activated/mouseOver + self.active = true + self:SetScript('OnKeyDown', kb.bind) + + local bindText = self.command + if self.bind:GetText() then + bindText = bindText .. ': |cFF00FF00' .. self.bind:GetText() + end + + kb.bindlist:SetText(bindText) + GameTooltip:SetOwner(self) + GameTooltip:SetAnchorType('ANCHOR_BOTTOMRIGHT') + GameTooltip:SetText(self.actionName) + GameTooltip:Show() + end + else + if self.active then + GameTooltip:Hide() + self.active = nil + self:SetScript('OnKeyDown', nil) + end + end +end + +--- Cursor pickup handler + -- Walks through PICKUP_TYPES and runs the function if match(command, key) turns up a result. + -- Passes the result through PICKUP_VALUES[pattern]() if defined. + +kb.pickup = function(self) + for pattern, pickup in pairs(PICKUP_TYPES) do + local value = self.command:match(pattern) + if value then + if PICKUP_VALUES[pattern] then + value = PICKUP_VALUES[pattern](value) + end + + pickup(value) + kb.release(self) + break + end + end +end + +--- Setup an action button base on template info +kb.action = function(type, id) + + local macroName = type .. id + macroName = macroName:gsub(' ', '') + + local attribute = '*macrotext-'..macroName + local value = ACTION_SCRIPT[type]:format(id) + local command = 'CLICK KeyBinderMacro:'.. macroName + profile.macros[attribute] = {value, command} + + KeyBinderMacro:SetAttribute(attribute, value) + return command +end + +KeyButton.OnDragStart = function(self) + if not self.command then + return + end + kb.pickup(self) +end + +KeyButton.OnReceiveDrag = function(self, ...) + print(self:GetName(),'|cFF0088FFreceived|r', ...) + local type, value, subType, subData = GetCursorInfo() + print('GetCursorInfo', type, value, subType, subData) + if type then + if type == 'spell' then + value = subData + end + + local command, name, icon, _ + if type == 'spell' then + name, _, icon = GetSpellInfo(value) + command = 'SPELL ' .. name + name = '' + elseif type == 'macro' then + name, icon = GetMacroInfo(value) + command = 'MACRO ' .. name + elseif type == 'mount' then + if subType == 0 then + name, _, icon = GetSpellInfo(SUMMON_RANDOM_FAVORITE_MOUNT_SPELL) + value= 0 + else + name, _, icon = C_MountJournal.GetMountInfoByID(value) + end + command = kb.action(type, value) + elseif type == 'item' then + name = GetItemInfo(value) + icon = GetItemIcon(value) + command = 'ITEM ' .. name + end + kb.assign(self, command, name, icon) + kb.refresh(self) + ClearCursor() + end +end + +KeyButton.OnMouseDown = function(self, click) + print(self:GetName(), 'OnMouseDown', click) + if click == 'LeftButton' then + KeyButton.OnReceiveDrag(self) + elseif click == 'RightButton' then + kb.release(self) + else + kb.bind(self) + end +end + + +--- Updates the current KeyBinding for the button's command +kb.bind = function(self, key) + + print('|cFFFFFF00bind|cFFFFFF00', self:GetID(), '|cFF00FFFF', 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 + + if protected[GetBindingAction(key)] then + return + kb.bindlist:SetText(BINDING_FAILED_PROTECTED:format(key, GetBindingAction(key))) + end + + if key == 'ESCAPE' then + local key1, key2 = GetBindingKey(self.command) + if key1 then + SetBinding(key1, nil) + print('Unbound', key1) + end + if key2 then + SetBinding(key2, nil) + print('Unbound', key2) + end + self.active = false + return + end + + 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 + self.pending = true + self.border:SetColorTexture(1,.5,0, 1) + + local old = GetBindingAction(self.binding) + local binding1, binding2, new1, new2 + if old and old ~= self.command then + print('Discarding keybind for', old) + local binding1, binding2 = GetBindingKey(old) + -- need to preserve argument order + end + tinsert(reverts, {old, binding1, binding2, new1, new2}) + + + bindsCommitted = false + SetBinding(self.binding, self.command) + for level, profile in ipairs(priority) do + profile.bindings[self.binding] = (level == bindMode) and self.command or nil + end + print(BINDING_ASSIGNED:format(self.binding, self.command, BINDING_MODE[bindMode]:format(bindHeader))) + + kb.refresh(self) + end +end + +--- Resets button command +kb.release = function(self) + local index = self:GetID() + self.command = nil + self.actionName = nil + self.macro:SetText(nil) + self.profile = nil + self.bind:SetText(nil) + self.icon:SetTexture(nil) + self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) + self:EnableKeyboard(false) + self:SetScript('OnKeyDown', nil) + + + if profile.buttons[index] then + profile.buttons[index] = nil + end +end + +-- Sets button command + +kb.assign = function(self, command, name, icon) + local index = self:GetID() + print('|cFF00FFFFassign|cFF0088FF', index, '|cFFFFFF00'.. (command or 'none'), '|cFF00FF00'.. (name or ''), '|cFF00FFFF' .. (icon or '')) + + + if command then + if command:match(COMMAND_SPELL) then + name = command:match(COMMAND_SPELL) + end + + + self:EnableKeyboard(true) + print('profile.buttons['..index..'] |cFF00FFFF=|r ', command, name, icon) + profile.buttons[index] = {command, name, icon} + + --- Clean up any residual buttons + local previous = profile.commands[command] + if previous ~= index and buttons[previous] then + kb.release(buttons[previous]) + end + + profile.commands[command] = index + end + + self.profile = bindMode + self.actionName = name + self.command = command + self.icon:SetTexture(icon) + self:RegisterForDrag('LeftButton') +end + +--- Retrieves button at index; creates said button and instates any stored parameters +kb.keyslot = function(index) + if not buttons[index] then + local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, kb, 'KeyButton') + button:SetScript('OnMouseDown', KeyButton.OnMouseDown) + button:SetScript('OnMouseUp', KeyButton.OnMouseUp) + button:SetScript('OnUpdate', KeyButton.OnUpdate) + button:SetScript('OnDragStart', KeyButton.OnDragStart) + button:SetScript('OnReceiveDrag', KeyButton.OnReceiveDrag) + button:SetID(index) + + if profile.buttons[index] and type(profile.buttons[index] ) == 'table' then + kb.assign(button, unpack(profile.buttons[index] )) + else + kb.release(button) + end + + local x, y = BUTTON_PADDING, - (BUTTON_PADDING + HEADER_OFFSET) + if index ~= 1 then + local col = mod(index, BINDS_PER_ROW) + if col == 0 then + col = BINDS_PER_ROW - 1 + else + col = col - 1 + end + x = col * (KEY_BUTTON_SIZE + BUTTON_SPACING) + BUTTON_PADDING + y = (ceil(index/ BINDS_PER_ROW)-1) * - (KEY_BUTTON_SIZE + BUTTON_SPACING) - BUTTON_PADDING - HEADER_OFFSET + end + button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE) + button:SetPoint('TOPLEFT', kb, 'TOPLEFT', x, y) + button:Show() + buttons[index] = button + end + return buttons[index] +end + +--- Updates profile assignment and button contents +kb.refresh = function(self) + if self.profile ~= bindMode then + if profile.buttons[self:GetID()] then + kb.assign(self, unpack(profile.buttons[self:GetID()])) + else + kb.release(self) + end + end + + if self.command then + if self.pending then + self.border:SetColorTexture(unpack(BORDER_PENDING)) + else + self.border:SetColorTexture(unpack(BORDER_ASSIGNED)) + end + --self.macro:SetText(self.actionName) + self.bind:SetText(BindingString(GetBindingKey(self.command))) + local locked, layer = CommandIsLocked(self) + self.icon:SetDesaturated(locked) + self.icon:SetVertexColor(unpack(BINDING_SCHEME_VERTEX[layer])) + else + self.border:SetColorTexture(unpack(BORDER_UNASSIGNED)) + --self.macro:SetText(nil) + self.bind:SetText(nil) + end +end + +local SetupUI = function() + + + kb.tabAnchor = {'TOPLEFT', kb, 'TOPRIGHT', 2, -TAB_OFFSET} + kb.tabGrowth = {'TOPLEFT', nil,'BOTTOMLEFT', 0, -TAB_SPACING} + kb.tabSize = {TAB_HEIGHT, TAB_HEIGHT } + kb.UIPanelAnchor = {'TOPLEFT', kb, 'TOPLEFT', BUTTON_PADDING + 12, -BUTTON_PADDING} + kb.UIPanelGrowth = {'TOPLEFT', nil, 'TOPRIGHT', 14, 0 } + kb.controlsAnchor = {'BOTTOMLEFT', kb, BUTTON_PADDING, BUTTON_PADDING } + kb.controlsGrowth = {'BOTTOMLEFT', nil, 'BOTTOMRIGHT', BUTTON_SPACING, 0} + + --tab() frame, name, tooltip, texture, coords + kb:tab('KeyBinderGlobalTab', BINDING_MODE[1], "Interface\\ICONS\\item_azereansphere", {0.15,.85,.15,.85}) + kb:tab('KeyBinderCharacterTab', characterHeader, nil) + kb:tab('KeyBinderSpecTab', specHeader, specTexture) + SetPortraitTexture(KeyBinderCharacterTab.icon, 'player') + KeyBinderCharacterTab.icon:SetTexCoord(0.15,.85,.15,.85) + + saveButton = kb:button('KeyBinderSaveButton', 'Save', 'Commit all changes.', nil, kb.save) + restoreButton = kb:button('KeyBinderRestoreButton', 'Discard', 'Revert all changes.', nil, kb.restore) + clearButton = kb:button('KeyBinderClearButton', 'Clear Page', 'Release all buttons.', nil, kb.ResetProfile) + + kb:uibutton( + 'KeyBinderSpellBookButton', 'SpellBook', nil, + function() ToggleSpellBook(BOOKTYPE_SPELL) end, + "Interface\\Spellbook\\Spellbook-Icon") + kb:uibutton( + 'KeyBinderTalentFrameButton', 'Talents', nil, + function() ToggleTalentFrame() end, + "Interface\\TargetingFrame\\UI-Classes-Circles", + CLASS_ICON_TCOORDS[strupper(select(2,UnitClass("player")))]) + + kb:uibutton( + 'KeyBinderMacroFrameButton', 'Macros', nil, + function() if MacroFrame then HideUIPanel(MacroFrame) else ShowMacroFrame() end end, + "Interface\\MacroFrame\\MacroFrame-Icon") + + kb:uibutton( + 'KeyBinderInventoryButton', 'Bags', nil, + function() OpenAllBags() end, + "Interface\\BUTTONS\\Button-Backpack-Up") + + kb.info:SetPoint('TOPLEFT', kb.UIPanels[1], 'BOTTOMLEFT', 0, -BUTTON_SPACING) + HEADER_OFFSET = kb.UIPanels[1]:GetHeight() + BUTTON_PADDING + FOOTER_OFFSET = saveButton:GetHeight() + BUTTON_PADDING +end + +--- Invokes the KeyBinder frame (from the /kb function or some other source) +kb.ui = function() + if not KT.db.bindMode then + return + end + + if not kb:IsVisible() then + kb:Show() + KT.db.bindMode = true + end + + if not kb.loaded then + SetupUI() + kb.loaded = true + end + + for i = 1, numButtons do + kb.refresh(kb.keyslot(i)) + end + + if bindMode == BINDING_TYPE_SPECIALIZATION then + bindHeader = select(2,GetSpecializationInfo(GetSpecialization())) + elseif bindMode == BINDING_TYPE_CHARACTER then + bindHeader = UnitName('player') + else + bindHeader = '' + end + + if bindsCommitted then + KeyBinderSaveButton:Disable() + KeyBinderRestoreButton:Disable() + else + KeyBinderSaveButton:Enable() + KeyBinderRestoreButton:Enable() + end + + --- panel attributes + local numRows = numButtons/BINDS_PER_ROW + kb:SetHeight( numRows * (KEY_BUTTON_SIZE) + (numRows - 1) * BUTTON_SPACING + HEADER_OFFSET + FOOTER_OFFSET + BUTTON_PADDING * 2) + kb:SetWidth((BINDS_PER_ROW - 1) * BUTTON_SPACING + BINDS_PER_ROW * KEY_BUTTON_SIZE + BUTTON_PADDING * 2) + kb.bg:SetColorTexture(unpack(BINDING_SCHEME_COLOR[bindMode])) + + + for i, tab in ipairs(kb.tabButtons) do + + local n = 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 + end + n:SetTexture(tabTexture) + n:SetPoint('TOPLEFT', tab, 'TOPLEFT', left, top) + n:SetPoint('BOTTOMRIGHT', tab, 'BOTTOMRIGHT', right, bottom) + end +end + +kb.loadbinds = function (bindings) + for key, command in pairs(bindings) do + -- store for reversion + local oldAction = GetBindingAction(key) + if oldAction ~= command then + local bind1, bind2 = GetBindingKey(oldAction) + if bind1 and not reverts[bind1] then + reverts[bind1] = oldAction + end + if bind2 and not reverts[bind2] then + reverts[bind2] = oldAction + end + end + SetBindings(key, command) + end + SaveBindings() +end + +local ACTION_BARS = { + 'MultiBarBottomLeftButton', + 'MultiBarBottomRighttButton', + 'MultiBarLeftButton', + 'MultiBarRightButton', + 'ActionButton' +} +kb.HotKeyText = function () + for _, prefix in ipairs(ACTION_BARS) do + for i = 1,12 do + local button = _G[prefix .. i] + if button and button.action then + local type, id, subType, subID = GetActionInfo(button.action) + if type == 'spell' then + local name = GetSpellInfo(id) + local bind, bind2 = GetBindingKey('SPELL '..name) + if bind or bind2 then + --print('SPELL '..name, GetBindingKey('SPELL '..name)) + button.HotKey:SetText(BindingString(bind)) + button.HotKey:Show() + end + end + end + end + end +end + +kb.InitProfile = function(profile) + profile.buttons = profile.buttons or {} + profile.commands = profile.commands or {} + profile.bindings = profile.bindings or {} + profile.macros = profile.macros or {} + return profile +end +kb.ResetProfile = function() + + for i, button in pairs(buttons) do + kb.release(button) + end + + profile.commands = {} + profile.bindings = {} + profile.macros = {} +end + +--- Gives us the profile structure to work with while instating data +kb.profile = function(name) + KT.db = KT.db or {} + global = kb.InitProfile(KT.db) + profile = global + local subtitle + if name then + KT.db[name] = KT.db[name] or {} + KT.db[name] = kb.InitProfile(KT.db[name]) + character = KT.db[name] + local spec = GetSpecialization() + if spec then + KT.db[name][spec] = KT.db[name][spec] or {} + profile = kb.InitProfile(KT.db[name][spec]) + bindMode = BINDING_TYPE_SPECIALIZATION + subtitle = select(2,GetSpecializationInfo(spec)) + specialization = KT.db[name][spec] + else + profile = kb.InitProfile(KT.db[name]) + bindMode = BINDING_TYPE_CHARACTER + subtitle = name + specialization = character + end + end + priority = {global, character, specialization } + + + + if not KT.db.bindsPage then + KT.db.bindsPage = bindMode + end + bindMode = KT.db.bindsPage + + + if not BINDING_MODE[bindMode] then + bindMode = 3 + KT.db.bindsPage = 3 + print('overriding', bindMode) + end + + profile = priority[bindMode] + + + local _ + _, specHeader, _, specTexture = GetSpecializationInfo(GetSpecialization()) + print(GetSpecializationInfo(GetSpecialization())) + specHeader = BINDING_MODE[2]:format(specHeader) + characterHeader = BINDING_MODE[2]:format(UnitName('player')) + + print('Using binding profile |cFF00FF88'..BINDING_MODE[bindMode]:format(subtitle)..'|r') +end + +kb.SelectTab = function(self) + bindMode = self:GetID() + profile = priority[self:GetID()] + KT.db.bindsPage = self:GetID() + kb.ui() +end +kb.save = function() + SaveBindings(GetCurrentBindingSet()) + bindsCommitted = true + for i, button in ipairs(buttons) do + button.pending = false + end + + kb.ui() + print('Bindings saved.') +end +kb.restore = function() + for i, button in pairs(buttons) do + button.pending = false + end + bindsCommitted = true + LoadBindings(GetCurrentBindingSet()) + print('All changes discarded.') +end + +--- Tells all the hud buttons what to do +kb.init = function() + KeyBinderMacro:SetAttribute('*type*', 'macro') +end + +--- Get started +kb.variables = function() + kb.profile(GetUnitName('player', true)) + for i = 1, 3 do + for attribute, data in pairs(priority[i].macros) do + KeyBinderMacro:SetAttribute(attribute, data[1]) + end + end + + kb.UPDATE_BINDINGS() + kb:RegisterEvent('UPDATE_BINDINGS') + kb:RegisterEvent('UPDATE_MACROS') + kb:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED') + kb:RegisterEvent('PLAYER_EQUIPMENT_CHANGED') + kb:RegisterEvent('PLAYER_REGEN_DISABLED') + kb:RegisterEvent('PLAYER_REGEN_ENABLED') + kb:RegisterEvent('ACTIONBAR_SLOT_CHANGED') +end + +kb.close = function() + KT.db.bindMode = false + kb:Hide() +end + +kb.PLAYER_REGEN_DISABLED = function() + if KT.db.bindMode then + + kb:Hide() + end +end + +kb.PLAYER_REGEN_ENABLED = function() + if KT.db.bindMode then + kb.ui() + end +end +--- Refresh buttons if macros are updated +kb.UPDATE_BINDINGS = function() + if KT.db.bindMode then + kb.ui() + end + kb.HotKeyText() +end + +kb.ACTIONBAR_SLOT_CHANGED = function() + kb.HotKeyText() +end + + + +kb.UPDATE_MACROS = kb.UPDATE_BINDINGS + + +SLASH_KB1 = "/kb" +SlashCmdList.KB = function() + if KT.db.bindMode then + KT.db.bindMode = false + print('|cFFFFFF00KeyBinds|r trace, |cFFFF0000OFF|r.') + kb:Hide() + else + KT.db.bindMode = true + print('|cFFFFFF00KeyBinds|r trace, |cFF00FF00ON|r.') + kb.ui() + end +end \ No newline at end of file diff -r 000000000000 -r 69e828f4238a SkeletonKey/KeyBinds.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/KeyBinds.xml Mon Jun 20 06:35:11 2016 -0400 @@ -0,0 +1,120 @@ + + + + + \ No newline at end of file diff -r 000000000000 -r 69e828f4238a SkeletonKey/SkeletonKey.iml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/SkeletonKey.iml Mon Jun 20 06:35:11 2016 -0400 @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff -r 000000000000 -r 69e828f4238a SkeletonKey/SkeletonKey.toc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonKey/SkeletonKey.toc Mon Jun 20 06:35:11 2016 -0400 @@ -0,0 +1,14 @@ +## Interface: 70000 +## Title: KTest +## Notes: tools and things +## Author: Krakyn +## Version: 1.0-@project-revision@ +## SavedVariables: KTestDB +## X-Category: Interface Enhancements +## DefaultState: Enabled +## LoadOnDemand: 0 + +libKT-1.0\libKT-1.0.xml + +KeyBinds.xml +KeyBinds.lua \ No newline at end of file diff -r 000000000000 -r 69e828f4238a SkeletonStats/DamageMeter.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonStats/DamageMeter.lua Mon Jun 20 06:35:11 2016 -0400 @@ -0,0 +1,276 @@ +-------------------------------------------- +-- KrakTool +-- DamageMeter +-- @project-revision@ @project-hash@ +-- @file-revision@ @file-hash@ +-- Created: 6/19/2016 10:43 AM +-------------------------------------------- +-- dm +-- {...} = actor ( name, guid ) -- returns actor table +-- .showbar (bar ) -- toggle row +-- .hidebar ( bar ) -- +-- .ui () -- update chart +local KT = select(2,...) +local dm = DamageMeter +KT.register(dm) + +local segments = {} +local actors = {} +local ordered = {} +local actorsOrdered = {} +local prototypes = {} + +local segmentUID +local viewPos +local view +local handler +local viewType = 'damageDone' +local sortType +local meterWidth = 230 + +local SortByDamage = function(a, b) +end + +dm.init = function() + dm:RegisterEvent('COMBAT_LOG_EVENT_UNFILTERED') + dm:RegisterEvent('ENCOUNTER_START') + dm.bars = dm.bars or {} + dm.headings = dm.headings or {} + + sortType = SortByDamage +end + +dm.ENCOUNTER_START = function() + dm.new() +end + +dm.variables = function() + KT.db.segments = KT.db.segments or {} + KT.db.currentSegment = KT.db.currentSegment or 0 + KT.db.actors = KT.db.actors or {} + actors = KT.db.actors + segments = KT.db.segments + viewPos = KT.db.currentSegment + + + dm.handler(viewType) + + -- resolve segment + if not segments[viewPos] then + viewPos = dm.new() + else + view = segments[viewPos] + print('Using segment #', viewPos) + end + KT.db.currentSegment = viewPos + + dm.ui() +end + +dm.handler = function (viewType) + handler = prototypes[viewType] + dm.header:SetText(handler.header) +end + +dm.new = function() + segmentUID = (KT.db.segUID or 0) + 1 + KT.db.segUID = segmentUID + view = {} + viewPos = #segments+1 + segments[viewPos] = view + KT.db.currentSegment = viewPos + print('Starting new segment #', viewPos) + return viewPos +end +local dummyColor = { + r = 0, + g = 0.5, + b = 0 +} +local dummyActor = { + name = 'Unknown', + flags = 0, + class = 'NA', + classFilename = '', + race = 'Unknown', + raceFilename = '', + sex = 1, + realm = '' +} + +dm.actor = function (guid, name, flags) + --if not actors[guid] then + local class, classFilename, race, raceFilename, sex, name, realm = GetPlayerInfoByGUID(guid) + + print('|cFFFFFF00guid|r =', name, flags, 'class', class, classFilename) + actors[guid] = { + name = name, + flags = flags, + class = class, + classFilename = classFilename, + race = race, + raceFilename = raceFilename, + sex = sex, + realm = realm + } + --end + return actors[guid] +end + + +prototypes.damageDone = { + header = 'Damage Done', +} + +dm.COMBAT_LOG_EVENT_UNFILTERED = function(self, event, timeStemp, subEvent, u1, ...) + local sourceGUID, sourceName, sourceFlags, _, destGUID, destName, destFlags = ... + + + local args = {...} + for key, prototype in pairs(prototypes) do + --print(subEvent) + if prototype[subEvent] then + prototype[subEvent](subEvent, ...) + print('|cFFFFFF00' .. key .. '|r.|cFF00FFFF'..subEvent, '|r', ...) + end + end + + dm.ui() + return true +end + +--- [name] +-- .COMBAT_EVENT = function(event, ...) +-- .init = function() +-- .calculate = function(bar, data, actor) +-- .refresh = function(bar, data, actor + +dm.showbar = function(bar) + bar:Show() + bar.icon:Show() + bar.header:Show() + bar.headerRight:Show() +end + +dm.hidebar = function(bar) + bar:Hide() + bar.icon:Hide() + bar.header:Hide() + bar.headerRight:Hide() +end + +dm.ui = function() + --table.sort(view, sortType) + + + table.wipe(ordered) + for k,v in pairs(view) do + if type(v) ~= 'table' then + view[k] = nil + else + tinsert(ordered, v) + end + end + table.sort(ordered, handler.sort) + + handler.init() + + for i = 1, 12 do + if ordered[i] then + if not dm.bars[i] then + dm.bars[i] = dm:CreateTexture('MeterBar'..i, 'BORDER') + dm.bars[i]:SetHeight(24) + dm.bars[i]:SetPoint('TOPLEFT', dm, 0, i * -24) + dm.bars[i].icon = dm:CreateTexture('MeterIcon' .. i, 'OVERLAY') + dm.bars[i].icon:SetSize(24,24) + dm.bars[i].icon:SetPoint('TOPLEFT', dm.bars[i], 'TOPLEFT', -12, 0) + + dm.bars[i].header = dm:CreateFontString('MeterHeader'..i, 'OVERLAY', 'MeterHeaderLeft') + dm.bars[i].header:SetPoint('LEFT', dm.bars[i], 'LEFT', 22, 0) + + dm.bars[i].headerRight = dm:CreateFontString('MeterHeaderRight'..i, 'OVERLAY', 'MeterHeaderRight') + dm.bars[i].headerRight:SetPoint('TOP', dm.bars[i], 'TOP', 0, -6) + end + handler.calculate(dm.bars[i], ordered[i], ordered[i].actor) + end + end + + for i, bar in ipairs(dm.bars) do + if ordered[i] then + handler.refresh(bar, ordered[i], ordered[i].actor) + dm.showbar(bar) + else + dm.hidebar(bar) + end + end + dm:SetHeight((#ordered + 1) * 24) + dm:SetWidth(meterWidth) +end +--------------------------------------------------------- +-- DAMAGE DONE +local dd = prototypes.damageDone +dd.SPELL_DAMAGE = function(subEvent, ...) + local sourceGUID, sourceName, sourceFlags, _, destGUID, destName, destFlags, _, spellID, spellName, spellSchool, amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = ... + + view[sourceName] = view[sourceName] or {} + local p = view[sourceName] + + p.actor = dm.actor(sourceGUID, sourceName, sourceFlags) + dm.actor(destGUID, destName, destFlags) + + p.last = amount + p.damage = (view[sourceName].damage or 0) + amount + p.name = (sourceName or 'Unknown') + + p.child = p.child or {} + p.child[spellName] = p.child[spellName] or {} + p.child[spellName].hit = (p.child[spellName].hit or 0) + 1 +end +dd.SPELL_DAMAGE_PERIODIC = dd.SPELL_DAMAGE +dd.RANGE_DAMAGE = dd.SPELL_DAMAGE + +dd.SWING_DAMAGE = function(subEvent, ...) + local sourceGUID, sourceName, sourceFlags, _, destGUID, destName, destFlags, _, amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = ... + local spellID, spellName, spellSchool = -1, 'Attack', 1 + dd.SPELL_DAMAGE(subEvent, sourceGUID, sourceName, sourceFlags, _, destGUID, destName, destFlags, _, spellID, spellName, spellSchool, amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing) +end + +dd.init = function() + dd.maxDamage = 0 +end + +dd.sort = function(a, b) + return a.damage > b.damage +end + +dd.calculate = function(bar, data, actor) + if dd.maxDamage < data.damage then + dd.maxDamage = data.damage + end + +end + +dd.refresh = function(bar, data, actor) + if actor.class and CLASS_ICON_TCOORDS[actor.classFilename] then + bar.icon:Show() + bar.icon:SetTexture("Interface\\TargetingFrame\\UI-Classes-Circles") + bar.icon:SetTexCoord(unpack(CLASS_ICON_TCOORDS[actor.classFilename])) + else + bar.icon:Hide() + end + bar.header:SetText(data.name) + bar.headerRight:SetText(data.damage .. ' ('..data.last..')') + + local color = dummyColor + if actor.class and RAID_CLASS_COLORS[actor.classFilename] then + color = RAID_CLASS_COLORS[actor.classFilename] + end + + bar:SetColorTexture(color.r, color.g, color.b, 1) + + bar:SetWidth(meterWidth * (data.damage / dd.maxDamage)) +end + + +--------------------------------------------------------- +-- HEALING DONE \ No newline at end of file diff -r 000000000000 -r 69e828f4238a SkeletonStats/DamageMeter.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonStats/DamageMeter.xml Mon Jun 20 06:35:11 2016 -0400 @@ -0,0 +1,79 @@ + + + + + + + + + + + self:RegisterForDrag('LeftButton') + + + self:StartMoving() + + + self:StopMovingOrSizing() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 000000000000 -r 69e828f4238a SkeletonStats/SkeletonStats.iml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonStats/SkeletonStats.iml Mon Jun 20 06:35:11 2016 -0400 @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff -r 000000000000 -r 69e828f4238a SkeletonUnit/SkeletonUnit.iml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonUnit/SkeletonUnit.iml Mon Jun 20 06:35:11 2016 -0400 @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff -r 000000000000 -r 69e828f4238a SkeletonUnit/UnitFrame.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SkeletonUnit/UnitFrame.lua Mon Jun 20 06:35:11 2016 -0400 @@ -0,0 +1,90 @@ +-------------------------------------------- +-- KrakTool +-- Nick +-- @project - r e v i s i o n @ @project-hash@ +-- @file - r e v i s i o n @ @file-hash@ +-- Created: 6/16/2016 3:46 AM +-------------------------------------------- + +local KT = select(2,...) +local PLAYER_NAMEPLATE +local PLAYER_WIDTH = 220 +local BUFF_SIZE = 24 + + +KT.register(KTplayerFrame) +KTplayerFrame:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", "player") +KTplayerFrame:RegisterUnitEvent("UNIT_POWER_FREQUENT", "player") +KTplayerFrame:RegisterUnitEvent("UNIT_AURA", 'player') +KTplayerFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED") +KTplayerFrame:RegisterEvent("NAME_PLATE_UNIT_REMOVED") +KTplayerFrame.event = function(self) + -- print(C_NamePlate.GetNamePlateForUnit('player')) +end + +local buttons = {} +local SetupButton = function(self, unit, index) + if not buttons[index] then + buttons[index] = CreateFrame('Frame', 'KT'..unit..'Buff'..index, self, 'KTAuraButton') + buttons[index]:SetSize(BUFF_SIZE, BUFF_SIZE) + buttons[index].cooldown:SetHideCountdownNumbers(true) + + end + return buttons[index] +end + +KTplayerFrame.UNIT_AURA = function(self, event, unit) + local buffOffset = 0 + for i = 1, 16 do + --UnitAura() + local aura, _, texture, count, dispelType, duration, expires, caster = UnitAura(unit, i, nil, 'HELPFUL') + if aura then + local button = SetupButton(self, unit, i) + + button.icon:SetTexture(texture) + button.cooldown:SetCooldown(expires - duration, duration) + button.cooldown:Show() + button.count:SetText(count > 0 and count or nil) + button:SetPoint('BOTTOMLEFT', self, 'TOPLEFT', buffOffset* BUFF_SIZE, 2) + button:Show() + buffOffset = buffOffset + 1 + else + if buttons[i] then + buttons[i]:Hide() + end + end + end +end + +KTplayerFrame.NAME_PLATE_UNIT_ADDED = function(self, event, unit) + print('|cFF008800'..unit) + if UnitIsUnit('player', unit) then + PLAYER_NAMEPLATE = unit + self:ClearAllPoints() + self:SetPoint('TOP', C_NamePlate.GetNamePlateForUnit(unit), 'BOTTOM', 0, 0) + end +end +KTplayerFrame.NAME_PLATE_UNIT_REMOVED = function(self, event, unit) + if unit == PLAYER_NAMEPLATE then + PLAYER_NAMEPLATE = nil + self:ClearAllPoints() + self:SetPoint('LEFT', UIParent, 'LEFT', 25, 0) + end +end + +KTplayerFrame.UNIT_HEALTH_FREQUENT = function(self, ...) + --print(UnitHealth('player') / UnitHealthMax('player')) + self.healthbar:SetWidth(PLAYER_WIDTH * UnitHealth('player') / UnitHealthMax('player')) + return true +end + +KTplayerFrame.UNIT_POWER_FREQUENT = function(self) + self.powerbar:SetWidth(PLAYER_WIDTH * UnitPower('player') / UnitPowerMax('player')) + return true +end + +KTplayerFrame:SetWidth(PLAYER_WIDTH) +KTplayerFrame.variables = function() + KTplayerFrame:UNIT_HEALTH_FREQUENT() + KTplayerFrame:UNIT_POWER_FREQUENT() +end \ No newline at end of file