ElvUI/Modules/ActionBars/ActionBars.lua

1400 lines
46 KiB
Lua

local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local AB = E:GetModule('ActionBars')
local _G = _G
local next, unpack = next, unpack
local ipairs, pairs, select, strmatch = ipairs, pairs, select, strmatch
local format, gsub, strsplit, strfind = format, gsub, strsplit, strfind
local ClearOnBarHighlightMarks = ClearOnBarHighlightMarks
local ClearOverrideBindings = ClearOverrideBindings
local ClearPetActionHighlightMarks = ClearPetActionHighlightMarks
local CreateFrame = CreateFrame
local GetBindingKey = GetBindingKey
local GetOverrideBarIndex = GetOverrideBarIndex
local GetSpellBookItemInfo = GetSpellBookItemInfo
local GetVehicleBarIndex = GetVehicleBarIndex
local hooksecurefunc = hooksecurefunc
local InCombatLockdown = InCombatLockdown
local PetDismiss = PetDismiss
local RegisterStateDriver = RegisterStateDriver
local SecureHandlerSetFrameRef = SecureHandlerSetFrameRef
local SetClampedTextureRotation = SetClampedTextureRotation
local SetCVar = SetCVar
local SetModifiedClick = SetModifiedClick
local SetOverrideBindingClick = SetOverrideBindingClick
local UnitAffectingCombat = UnitAffectingCombat
local UnitCastingInfo = UnitCastingInfo
local UnitChannelInfo = UnitChannelInfo
local UnitExists = UnitExists
local UnitHealth = UnitHealth
local UnitHealthMax = UnitHealthMax
local UnregisterStateDriver = UnregisterStateDriver
local UpdateOnBarHighlightMarksByFlyout = UpdateOnBarHighlightMarksByFlyout
local UpdateOnBarHighlightMarksByPetAction = UpdateOnBarHighlightMarksByPetAction
local UpdateOnBarHighlightMarksBySpell = UpdateOnBarHighlightMarksBySpell
local UpdatePetActionHighlightMarks = UpdatePetActionHighlightMarks
local VehicleExit = VehicleExit
local SPELLS_PER_PAGE = SPELLS_PER_PAGE
local TOOLTIP_UPDATE_TIME = TOOLTIP_UPDATE_TIME
local NUM_ACTIONBAR_BUTTONS = NUM_ACTIONBAR_BUTTONS
local COOLDOWN_TYPE_LOSS_OF_CONTROL = COOLDOWN_TYPE_LOSS_OF_CONTROL
local C_PetBattles_IsInBattle = C_PetBattles.IsInBattle
local LAB = E.Libs.LAB
local LSM = E.Libs.LSM
local Masque = E.Masque
local MasqueGroup = Masque and Masque:Group('ElvUI', 'ActionBars')
local hiddenParent = CreateFrame('Frame', nil, _G.UIParent)
hiddenParent:SetAllPoints()
hiddenParent:Hide()
AB.RegisterCooldown = E.RegisterCooldown
AB.handledBars = {} --List of all bars
AB.handledbuttons = {} --List of all buttons that have been modified.
AB.barDefaults = {
bar1 = {
page = 1,
bindButtons = 'ACTIONBUTTON',
conditions = format('[overridebar] %d; [vehicleui] %d; [possessbar] %d; [shapeshift] 13; [form,noform] 0; [bar:2] 2; [bar:3] 3; [bar:4] 4; [bar:5] 5; [bar:6] 6;', GetOverrideBarIndex(), GetVehicleBarIndex(), GetVehicleBarIndex()),
position = 'BOTTOM,ElvUIParent,BOTTOM,-1,191',
},
bar2 = {
page = 5,
bindButtons = 'MULTIACTIONBAR2BUTTON',
conditions = '',
position = 'BOTTOM,ElvUIParent,BOTTOM,0,4',
},
bar3 = {
page = 6,
bindButtons = 'MULTIACTIONBAR1BUTTON',
conditions = '',
position = 'BOTTOM,ElvUIParent,BOTTOM,-1,139',
},
bar4 = {
page = 4,
bindButtons = 'MULTIACTIONBAR4BUTTON',
conditions = '',
position = 'RIGHT,ElvUIParent,RIGHT,-4,0',
},
bar5 = {
page = 3,
bindButtons = 'MULTIACTIONBAR3BUTTON',
conditions = '',
position = 'BOTTOM,ElvUIParent,BOTTOM,-92,57',
},
bar6 = {
page = 2,
bindButtons = 'ELVUIBAR6BUTTON',
conditions = '',
position = 'BOTTOM,ElvUI_Bar2,TOP,0,2',
},
bar7 = {
page = 7,
bindButtons = 'EXTRABAR7BUTTON',
conditions = '',
position = 'BOTTOM,ElvUI_Bar1,TOP,0,82',
},
bar8 = {
page = 8,
bindButtons = 'EXTRABAR8BUTTON',
conditions = '',
position = 'BOTTOM,ElvUI_Bar1,TOP,0,122',
},
bar9 = {
page = 9,
bindButtons = 'EXTRABAR9BUTTON',
conditions = '',
position = 'BOTTOM,ElvUI_Bar1,TOP,0,162',
},
bar10 = {
page = 10,
bindButtons = 'EXTRABAR10BUTTON',
conditions = '',
position = 'BOTTOM,ElvUI_Bar1,TOP,0,202',
},
}
AB.customExitButton = {
func = function()
if UnitExists('vehicle') then
VehicleExit()
else
PetDismiss()
end
end,
texture = [[Interface\Icons\Spell_Shadow_SacrificialShield]],
tooltip = _G.LEAVE_VEHICLE,
}
function AB:HandleBackdropMultiplier(bar, backdropSpacing, buttonSpacing, widthMult, heightMult, anchorUp, anchorLeft, horizontal, lastShownButton, anchorRowButton)
if not bar.backdrop:IsShown() then return end
local useWidthMult = widthMult > 1
local useHeightMult = heightMult > 1
if useWidthMult or useHeightMult then
local oldWidth, oldHeight = bar.backdrop:GetSize()
if useHeightMult then
local offset = ((oldHeight + buttonSpacing) * (heightMult - 1)) - backdropSpacing
local anchorPoint = anchorUp and 'TOP' or 'BOTTOM'
bar.backdrop:Point(anchorPoint, lastShownButton, anchorPoint, 0, anchorUp and offset or -offset)
end
if useWidthMult then
local offset = ((oldWidth + buttonSpacing) * (widthMult - 1)) - backdropSpacing
bar.backdrop:Point(horizontal, anchorRowButton, horizontal, anchorLeft and -offset or offset, 0)
end
end
end
function AB:HandleBackdropMover(bar, backdropSpacing)
local width, height = bar.backdrop:GetSize()
if not bar.backdrop:IsShown() then
local spacing = backdropSpacing * 2
bar:SetSize(width - spacing, height - spacing)
else
bar:SetSize(width, height)
end
end
function AB:HandleButton(bar, button, index, lastButton, lastColumnButton)
local db = bar.db
local numButtons = db.buttons
local buttonsPerRow = db.buttonsPerRow
local buttonWidth = (db.buttonsize or db.buttonSize)
local buttonHeight = db.keepSizeRatio and (db.buttonsize or db.buttonSize * 1.4) or db.buttonHeight
if bar.LastButton then
if numButtons > bar.LastButton then numButtons = bar.LastButton end
if buttonsPerRow > bar.LastButton then buttonsPerRow = bar.LastButton end
end
if numButtons < buttonsPerRow then buttonsPerRow = numButtons end
local _, horizontal, anchorUp, anchorLeft = AB:GetGrowth(db.point)
local point, relativeFrame, relativePoint, x, y
if index == 1 then
local firstButtonSpacing = db.backdrop and (E.Border + db.backdropSpacing) or E.Spacing
if db.point == 'BOTTOMLEFT' then
x, y = firstButtonSpacing, firstButtonSpacing
elseif db.point == 'TOPRIGHT' then
x, y = -firstButtonSpacing, -firstButtonSpacing
elseif db.point == 'TOPLEFT' then
x, y = firstButtonSpacing, -firstButtonSpacing
else
x, y = -firstButtonSpacing, firstButtonSpacing
end
point, relativeFrame, relativePoint = db.point, bar, db.point
elseif (index - 1) % buttonsPerRow == 0 then
point, relativeFrame, relativePoint, x, y = 'TOP', lastColumnButton, 'BOTTOM', 0, -(db.buttonspacing or db.buttonSpacing)
if anchorUp then
point, relativePoint, y = 'BOTTOM', 'TOP', (db.buttonspacing or db.buttonSpacing)
end
else
point, relativeFrame, relativePoint, x, y = 'LEFT', lastButton, 'RIGHT', (db.buttonspacing or db.buttonSpacing), 0
if anchorLeft then
point, relativePoint, x = 'RIGHT', 'LEFT', -(db.buttonspacing or db.buttonSpacing)
end
end
button:SetParent(bar)
button:ClearAllPoints()
button:SetAttribute('showgrid', 1)
button:EnableMouse(not db.clickThrough)
button:Size(buttonWidth, buttonHeight)
button:Point(point, relativeFrame, relativePoint, x, y)
if index == 1 then
bar.backdrop:Point(point, button, point, anchorLeft and db.backdropSpacing or -db.backdropSpacing, anchorUp and -db.backdropSpacing or db.backdropSpacing)
elseif index == buttonsPerRow then
bar.backdrop:Point(horizontal, button, horizontal, anchorLeft and -db.backdropSpacing or db.backdropSpacing, 0)
end
if button.handleBackdrop then
local anchorPoint = anchorUp and 'TOP' or 'BOTTOM'
bar.backdrop:Point(anchorPoint, button, anchorPoint, 0, anchorUp and db.backdropSpacing or -db.backdropSpacing)
end
end
function AB:TrimIcon(button, masque)
if not button.icon then return end
local left, right, top, bottom = unpack(button.db and button.db.customCoords or E.TexCoords)
local changeRatio = button.db and not button.db.keepSizeRatio
if changeRatio then
local width, height = button:GetSize()
local ratio = width / height
if ratio > 1 then
local trimAmount = (1 - (1 / ratio)) / 2
top = top + trimAmount
bottom = bottom - trimAmount
else
local trimAmount = (1 - ratio) / 2
left = left + trimAmount
right = right - trimAmount
end
end
-- always when masque is off, otherwise only when keepSizeRatio is off
if not masque or changeRatio then
button.icon:SetTexCoord(left, right, top, bottom)
end
end
function AB:GetGrowth(point)
local vertical = (point == 'TOPLEFT' or point == 'TOPRIGHT') and 'DOWN' or 'UP'
local horizontal = (point == 'BOTTOMLEFT' or point == 'TOPLEFT') and 'RIGHT' or 'LEFT'
local anchorUp, anchorLeft = vertical == 'UP', horizontal == 'LEFT'
return vertical, horizontal, anchorUp, anchorLeft
end
function AB:MoverMagic(bar) -- ~Simpy
local _, _, anchorUp, anchorLeft = AB:GetGrowth(bar.db.point)
bar:ClearAllPoints()
if not bar.backdrop:IsShown() then
bar:SetPoint('BOTTOMLEFT', bar.mover)
elseif anchorUp then
bar:SetPoint('BOTTOMLEFT', bar.mover, 'BOTTOMLEFT', anchorLeft and E.Border or -E.Border, -E.Border)
else
bar:SetPoint('TOPLEFT', bar.mover, 'TOPLEFT', anchorLeft and E.Border or -E.Border, E.Border)
end
end
function AB:PositionAndSizeBar(barName)
local db = AB.db[barName]
local bar = AB.handledBars[barName]
local buttonSpacing = db.buttonspacing
local backdropSpacing = db.backdropSpacing
local buttonsPerRow = db.buttonsPerRow
local numButtons = db.buttons
local point = db.point
local visibility = db.visibility
bar.db = db
bar.mouseover = db.mouseover
if numButtons < buttonsPerRow then buttonsPerRow = numButtons end
bar:SetParent(db.inheritGlobalFade and AB.fadeParent or E.UIParent)
bar:EnableMouse(not db.clickThrough)
bar:SetAlpha(bar.mouseover and 0 or db.alpha)
AB:FadeBarBlings(bar, bar.mouseover and 0 or db.alpha)
bar.backdrop:SetShown(db.backdrop)
bar.backdrop:ClearAllPoints()
AB:MoverMagic(bar)
local _, horizontal, anchorUp, anchorLeft = AB:GetGrowth(point)
local button, lastButton, lastColumnButton, anchorRowButton, lastShownButton
for i = 1, NUM_ACTIONBAR_BUTTONS do
lastButton = bar.buttons[i-1]
lastColumnButton = bar.buttons[i-buttonsPerRow]
button = bar.buttons[i]
button.db = db
if i == 1 or i == buttonsPerRow then
anchorRowButton = button
end
if i > numButtons then
button:Hide()
button.handleBackdrop = nil
else
button:Show()
button.handleBackdrop = true -- keep over HandleButton
lastShownButton = button
end
AB:HandleButton(bar, button, i, lastButton, lastColumnButton)
AB:StyleButton(button, nil, MasqueGroup and E.private.actionbar.masque.actionbars)
end
AB:HandleBackdropMultiplier(bar, backdropSpacing, buttonSpacing, db.widthMult, db.heightMult, anchorUp, anchorLeft, horizontal, lastShownButton, anchorRowButton)
AB:HandleBackdropMover(bar, backdropSpacing)
-- paging needs to be updated even if the bar is disabled
local defaults = AB.barDefaults[barName]
local page = AB:GetPage(barName, defaults.page, defaults.conditions)
RegisterStateDriver(bar, 'page', page)
bar:SetAttribute('page', page)
if not bar.initialized then
bar.initialized = true
if defaults.conditions:find('[form,noform]') then
bar:SetAttribute('newCondition', gsub(defaults.conditions, ' %[form,noform%] 0; ', ''))
bar:SetAttribute('hasTempBar', true)
else
bar:SetAttribute('hasTempBar', false)
end
end
if db.enabled or not bar.initialized then
visibility = gsub(visibility, '[\n\r]','')
E:EnableMover(bar.mover:GetName())
RegisterStateDriver(bar, 'visibility', visibility)
bar:Show()
else
E:DisableMover(bar.mover:GetName())
UnregisterStateDriver(bar, 'visibility')
bar:Hide()
end
E:SetMoverSnapOffset('ElvAB_'..bar.id, db.buttonspacing / 2)
if MasqueGroup and E.private.actionbar.masque.actionbars then
MasqueGroup:ReSkin()
-- masque retrims them all so we have to too
for btn in pairs(AB.handledbuttons) do
AB:TrimIcon(btn, true)
end
end
end
function AB:CreateBar(id)
local bar = CreateFrame('Frame', 'ElvUI_Bar'..id, E.UIParent, 'SecureHandlerStateTemplate')
SecureHandlerSetFrameRef(bar, 'MainMenuBarArtFrame', _G.MainMenuBarArtFrame)
local defaults = AB.barDefaults['bar'..id]
local point, anchor, attachTo, x, y = strsplit(',', defaults.position)
bar:Point(point, anchor, attachTo, x, y)
bar:SetFrameStrata('LOW')
bar.id = id
bar:CreateBackdrop(AB.db.transparent and 'Transparent')
bar.backdrop:SetFrameLevel(0)
bar.buttons = {}
bar.bindButtons = defaults.bindButtons
AB:HookScript(bar, 'OnEnter', 'Bar_OnEnter')
AB:HookScript(bar, 'OnLeave', 'Bar_OnLeave')
for i = 1, 12 do
bar.buttons[i] = LAB:CreateButton(i, format(bar:GetName()..'Button%d', i), bar, nil)
bar.buttons[i]:SetState(0, 'action', i)
for k = 1, 14 do
bar.buttons[i]:SetState(k, 'action', (k - 1) * 12 + i)
end
if i == 12 then
bar.buttons[i]:SetState(12, 'custom', AB.customExitButton)
end
if MasqueGroup and E.private.actionbar.masque.actionbars then
bar.buttons[i]:AddToMasque(MasqueGroup)
end
AB:HookScript(bar.buttons[i], 'OnEnter', 'Button_OnEnter')
AB:HookScript(bar.buttons[i], 'OnLeave', 'Button_OnLeave')
end
AB:UpdateButtonConfig(bar, bar.bindButtons)
if defaults.conditions:find('[form]') then
bar:SetAttribute('hasTempBar', true)
else
bar:SetAttribute('hasTempBar', false)
end
bar:SetAttribute('_onstate-page', [[
if HasTempShapeshiftActionBar() and self:GetAttribute('hasTempBar') then
newstate = GetTempShapeshiftBarIndex() or newstate
end
if newstate ~= 0 then
self:SetAttribute('state', newstate)
control:ChildUpdate('state', newstate)
self:GetFrameRef('MainMenuBarArtFrame'):SetAttribute('actionpage', newstate) --Update MainMenuBarArtFrame too. See issue #1848
else
local newCondition = self:GetAttribute('newCondition')
if newCondition then
newstate = SecureCmdOptionParse(newCondition)
self:SetAttribute('state', newstate)
control:ChildUpdate('state', newstate)
self:GetFrameRef('MainMenuBarArtFrame'):SetAttribute('actionpage', newstate)
end
end
]])
AB.handledBars['bar'..id] = bar
E:CreateMover(bar, 'ElvAB_'..id, L["Bar "]..id, nil, nil, nil,'ALL,ACTIONBARS',nil,'actionbar,playerBars,bar'..id)
return bar
end
function AB:PLAYER_REGEN_ENABLED()
if AB.NeedsUpdateButtonSettings then
AB:UpdateButtonSettings()
AB.NeedsUpdateButtonSettings = nil
end
if AB.NeedsUpdateMicroBarVisibility then
AB:UpdateMicroBarVisibility()
AB.NeedsUpdateMicroBarVisibility = nil
end
if AB.NeedsAdjustMaxStanceButtons then
AB:AdjustMaxStanceButtons(AB.NeedsAdjustMaxStanceButtons) --sometimes it holds the event, otherwise true. pass it before we nil it.
AB.NeedsAdjustMaxStanceButtons = nil
end
AB:UnregisterEvent('PLAYER_REGEN_ENABLED')
end
function AB:CreateVehicleLeave()
local db = E.db.actionbar.vehicleExitButton
if not db.enable then return end
local holder = CreateFrame('Frame', 'VehicleLeaveButtonHolder', E.UIParent)
holder:Point('BOTTOM', E.UIParent, 'BOTTOM', 0, 300)
holder:Size(_G.MainMenuBarVehicleLeaveButton:GetSize())
E:CreateMover(holder, 'VehicleLeaveButton', L["VehicleLeaveButton"], nil, nil, nil, 'ALL,ACTIONBARS', nil, 'actionbar,vehicleExitButton')
local Button = _G.MainMenuBarVehicleLeaveButton
Button:ClearAllPoints()
Button:SetParent(_G.UIParent)
Button:Point('CENTER', holder, 'CENTER')
if MasqueGroup and E.private.actionbar.masque.actionbars then
Button:StyleButton(true, true, true)
else
Button:CreateBackdrop(nil, true)
Button:GetNormalTexture():SetTexCoord(0.140625 + .08, 0.859375 - .06, 0.140625 + .08, 0.859375 - .08)
Button:GetPushedTexture():SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
Button:StyleButton(nil, true, true)
end
hooksecurefunc(Button, 'SetPoint', function(_, _, parent)
if parent ~= holder then
Button:ClearAllPoints()
Button:SetParent(_G.UIParent)
Button:Point('CENTER', holder, 'CENTER')
end
end)
hooksecurefunc(Button, 'SetHighlightTexture', function(btn, tex)
if tex ~= btn.hover then
Button:SetHighlightTexture(btn.hover)
end
end)
AB:UpdateVehicleLeave()
end
function AB:UpdateVehicleLeave()
local db = E.db.actionbar.vehicleExitButton
_G.MainMenuBarVehicleLeaveButton:Size(db.size)
_G.MainMenuBarVehicleLeaveButton:SetFrameStrata(db.strata)
_G.MainMenuBarVehicleLeaveButton:SetFrameLevel(db.level)
_G.VehicleLeaveButtonHolder:Size(db.size)
end
function AB:ReassignBindings(event)
if event == 'UPDATE_BINDINGS' then
AB:UpdatePetBindings()
AB:UpdateStanceBindings()
AB:UpdateExtraBindings()
end
AB:UnregisterEvent('PLAYER_REGEN_DISABLED')
if InCombatLockdown() then return end
for _, bar in pairs(AB.handledBars) do
if bar then
ClearOverrideBindings(bar)
for _, button in ipairs(bar.buttons) do
if button.keyBoundTarget then
for k=1, select('#', GetBindingKey(button.keyBoundTarget)) do
local key = select(k, GetBindingKey(button.keyBoundTarget))
if key and key ~= '' then
SetOverrideBindingClick(bar, false, key, button:GetName())
end
end
end
end
end
end
end
function AB:RemoveBindings()
if InCombatLockdown() then return end
for _, bar in pairs(AB.handledBars) do
if bar then
ClearOverrideBindings(bar)
end
end
AB:RegisterEvent('PLAYER_REGEN_DISABLED', 'ReassignBindings')
end
function AB:UpdateBar1Paging()
if AB.db.bar6.enabled then
AB.barDefaults.bar1.conditions = format('[possessbar] %d; [overridebar] %d; [shapeshift] 13; [form,noform] 0; [bar:3] 3; [bar:4] 4; [bar:5] 5; [bar:6] 6;', GetVehicleBarIndex(), GetOverrideBarIndex())
else
AB.barDefaults.bar1.conditions = format('[possessbar] %d; [overridebar] %d; [shapeshift] 13; [form,noform] 0; [bar:2] 2; [bar:3] 3; [bar:4] 4; [bar:5] 5; [bar:6] 6;', GetVehicleBarIndex(), GetOverrideBarIndex())
end
end
function AB:UpdateButtonSettingsForBar(barName)
local bar = AB.handledBars[barName]
AB:UpdateButtonConfig(bar, bar.bindButtons)
end
function AB:UpdateButtonSettings()
if not E.private.actionbar.enable then return end
if InCombatLockdown() then
AB.NeedsUpdateButtonSettings = true
AB:RegisterEvent('PLAYER_REGEN_ENABLED')
return
end
for barName, bar in pairs(AB.handledBars) do
if bar then
AB:UpdateButtonConfig(bar, bar.bindButtons) -- config them first
AB:PositionAndSizeBar(barName) -- db is set here, button style also runs here
end
end
for button in pairs(AB.handledbuttons) do
if button then
AB:StyleFlyout(button)
else
AB.handledbuttons[button] = nil
end
end
-- we can safely toggle these events when we arent using the handle overlay
if AB.db.handleOverlay then
LAB.eventFrame:RegisterEvent('SPELL_ACTIVATION_OVERLAY_GLOW_SHOW')
LAB.eventFrame:RegisterEvent('SPELL_ACTIVATION_OVERLAY_GLOW_HIDE')
else
LAB.eventFrame:UnregisterEvent('SPELL_ACTIVATION_OVERLAY_GLOW_SHOW')
LAB.eventFrame:UnregisterEvent('SPELL_ACTIVATION_OVERLAY_GLOW_HIDE')
end
AB:AdjustMaxStanceButtons()
AB:PositionAndSizeBarPet()
AB:PositionAndSizeBarShapeShift()
AB:UpdatePetBindings()
AB:UpdateStanceBindings() -- call after AdjustMaxStanceButtons
AB:UpdateFlyoutButtons()
end
function AB:GetPage(bar, defaultPage, condition)
local page = AB.db[bar].paging[E.myclass]
if not condition then condition = '' end
if not page then
page = ''
elseif page:match('[\n\r]') then
page = page:gsub('[\n\r]','')
end
if page then
condition = condition..' '..page
end
condition = condition..' '..defaultPage
return condition
end
function AB:StyleButton(button, noBackdrop, useMasque, ignoreNormal)
local name = button:GetName()
local macroText = _G[name..'Name']
local icon = _G[name..'Icon']
local shine = _G[name..'Shine']
local count = _G[name..'Count']
local flash = _G[name..'Flash']
local hotkey = _G[name..'HotKey']
local border = _G[name..'Border']
local normal = _G[name..'NormalTexture']
local normal2 = button:GetNormalTexture()
local db = button:GetParent().db
local color = AB.db.fontColor
local countPosition = AB.db.countTextPosition or 'BOTTOMRIGHT'
local countXOffset = AB.db.countTextXOffset or 0
local countYOffset = AB.db.countTextYOffset or 2
button.noBackdrop = noBackdrop
button.useMasque = useMasque
button.ignoreNormal = ignoreNormal
if normal and not ignoreNormal then normal:SetTexture(); normal:Hide(); normal:SetAlpha(0) end
if normal2 then normal2:SetTexture(); normal2:Hide(); normal2:SetAlpha(0) end
if border and not button.useMasque then border:Kill() end
if count then
count:ClearAllPoints()
if db and db.customCountFont then
count:Point(db.countTextPosition, db.countTextXOffset, db.countTextYOffset)
count:FontTemplate(LSM:Fetch('font', db.countFont), db.countFontSize, db.countFontOutline)
else
count:Point(countPosition, countXOffset, countYOffset)
count:FontTemplate(LSM:Fetch('font', AB.db.font), AB.db.fontSize, AB.db.fontOutline)
end
count:SetTextColor(color.r, color.g, color.b)
end
if macroText then
macroText:ClearAllPoints()
macroText:Point('BOTTOM', 0, 1)
macroText:FontTemplate(LSM:Fetch('font', AB.db.font), AB.db.fontSize, AB.db.fontOutline)
macroText:SetTextColor(color.r, color.g, color.b)
end
if not button.noBackdrop and not button.backdrop and not button.useMasque then
button:CreateBackdrop(AB.db.transparent and 'Transparent', true)
button.backdrop:SetAllPoints()
end
if flash then
if AB.db.flashAnimation then
flash:SetColorTexture(1.0, 0.2, 0.2, 0.45)
flash:ClearAllPoints()
flash:SetOutside(icon, 2, 2)
flash:SetDrawLayer('BACKGROUND', -1)
else
flash:SetTexture()
end
end
if icon and not useMasque then
AB:TrimIcon(button)
icon:SetInside()
end
if shine then
shine:SetAllPoints()
end
if button.SpellHighlightTexture then
button.SpellHighlightTexture:SetColorTexture(1, 1, 0, 0.45)
button.SpellHighlightTexture:SetAllPoints()
end
if AB.db.hotkeytext or AB.db.useRangeColorText then
if db and db.customHotkeyFont then
hotkey:FontTemplate(LSM:Fetch('font', db.hotkeyFont), db.hotkeyFontSize, db.hotkeyFontOutline)
else
hotkey:FontTemplate(LSM:Fetch('font', AB.db.font), AB.db.fontSize, AB.db.fontOutline)
end
if button.config and (button.config.outOfRangeColoring ~= 'hotkey') then
button.HotKey:SetTextColor(color.r, color.g, color.b)
end
end
--Extra Action Button
if button.style then
button.style:SetDrawLayer('BACKGROUND', -7)
end
button.FlyoutUpdateFunc = AB.StyleFlyout
AB:FixKeybindText(button)
if not button.useMasque then
button:StyleButton()
else
button:StyleButton(true, true, true)
end
if not AB.handledbuttons[button] then
button.cooldown.CooldownOverride = 'actionbar'
E:RegisterCooldown(button.cooldown)
AB.handledbuttons[button] = true
end
end
function AB:ColorSwipeTexture(cooldown)
if not cooldown then return end
local color = (cooldown.currentCooldownType == COOLDOWN_TYPE_LOSS_OF_CONTROL and AB.db.colorSwipeLOC) or AB.db.colorSwipeNormal
cooldown:SetSwipeColor(color.r, color.g, color.b, color.a)
end
function AB:FadeBlingTexture(cooldown, alpha)
if not cooldown then return end
cooldown:SetBlingTexture(alpha > 0.5 and 131010 or [[Interface\AddOns\ElvUI\Media\Textures\Blank]]) -- interface/cooldown/star4.blp
end
function AB:FadeBlings(alpha)
if AB.db.hideCooldownBling then return end
for i = 1, AB.fadeParent:GetNumChildren() do
local bar = select(i, AB.fadeParent:GetChildren())
if bar.buttons then
for _, button in ipairs(bar.buttons) do
AB:FadeBlingTexture(button.cooldown, alpha)
end
end
end
end
function AB:FadeBarBlings(bar, alpha)
if AB.db.hideCooldownBling then return end
for _, button in ipairs(bar.buttons) do
AB:FadeBlingTexture(button.cooldown, alpha)
end
end
function AB:Bar_OnEnter(bar)
if bar:GetParent() == AB.fadeParent and not AB.fadeParent.mouseLock then
E:UIFrameFadeIn(AB.fadeParent, 0.2, AB.fadeParent:GetAlpha(), 1)
AB:FadeBlings(1)
end
if bar.mouseover then
E:UIFrameFadeIn(bar, 0.2, bar:GetAlpha(), bar.db.alpha)
AB:FadeBarBlings(bar, bar.db.alpha)
end
end
function AB:Bar_OnLeave(bar)
if bar:GetParent() == AB.fadeParent and not AB.fadeParent.mouseLock then
local a = 1 - AB.db.globalFadeAlpha
E:UIFrameFadeOut(AB.fadeParent, 0.2, AB.fadeParent:GetAlpha(), a)
AB:FadeBlings(a)
end
if bar.mouseover then
E:UIFrameFadeOut(bar, 0.2, bar:GetAlpha(), 0)
AB:FadeBarBlings(bar, 0)
end
end
function AB:Button_OnEnter(button)
local bar = button:GetParent()
if bar:GetParent() == AB.fadeParent and not AB.fadeParent.mouseLock then
E:UIFrameFadeIn(AB.fadeParent, 0.2, AB.fadeParent:GetAlpha(), 1)
AB:FadeBlings(1)
end
if bar.mouseover then
E:UIFrameFadeIn(bar, 0.2, bar:GetAlpha(), bar.db.alpha)
AB:FadeBarBlings(bar, bar.db.alpha)
end
end
function AB:Button_OnLeave(button)
local bar = button:GetParent()
if bar:GetParent() == AB.fadeParent and not AB.fadeParent.mouseLock then
local a = 1 - AB.db.globalFadeAlpha
E:UIFrameFadeOut(AB.fadeParent, 0.2, AB.fadeParent:GetAlpha(), a)
AB:FadeBlings(a)
end
if bar.mouseover then
E:UIFrameFadeOut(bar, 0.2, bar:GetAlpha(), 0)
AB:FadeBarBlings(bar, 0)
end
end
function AB:BlizzardOptionsPanel_OnEvent()
_G.InterfaceOptionsActionBarsPanelBottomRight.Text:SetFormattedText(L["Remove Bar %d Action Page"], 2)
_G.InterfaceOptionsActionBarsPanelBottomLeft.Text:SetFormattedText(L["Remove Bar %d Action Page"], 3)
_G.InterfaceOptionsActionBarsPanelRightTwo.Text:SetFormattedText(L["Remove Bar %d Action Page"], 4)
_G.InterfaceOptionsActionBarsPanelRight.Text:SetFormattedText(L["Remove Bar %d Action Page"], 5)
_G.InterfaceOptionsActionBarsPanelBottomRight:SetScript('OnEnter', nil)
_G.InterfaceOptionsActionBarsPanelBottomLeft:SetScript('OnEnter', nil)
_G.InterfaceOptionsActionBarsPanelRightTwo:SetScript('OnEnter', nil)
_G.InterfaceOptionsActionBarsPanelRight:SetScript('OnEnter', nil)
end
function AB:FadeParent_OnEvent()
if UnitCastingInfo('player') or UnitChannelInfo('player') or UnitExists('target') or UnitExists('focus')
or UnitAffectingCombat('player') or (UnitHealth('player') ~= UnitHealthMax('player')) then
self.mouseLock = true
E:UIFrameFadeIn(self, 0.2, self:GetAlpha(), 1)
AB:FadeBlings(1)
else
self.mouseLock = false
local a = 1 - AB.db.globalFadeAlpha
E:UIFrameFadeOut(self, 0.2, self:GetAlpha(), a)
AB:FadeBlings(a)
end
end
function AB:IconIntroTracker_Toggle()
local IconIntroTracker = _G.IconIntroTracker
if AB.db.addNewSpells then
IconIntroTracker:RegisterEvent('SPELL_PUSHED_TO_ACTIONBAR')
UnregisterStateDriver(IconIntroTracker, 'visibility')
else
IconIntroTracker:UnregisterAllEvents()
RegisterStateDriver(IconIntroTracker, 'visibility', 'hide')
end
end
-- these calls are tainted when accessed by ValidateActionBarTransition
local noops = { 'ClearAllPoints', 'SetPoint', 'SetScale', 'SetShown' }
function AB:SetNoopsi(frame)
for _, func in pairs(noops) do
if frame[func] ~= E.noop then
frame[func] = E.noop
end
end
end
local SpellBookTooltip = CreateFrame('GameTooltip', 'ElvUISpellBookTooltip', E.UIParent, 'GameTooltipTemplate, BackdropTemplate')
function AB:SpellBookTooltipOnUpdate(elapsed)
self.elapsed = (self.elapsed or 0) + elapsed
if self.elapsed < TOOLTIP_UPDATE_TIME then return end
self.elapsed = 0
local owner = self:GetOwner()
if owner then AB.SpellButtonOnEnter(owner) end
end
function AB:SpellButtonOnEnter(_, tt)
-- copied from SpellBookFrame to remove:
--- ActionBarController_UpdateAll, PetActionHighlightMarks, and BarHighlightMarks
-- TT:MODIFIER_STATE_CHANGED uses this function to safely update the spellbook tooltip when the actionbar module is disabled
if not tt then tt = SpellBookTooltip end
if tt:IsForbidden() then return end
tt:SetOwner(self, 'ANCHOR_RIGHT')
local slot = _G.SpellBook_GetSpellBookSlot(self)
local needsUpdate = tt:SetSpellBookItem(slot, _G.SpellBookFrame.bookType)
ClearOnBarHighlightMarks()
ClearPetActionHighlightMarks()
local slotType, actionID = GetSpellBookItemInfo(slot, _G.SpellBookFrame.bookType)
if slotType == 'SPELL' then
UpdateOnBarHighlightMarksBySpell(actionID)
elseif slotType == 'FLYOUT' then
UpdateOnBarHighlightMarksByFlyout(actionID)
elseif slotType == 'PETACTION' then
UpdateOnBarHighlightMarksByPetAction(actionID)
UpdatePetActionHighlightMarks(actionID)
end
local highlight = self.SpellHighlightTexture
if highlight and highlight:IsShown() then
local color = _G.LIGHTBLUE_FONT_COLOR
tt:AddLine(_G.SPELLBOOK_SPELL_NOT_ON_ACTION_BAR, color.r, color.g, color.b)
end
if tt == SpellBookTooltip then
tt:SetScript('OnUpdate', (needsUpdate and AB.SpellBookTooltipOnUpdate) or nil)
end
tt:Show()
end
function AB:UpdateSpellBookTooltip(event)
-- only need to check the shown state when its not called from TT:MODIFIER_STATE_CHANGED which already checks the shown state
local button = (not event or SpellBookTooltip:IsShown()) and SpellBookTooltip:GetOwner()
if button then AB.SpellButtonOnEnter(button) end
end
function AB:SpellButtonOnLeave()
ClearOnBarHighlightMarks()
ClearPetActionHighlightMarks()
SpellBookTooltip:Hide()
SpellBookTooltip:SetScript('OnUpdate', nil)
end
function AB:ButtonEventsRegisterFrame(added)
local frames = _G.ActionBarButtonEventsFrame.frames
for index = #frames, 1, -1 do
local frame = frames[index]
local wasAdded = frame == added
if not added or wasAdded then
if not strmatch(frame:GetName(), 'ExtraActionButton%d') then
_G.ActionBarButtonEventsFrame.frames[index] = nil
end
if wasAdded then
break
end
end
end
end
function AB:DisableBlizzard()
-- dont blindly add to this table, the first 5 get their events registered
for i, name in ipairs({'OverrideActionBar', 'StanceBarFrame', 'PossessBarFrame', 'PetActionBarFrame', 'MultiCastActionBarFrame', 'MainMenuBar', 'MicroButtonAndBagsBar', 'MultiBarBottomLeft', 'MultiBarBottomRight', 'MultiBarLeft', 'MultiBarRight'}) do
_G.UIPARENT_MANAGED_FRAME_POSITIONS[name] = nil
local frame = _G[name]
if i < 6 then frame:UnregisterAllEvents() end
frame:SetParent(hiddenParent)
AB:SetNoopsi(frame)
end
-- let spell book buttons work without tainting by replacing this function
for i = 1, SPELLS_PER_PAGE do
local button = _G['SpellButton'..i]
button:SetScript('OnEnter', AB.SpellButtonOnEnter)
button:SetScript('OnLeave', AB.SpellButtonOnLeave)
end
-- MainMenuBar:ClearAllPoints taint during combat
_G.MainMenuBar.SetPositionForStatusBars = E.noop
-- Spellbook open in combat taint, only happens sometimes
_G.MultiActionBar_HideAllGrids = E.noop
_G.MultiActionBar_ShowAllGrids = E.noop
-- shut down some events for things we dont use
AB:SetNoopsi(_G.MainMenuBarArtFrame)
AB:SetNoopsi(_G.MainMenuBarArtFrameBackground)
_G.MainMenuBarArtFrame:UnregisterAllEvents()
_G.StatusTrackingBarManager:UnregisterAllEvents()
_G.ActionBarButtonEventsFrame:UnregisterAllEvents()
_G.ActionBarButtonEventsFrame:RegisterEvent('ACTIONBAR_SLOT_CHANGED') -- these are needed to let the ExtraActionButton show
_G.ActionBarButtonEventsFrame:RegisterEvent('ACTIONBAR_UPDATE_COOLDOWN') -- needed for ExtraActionBar cooldown
_G.ActionBarActionEventsFrame:UnregisterAllEvents()
_G.ActionBarController:UnregisterAllEvents()
_G.ActionBarController:RegisterEvent('UPDATE_EXTRA_ACTIONBAR') -- this is needed to let the ExtraActionBar show
-- lets only keep ExtraActionButtons in here
hooksecurefunc(_G.ActionBarButtonEventsFrame, 'RegisterFrame', AB.ButtonEventsRegisterFrame)
AB.ButtonEventsRegisterFrame()
-- this would taint along with the same path as the SetNoopers: ValidateActionBarTransition
_G.VerticalMultiBarsContainer:Size(10, 10) -- dummy values so GetTop etc doesnt fail without replacing
AB:SetNoopsi(_G.VerticalMultiBarsContainer)
-- hide some interface options we dont use
_G.InterfaceOptionsActionBarsPanelStackRightBars:SetScale(0.5)
_G.InterfaceOptionsActionBarsPanelStackRightBars:SetAlpha(0)
_G.InterfaceOptionsActionBarsPanelStackRightBarsText:Hide() -- hides the !
_G.InterfaceOptionsActionBarsPanelRightTwoText:SetTextColor(1,1,1) -- no yellow
_G.InterfaceOptionsActionBarsPanelRightTwoText.SetTextColor = E.noop -- i said no yellow
_G.InterfaceOptionsActionBarsPanelAlwaysShowActionBars:SetScale(0.0001)
_G.InterfaceOptionsActionBarsPanelAlwaysShowActionBars:SetAlpha(0)
_G.InterfaceOptionsActionBarsPanelPickupActionKeyDropDownButton:SetScale(0.0001)
_G.InterfaceOptionsActionBarsPanelPickupActionKeyDropDownButton:SetAlpha(0)
_G.InterfaceOptionsActionBarsPanelPickupActionKeyDropDown:SetScale(0.0001)
_G.InterfaceOptionsActionBarsPanelPickupActionKeyDropDown:SetAlpha(0)
_G.InterfaceOptionsActionBarsPanelLockActionBars:SetScale(0.0001)
_G.InterfaceOptionsActionBarsPanelLockActionBars:SetAlpha(0)
AB:IconIntroTracker_Toggle() --Enable/disable functionality to automatically put spells on the actionbar.
AB:SecureHook('BlizzardOptionsPanel_OnEvent')
if _G.PlayerTalentFrame then
_G.PlayerTalentFrame:UnregisterEvent('ACTIVE_TALENT_GROUP_CHANGED')
else
hooksecurefunc('TalentFrame_LoadUI', function()
_G.PlayerTalentFrame:UnregisterEvent('ACTIVE_TALENT_GROUP_CHANGED')
end)
end
end
function AB:ToggleCountDownNumbers(bar, button, cd)
if cd then -- ref: E:CreateCooldownTimer
local b = cd.GetParent and cd:GetParent()
if cd.timer and (b and b.config) then
-- update the new cooldown timer button config with the new setting
b.config.disableCountDownNumbers = not not E:ToggleBlizzardCooldownText(cd, cd.timer, true)
end
elseif button then -- ref: AB:UpdateButtonConfig
if button.cooldown and button.cooldown.timer and (bar and bar.buttonConfig) then
-- button.config will get updated from `button:UpdateConfig` in `AB:UpdateButtonConfig`
bar.buttonConfig.disableCountDownNumbers = not not E:ToggleBlizzardCooldownText(button.cooldown, button.cooldown.timer, true)
end
elseif bar then -- ref: E:UpdateCooldownOverride
if bar.buttons then
for _, btn in ipairs(bar.buttons) do
if btn and btn.config and (btn.cooldown and btn.cooldown.timer) then
-- update the buttons config
btn.config.disableCountDownNumbers = not not E:ToggleBlizzardCooldownText(btn.cooldown, btn.cooldown.timer, true)
end
end
if bar.buttonConfig then
-- we can actually clear this variable because it wont get used when this code runs
bar.buttonConfig.disableCountDownNumbers = nil
end
end
end
end
function AB:UpdateButtonConfig(bar, buttonName)
if InCombatLockdown() then
AB.NeedsUpdateButtonSettings = true
AB:RegisterEvent('PLAYER_REGEN_ENABLED')
return
end
if not bar.buttonConfig then bar.buttonConfig = { hideElements = {}, colors = {} } end
bar.buttonConfig.hideElements.macro = not AB.db.macrotext
bar.buttonConfig.hideElements.hotkey = not AB.db.hotkeytext
bar.buttonConfig.showGrid = AB.db['bar'..bar.id].showGrid
bar.buttonConfig.clickOnDown = AB.db.keyDown
bar.buttonConfig.outOfRangeColoring = (AB.db.useRangeColorText and 'hotkey') or 'button'
bar.buttonConfig.colors.range = E:SetColorTable(bar.buttonConfig.colors.range, AB.db.noRangeColor)
bar.buttonConfig.colors.mana = E:SetColorTable(bar.buttonConfig.colors.mana, AB.db.noPowerColor)
bar.buttonConfig.colors.usable = E:SetColorTable(bar.buttonConfig.colors.usable, AB.db.usableColor)
bar.buttonConfig.colors.notUsable = E:SetColorTable(bar.buttonConfig.colors.notUsable, AB.db.notUsableColor)
bar.buttonConfig.useDrawBling = not AB.db.hideCooldownBling
bar.buttonConfig.useDrawSwipeOnCharges = AB.db.useDrawSwipeOnCharges
bar.buttonConfig.handleOverlay = AB.db.handleOverlay
SetModifiedClick('PICKUPACTION', AB.db.movementModifier)
for i, button in ipairs(bar.buttons) do
AB:ToggleCountDownNumbers(bar, button)
bar.buttonConfig.keyBoundTarget = format(buttonName..'%d', i)
button.keyBoundTarget = bar.buttonConfig.keyBoundTarget
button.postKeybind = AB.FixKeybindText
button:SetAttribute('buttonlock', AB.db.lockActionBars)
button:SetAttribute('checkselfcast', true)
button:SetAttribute('checkfocuscast', true)
if AB.db.rightClickSelfCast then
button:SetAttribute('unit2', 'player')
end
button:UpdateConfig(bar.buttonConfig)
end
end
function AB:FixKeybindText(button)
local hotkey = _G[button:GetName()..'HotKey']
local text = hotkey:GetText()
local db = button:GetParent().db
local hotkeyPosition = db and db.customHotkeyFont and db.hotkeyTextPosition or E.db.actionbar.hotkeyTextPosition or 'TOPRIGHT'
local hotkeyXOffset = db and db.customHotkeyFont and db.hotkeyTextXOffset or E.db.actionbar.hotkeyTextXOffset or 0
local hotkeyYOffset = db and db.customHotkeyFont and db.hotkeyTextYOffset or E.db.actionbar.hotkeyTextYOffset or -3
local justify = 'RIGHT'
if hotkeyPosition == 'TOPLEFT' or hotkeyPosition == 'BOTTOMLEFT' then
justify = 'LEFT'
elseif hotkeyPosition == 'TOP' or hotkeyPosition == 'BOTTOM' then
justify = 'CENTER'
end
if text then
text = gsub(text, 'SHIFT%-', L["KEY_SHIFT"])
text = gsub(text, 'ALT%-', L["KEY_ALT"])
text = gsub(text, 'CTRL%-', L["KEY_CTRL"])
text = gsub(text, 'BUTTON', L["KEY_MOUSEBUTTON"])
text = gsub(text, 'MOUSEWHEELUP', L["KEY_MOUSEWHEELUP"])
text = gsub(text, 'MOUSEWHEELDOWN', L["KEY_MOUSEWHEELDOWN"])
text = gsub(text, 'NUMPAD', L["KEY_NUMPAD"])
text = gsub(text, 'PAGEUP', L["KEY_PAGEUP"])
text = gsub(text, 'PAGEDOWN', L["KEY_PAGEDOWN"])
text = gsub(text, 'SPACE', L["KEY_SPACE"])
text = gsub(text, 'INSERT', L["KEY_INSERT"])
text = gsub(text, 'HOME', L["KEY_HOME"])
text = gsub(text, 'DELETE', L["KEY_DELETE"])
text = gsub(text, 'NMULTIPLY', '*')
text = gsub(text, 'NMINUS', 'N-')
text = gsub(text, 'NPLUS', 'N+')
text = gsub(text, 'NEQUALS', 'N=')
hotkey:SetText(text)
hotkey:SetJustifyH(justify)
end
if not button.useMasque then
hotkey:ClearAllPoints()
hotkey:Point(hotkeyPosition, hotkeyXOffset, hotkeyYOffset)
end
end
local function flyoutButtonAnchor(frame)
local parent = frame:GetParent()
local _, parentAnchorButton = parent:GetPoint()
if not AB.handledbuttons[parentAnchorButton] then return end
return parentAnchorButton:GetParent()
end
function AB:FlyoutButton_OnEnter()
local anchor = flyoutButtonAnchor(self)
if anchor then AB:Bar_OnEnter(anchor) end
AB:BindUpdate(self, 'FLYOUT')
end
function AB:FlyoutButton_OnLeave()
local anchor = flyoutButtonAnchor(self)
if anchor then AB:Bar_OnLeave(anchor) end
end
local function spellFlyoutAnchor(frame)
local _, anchorButton = frame:GetPoint()
if not AB.handledbuttons[anchorButton] then return end
return anchorButton:GetParent()
end
function AB:SpellFlyout_OnEnter()
local anchor = spellFlyoutAnchor(self)
if anchor then AB:Bar_OnEnter(anchor) end
end
function AB:SpellFlyout_OnLeave()
local anchor = spellFlyoutAnchor(self)
if anchor then AB:Bar_OnLeave(anchor) end
end
function AB:UpdateFlyoutButtons()
local btn, i = _G['SpellFlyoutButton1'], 1
while btn do
AB:SetupFlyoutButton(btn)
btn.isFlyout = true
i = i + 1
btn = _G['SpellFlyoutButton'..i]
end
end
function AB:SetupFlyoutButton(button)
if not AB.handledbuttons[button] then
AB:StyleButton(button, nil, (MasqueGroup and E.private.actionbar.masque.actionbars) or nil)
button:HookScript('OnEnter', AB.FlyoutButton_OnEnter)
button:HookScript('OnLeave', AB.FlyoutButton_OnLeave)
end
if not InCombatLockdown() then
button:Size(AB.db.flyoutSize)
end
if MasqueGroup and E.private.actionbar.masque.actionbars then
MasqueGroup:RemoveButton(button) --Remove first to fix issue with backdrops appearing at the wrong flyout menu
MasqueGroup:AddButton(button)
end
end
function AB:StyleFlyout(button)
if not (button.FlyoutBorder and button.FlyoutArrow and button.FlyoutArrow:IsShown() and LAB.buttonRegistry[button]) then return end
button.FlyoutBorder:SetAlpha(0)
button.FlyoutBorderShadow:SetAlpha(0)
_G.SpellFlyoutHorizontalBackground:SetAlpha(0)
_G.SpellFlyoutVerticalBackground:SetAlpha(0)
_G.SpellFlyoutBackgroundEnd:SetAlpha(0)
local actionbar = button:GetParent()
local parent = actionbar and actionbar:GetParent()
local parentName = parent and parent:GetName()
if parentName == 'SpellBookSpellIconsFrame' then
return
elseif actionbar then
-- Change arrow direction depending on what bar the button is on
local arrowDistance = 2
if _G.SpellFlyout:IsShown() and _G.SpellFlyout:GetParent() == button then
arrowDistance = 5
end
local direction = (actionbar.db and actionbar.db.flyoutDirection) or 'AUTOMATIC'
local point = direction == 'AUTOMATIC' and E:GetScreenQuadrant(actionbar)
if point == 'UNKNOWN' then return end
local noCombat = not InCombatLockdown()
if direction == 'DOWN' or (point and strfind(point, 'TOP')) then
button.FlyoutArrow:ClearAllPoints()
button.FlyoutArrow:Point('BOTTOM', button, 'BOTTOM', 0, -arrowDistance)
SetClampedTextureRotation(button.FlyoutArrow, 180)
if noCombat then button:SetAttribute('flyoutDirection', 'DOWN') end
elseif direction == 'LEFT' or point == 'RIGHT' then
button.FlyoutArrow:ClearAllPoints()
button.FlyoutArrow:Point('LEFT', button, 'LEFT', -arrowDistance, 0)
SetClampedTextureRotation(button.FlyoutArrow, 270)
if noCombat then button:SetAttribute('flyoutDirection', 'LEFT') end
elseif direction == 'RIGHT' or point == 'LEFT' then
button.FlyoutArrow:ClearAllPoints()
button.FlyoutArrow:Point('RIGHT', button, 'RIGHT', arrowDistance, 0)
SetClampedTextureRotation(button.FlyoutArrow, 90)
if noCombat then button:SetAttribute('flyoutDirection', 'RIGHT') end
elseif direction == 'UP' or point == 'CENTER' or (point and strfind(point, 'BOTTOM')) then
button.FlyoutArrow:ClearAllPoints()
button.FlyoutArrow:Point('TOP', button, 'TOP', 0, arrowDistance)
SetClampedTextureRotation(button.FlyoutArrow, 0)
if noCombat then button:SetAttribute('flyoutDirection', 'UP') end
end
end
end
function AB:UpdateChargeCooldown(button, duration)
local cd = button and button.chargeCooldown
if not cd then return end
local oldstate = cd.hideText
cd.hideText = (duration and duration > 1.5) or (AB.db.chargeCooldown == false) or nil
if cd.timer and (oldstate ~= cd.hideText) then
E:ToggleBlizzardCooldownText(cd, cd.timer)
E:Cooldown_ForceUpdate(cd.timer)
end
end
function AB:ToggleCooldownOptions()
for button in pairs(LAB.actionButtons) do
if button._state_type == 'action' then
local _, duration = button:GetCooldown()
AB:UpdateChargeCooldown(button, duration)
AB:SetButtonDesaturation(button, duration)
end
end
end
function AB:SetButtonDesaturation(button, duration)
if button.LevelLinkLockIcon:IsShown() then
button.saturationLocked = nil
return
end
if AB.db.desaturateOnCooldown and (duration and duration > 1.5) then
button.icon:SetDesaturated(true)
button.saturationLocked = true
else
button.icon:SetDesaturated(false)
button.saturationLocked = nil
end
end
function AB:LAB_ChargeCreated(_, cd)
cd.CooldownOverride = 'actionbar'
E:RegisterCooldown(cd)
end
function AB:LAB_MouseUp()
if self.config.clickOnDown then
self:GetPushedTexture():SetAlpha(0)
end
end
function AB:LAB_MouseDown()
if self.config.clickOnDown then
self:GetPushedTexture():SetAlpha(1)
end
end
function AB:LAB_ButtonCreated(button)
-- this fixes Key Down getting the pushed texture stuck
button:HookScript('OnMouseUp', AB.LAB_MouseUp)
button:HookScript('OnMouseDown', AB.LAB_MouseDown)
end
function AB:LAB_ButtonUpdate(button)
local color = AB.db.fontColor
button.Count:SetTextColor(color.r, color.g, color.b)
if button.config and (button.config.outOfRangeColoring ~= 'hotkey') then
button.HotKey:SetTextColor(color.r, color.g, color.b)
end
if button.backdrop then
color = (AB.db.equippedItem and button:IsEquipped() and AB.db.equippedItemColor) or E.db.general.bordercolor
button.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
end
end
function AB:LAB_CooldownDone(button)
AB:SetButtonDesaturation(button, 0)
end
function AB:LAB_CooldownUpdate(button, _, duration)
if button._state_type == 'action' then
AB:UpdateChargeCooldown(button, duration)
AB:SetButtonDesaturation(button, duration)
end
if button.cooldown then
AB:ColorSwipeTexture(button.cooldown)
end
end
function AB:PLAYER_ENTERING_WORLD()
AB:AdjustMaxStanceButtons('PLAYER_ENTERING_WORLD')
end
function AB:Initialize()
AB.db = E.db.actionbar
if not E.private.actionbar.enable then return end
AB.Initialized = true
LAB.RegisterCallback(AB, 'OnButtonUpdate', AB.LAB_ButtonUpdate)
LAB.RegisterCallback(AB, 'OnButtonCreated', AB.LAB_ButtonCreated)
LAB.RegisterCallback(AB, 'OnChargeCreated', AB.LAB_ChargeCreated)
LAB.RegisterCallback(AB, 'OnCooldownUpdate', AB.LAB_CooldownUpdate)
LAB.RegisterCallback(AB, 'OnCooldownDone', AB.LAB_CooldownDone)
AB.fadeParent = CreateFrame('Frame', 'Elv_ABFade', _G.UIParent)
AB.fadeParent:SetAlpha(1 - AB.db.globalFadeAlpha)
AB.fadeParent:RegisterEvent('PLAYER_REGEN_DISABLED')
AB.fadeParent:RegisterEvent('PLAYER_REGEN_ENABLED')
AB.fadeParent:RegisterEvent('PLAYER_TARGET_CHANGED')
AB.fadeParent:RegisterUnitEvent('UNIT_SPELLCAST_START', 'player')
AB.fadeParent:RegisterUnitEvent('UNIT_SPELLCAST_STOP', 'player')
AB.fadeParent:RegisterUnitEvent('UNIT_SPELLCAST_CHANNEL_START', 'player')
AB.fadeParent:RegisterUnitEvent('UNIT_SPELLCAST_CHANNEL_STOP', 'player')
AB.fadeParent:RegisterUnitEvent('UNIT_HEALTH', 'player')
AB.fadeParent:RegisterEvent('PLAYER_FOCUS_CHANGED')
AB.fadeParent:SetScript('OnEvent', AB.FadeParent_OnEvent)
AB:DisableBlizzard()
AB:SetupExtraButton()
AB:SetupMicroBar()
AB:UpdateBar1Paging()
for i = 1, 10 do
AB:CreateBar(i)
end
AB:CreateBarPet()
AB:CreateBarShapeShift()
AB:CreateVehicleLeave()
AB:UpdateButtonSettings()
AB:UpdatePetCooldownSettings()
AB:ToggleCooldownOptions()
AB:LoadKeyBinder()
AB:RegisterEvent('PLAYER_ENTERING_WORLD')
AB:RegisterEvent('UPDATE_BINDINGS', 'ReassignBindings')
AB:RegisterEvent('PET_BATTLE_CLOSE', 'ReassignBindings')
AB:RegisterEvent('PET_BATTLE_OPENING_DONE', 'RemoveBindings')
AB:RegisterEvent('SPELL_UPDATE_COOLDOWN', 'UpdateSpellBookTooltip')
if _G.KeyBindingFrame then
AB:SwapKeybindButton()
else
AB:RegisterEvent('ADDON_LOADED', 'SwapKeybindButton')
end
if C_PetBattles_IsInBattle() then
AB:RemoveBindings()
else
AB:ReassignBindings()
end
-- We handle actionbar lock for regular bars, but the lock on PetBar needs to be handled by WoW so make some necessary updates
SetCVar('lockActionBars', (AB.db.lockActionBars == true and 1 or 0))
_G.LOCK_ACTIONBAR = (AB.db.lockActionBars == true and '1' or '0') -- Keep an eye on this, in case it taints
hooksecurefunc(_G.SpellFlyout, 'Show', AB.UpdateFlyoutButtons)
_G.SpellFlyout:HookScript('OnEnter', AB.SpellFlyout_OnEnter)
_G.SpellFlyout:HookScript('OnLeave', AB.SpellFlyout_OnLeave)
end
E:RegisterModule(AB:GetName())