Mercurial > wow > skeletonkey
diff BindingsFrame.lua @ 70:131d9190db6b
Curseforge migration
author | Nenue |
---|---|
date | Wed, 28 Dec 2016 16:31:15 -0500 |
parents | |
children | ca3118127e5e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BindingsFrame.lua Wed Dec 28 16:31:15 2016 -0500 @@ -0,0 +1,652 @@ +-- KrakTool +-- BindingsFrame.lua +-- Created: 7/28/2016 3:39 PM +-- %file-revision% +-- Handles the arrangement of and interaction with the SkeletonKey frame +--[=[ + -- some useful texture paths + [[Interface\PaperDollInfoFrame\UI-GearManager-Undo]] + [[Interface\PetPaperDollFrame\UI-PetHappiness]] + [[Interface\RAIDFRAME\ReadyCheck-Waiting]] + [[Interface\RAIDFRAME\ReadyCheck-Read]] + [[Interface\RAIDFRAME\ReadyCheck-NotReady]] + [[Interface\TradeSkillFrame\UI-TradeSkill-LinkButton]] + [[Interface\TUTORIALFRAME\UI-TUTORIAL-FRAME]] + [[Interface\UI-TutorialFrame-QuestGiver\UI-TutorialFrame-QuestGray]] +--]=] + +SkeletonKeyButtonMixin = {} +local _, kb = ... +local print = (DEVIAN_PNAME == 'SkeletonKey') and function(...) _G.print('SK', ...) end or nop +local L = kb.L +local BINDS_PER_ROW = 2 +local BINDING_TYPE_SPECIALIZATION = 3 +local BINDING_TYPE_CHARACTER = 2 +local BINDING_TYPE_GLOBAL = 1 +local BUTTON_HSPACING = 128 +local BUTTON_SPACING = 4 +local BUTTON_PADDING = 12 +local TAB_HEIGHT = 24 +local KEY_BUTTON_SIZE = 48 +local NUM_KEY_SLOTS = BINDS_PER_ROW * 8 +local TAB_HEIGHT = 40 +local BG_INSET = 4 + +local BINDING_SCHEME_COLOR = { + [BINDING_TYPE_GLOBAL] = {0,.125,.5,.8}, + [BINDING_TYPE_CHARACTER] = {0,0.25,0,0.8}, + [BINDING_TYPE_SPECIALIZATION] = {.25,0,0,0.8}, +} +local BINDING_SCHEME_VERTEX = { + [BINDING_TYPE_GLOBAL] = {0,.5,1,1}, + [BINDING_TYPE_CHARACTER] = {0,1,0,1}, + [BINDING_TYPE_SPECIALIZATION] = {1,1,1,1}, +} +local BINDING_SCHEME_TEXT = { + [BINDING_TYPE_SPECIALIZATION] = {0, 1, 1}, + [BINDING_TYPE_CHARACTER] = {0, 1, 0}, + [BINDING_TYPE_GLOBAL] = {0, 1, 1} +} + +local match, strupper = string.match, string.upper +local tremove, tinsert, ipairs, pairs, unpack = table.remove, table.insert, ipairs, pairs, unpack +local tonumber, tostring = tonumber, tostring +local GetCursorInfo, ClearCursor, ResetCursor = GetCursorInfo, ClearCursor, ResetCursor +local IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown = IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown +local GetBindingAction, GetBindingKey, GetCurrentBindingSet = GetBindingAction, GetBindingKey, GetCurrentBindingSet +local SetBinding, SaveBindings = SetBinding, SaveBindings +local GetSpellInfo, InCombatLockdown = GetSpellInfo, InCombatLockdown + + +local ActionListPanel = { + tabButtons = { + [BINDING_TYPE_GLOBAL] = { + icon = "Interface\\WORLDMAP\\WorldMap-Icon", + label = "Global", + }, + [BINDING_TYPE_CHARACTER] ={ + func = function(self, index) + SetPortraitTexture(self.Icon, 'player') + self.Label:SetText(kb.configHeaders[index]) + self.tooltipText = kb.configHeaders[index] + end + }, + [BINDING_TYPE_SPECIALIZATION] = { + func = function(self, index) + self.Icon:SetTexture(kb.specInfo.texture) + self.Label:SetText(kb.configHeaders[index]) + self.tooltipText = kb.configHeaders[index] + end + }, + } +} +local SystemBindingsPanel = { + tabButtons = { + {label = "Global"}, + {label = "Character"} + } +} +function SkeletonKeyMixin:ProcessInput (key) + if self.currentPanel then + if self.currentPanel:OnInput(key) then + self:Update(true) + end + end +end + +local lastFolder +local restingAlpha = 0.7 +local fadeTime, fadeDelay = .30, 0.15 +local saveButton + + + +local frameCount = 0 +local lastCheckFrame +local KeyBinder_CheckButton = function(frame ,enableText, disableText, dbKey, tooltipText, callback, header) + if kb.db[dbKey] then + frame:SetChecked(true) + end + + frame.header:SetText(header) + + frame:SetScript('OnClick', function(self) + kb.db[dbKey] = self:GetChecked() + if callback then + callback(self) + end + kb.ui() + end) + + frame:SetScript('OnEnter', function(self) + if tooltipText then + GameTooltip:SetOwner(self) + GameTooltip:SetText(tooltipText) + GameTooltip:Show() + end + end) + + frame:SetScript('OnLeave', function(self) + if tooltipText and GameTooltip:GetOwner() == self then + GameTooltip:Hide() + end + end) + + if frame:GetID() == 0 then + frameCount = frameCount + 1 + frame:SetID(frameCount) + print('checkbutton #', frameCount) + if frameCount == 1 then + frame:ClearAllPoints() + frame:SetPoint('TOP', KeyBinderInventoryButton, 'BOTTOM', 0, -22) + frame:SetPoint('LEFT', SkeletonKey 'LEFT', 2, 0) + else + frame:ClearAllPoints() + frame:SetPoint('TOPLEFT', lastCheckFrame, 'BOTTOMLEFT', 0, -2) + end + + frame.header:ClearAllPoints() + frame.header:SetPoint('LEFT', frame, 'RIGHT', 2, 0) + + lastCheckFrame = frame + end +end + + + +function SkeletonKeyMixin:OnMouseWheel(delta) + + -- let the updaters handle range + if IsControlKeyDown() then + self.zoomScale = self.zoomScale - (delta/10) + else + self.scrollOffset = ceil(self.scrollOffset - delta) + end + + self:Update(true) + print(self.zoomScale, self.scrollOffset) +end + +function SkeletonKeyMixin:OnHide() + KeyBinderImportLog:Hide() +end + + +local tabID = 0 +local prevTab + +function SkeletonKeyMixin:SetupTabButton (index, text, icon, func) + print('|cFF00FFFF'..self:GetName()..':SetupTabButton()', index, text, icon, func) + local tabName = 'SkeletonKeyProfileTab'..index + local tab = _G[tabName] + + if not tab then + tab = CreateFrame('Button', tabName, self, 'SkeletonKeyTabTemplate') + self.numTabs = self.numTabs + 1 + tab:SetID(self.numTabs) + TAB_HEIGHT = tab:GetHeight() + + if self.numTabs == 1 then + tab:SetPoint('TOPLEFT', self.profilebg, 'TOPLEFT', BUTTON_PADDING, -BUTTON_SPACING) + else + tab:SetPoint('TOPLEFT', self.lastTab,'TOPRIGHT', BUTTON_SPACING, 0) + end + + tab.tooltipText = text + tab:SetScript('OnEnter', function(button) + if button.tooltipText then + GameTooltip:SetOwner(button) + GameTooltip:SetText(button.tooltipText) + GameTooltip:Show() + end + end) + + tab:SetScript('OnLeave', function(button) + if GameTooltip:IsOwned(button) then + GameTooltip:Hide() + end + end) + + tab:SetScript('OnClick', function(button) + self.selectedTabIndex = button:GetID() + self:Update(true) + end) + self.lastTab = tab + end + if text then + + tab.Label:SetText(text) + end + + if icon then + tab.Icon:SetTexture(icon) + end + if func then + func(tab, index, text) + end + + local selected = (index == self.selectedTabIndex) + if selected then + tab.Icon:SetDesaturated(false) + tab.Label:SetTextColor(0,1,0, 1) + else + + tab.Icon:SetDesaturated(true) + tab.Label:SetTextColor(1,1,1,0.7) + end + + tab.used = true + + tab:SetSize(tab.Icon:GetWidth()+tab.Label:GetStringWidth()+3, tab.Icon:GetHeight()) + tab:Show() + print(tab:GetPoint(1)) + print(tab:GetSize()) + + return tab +end + + + +--- push current information into living UI +function SkeletonKeyMixin:Update(force) + print('|cFFFF8800'..self:GetName()..':Update()|r', InCombatLockdown() and 'combat', self:IsShown()) + for index, frame in ipairs(self.Plugins) do + if frame.Update then + frame:Update(force) + end + end + + self.currentPanel = self.currentPanel or self.Panels[1] + if InCombatLockdown() or not self:IsShown() then + return + end + + self.numTabs = 0 + for index, tab in ipairs(self.tabButtons) do + tab.used = nil + tab:Hide() + end + + for index, panel in ipairs(self.Panels) do + print(panel:GetName()) + if panel == self.currentPanel then + print('Updating panel:', panel:GetName()) + panel:SetAllPoints(self.bg) + self.selectedTabIndex, self.scrollOffset = panel:Update(force) + panel:Show() + + for tabIndex, info in ipairs(panel.tabButtons) do + self:SetupTabButton(tabIndex, info.label, info.icon, info.func) + end + + else + panel:Hide() + end + end + + + + --- Frame Sizing + self.profilebg:SetHeight(TAB_HEIGHT + BUTTON_PADDING * 2 + self.profiletext:GetStringHeight()) + + self.bg:SetWidth((KEY_BUTTON_SIZE + BUTTON_HSPACING + BUTTON_SPACING) * BINDS_PER_ROW + BUTTON_PADDING*2 - BUTTON_SPACING - BG_INSET*2) + local numRows = NUM_KEY_SLOTS/BINDS_PER_ROW + + self.bg:SetHeight((KEY_BUTTON_SIZE + BUTTON_SPACING) * numRows + BUTTON_PADDING*2 - BUTTON_SPACING - BG_INSET*2) + + + self:SetHeight(self.headerbg:GetHeight() + self.profilebg:GetHeight() + self.bg:GetHeight() + self.footer:GetHeight()+BG_INSET*2) + self:SetWidth(((BINDS_PER_ROW * (KEY_BUTTON_SIZE + BUTTON_HSPACING) + (BINDS_PER_ROW - 1) * BUTTON_SPACING + BUTTON_PADDING * 2) )) + + + self.backdrop.insets.left = BG_INSET + self.backdrop.insets.right = BG_INSET + self.backdrop.insets.top = BG_INSET + self.backdrop.insets.bottom = BG_INSET + self:SetBackdrop(self.backdrop) + self:SetBackdropColor(unpack(self.backdropColor)) + self:SetBackdropBorderColor(unpack(self.backdropBorder)) + + self:SetScale(self.zoomScale) + + self.profiletext:SetText(kb.configHeaders[kb.db.bindMode]) + print(kb.db.bindMode, kb.configHeaders[kb.db.bindMode], self:GetSize()) + print(self:GetPoint(1)) + + + self:EnableKeyboard((kb.saveTarget and true) or false) + print('keyboard input:', (kb.saveTarget and true) or false) + + -- Reset this so talent cache can be rebuilt + kb.talentsPushed = nil +end + +local SkeletonKeyPanel = {} +function SkeletonKeyPanel:OnShow() + print('|cFFFFFF00'..self:GetName()..':OnShow()|r') +end + +function ActionListPanel:OnLoad() + + + self.UnbindButton:SetScript('OnClick', function() + self:UnbindSlot(kb.saveTarget) + SkeletonKey:Update() + end) +end + +function ActionListPanel:Update(force) + local parent = self:GetParent() + local tabID = parent.selectedTabIndex + local scrollOffset = parent.scrollOffset + if not tabID then + tabID = kb.db.bindMode or BINDING_TYPE_GLOBAL + end + print('|cFF0088FF'..self:GetName()..':Update()|r', 'tab', parent.selectedTabIndex, 'scroll', parent.scrollOffset) + + local selectedProfile = kb.loadedProfiles[tabID] + if selectedProfile then + kb.currentProfile = selectedProfile + kb.db.bindMode = tabID + else + tabID = BINDING_TYPE_GLOBAL + end + scrollOffset = scrollOffset or 0 + + local leftSlot, upSlot + local buttonTable = self.buttons or {} + for index = 1, NUM_KEY_SLOTS do + if not buttonTable[index] then + local button = CreateFrame('CheckButton', 'KeyBinderSlot'..index, self, 'KeyButton') + local newRow = (mod(index, BINDS_PER_ROW) == 1) + + if index == 1 then + button:SetPoint('TOPLEFT', self, 'TOPLEFT', BUTTON_PADDING, - BUTTON_PADDING) + upSlot = button + elseif newRow then + button:SetPoint('TOPLEFT', upSlot, 'BOTTOMLEFT', 0, -BUTTON_SPACING) + upSlot = button + else + button:SetPoint('TOPLEFT', leftSlot, 'TOPRIGHT', BUTTON_HSPACING, 0) + end + + button:SetSize(KEY_BUTTON_SIZE, KEY_BUTTON_SIZE) + button:Show() + buttonTable[index] = button + leftSlot = button + end + end + self.buttons = buttonTable + + local startIndex = scrollOffset * BINDS_PER_ROW + for i, button in ipairs(self.buttons) do + button:SetID(startIndex+i) + button:UpdateSlot(force) + button:SetFrameLevel(50 + i + (button.isActive and #self.buttons or 0)) + end + + + local r,g,b,a = unpack(BINDING_SCHEME_COLOR[kb.db.bindMode]) + self.profileStripe:SetColorTexture(r,g,b) + if kb.saveTarget then + self.bg:SetColorTexture(.2,.5, .2, .5) + self.UnbindButton:SetFrameLevel(kb.saveTarget:GetFrameLevel()-1) + self.UnbindButton:SetPoint('TOPLEFT', kb.saveTarget, 'BOTTOMLEFT', 0, -1) + self.UnbindButton:Show() + + else + self.bg:SetColorTexture(.2,.2,.2,1) + self.UnbindButton:Hide() + end + + return tabID, scrollOffset +end + + +function ActionListPanel:ActivateSlot (button) + if kb.saveTarget then + kb.saveTarget.isActive = nil + end + button.isActive = true + kb.saveTarget = button + return true +end + +function ActionListPanel:DeactivateSlot (button) + button.isActive = nil + kb.saveTarget = nil + return true +end + +function ActionListPanel:OnInput(key) + + if key == 'ESCAPE' then + return self:DeactivateSlot(kb.saveTarget) + end + + if (match(key, '[RL]SHIFT') or match(key, '[RL]ALT') or match(key, '[RL]CTRL')) then + return + end + + if kb.saveTarget then + if kb.saveTarget:SaveSlot(key) then + if not (kb.db.stickyMode or kb.db.hoverInput) then + return self:DeactivateSlot(kb.saveTarget) + end + return true + end + end +end + + +function SystemBindingsPanel:Update(force) +end + +--- Associate processed input with the given slot's metadata +function SkeletonKeyButtonMixin:SaveSlot (key) + + if not self.command then + return + end + if InCombatLockdown() then + kb:print(L('Bindings cannot be changed during combat.')) + return + end + + local spellName = self.actionName + + print('|cFFFFFF00received|cFFFFFF00', self:GetID(), '|cFF00FFFF', key) + + local modifier = '' + if IsAltKeyDown() then + modifier = 'ALT-' + end + if IsControlKeyDown() then + modifier = modifier.. 'CTRL-' + end + if IsShiftKeyDown() then + modifier = modifier..'SHIFT-' + end + local binding = modifier..key + + -- check for system bindings + --bprint('|cFFFFFF00SaveBind|r', 'protectKeys', kb.db.protectBlizKeys) + if kb.db.protectBlizKeys and kb.SystemBindings[binding] then + kb:print(L('BINDING_FAILED_PROTECTED', binding, kb.SystemBindings[binding])) + return false + end + + -- check for other keys + local previousCommand = GetBindingAction(binding) + if previousCommand ~= "" and previousCommand ~= self.command then + local actionType, actionID, name = kb.GetCommandAction(previousCommand) + if actionType then + local keys = {GetBindingKey(previousCommand) } + local i = 1 + while keys[i] do + if keys[i] == binding then + tremove(keys, i) + kb.UpdateBindingsCache(actionType, actionID, keys) + break + end + i = i + 1 + end + end + end + + + if self.isAvailable then + print('Binding available spell', binding, self.command) + SetBinding(binding, self.command) + SaveBindings(GetCurrentBindingSet()) + self.assignedKeys = {GetBindingKey(self.command) } + + kb:print(L('BINDING_ASSIGNED', binding, self.actionName, kb.currentHeader)) + else + kb:print(L('UNSELECTED_TALENT_ASSIGNED', binding, self.actionName, kb.currentHeader)) + end + + if not tContains(self.assignedKeys, binding) then + tinsert(self.assignedKeys, 1, binding) + end + + local talentInfo + if spellName and kb.TalentCache[spellName] then + print('store dynamicType talent') + talentInfo = { + macroName = self.macroName, + actionName = self.actionName, + actionType = self.actionType, + actionID = self.actionID, + assignedKeys = self.assignedKeys + } + kb.currentProfile.talents[spellName] = talentInfo + end + + for _, key in ipairs(self.assignedKeys) do + if not kb.currentProfile.bindings[key] then + kb.currentProfile.bindings[key] = self.command + end + end + + for level, profile in ipairs(kb.orderedProfiles) do + if (level > kb.db.bindMode) then + profile.bindings[binding] = nil + profile.commands[self.command] = nil + profile.bound[self.command] = nil + if spellName then + profile.talents[spellName] = nil + end + end + end + + kb.UpdateBindingsCache(self.actionType, self.actionID, self.assignedKeys) + + self.binding = binding + + return true +end + +function SkeletonKeyMixin:OnKeyDown(key) + self:ProcessInput(key) +end +function SkeletonKeyMixin:OnKeyUp(key) +end + +function SkeletonKeyMixin:OnDragStart() + self:StartMoving() +end +function SkeletonKeyMixin:OnDragStop() + self:StopMovingOrSizing() +end + +function ActionListPanel:UnbindSlot (button) + + local button = button or kb.saveTarget + if not button then + return + end + + local command = button.command + local actionType = button.actionType + local actionID = button.actionID + + local keys = {GetBindingKey(command) } + if #keys >= 1 then + kb.UpdateBindingsCache(actionType, actionID, {}) + end + + local talentName = button.actionName + if actionType == 'macro' then + local spellName, _, spellID = GetMacroSpell(actionID) + talentName = spellName + end + + + --print('detected', #keys, 'bindings') + for i, key in pairs(keys) do + --print('clearing', key) + SetBinding(key, nil) + SaveBindings(GetCurrentBindingSet()) + if kb.currentProfile.bindings[key] then + --kb:print(L('BINDING_REMOVED', self.actionName, kb.currentHeader)) + kb.currentProfile.bindings[key] = nil + end + if kb.currentProfile.talents[talentName] then + kb.currentProfile.talents[talentName] = nil + end + + kb.bindings[tostring(actionType)..'_'..tostring(actionID)] = nil + end + if kb.currentProfile.bound[command] then + kb.currentProfile.bound[command] = nil + --kb:print(BINDING_REMOVED:format(self.actionName, configHeaders[db.bindMode])) + end + kb.saveTarget = nil + + return true +end + +kb.AcceptAssignment = function(self, ...) + local popup = StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] + local source = kb. loadedProfiles[popup.oldProfile] + popup.slot:SetSlot(unpack(popup.args)) + popup.slot:UpdateSlot() + --kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) -- re-enable scrolling + ClearCursor() + ResetCursor() +end + +--- Add to blizzard interfaces +StaticPopupDialogs["SKELETONKEY_CONFIRM_ASSIGN_SLOT"] = { + text = "Confirm moving an assigned command.", + button1 = OKAY, + button2 = CANCEL, + timeout = 0, + whileDead = 1, + showAlert = 1, + OnAccept = kb.AcceptAssignment, + --OnCancel = function() kb:SetScript('OnMouseWheel', KeyBinder_OnMouseWheel) end +} + + + +do + local MACRO_SELECTED_ID = 1 + local MACRO_SELECTED_NAME = GetMacroInfo(1) + kb.CreateMacroHooks = function() + print('|cFF00FF00setting up MacroUI hooks') + hooksecurefunc("MacroFrame_SelectMacro", function(id) + print('|cFF0088FFMacroFrame_SelectMacro|r', id) + MACRO_SELECTED_ID = id + for k,v in pairs(kb.bindings) do + --print(k,v) + end + + end) + end +end + + +SkeletonKeyActionListMixin = Mixin(ActionListPanel, SkeletonKeyPanel) +SkeletonKeySystemBindingsMixin = Mixin(SystemBindingsPanel, SkeletonKeyPanel) \ No newline at end of file