# 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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForDrag('LeftButton')
+
+
+ self:StartMoving()
+
+
+ self:StopMovingOrSizing()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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