diff --git a/ElvUI/Modules/ActionBars/ActionBars.lua b/ElvUI/Modules/ActionBars/ActionBars.lua index a574fe3..42a7599 100644 --- a/ElvUI/Modules/ActionBars/ActionBars.lua +++ b/ElvUI/Modules/ActionBars/ActionBars.lua @@ -486,7 +486,7 @@ function AB:Initialize() end self:UpdateButtonSettings() - --self:LoadKeyBinder() + self:LoadKeyBinder() self:SecureHook("ActionButton_Update") self:RawHook("ActionButton_GetPagedID") diff --git a/ElvUI/Modules/ActionBars/Bind.lua b/ElvUI/Modules/ActionBars/Bind.lua new file mode 100644 index 0000000..21ae9cd --- /dev/null +++ b/ElvUI/Modules/ActionBars/Bind.lua @@ -0,0 +1,368 @@ +local E, L, V, P, G = unpack(ElvUI); --Inport: Engine, Locales, PrivateDB, ProfileDB, GlobalDB +local AB = E:GetModule("ActionBars"); + +--Cache global variables +--Lua functions +local _G = _G +local select, tonumber, pairs, getn = select, tonumber, pairs, getn +local floor = math.floor +local find, format = string.find, string.format +--WoW API / Variables +local hooksecurefunc = hooksecurefunc +local EnumerateFrames = EnumerateFrames +local CreateFrame = CreateFrame +local IsAddOnLoaded = IsAddOnLoaded +local LoadBindings, SaveBindings = LoadBindings, SaveBindings +local GetCurrentBindingSet = GetCurrentBindingSet +local SetBinding = SetBinding +local GetBindingKey = GetBindingKey +local IsAltKeyDown, IsControlKeyDown = IsAltKeyDown, IsControlKeyDown +local IsShiftKeyDown, IsModifiedClick = IsShiftKeyDown, IsModifiedClick +local InCombatLockdown = InCombatLockdown +local GameTooltip_ShowCompareItem = GameTooltip_ShowCompareItem +local GetMacroInfo = GetMacroInfo +local SecureActionButton_OnClick = SecureActionButton_OnClick +local GameTooltip_Hide = GameTooltip_Hide +local CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP = CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP +local CHARACTER_SPECIFIC_KEYBINDINGS = CHARACTER_SPECIFIC_KEYBINDINGS + +local bind = CreateFrame("Frame", "ElvUI_KeyBinder", E.UIParent) + +function AB:ActivateBindMode() + bind.active = true + E:StaticPopupSpecial_Show(ElvUIBindPopupWindow) + AB:RegisterEvent("PLAYER_REGEN_DISABLED", "DeactivateBindMode", false) +end + +function AB:DeactivateBindMode(save) + if save then + SaveBindings(GetCurrentBindingSet()) + E:Print(L["Binds Saved"]) + else + LoadBindings(GetCurrentBindingSet()) + E:Print(L["Binds Discarded"]) + end + bind.active = false + self:BindHide() + self:UnregisterEvent("PLAYER_REGEN_DISABLED") + E:StaticPopupSpecial_Hide(ElvUIBindPopupWindow) + AB.bindingsChanged = false +end + +function AB:BindHide() + bind:ClearAllPoints() + bind:Hide() + GameTooltip:Hide() +end + +function AB:BindListener(key) + AB.bindingsChanged = true + if key == "ESCAPE" or key == "RightButton" then + if bind.button.bindings then + for i = 1, getn(bind.button.bindings) do + SetBinding(bind.button.bindings[i]) + end + end + E:Print(format(L["All keybindings cleared for |cff00ff00%s|r."], bind.button.name)) + self:BindUpdate(bind.button, bind.spellmacro) + if bind.spellmacro~="MACRO" then GameTooltip:Hide() end + return + end + + if key == "LSHIFT" + or key == "RSHIFT" + or key == "LCTRL" + or key == "RCTRL" + or key == "LALT" + or key == "RALT" + or key == "UNKNOWN" + or key == "LeftButton" + then return end + + if key == "MiddleButton" then key = "BUTTON3" end + if find(key, "Button%d") then + key = key:upper() + end + + local alt = IsAltKeyDown() and "ALT-" or "" + local ctrl = IsControlKeyDown() and "CTRL-" or "" + local shift = IsShiftKeyDown() and "SHIFT-" or "" + + if not bind.spellmacro or bind.spellmacro == "PET" or bind.spellmacro == "SHAPESHIFT" then + SetBinding(alt..ctrl..shift..key, bind.button.bindstring) + else + SetBinding(alt..ctrl..shift..key, bind.spellmacro.." "..bind.button.name) + end + E:Print(alt..ctrl..shift..key..L[" |cff00ff00bound to |r"]..bind.button.name..".") + self:BindUpdate(bind.button, bind.spellmacro) + if bind.spellmacro~="MACRO" then GameTooltip:Hide() end +end + +function AB:BindUpdate(button, spellmacro) + if not bind.active or InCombatLockdown() then return end + + bind.button = button + bind.spellmacro = spellmacro + + bind:ClearAllPoints() + bind:SetAllPoints(button) + bind:Show() + + ShoppingTooltip1:Hide() + + if not bind:IsMouseEnabled() then + bind:EnableMouse(true) + end + + if spellmacro == "MACRO" then + bind.button.id = bind.button:GetID() + + if floor(.5+select(2,MacroFrameTab1Text:GetTextColor())*10)/10==.8 then bind.button.id = bind.button.id + MAX_ACCOUNT_MACROS end + + bind.button.name = GetMacroInfo(bind.button.id) + + GameTooltip:SetOwner(bind, "ANCHOR_TOP") + GameTooltip:SetPoint("BOTTOM", bind, "TOP", 0, 1) + GameTooltip:AddLine(bind.button.name, 1, 1, 1) + + bind.button.bindings = {GetBindingKey(spellmacro.." "..bind.button.name)} + if getn(bind.button.bindings == 0) then + GameTooltip:AddLine(L["No bindings set."], .6, .6, .6) + else + GameTooltip:AddDoubleLine(L["Binding"], L["Key"], .6, .6, .6, .6, .6, .6) + for i = 1, getn(bind.button.bindings) do + GameTooltip:AddDoubleLine(L["Binding"]..i, bind.button.bindings[i], 1, 1, 1) + end + end + GameTooltip:Show() + elseif spellmacro=="SHAPESHIFT" or spellmacro=="PET" then + bind.button.id = tonumber(button:GetID()) + bind.button.name = button:GetName() + + if not bind.button.name then return end + + if not bind.button.id or bind.button.id < 1 or bind.button.id > (spellmacro=="SHAPESHIFT" and 10 or 12) then + bind.button.bindstring = "CLICK "..bind.button.name..":LeftButton" + else + bind.button.bindstring = (spellmacro=="SHAPESHIFT" and "SHAPESHIFTBUTTON" or "BONUSACTIONBUTTON")..bind.button.id + end + + GameTooltip:AddLine(L["Trigger"]) + GameTooltip:Show() + GameTooltip:SetScript("OnHide", function(tt) + tt:SetOwner(bind, "ANCHOR_NONE") + tt:SetPoint("BOTTOM", bind, "TOP", 0, 1) + tt:AddLine(bind.button.name, 1, 1, 1) + bind.button.bindings = {GetBindingKey(bind.button.bindstring)} + if getn(bind.button.bindings) == 0 then + tt:AddLine(L["No bindings set."], .6, .6, .6) + else + tt:AddDoubleLine(L["Binding"], L["Key"], .6, .6, .6, .6, .6, .6) + for i = 1, getn(bind.button.bindings) do + tt:AddDoubleLine(i, bind.button.bindings[i]) + end + end + tt:Show() + tt:SetScript("OnHide", nil) + end) + else + bind.button.action = tonumber(button.action) + bind.button.name = button:GetName() + + if not bind.button.name then return end + if (not bind.button.action or bind.button.action < 1 or bind.button.action > 132) and not (bind.button.keyBoundTarget) then + bind.button.bindstring = "CLICK "..bind.button.name..":LeftButton" + elseif bind.button.keyBoundTarget then + bind.button.bindstring = bind.button.keyBoundTarget + else + local modact = 1+(bind.button.action-1) + modact = modact - floor(modact/12)*12 + if bind.button.action < 25 or bind.button.action > 72 then + bind.button.bindstring = "ACTIONBUTTON"..modact + elseif bind.button.action < 73 and bind.button.action > 60 then + bind.button.bindstring = "MULTIACTIONBAR1BUTTON"..modact + elseif bind.button.action < 61 and bind.button.action > 48 then + bind.button.bindstring = "MULTIACTIONBAR2BUTTON"..modact + elseif bind.button.action < 49 and bind.button.action > 36 then + bind.button.bindstring = "MULTIACTIONBAR4BUTTON"..modact + elseif bind.button.action < 37 and bind.button.action > 24 then + bind.button.bindstring = "MULTIACTIONBAR3BUTTON"..modact + end + end + + GameTooltip:AddLine(L["Trigger"]) + GameTooltip:Show() + GameTooltip:SetScript("OnHide", function(tt) + tt:SetOwner(bind, "ANCHOR_TOP") + tt:SetPoint("BOTTOM", bind, "TOP", 0, 4) + tt:AddLine(bind.button.name, 1, 1, 1) + bind.button.bindings = {GetBindingKey(bind.button.bindstring)} + if getn(bind.button.bindings) == 0 then + tt:AddLine(L["No bindings set."], .6, .6, .6) + else + tt:AddDoubleLine(L["Binding"], L["Key"], .6, .6, .6, .6, .6, .6) + for i = 1, getn(bind.button.bindings) do + tt:AddDoubleLine(i, bind.button.bindings[i]) + end + end + tt:Show() + tt:SetScript("OnHide", nil) + end) + end +end + +local script +local shapeshift = ShapeshiftButton1:GetScript("OnClick") +local pet = PetActionButton1:GetScript("OnClick") +local button = SecureActionButton_OnClick + +function AB:RegisterButton(b, override) + if b.IsProtected and b.IsObjectType and b.GetScript and b:IsObjectType("CheckButton") and b:IsProtected() then + script = b:GetScript("OnClick") + if script == button or override then + b:HookScript("OnEnter", function() self:BindUpdate(b) end) + if script == shapeshift then + b:HookScript("OnEnter", function() self:BindUpdate(b, "SHAPESHIFT") end) + elseif script == pet then + b:HookScript("OnEnter", function() self:BindUpdate(b, "PET") end) + end + end + end +end + +function AB:RegisterMacro(addon) + if addon == "Blizzard_MacroUI" then + for i=1, MAX_ACCOUNT_MACROS do + local b = _G["MacroButton"..i] + b:HookScript("OnEnter", function(b) AB:BindUpdate(b, "MACRO") end) + end + end +end + +function AB:ChangeBindingProfile() + if ( ElvUIBindPopupWindowCheckButton:GetChecked() ) then + LoadBindings(2) + SaveBindings(2) + else + LoadBindings(1) + SaveBindings(1) + end +end + +function AB:LoadKeyBinder() + bind:SetFrameStrata("DIALOG") + bind:SetFrameLevel(99) + bind:EnableMouse(true) + bind:EnableKeyboard(true) + bind:EnableMouseWheel(true) + bind.texture = bind:CreateTexture() + bind.texture:SetAllPoints(bind) + bind.texture:SetTexture(0, 0, 0, .25) + bind:Hide() + + bind:SetScript("OnEnter", function(self) local db = self.button:GetParent().db if db and db.mouseover then AB:Button_OnEnter(self.button) end end) + bind:SetScript("OnLeave", function(self) AB:BindHide() local db = self.button:GetParent().db if db and db.mouseover then AB:Button_OnLeave(self.button) end end) + bind:SetScript("OnKeyUp", function(_, key) self:BindListener(key) end) + bind:SetScript("OnMouseUp", function(_, key) self:BindListener(key) end) + bind:SetScript("OnMouseWheel", function(_, delta) if delta>0 then self:BindListener("MOUSEWHEELUP") else self:BindListener("MOUSEWHEELDOWN") end end) + + local b = EnumerateFrames() + while b do + self:RegisterButton(b) + b = EnumerateFrames(b) + end + + for b, _ in pairs(self["handledButtons"]) do + self:RegisterButton(b, true) + end + + if not IsAddOnLoaded("Blizzard_MacroUI") then + self:SecureHook("LoadAddOn", "RegisterMacro") + else + self:RegisterMacro("Blizzard_MacroUI") + end + + --Special Popup + local f = CreateFrame("Frame", "ElvUIBindPopupWindow", UIParent) + f:SetFrameStrata("DIALOG") + f:SetToplevel(true) + f:EnableMouse(true) + f:SetMovable(true) + f:SetFrameLevel(99) + f:SetClampedToScreen(true) + f:SetWidth(360) + f:SetHeight(130) + E:SetTemplate(f, "Transparent") + f:Hide() + + local header = CreateFrame("Button", nil, f) + E:SetTemplate(header, "Default", true) + header:SetWidth(100) + header:SetHeight(25) + header:SetPoint("CENTER", f, "TOP") + header:SetFrameLevel(header:GetFrameLevel() + 2) + header:EnableMouse(true) + header:RegisterForClicks("AnyUp", "AnyDown") + header:SetScript("OnMouseDown", function() f:StartMoving() end) + header:SetScript("OnMouseUp", function() f:StopMovingOrSizing() end) + + local title = header:CreateFontString("OVERLAY") + E:FontTemplate(title) + title:SetPoint("CENTER", header, "CENTER") + title:SetText("Key Binds") + + local desc = f:CreateFontString("ARTWORK") + desc:SetFontObject("GameFontHighlight") + desc:SetJustifyV("TOP") + desc:SetJustifyH("LEFT") + desc:SetPoint("TOPLEFT", 18, -32) + desc:SetPoint("BOTTOMRIGHT", -18, 48) + desc:SetText(L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the escape key or right click to clear the current actionbutton's keybinding."]) + + local perCharCheck = CreateFrame("CheckButton", f:GetName().."CheckButton", f, "OptionsCheckButtonTemplate") + _G[perCharCheck:GetName() .. "Text"]:SetText(CHARACTER_SPECIFIC_KEYBINDINGS) + + perCharCheck:SetScript("OnShow", function() + perCharCheck:SetChecked(GetCurrentBindingSet() == 2) + end) + + perCharCheck:SetScript("OnClick", function() + if ( AB.bindingsChanged ) then + E:StaticPopup_Show("CONFIRM_LOSE_BINDING_CHANGES") + else + AB:ChangeBindingProfile() + end + end) + + perCharCheck:SetScript("OnEnter", function() + GameTooltip:SetOwner(perCharCheck, "ANCHOR_RIGHT") + GameTooltip:SetText(CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP, nil, nil, nil, nil, 1) + end) + + perCharCheck:SetScript("OnLeave", GameTooltip_Hide) + + local save = CreateFrame("Button", f:GetName().."SaveButton", f, "OptionsButtonTemplate") + _G[save:GetName() .. "Text"]:SetText(L["Save"]) + save:SetWidth(150) + save:SetScript("OnClick", function() + AB:DeactivateBindMode(true) + end) + + local discard = CreateFrame("Button", f:GetName().."DiscardButton", f, "OptionsButtonTemplate") + discard:SetWidth(150) + _G[discard:GetName() .. "Text"]:SetText(L["Discard"]) + + discard:SetScript("OnClick", function() + AB:DeactivateBindMode(false) + end) + + --position buttons + perCharCheck:SetPoint("BOTTOMLEFT", discard, "TOPLEFT", 0, 2) + save:SetPoint("BOTTOMRIGHT", -14, 10) + discard:SetPoint("BOTTOMLEFT", 14, 10) + + local S = E:GetModule("Skins") + S:HandleCheckBox(perCharCheck) + S:HandleButton(save) + S:HandleButton(discard) +end