ElvUI/Modules/ActionBars/Bind.lua

398 lines
13 KiB
Lua

local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local AB = E:GetModule('ActionBars')
local Skins = E:GetModule('Skins')
local _G = _G
local tonumber, format = tonumber, format
local select, pairs, floor = select, pairs, floor
local CreateFrame = CreateFrame
local HideUIPanel = HideUIPanel
local GameTooltip_Hide = GameTooltip_Hide
local GameTooltip_ShowCompareItem = GameTooltip_ShowCompareItem
local GetBindingKey = GetBindingKey
local GetCurrentBindingSet = GetCurrentBindingSet
local GetMacroInfo = GetMacroInfo
local GetSpellBookItemName = GetSpellBookItemName
local InCombatLockdown = InCombatLockdown
local IsAddOnLoaded = IsAddOnLoaded
local IsAltKeyDown, IsControlKeyDown = IsAltKeyDown, IsControlKeyDown
local IsShiftKeyDown, IsModifiedClick = IsShiftKeyDown, IsModifiedClick
local LoadBindings, SaveBindings = LoadBindings, SaveBindings
local SecureActionButton_OnClick = SecureActionButton_OnClick
local SetBinding = SetBinding
local GameTooltip = GameTooltip
local SpellBook_GetSpellBookSlot = SpellBook_GetSpellBookSlot
local MAX_ACCOUNT_MACROS = MAX_ACCOUNT_MACROS
local CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP = CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP
local CHARACTER_SPECIFIC_KEYBINDINGS = CHARACTER_SPECIFIC_KEYBINDINGS
-- GLOBALS: ElvUIBindPopupWindow, ElvUIBindPopupWindowCheckButton
local bind = CreateFrame('Frame', 'ElvUI_KeyBinder', E.UIParent)
function AB:ActivateBindMode()
if InCombatLockdown() then return end
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()
if not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:Hide()
end
end
function AB:BindListener(key)
AB.bindingsChanged = true
if key == 'ESCAPE' then
if bind.button.bindings then
for i = 1, #bind.button.bindings do
SetBinding(bind.button.bindings[i])
end
end
E:Print(format(L["All keybindings cleared for |cff00ff00%s|r."], bind.name))
self:BindUpdate(bind.button, bind.spellmacro)
if bind.spellmacro~='MACRO' and not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:Hide()
end
return
end
--Check if this button can open a flyout menu
local isFlyout = (bind.button.FlyoutArrow and bind.button.FlyoutArrow:IsShown())
if key == 'LSHIFT' or key == 'RSHIFT' or key == 'LCTRL' or key == 'RCTRL'
or key == 'LALT' or key == 'RALT' or key == 'UNKNOWN' then return end
--Redirect LeftButton click to open flyout
if key == 'LeftButton' and isFlyout then
SecureActionButton_OnClick(bind.button)
end
if key == 'MiddleButton' then key = 'BUTTON3' end
if key:find('Button%d') then key = key:upper() end
local allowBinding = not isFlyout or (key ~= 'LeftButton') --Don't attempt to bind left mouse button for flyout buttons
if allowBinding and bind.button.bindstring then
local alt = IsAltKeyDown() and 'ALT-' or ''
local ctrl = IsControlKeyDown() and 'CTRL-' or ''
local shift = IsShiftKeyDown() and 'SHIFT-' or ''
SetBinding(alt..ctrl..shift..key, bind.button.bindstring)
E:Print(alt..ctrl..shift..key..L[" |cff00ff00bound to |r"]..bind.name..'.')
end
self:BindUpdate(bind.button, bind.spellmacro)
if bind.spellmacro~='MACRO' and bind.spellmacro~='FLYOUT' and not _G.GameTooltip:IsForbidden() then
_G.GameTooltip:Hide()
end
end
function AB:DisplayBindsTooltip()
GameTooltip:SetOwner(bind, 'ANCHOR_TOP')
GameTooltip:Point('BOTTOM', bind, 'TOP', 0, 1)
GameTooltip:AddLine(bind.name, 1, 1, 1)
end
function AB:DisplayBindings()
if #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, #bind.button.bindings do
GameTooltip:AddDoubleLine(L["Binding"]..i, bind.button.bindings[i], 1, 1, 1)
end
end
end
function AB:BindTooltip(triggerTooltip)
if GameTooltip:IsForbidden() then return end
if triggerTooltip then -- this is needed for some tooltip magic, also it helps show a tooltip when a spell isnt there
AB:DisplayBindsTooltip()
GameTooltip:AddLine(L["Trigger"])
GameTooltip:Show()
GameTooltip:SetScript('OnHide', function(tt)
AB:DisplayBindsTooltip()
AB:DisplayBindings()
tt:Show()
tt:SetScript('OnHide', nil)
end)
else
AB:DisplayBindsTooltip()
AB:DisplayBindings()
GameTooltip:Show()
end
end
function AB:BindUpdate(button, spellmacro)
if not bind.active or InCombatLockdown() then return end
local triggerTooltip = false
bind.button = button
bind.spellmacro = spellmacro
bind.name = nil
bind:ClearAllPoints()
bind:SetAllPoints(button)
bind:Show()
_G.ShoppingTooltip1:Hide()
button.bindstring = nil -- keep this clean
if spellmacro == 'FLYOUT' then
bind.name = button.spellName
button.bindstring = spellmacro..' '..bind.name
elseif spellmacro == 'SPELL' then
button.id = SpellBook_GetSpellBookSlot(button)
bind.name = GetSpellBookItemName(button.id, _G.SpellBookFrame.bookType)
button.bindstring = spellmacro..' '..bind.name
elseif spellmacro == 'MACRO' then
button.id = button:GetID()
-- no clue what this is, leaving it alone tho lol
if floor(.5+select(2,_G.MacroFrameTab1Text:GetTextColor())*10)/10==.8 then
button.id = button.id + MAX_ACCOUNT_MACROS
end
bind.name = GetMacroInfo(button.id)
button.bindstring = spellmacro..' '..bind.name
elseif spellmacro == 'MICRO' then
bind.name = button.tooltipText
button.bindstring = button.commandName
triggerTooltip = true
elseif spellmacro == 'BAG' then
if button.itemID then
bind.name = button.name
button.bindstring = 'ITEM item:'..button.itemID
triggerTooltip = true
end
else
bind.name = button:GetName()
if not bind.name then return end
triggerTooltip = true
if button.keyBoundTarget then
button.bindstring = button.keyBoundTarget
elseif button.commandName then
button.bindstring = button.commandName
elseif button.action then
local action = tonumber(button.action)
local modact = 1+(action-1)%12
if bind.name == 'ExtraActionButton1' then
button.bindstring = 'EXTRAACTIONBUTTON1'
elseif action < 25 or action > 72 then
button.bindstring = 'ACTIONBUTTON'..modact
elseif action < 73 and action > 60 then
button.bindstring = 'MULTIACTIONBAR1BUTTON'..modact
elseif action < 61 and action > 48 then
button.bindstring = 'MULTIACTIONBAR2BUTTON'..modact
elseif action < 49 and action > 36 then
button.bindstring = 'MULTIACTIONBAR4BUTTON'..modact
elseif action < 37 and action > 24 then
button.bindstring = 'MULTIACTIONBAR3BUTTON'..modact
end
end
end
if button.bindstring then
button.bindings = {GetBindingKey(button.bindstring)}
AB:BindTooltip(triggerTooltip)
end
end
local elapsed = 0
function AB:Tooltip_OnUpdate(tooltip, e)
if tooltip:IsForbidden() then return end
elapsed = elapsed + e
if elapsed < .2 then return else elapsed = 0 end
local compareItems = IsModifiedClick('COMPAREITEMS')
if not tooltip.comparing and compareItems and tooltip:GetItem() then
GameTooltip_ShowCompareItem(tooltip)
tooltip.comparing = true
elseif tooltip.comparing and not compareItems then
for _, frame in pairs(tooltip.shoppingTooltips) do frame:Hide() end
tooltip.comparing = false
end
end
function AB:RegisterMacro(addon)
if addon == 'Blizzard_MacroUI' then
for i=1, MAX_ACCOUNT_MACROS do
_G['MacroButton'..i]:HookScript('OnEnter', function(btn) AB:BindUpdate(btn, 'MACRO') end)
end
end
end
function AB:ChangeBindingProfile()
if ElvUIBindPopupWindowCheckButton:GetChecked() then
LoadBindings(2)
SaveBindings(2)
else
LoadBindings(1)
SaveBindings(1)
end
end
local function keybindButtonClick()
if InCombatLockdown() then return end
AB:ActivateBindMode()
HideUIPanel(_G.KeyBindingFrame)
HideUIPanel(_G.GameMenuFrame)
end
function AB:SwapKeybindButton(event, addon)
if event and addon ~= 'Blizzard_BindingUI' then return end
local parent = _G.KeyBindingFrame
parent.quickKeybindButton:Hide()
local frame = CreateFrame('Button', 'ElvUI_KeybindButton', parent, 'OptionsButtonTemplate, BackdropTemplate')
frame:Width(150)
frame:Point('TOPLEFT', parent.quickKeybindButton)
frame:SetScript('OnClick', keybindButtonClick)
frame:SetText('ElvUI Keybind')
Skins:HandleButton(frame)
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:SetColorTexture(0, 0, 0, .25)
bind:Hide()
self:SecureHookScript(_G.GameTooltip, 'OnUpdate', 'Tooltip_OnUpdate')
bind:SetScript('OnEnter', function(b) local db = b.button:GetParent().db if db and db.mouseover then AB:Button_OnEnter(b.button) end end)
bind:SetScript('OnLeave', function(b) AB:BindHide() local db = b.button:GetParent().db if db and db.mouseover then AB:Button_OnLeave(b.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)
for i = 1, 12 do
local b = _G['SpellButton'..i]
b:HookScript('OnEnter', function(s) AB:BindUpdate(s, 'SPELL') end)
end
local function buttonOnEnter(b) AB:BindUpdate(b) end
for b in pairs(self.handledbuttons) do
if b:IsProtected() and b:IsObjectType('CheckButton') and not b.isFlyout then
b:HookScript('OnEnter', buttonOnEnter)
end
end
if not IsAddOnLoaded('Blizzard_MacroUI') then
self:SecureHook('LoadAddOn', 'RegisterMacro')
else
self:RegisterMacro('Blizzard_MacroUI')
end
--Special Popup
local Popup = CreateFrame('Frame', 'ElvUIBindPopupWindow', _G.UIParent, 'BackdropTemplate')
Popup:SetFrameStrata('DIALOG')
Popup:EnableMouse(true)
Popup:SetMovable(true)
Popup:SetFrameLevel(99)
Popup:SetClampedToScreen(true)
Popup:Size(360, 130)
Popup:SetTemplate('Transparent')
Popup:RegisterForDrag('AnyUp', 'AnyDown')
Popup:SetScript('OnMouseDown', Popup.StartMoving)
Popup:SetScript('OnMouseUp', Popup.StopMovingOrSizing)
Popup:Hide()
Popup.header = CreateFrame('Button', nil, Popup, 'OptionsButtonTemplate, BackdropTemplate')
Popup.header:Size(100, 25)
Popup.header:Point('CENTER', Popup, 'TOP')
Popup.header:RegisterForClicks('AnyUp', 'AnyDown')
Popup.header:SetScript('OnMouseDown', function() Popup:StartMoving() end)
Popup.header:SetScript('OnMouseUp', function() Popup:StopMovingOrSizing() end)
Popup.header:SetText('Key Binds')
Popup.desc = Popup:CreateFontString(nil, 'ARTWORK')
Popup.desc:SetFontObject('GameFontHighlight')
Popup.desc:SetJustifyV('TOP')
Popup.desc:SetJustifyH('LEFT')
Popup.desc:Point('TOPLEFT', 18, -32)
Popup.desc:Point('BOTTOMRIGHT', -18, 48)
Popup.desc:SetText(L["Hover your mouse over any |cFF1784d1action|r, |cFF1784d1micro|r, |cFF1784d1macro|r, or |cFF1784d1spellbook|r button to bind it. This also works for items in your |cFF1784d1bag|r. Press the |cfd9b9b9bESC|r key to |cfd9b9b9bclear|r the current bindings."])
Popup.save = CreateFrame('Button', Popup:GetName()..'SaveButton', Popup, 'OptionsButtonTemplate, BackdropTemplate')
Popup.save:SetText(L["Save"])
Popup.save:Width(150)
Popup.save:SetScript('OnClick', function() AB:DeactivateBindMode(true) end)
Popup.discard = CreateFrame('Button', Popup:GetName()..'DiscardButton', Popup, 'OptionsButtonTemplate, BackdropTemplate')
Popup.discard:Width(150)
Popup.discard:SetText(L["Discard"])
Popup.discard:SetScript('OnClick', function() AB:DeactivateBindMode(false) end)
Popup.perCharCheck = CreateFrame('CheckButton', Popup:GetName()..'CheckButton', Popup, 'OptionsCheckButtonTemplate, BackdropTemplate')
_G[Popup.perCharCheck:GetName()..'Text']:SetText(CHARACTER_SPECIFIC_KEYBINDINGS)
Popup.perCharCheck:SetScript('OnLeave', GameTooltip_Hide)
Popup.perCharCheck:SetScript('OnShow', function(checkBtn) checkBtn:SetChecked(GetCurrentBindingSet() == 2) end)
Popup.perCharCheck:SetScript('OnClick', function()
if AB.bindingsChanged then
E:StaticPopup_Show('CONFIRM_LOSE_BINDING_CHANGES')
else
AB:ChangeBindingProfile()
end
end)
Popup.perCharCheck:SetScript('OnEnter', function(checkBtn)
_G.GameTooltip:SetOwner(checkBtn, 'ANCHOR_RIGHT')
_G.GameTooltip:SetText(CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP, nil, nil, nil, nil, 1)
end)
--position buttons
Popup.perCharCheck:Point('BOTTOMLEFT', Popup.discard, 'TOPLEFT', 0, 2)
Popup.save:Point('BOTTOMRIGHT', -14, 10)
Popup.discard:Point('BOTTOMLEFT', 14, 10)
Skins:HandleCheckBox(Popup.perCharCheck)
Skins:HandleButton(Popup.discard)
Skins:HandleButton(Popup.header)
Skins:HandleButton(Popup.save)
Popup.discard.backdrop:SetFrameLevel(Popup.discard:GetFrameLevel())
Popup.header.backdrop:SetFrameLevel(Popup.header:GetFrameLevel())
Popup.save.backdrop:SetFrameLevel(Popup.save:GetFrameLevel())
end