Files
pfUI/modules/actionbar.lua
T
2025-02-04 18:09:50 +01:00

1693 lines
52 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
pfUI:RegisterModule("actionbar", "vanilla:tbc", function ()
local _, class = UnitClass("player")
local color = RAID_CLASS_COLORS[class]
local cr, cg, cb = color.r , color.g, color.b
local er, eg, eb, ea = GetStringColor(pfUI_config.appearance.border.color)
local backdrop_highlight = { edgeFile = pfUI.media["img:glow"], edgeSize = 8 }
local showgrid = 0
local showgrid_pet = 0
local rawborder, border = GetBorderSize("actionbars")
local bpad = rawborder > 1 and border - GetPerfectPixel() or GetPerfectPixel()
local eventcache = { } -- contains a list of events that shall be processed later -> [event] = true
local updatecache = { } -- contains a list of buttons slots that shall be refreshed later -> [slot] = true
local buttoncache = { } -- contains a list of all buttons ever created -> [slot] = frame
local petvisibility = "[pet] show; hide"
-- try to assume based on the current mouse positions if a button drag
-- should happen even if action-on-key-down is used. By that replace the
-- cast events by reverting the active buttons to the old mouse-up state.
local drag_await
local drag_active
local function AssumeButtonDrag()
-- skip during combat
if InCombatLockdown and InCombatLockdown() then return end
-- skip if keydown press is not enabled
if C.bars.keydown ~= "1" then return end
-- skip if always shift-drag is not enabled
if C.bars.shiftdrag ~= "1" then return end
if drag_await and not drag_active and IsShiftKeyDown() then
drag_active = true
-- set all buttons to regular on release clicks
for id, button in pairs(buttoncache) do
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
end
elseif drag_active and not IsShiftKeyDown() then
drag_active = nil
-- set all buttons back to their defaults
for id, button in pairs(buttoncache) do
button:RegisterForClicks("LeftButtonDown", "RightButtonDown")
end
end
end
-- hide blizzard bars
local function kill(f, killshow)
if f.Show and killshow then f.Show = function() return end end
if f.UnregisterAllEvents then f:UnregisterAllEvents() end
if f.Hide then f:Hide() end
end
-- also abbreviate mouse buttons
local OrigGetBindingText = GetBindingText
local function GetBindingText(msg, mod, abbrev)
local txt = OrigGetBindingText(msg, mod, abbrev)
if abbrev then
txt = string.gsub(txt, _G[string.format("%s%s", mod, "BUTTON3")], "MB3")
txt = string.gsub(txt, _G[string.format("%s%s", mod, "BUTTON4")], "MB4")
txt = string.gsub(txt, _G[string.format("%s%s", mod, "BUTTON5")], "MB5")
txt = string.gsub(txt, _G[string.format("%s%s", mod, "MOUSEWHEELDOWN")], "MWD")
txt = string.gsub(txt, _G[string.format("%s%s", mod, "MOUSEWHEELUP")], "MWU")
end
return txt
end
kill(MainMenuBar)
local blizzard_elements = { MultiBarBottomLeft,
MultiBarBottomRight, MultiBarLeft, MultiBarRight }
for _, f in pairs(blizzard_elements) do
kill(f, true)
end
-- enable all possible actionbar pages
SetActionBarToggles(0, 0, 0, 0)
_G.SHOW_MULTI_ACTIONBAR_1 = nil
_G.SHOW_MULTI_ACTIONBAR_2 = nil
_G.SHOW_MULTI_ACTIONBAR_3 = nil
_G.SHOW_MULTI_ACTIONBAR_4 = nil
-- events that provide special updater functions
local special_events = {
["ACTIONBAR_UPDATE_COOLDOWN"] = true,
["ACTIONBAR_UPDATE_USABLE"] = true,
["ACTIONBAR_UPDATE_STATE"] = true,
}
-- events that are shared across all buttons
local global_events = {
-- slot/button updates
["PLAYER_ENTERING_WORLD"] = true,
["ACTIONBAR_SLOT_CHANGED"] = true,
["UPDATE_BINDINGS"] = true,
["ACTIONBAR_PAGE_CHANGED"] = true,
["UPDATE_BONUS_ACTIONBAR"] = true,
["CRAFT_SHOW"] = true,
["CRAFT_CLOSE"] = true,
["TRADE_SKILL_SHOW"] = true,
["TRADE_SKILL_CLOSE"] = true,
["PLAYER_ENTER_COMBAT"] = true,
["PLAYER_LEAVE_COMBAT"] = true,
-- cooldown updates
["UNIT_INVENTORY_CHANGED"] = true,
-- auto repeat action
["START_AUTOREPEAT_SPELL"] = true,
["STOP_AUTOREPEAT_SPELL"] = true,
}
-- events that are used for the aura/shapeshift bar
local aura_events = {
["UPDATE_SHAPESHIFT_FORMS"] = true,
["PLAYER_AURAS_CHANGED"] = true,
}
-- events that are used for the pet bar
local pet_events = {
["PLAYER_CONTROL_LOST"] = true,
["PLAYER_CONTROL_GAINED"] = true,
["PLAYER_FARSIGHT_FOCUS_CHANGED"] = true,
["UNIT_PET"] = true,
["PET_BAR_UPDATE"] = true,
["PET_BAR_UPDATE_COOLDOWN"] = true,
}
local buttontypes = {
-- blizzard keybinds
[3] = "MULTIACTIONBAR3BUTTON",
[4] = "MULTIACTIONBAR4BUTTON",
[5] = "MULTIACTIONBAR2BUTTON",
[6] = "MULTIACTIONBAR1BUTTON",
[11] = "SHAPESHIFTBUTTON",
[12] = "BONUSACTIONBUTTON",
-- additional keybinds
[2] = "PFPAGING",
[7] = "PFSTANCEONE",
[8] = "PFSTANCETWO",
[9] = "PFSTANCETHREE",
[10] = "PFSTANCEFOUR",
}
local blizzbarmapping = {
["MultiBarRight"] = 3,
["MultiBarLeft"] = 4,
["MultiBarBottomRight"] = 5,
["MultiBarBottomLeft"] = 6,
["ShapeShiftBar"] = 11,
["BonusActionBar"] = 12,
}
local barnames = {
[1] = "Main",
[2] = "Paging",
[3] = "Right",
[4] = "Vertical",
[5] = "Left",
[6] = "Top",
[7] = "StanceBar1",
[8] = "StanceBar2",
[9] = "StanceBar3",
[10] = "StanceBar4",
[11] = "Stances",
[12] = "Pet",
}
local button_animations = {
["none"] = function()
this.active = nil
this:Hide()
end,
["zoomfade"] = function()
if this.active == 0 then
-- init animation
this:SetWidth(this.parent:GetWidth())
this:SetHeight(this.parent:GetHeight())
this:SetScale(this.parent:GetScale())
this.tex:SetTexture(this.parent.icon:GetTexture())
this.tex:SetVertexColor(this.parent.icon:GetVertexColor())
this:SetAlpha(1)
this.active = 1
return
elseif this.active == 1 then
-- run animation
local fade = 30/GetFramerate()*0.05
this:SetAlpha(this:GetAlpha() - fade)
this:SetScale(this:GetScale() + fade)
if this:GetAlpha() > 0 then return end
end
-- stop animation
this.active = nil
this:Hide()
end,
["shrinkreturn"] = function()
if this.active == 0 then
-- init animation
this:SetWidth(this.parent:GetWidth())
this:SetHeight(this.parent:GetHeight())
this:SetScale(this.parent:GetScale())
this.tex:SetTexture(this.parent.icon:GetTexture())
this.tex:SetVertexColor(this.parent.icon:GetVertexColor())
this:SetAlpha(1)
this.parent.icon:Hide()
this.active = 1
this.time = 0
return
elseif this.active == 1 then
-- run animation
this.time = this.time + 30/GetFramerate()*0.1
local fade = 1 -math.exp(-this.time)*math.sin(this.time*math.pi)
this:SetAlpha(fade)
this:SetScale(fade)
if this.time < 1 then return end
end
-- stop animation
this.active = nil
this:Hide()
this.parent.icon:Show()
end,
["elasticzoom"] = function()
if this.active == 0 then
-- init animation
this:SetWidth(this.parent:GetWidth())
this:SetHeight(this.parent:GetHeight())
this:SetScale(this.parent:GetScale())
this.tex:SetTexture(this.parent.icon:GetTexture())
this.tex:SetVertexColor(this.parent.icon:GetVertexColor())
this:SetAlpha(1)
this.parent.icon:Hide()
this.active = 1
this.time = 0
return
elseif this.active == 1 then
-- run animation
this.time = this.time + 30/GetFramerate()*0.03
local fade = 1 -math.exp(-this.time*6)*math.sin(this.time*4*math.pi)
this:SetAlpha(fade)
this:SetScale(fade)
if this.time < 1 then return end
end
-- stop animation
this.active = nil
this:Hide()
this.parent.icon:Show()
end,
["wobblezoom"] = function()
if this.active == 0 then
-- init animation
this:SetWidth(this.parent:GetWidth())
this:SetHeight(this.parent:GetHeight())
this:SetScale(this.parent:GetScale())
this.tex:SetTexture(this.parent.icon:GetTexture())
this.tex:SetVertexColor(this.parent.icon:GetVertexColor())
this:SetAlpha(1)
this.parent.icon:Hide()
this.active = 1
this.time = 0
return
elseif this.active == 1 then
-- run animation
this.time = this.time + 30/GetFramerate()*0.02
local fade = 1 -math.exp(-this.time*6)*math.sin(this.time*10*math.pi)
this:SetAlpha(fade)
this:SetScale(fade)
if this.time < 1 then return end
end
-- stop animation
this.active = nil
this:Hide()
this.parent.icon:Show()
end,
}
local function GetActiveBar()
if CURRENT_ACTIONBAR_PAGE == 1 and GetBonusBarOffset() ~= 0 then
return NUM_ACTIONBAR_PAGES + GetBonusBarOffset()
else
return CURRENT_ACTIONBAR_PAGE
end
end
local function ButtonDrag(self)
-- skip during combat
if InCombatLockdown and InCombatLockdown() then return end
local self = self or this
if _G.LOCK_ACTIONBAR == "1" and not (pfUI_config.bars.shiftdrag == "1" and IsShiftKeyDown()) then return end
if self.bar == 12 then
PickupPetAction(self.id)
else
PickupAction(self.id)
end
end
local function ButtonDragStop(self)
-- skip during combat
if InCombatLockdown and InCombatLockdown() then return end
local self = self or this
if MacroFrame_SaveMacro then
MacroFrame_SaveMacro()
end
if self.bar == 12 then
PickupPetAction(self.id)
else
PlaceAction(self.id)
end
end
local mouse
local function ButtonAnimate(self)
local self = self or this
mouse = arg1 and not keystate
-- trigger action animation
if ( pfUI_config.bars.keydown == "1" and keystate == "down" ) or (pfUI_config.bars.keydown == "0" and keystate == "up" ) or self.bar == 11 or mouse then
if C.bars.animmode == "keypress" and ( self:GetAlpha() > .1 or C.bars.animalways == "1" ) then
self.animation.active = 0
self.animation:Show()
end
end
-- handle button highlight
if keystate == "down" then
self.highlight:Show()
elseif not MouseIsOver(self) then
self.highlight:Hide()
end
end
local function ButtonClick(self)
local self = self or this
local grid = self.bar == 12 and showgrid_pet or showgrid
local mouse = arg1 and not keystate
local keystate = keystate
local slfcast = C.bars.altself == "1" and IsAltKeyDown() and true or self.slfcast
slfcast = C.bars.rightself == "1" and arg1 and arg1 == "RightButton" and true or slfcast
self.slfcast = nil
if ( pfUI_config.bars.keydown == "1" and keystate == "down" and not drag_active ) or (pfUI_config.bars.keydown == "0" and keystate == "up" or drag_active ) or self.bar == 11 or mouse then
if self.bar == 11 then
CastShapeshiftForm(self.id)
elseif grid == 1 then
if self.bar == 12 then
PickupPetAction(self.id)
else
PickupAction(self.id)
end
elseif self.bar == 12 then
if arg1 == "LeftButton" then
if IsPetAttackActive(self.id) then
PetStopAttack()
else
CastPetAction(self.id)
end
else
TogglePetAutocast(self.id)
end
else
if MacroFrame_SaveMacro then
MacroFrame_SaveMacro()
end
UseAction(self.id, nil, slfcast)
end
end
end
local function ButtonMacroScan(self)
if self.bar > 10 then return end
if not self.scanmacro then return end
if pfUI.bars.skip_macro then return end
local macro = GetActionText(self.id)
self.spellslot = nil
self.booktype = nil
if macro then
local name, body, _
for slot = 1, 36 do
name, _, body = GetMacroInfo(slot)
if name == macro then break end
end
if name and body then
local match
for line in gfind(body, "[^%\n]+") do
_, _, match = string.find(line, '^#showtooltip (.+)')
-- skip any further manual macro scanning on
-- gameclients with native macro spell detection
if pfUI.client > 11200 and match then
self.spellslot = nil
self.booktype = nil
return
end
-- allow the user to disable the scan
if match and strfind(match, "disable") then
return
end
if not match then
-- add support to specify custom tooltips via:
-- /run --showtooltip SPELLNAME
_, _, match = string.find(line, '%-%-showtooltip (.+)')
end
if not match then
_, _, match = string.find(line, '^/cast (.+)')
end
if not match then
_, _, match = string.find(line, '^/pfcast (.+)')
end
if not match then
_, _, match = string.find(line, '^/pfmouse (.+)')
end
if not match then
_, _, match = string.find(line, 'CastSpellByName%(%"(.+)%"%)')
end
if match then
local _, _, spell, rank = string.find(match, '(.+)%((.+)%)')
spell = spell or match
self.spellslot, self.booktype = libspell.GetSpellIndex(spell, rank)
if self.spellslot and self.spellslot > 0 then return end
end
end
end
end
end
local function ButtonEnter(self)
local self = self or this
-- indicate that dragging could get enabled
drag_await = true
GameTooltip:ClearLines()
GameTooltip_SetDefaultAnchor(GameTooltip, self)
if self.bar == 11 then
GameTooltip:SetShapeshift(self.id)
elseif self.bar == 12 then
local name, _, _, token = GetPetActionInfo(self.id)
if token then
GameTooltip:AddLine(_G[name])
GameTooltip:Show()
else
GameTooltip:SetPetAction(self.id)
end
elseif self.spellslot and self.booktype then
GameTooltip:SetSpell(self.spellslot, self.booktype)
else
GameTooltip:SetAction(self.id)
end
self.highlight:Show()
end
local function ButtonLeave(self)
local self = self or this
-- no longer wait for a drag event
drag_await = nil
self.highlight:Hide()
GameTooltip:Hide()
end
local start, duration, enable, castable, autocast, token
local grid, sid, id, bar, active, texture, _
local function ButtonSlotUpdate(self)
if not self then return end
local self = self or this
sid = self.id -- 1 to 120
-- reset shared variables
castable, autocast, token = nil, nil, nil
-- set the own ID for compatibility to some vanilla addons
if pfUI.client <= 11200 then self:SetID(self.id) end
grid = self.bar == 12 and showgrid_pet or showgrid
if self.bar == 11 then
-- stance button
bar = self.bar
id = sid
texture, _, active = GetShapeshiftFormInfo(id)
elseif self.bar == 12 then
-- pet button
bar = self.bar
id = sid
_, _, texture, token, active, castable, autocast = GetPetActionInfo(id)
texture = token and _G[texture] or texture
else
active = IsCurrentAction(sid) or IsAutoRepeatAction(sid)
texture = GetActionTexture(sid)
bar = GetActiveBar()
id = self.bar == 1 and self.slot or sid-((self.bar)-1)*12
end
-- overwrite with spell macro texture where possible
if self.spellslot and self.booktype then
texture = GetSpellTexture(self.spellslot, self.booktype)
end
if not self.showempty and self.backdrop and not texture and grid == 0 then
self.backdrop:Hide()
self.hide = true
else
self.backdrop:Show()
self.hide = nil
end
-- active border
if active then
if C.bars.animmode == "statechange" and not self.active:IsShown() then
self.animation.active = 0
self.animation:Show()
end
self.backdrop:SetBackdropBorderColor(cr,cg,cb,1)
self.active:Show()
else
self.backdrop:SetBackdropBorderColor(er,eg,eb,ea)
self.active:Hide()
end
if self.bar ~= 11 and self.bar ~= 12 then
-- update consumables
if IsConsumableAction(sid) then
self.count:SetText(GetActionCount(sid))
elseif IsReagentAction and IsReagentAction(sid) then
self.count:SetText(GetReagentCount(sid))
else
self.count:SetText(nil)
end
-- equipped item
if IsEquippedAction(sid) and C.bars.showequipped == "1" then
self.equipped:Show()
else
self.equipped:Hide()
end
-- update macro text
if C.bars["bar"..self.bar] and C.bars["bar"..self.bar].showmacro == "1" then
self.macro:SetText(GetActionText(sid))
else
self.macro:SetText("")
end
end
-- icon
if texture ~= self.texture then
self.icon:SetTexture(texture)
self.texture = texture
end
-- handle pet bar quirks
if self.bar == 12 then
-- desaturate disabled petbar
self.icon:SetDesaturated(not GetPetActionsUsable())
-- display autocast
if autocast then
self.autocast:Show()
else
self.autocast:Hide()
end
if castable and C.bars.showcastable == "1" then
self.autocastable:Show()
else
self.autocastable:Hide()
end
end
-- keybinds
if not self.hide and self.bar == 1 and self.bar ~= 11 and self.bar ~= 12 then
self.keybind:SetText(GetBindingText(GetBindingKey("ACTIONBUTTON"..id), "KEY_", 1))
elseif not self.hide and buttontypes[self.bar] then
self.keybind:SetText(GetBindingText(GetBindingKey(buttontypes[self.bar]..id), "KEY_", 1))
else
self.keybind:SetText("")
end
end
local sid, usable, oom, _
local function ButtonUsableUpdate(self)
local self = self or this
sid = self.id -- 1 to 120
if self.bar == 11 then
_, _, _, usable = GetShapeshiftFormInfo(sid)
elseif self.bar == 12 then
usable = true
else
usable, oom = IsUsableAction(sid)
end
-- update usable [out-of-range = 1, oom = 2, not-usable = 3, default = 0]
if self.outofrange and C.bars.glowrange == "1" then
if self.vertexstate ~= 1 then
self.icon:SetVertexColor(self.rangeColor[1], self.rangeColor[2], self.rangeColor[3], self.rangeColor[4])
self.vertexstate = 1
end
elseif oom and C.bars.showoom == "1" then
if self.vertexstate ~= 2 then
self.icon:SetVertexColor(self.oomColor[1], self.oomColor[2], self.oomColor[3], self.oomColor[4])
self.vertexstate = 2
end
elseif not usable and C.bars.showna == "1" then
if self.vertexstate ~= 3 then
self.icon:SetVertexColor(self.naColor[1], self.naColor[2], self.naColor[3], self.naColor[4])
self.vertexstate = 3
end
else
if self.vertexstate ~= 0 then
self.icon:SetVertexColor(1, 1, 1, 1)
self.vertexstate = 0
end
end
end
local function ButtonRangeUpdate(self)
local self = self or this
-- update range display
if C.bars.glowrange == "1" and self.bar ~= 11 and self.bar ~= 12 and HasAction(self.id) and ActionHasRange(self.id) and IsActionInRange(self.id) == 0 then
if not self.outofrange then
self.outofrange = true
ButtonUsableUpdate(self)
end
elseif self.outofrange then
self.outofrange = nil
ButtonUsableUpdate(self)
end
end
local start, duration, enable
local function ButtonCooldownUpdate(button)
if not button then return end
if button.bar == 11 then
start, duration, enable = GetShapeshiftFormCooldown(button.id)
elseif button.bar == 12 then
start, duration, enable = GetPetActionCooldown(button.id)
elseif button.spellslot and button.booktype then
start, duration = GetSpellCooldown(button.spellslot, button.booktype)
enable = 1
else
start, duration, enable = GetActionCooldown(button.id)
end
CooldownFrame_SetTimer(button.cd, start, duration, enable)
end
local _, active
local function ButtonIsActiveUpdate(button)
if not button then return end
if button.bar == 11 then
_, _, active, _ = GetShapeshiftFormInfo(button.id)
elseif button.bar == 12 then
_, _, _, _, active, _, _ = GetPetActionInfo(button.id)
else
active = IsCurrentAction(button.id) or IsAutoRepeatAction(button.id)
end
-- active border
if active then
if not button.border_active then
button.backdrop:SetBackdropBorderColor(cr,cg,cb,1)
button.border_active = true
end
button.active:Show()
else
if button.border_active then
button.backdrop:SetBackdropBorderColor(er,eg,eb,ea)
button.border_active = nil
end
button.active:Hide()
end
end
local function ButtonFullUpdate(button)
if not button then return end
ButtonMacroScan(button)
ButtonSlotUpdate(button)
ButtonRangeUpdate(button)
ButtonUsableUpdate(button)
ButtonCooldownUpdate(button)
ButtonIsActiveUpdate(button)
end
local function BarsEvent(self)
local self = self or this
-- refresh only specific slots
if event == "ACTIONBAR_SLOT_CHANGED" and arg1 and arg1 ~= 0 then
updatecache[arg1] = true
return
end
-- run special refresh functions on next update
if special_events[event] then
eventcache[event] = true
return
end
-- handle aura events
if aura_events[event] then
for j=1,12 do
if self[11] and self[11][j] then
updatecache[self[11][j].slot] = true
end
end
return
end
-- handle pet events
if pet_events[event] then
for j=1,12 do
if self[12] and self[12][j] then
updatecache[self[12][j].slot] = true
end
end
return
end
-- handle global events
for id in pairs(buttoncache) do
updatecache[id] = true
end
end
local self, button, unlock
local function BarsUpdate(self)
self = self or this
-- update buttons whenever a button drag is assumed
AssumeButtonDrag()
if pfUI.unlock then
-- update all bars when entering unlock
if pfUI.unlock:IsShown() ~= unlock then
pfUI.bars:UpdateConfig()
unlock = pfUI.unlock:IsShown()
end
end
-- run cached usable usable actions
if eventcache["ACTIONBAR_UPDATE_USABLE"] then
eventcache["ACTIONBAR_UPDATE_USABLE"] = nil
for id, button in pairs(buttoncache) do
ButtonUsableUpdate(button)
end
end
-- run cached cooldown events
if eventcache["ACTIONBAR_UPDATE_COOLDOWN"] then
eventcache["ACTIONBAR_UPDATE_COOLDOWN"] = nil
for id, button in pairs(buttoncache) do
ButtonCooldownUpdate(button)
end
end
-- run cached action state events
if eventcache["ACTIONBAR_UPDATE_STATE"] then
eventcache["ACTIONBAR_UPDATE_STATE"] = nil
for id, button in pairs(buttoncache) do
ButtonIsActiveUpdate(button)
end
end
for id in pairs(updatecache) do
-- run updates based on slot
pfUI.bars.ButtonFullUpdate(buttoncache[id])
-- run updates on paging actionbar if required
for i=1,12 do
if pfUI.bars[1][i].id == id then
pfUI.bars.ButtonFullUpdate(pfUI.bars[1][i])
end
end
-- clear update cache
updatecache[id] = nil
end
if ( this.tick or .2) > GetTime() then return else this.tick = GetTime() + .2 end
for id, button in pairs(buttoncache) do
if button:IsShown() then ButtonRangeUpdate(button) end
end
end
-- create the main event and update handler for pfUI actionbars
local bars = CreateFrame("Frame", "pfActionBar", UIParent)
for event in pairs(special_events) do bars:RegisterEvent(event) end
for event in pairs(global_events) do bars:RegisterEvent(event) end
for event in pairs(aura_events) do bars:RegisterEvent(event) end
for event in pairs(pet_events) do bars:RegisterEvent(event) end
-- refresh actionbar buttons on event
bars:SetScript("OnEvent", BarsEvent)
-- update actionbar buttons
bars:SetScript("OnUpdate", BarsUpdate)
-- enable bar paging via secure functions
local function ButtonSwitch(self, att, value)
if att == "state-parent" then
local action = SecureButton_GetModifiedAttribute(self, "action", SecureStateChild_GetEffectiveButton(self)) or self.id
if self.id == action then return end
updatecache[self.slot] = true
self.id = action
end
end
local function EnablePaging(bar)
if pfUI.client <= 11200 then
if not bar.pager then
bar.pager = CreateFrame("Frame")
bar.pager:RegisterEvent("PLAYER_ENTERING_WORLD")
bar.pager:RegisterEvent("UPDATE_BONUS_ACTIONBAR")
bar.pager:RegisterEvent("ACTIONBAR_PAGE_CHANGED")
bar.pager:SetScript("OnEvent", function()
for i=1, 10 do -- reload pageable bars
local pageable = C.bars["bar"..i] and C.bars["bar"..i].pageable == "1" and true or nil
_G.VIEWABLE_ACTION_BAR_PAGES[i] = pageable
end
local active = GetActiveBar()
for i=1,12 do
local id = i + (active-1)*12
bar[i].id = id
updatecache[i] = true
end
end)
end
else
-- append paging enabled bars to the filter list
for i=1,12 do bar[i]:SetScript("OnAttributeChanged", ButtonSwitch) end
-- fill all possible page states
local page, pages = nil, {}
while not pages[6] do
for i=1, 6 do
page = i == 1 and 1 or C.bars["bar"..i] and C.bars["bar"..i].pageable == "1" and i
if page then table.insert(pages, page) end
end
end
bar:SetAttribute("statemap-page", "$input")
bar:SetAttribute("state", (bar:GetAttribute("state-page") or 1))
-- prio posses bar
bar.filter = "[bonusbar: 5] 11;"
-- set bar 8 for druid stealth if enabled
local prowl = class == "DRUID" and C.bars["druidstealth"] == "1" and "8" or "7"
-- write default pages
for state, page in pairs(pages) do
if page ~= 1 then -- skip page 1 as it is supposed to stay dynamic for stances
bar.filter = string.format("%s[actionbar: %s] %s; ", bar.filter, state, page)
end
end
-- write page driver conditions
bar.filter = string.format("%s[bonusbar:1,nostealth] 7; [bonusbar:1,stealth] %s; [bonusbar:2] 10; [bonusbar:3] 9; [bonusbar:4] 10; 1", bar.filter, prowl)
-- prepend pagemaster states if enabled
if C.bars.pagemaster == "1" then
for mod, page in pairs({ ["shift"] = "6", ["ctrl"] = "5", ["alt"] = "3" }) do
bar.filter = string.format("[modifier:%s] %s;", mod, page) .. bar.filter
end
end
-- enable page driver conditions
RegisterStateDriver(bar, "page", bar.filter)
SecureStateHeader_Refresh(bar)
end
end
local function SwitchBar(bar)
if _G.CURRENT_ACTIONBAR_PAGE ~= bar then
_G.CURRENT_ACTIONBAR_PAGE = bar
ChangeActionBarPage(bar)
end
end
local cat, stealth
local function IsCatStealth()
if class ~= "DRUID" then return nil end
cat, stealth = nil, nil
for i = 0, 31 do
local texture = GetPlayerBuffTexture(i)
if not texture then break end
-- catform icon detected
if strfind(texture, "Ability_Druid_CatForm") then
if stealth then return true end
cat = true
end
-- stealth icon detected
if strfind(texture, "Ability_Ambush") then
if cat then return true end
stealth = true
end
end
return nil
end
-- pagemaster / meta page switch
if pfUI.expansion == "vanilla" then
local prowl, shift, ctrl, alt, default = 8, 6, 5, 3, 1
-- set temporary pagemaster bindings keybinds
if C.bars.pagemaster == "1" then
local modifier = { "ALT", "SHIFT", "CTRL" }
local buttons = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "=", "´" }
local current = CURRENT_ACTIONBAR_PAGE
bars.pagemaster = bars.pagemaster or CreateFrame("Frame", "pfPageMaster", UIParent)
bars.pagemaster:RegisterEvent("PLAYER_ENTERING_WORLD")
bars.pagemaster:SetScript("OnEvent", function()
for _,mod in pairs(modifier) do
for _,but in pairs(buttons) do
SetBinding(mod.."-"..but)
end
end
end)
end
-- setup page switch frame
local pageswitch = CreateFrame("Frame", "pfActionBarPageSwitch", UIParent)
pageswitch:SetScript("OnUpdate", function()
-- a different block for each mod key
if C.bars.pagemastershift == "1" then
if IsShiftKeyDown() then
SwitchBar(shift)
return
else
SwitchBar(default)
end
end
if C.bars.pagemasterctrl == "1" then
if IsControlKeyDown() then
SwitchBar(ctrl)
return
else
SwitchBar(default)
end
end
if C.bars.pagemasteralt == "1" then
if IsAltKeyDown() then
SwitchBar(alt)
return
else
SwitchBar(default)
end
end
if C.bars.druidstealth == "1" then
local stealth = IsCatStealth()
if stealth and _G.CURRENT_ACTIONBAR_PAGE == 1 then
SwitchBar(prowl)
elseif not stealth and _G.CURRENT_ACTIONBAR_PAGE == 8 then
SwitchBar(default)
end
end
end)
end
local function CreateActionButton(parent, bar, button)
-- load config
local size = C.bars["bar"..bar].icon_size
local font = pfUI.media[C.bars.font]
local font_offset = tonumber(C.bars.font_offset)
local macro_size = tonumber(C.bars.macro_size)
local macro_color = { strsplit(",", C.bars.macro_color) }
local count_size = tonumber(C.bars.count_size)
local count_color = { strsplit(",", C.bars.count_color) }
local bind_size = tonumber(C.bars.bind_size)
local bind_color = { strsplit(",", C.bars.bind_color) }
local cd_size = tonumber(C.bars.cd_size)
local showempty = C.bars["bar"..bar].showempty
local showmacro = C.bars["bar"..bar].showmacro
local showkybind = C.bars["bar"..bar].showkeybind
local showcount = C.bars["bar"..bar].showcount
-- sanitize font sizes
if macro_size == 0 then macro_size = 1 end
if count_size == 0 then macro_size = 1 end
if bind_size == 0 then macro_size = 1 end
if cd_size == 0 then cd_size = nil end
local button_name = "pfActionBar" .. barnames[bar] .. "Button" .. button
local id = (bar-1)*12+button
local exists = _G[button_name] and true or nil
local f = _G[button_name] or CreateFrame("Button", button_name, parent, ACTIONBAR_SECURE_TEMPLATE_BUTTON)
-- no button available, create a new one
if not exists then
-- prepare the button for vanilla
if not f.HookScript then
f.HookScript = HookScript
f:SetScript("OnClick", ButtonClick)
end
if bar ~= 11 then
f:RegisterForDrag("LeftButton", "RightButton")
f:SetScript("OnDragStart", ButtonDrag)
f:SetScript("OnReceiveDrag", ButtonDragStop)
end
-- add mouseovers
f:SetScript("OnEnter", ButtonEnter)
f:SetScript("OnLeave", ButtonLeave)
-- add click animation handler
f:HookScript("OnClick", ButtonAnimate)
f.id = id
-- set a static slot
f.slot = id
-- cooldown
f.cd = CreateFrame(COOLDOWN_FRAME_TYPE, f:GetName() .. "Cooldown", f, "CooldownFrameTemplate")
f.cd.pfCooldownStyleAnimation = 1
f.cd.pfCooldownType = "NOGCD"
f.cd.pfCooldownSize = cd_size
-- icon
f.icon = f:CreateTexture(button_name .. "Icon", "BACKGROUND")
f.icon:SetTexCoord(.08, .92, .08, .92)
f.icon:SetAllPoints()
-- animation
f.animation = CreateFrame("Frame", button_name .. "Animation", f)
f.animation.parent = f
f.animation:SetPoint("CENTER", 0, 0)
f.animation:Hide()
f.animation.tex = f.animation:CreateTexture(button_name .. "AnimationTexture", "BACKGROUND")
f.animation.tex:SetTexCoord(.08, .92, .08, .92)
f.animation.tex:SetAllPoints()
if bar ~= 11 and bar ~= 12 then
-- equipped item
f.equipped = f:CreateTexture(nil, "BORDER")
f.equipped:SetAllPoints()
f.equipped:Hide()
elseif bar == 12 then
f.autocast = CreateFrame("Model", nil, f)
f.autocast:SetAllPoints()
f.autocast:SetModel("Interface\\Buttons\\UI-AutoCastButton.mdx")
f.autocast:SetSequence(0)
f.autocast:SetSequenceTime(0, 0)
f.autocast:Hide()
f.autocastable = f:CreateTexture(nil, "BORDER")
f.autocastable:SetAllPoints()
f.autocastable:SetTexture("Interface\\Buttons\\UI-AutoCastableOverlay")
f.autocastable:SetTexCoord(.25, .75, .25, .75)
end
-- macro
f.macro = f:CreateFontString(button_name .. "Name", "LOW", "GameFontNormal")
-- keybind
f.keybind = f:CreateFontString(nil, "LOW", "GameFontNormal")
-- itemcount
f.count = f:CreateFontString(button_name .. "Count", "LOW", "GameFontNormal")
-- highlight
f.highlight = CreateFrame("Frame", nil, f)
f.highlight:SetBackdrop(backdrop_highlight)
f.highlight:SetBackdropBorderColor(1,1,1,.8)
f.highlight:SetAllPoints()
f.highlight:Hide()
-- active
f.active = CreateFrame("Frame", nil, f)
f.active:SetBackdrop(backdrop_highlight)
f.active:SetBackdropBorderColor(1,1,.5,1)
f.active:SetAllPoints()
f.active:Hide()
-- add to buttoncache
buttoncache[id] = f
end
-- set required attributes for regular tbc buttons
if pfUI.client > 11200 then
if bar == 11 then
f:SetAttribute("type", "spell")
f:SetAttribute('spell', select(2, GetShapeshiftFormInfo(button)))
elseif bar == 12 then
f:SetAttribute("type1", "pet")
f:SetAttribute("action1", button)
f:SetAttribute("type2", "macro")
f:SetAttribute("macrotext2", "/click PetActionButton".. button .. " RightButton")
else
bars[bar]:SetAttribute("addchild", f)
f:SetAttribute("type", "action")
f:SetAttribute("action", id)
f:SetAttribute("checkselfcast", true)
f:SetAttribute("useparent-unit", true)
f:SetAttribute("useparent-statebutton", true)
for state = 0, 11 do -- add custom states
local action = ((state == 0 and bar or state)-1)*12+button
f:SetAttribute(string.format("*type-S%d", state), "action")
f:SetAttribute(string.format("*type-S%dRight", state), "action")
f:SetAttribute(string.format("*action-S%d", state), action)
f:SetAttribute(string.format("*action-S%dRight", state), action)
if C.bars.rightself == "1" then
f:SetAttribute(string.format("*unit-S%dRight", state), "player")
else
f:SetAttribute(string.format("*unit-S%dRight", state), nil)
end
end
end
end
-- set keydown option
if C.bars.keydown == "1" then
f:RegisterForClicks("LeftButtonDown", "RightButtonDown")
else
f:RegisterForClicks("LeftButtonUp", "RightButtonUp")
end
-- set animation
f.animation:SetScript("OnUpdate", button_animations[C.bars.animation])
-- pet autocast
if bar == 12 then
f.autocast:SetScale(C.bars["bar"..bar].icon_size / 25)
f.autocast:SetAlpha(.10)
end
-- macro options
if showmacro == "1" then f.macro:Show() else f.macro:Hide() end
SetAllPointsOffset(f.macro, f, font_offset, -font_offset)
f.macro:SetFont(font, macro_size, "OUTLINE")
f.macro:SetTextColor(unpack(macro_color))
f.macro:SetJustifyH("LEFT")
f.macro:SetJustifyV("BOTTOM")
-- keybind options
if showkybind == "1" then f.keybind:Show() else f.keybind:Hide() end
SetAllPointsOffset(f.keybind, f, font_offset, -font_offset)
f.keybind:SetFont(font, bind_size, "OUTLINE")
f.keybind:SetTextColor(unpack(bind_color))
f.keybind:SetJustifyH("RIGHT")
f.keybind:SetJustifyV("TOP")
f.keybind:SetNonSpaceWrap(false)
-- item count options
if showcount == "1" then f.count:Show() else f.count:Hide() end
SetAllPointsOffset(f.count, f, font_offset, -font_offset)
f.count:SetFont(font, count_size, "OUTLINE")
f.count:SetTextColor(unpack(count_color))
f.count:SetJustifyH("RIGHT")
f.count:SetJustifyV("BOTTOM")
-- macro spell scan
if C.bars.macroscan == "0" then
f.scanmacro, f.spellslot, f.booktype = nil, nil, nil
else
f.scanmacro = true
end
-- range glow color
f.rangeColor = { strsplit(",", C.bars.rangecolor) }
-- out of mana color
f.oomColor = { strsplit(",", C.bars.oomcolor) }
-- not usable color
f.naColor = { strsplit(",", C.bars.nacolor) }
-- equipped color
if f.equipped then
f.equipped:SetTexture(strsplit(",", C.bars.eqcolor))
end
-- general appearance
f.showempty = showempty == "1" and true or nil
f:SetHeight(size)
f:SetWidth(size)
CreateBackdrop(f, border)
return f
end
local function CreateActionBar(i)
-- load config
local buttonbasename = "pfActionBar" .. barnames[i] .. "Button"
local enable = C.bars["bar"..i].enable
local size = C.bars["bar"..i].icon_size
local spacing = C.bars["bar"..i].spacing
local background = C.bars["bar"..i].background
local formfactor = C.bars["bar"..i].formfactor
local autohide = C.bars["bar"..i].autohide
local hide_time = C.bars["bar"..i].hide_time
local hide_combat = C.bars["bar"..i].hide_combat == "1" and true or nil
local buttons = tonumber(C.bars["bar"..i].buttons) or 12
if i == 11 and bars[i] then -- shapeshift buttons
buttons = GetNumShapeshiftForms()
elseif i == 12 and bars[i] then -- pet buttons
buttons = NUM_PET_ACTION_SLOTS
elseif i == 12 or i == 11 then
-- Fallback to 10 buttons on shapeshift and petbar during initialization.
-- This lets us load bars that aren't yet available for your class or level.
buttons = 10
end
-- don't process empty bars
if buttons == 0 then
bars[i]:Hide()
return
end
-- the stored layout is invalid, temporary fallback
if not pfGridmath[buttons][BarLayoutFormfactor(formfactor)] then
formfactor = BarLayoutOptions(buttons)[1]
end
local font = pfUI.font_unit
local font_size = C.global.font_unit_size
local realsize = size+border*2
-- create frame
local init = not bars[i]
bars[i] = bars[i] or CreateFrame("Frame", "pfActionBar" .. barnames[i], UIParent, ACTIONBAR_SECURE_TEMPLATE_BAR)
bars[i]:SetID(i)
-- autohide
if autohide == "1" then
EnableAutohide(bars[i], tonumber(hide_time), hide_combat)
else
DisableAutohide(bars[i])
end
-- apply visible settings
if enable == "1" then
-- handle pet bar
if i == 12 then
if pfUI.client > 11200 then
if InCombatLockdown and InCombatLockdown() then
-- don't process those events during combat
else
-- set state driver for pet bars
bars[i]:SetAttribute("unit", "pet")
local visibility = pfUI.unlock and pfUI.unlock:IsShown() and "show" or petvisibility
if bars[i].visibility ~= visibility then
RegisterStateDriver(bars[i], 'visibility', visibility)
bars[i].visibility = visibility
end
end
else
-- only show when pet actions exists
if PetHasActionBar() or pfUI.unlock and pfUI.unlock:IsShown() then
bars[i]:Show()
else
bars[i]:Hide()
end
-- show/hide petbar on petbar updates
if init then
bars[i]:RegisterEvent("PET_BAR_UPDATE")
bars[i]:SetScript("OnEvent", function()
-- hide obsolete buttons
for i=1, NUM_PET_ACTION_SLOTS do
if not PetHasActionBar() and bars[12][i] then
bars[12][i]:Hide()
end
end
-- refresh layout
CreateActionBar(12)
end)
end
end
-- handle shapeshift bar
elseif i == 11 then
-- only show when shapeshifts exist
if GetNumShapeshiftForms() > 0 then
bars[i]:Show()
else
bars[i]:Hide()
end
-- update shapeshift bar when amount of spells changes
if init then
bars[i]:RegisterEvent("PLAYER_ENTERING_WORLD")
bars[i]:RegisterEvent("UPDATE_BONUS_ACTIONBAR")
bars[i]:RegisterEvent("UPDATE_SHAPESHIFT_FORMS")
bars[i]:SetScript("OnEvent", function()
local count = GetNumShapeshiftForms()
if count ~= this.lastCount then
this.lastCount = count
-- hide obsolete buttons
for i=1, NUM_SHAPESHIFT_SLOTS do
if i > GetNumShapeshiftForms() and bars[11][i] then
bars[11][i]:Hide()
end
end
-- create new buttons and refresh layout
CreateActionBar(11)
end
end)
end
-- regular bars
else
bars[i]:Show()
end
elseif enable == "0" then
bars[i]:UnregisterAllEvents()
bars[i]:Hide()
end
-- create action buttons
local maxbuttons = (i == 11 or i == 12) and 10 or 12
for j=1,maxbuttons do
bars[i][j] = CreateActionButton(bars[i], i, j)
bars[i][j].bar = i
BarButtonAnchor(bars[i][j], buttonbasename, j, buttons, formfactor, size, border, spacing)
bars[i][j]:ClearAllPoints()
bars[i][j]:SetPoint(unpack(bars[i][j]._anchor))
bars[i][j]:Show()
if i > 10 then
bars[i][j].id = j
end
-- refresh button
updatecache[bars[i][j].slot] = true
end
for j=buttons+1,12 do
if bars[i][j] then
bars[i][j]:Hide()
end
end
-- add up to 0-11 button parent states to each bar
if i <= 10 and pfUI.client > 11200 then
bars[i]:SetAttribute("statebutton", "0:S0;1:S1;2:S2;3:S3;4:S4;5:S5;6:S6;7:S7;8:S8;9:S9;10:S10;11:S11;")
bars[i]:SetAttribute("statebutton2", "0:S0Right;1:S1Right;2:S2Right;3:S3Right;4:S4Right;5:S5Right;6:S6Right;7:S7Right;8:S8Right;9:S9Right;10:S10Right;11:S11Right;")
end
-- enable paging for the first actionbar
if i == 1 then
EnablePaging(bars[i])
end
-- adjust actionbar size
BarLayoutSize(bars[i], buttons, formfactor, size, border, spacing)
bars[i]:SetWidth(bars[i]._size[1])
bars[i]:SetHeight(bars[i]._size[2])
bars[i]:ClearAllPoints()
if i == 1 then -- main
bars[i]:SetPoint("BOTTOM", 0, 2*border)
elseif i == 3 then -- left
bars[i]:SetPoint("BOTTOMLEFT", bars[1], "BOTTOMRIGHT", 3*border, 0)
elseif i == 4 then -- vertical
bars[i]:SetPoint("RIGHT", -2*border, 0)
elseif i == 5 then -- right
bars[i]:SetPoint("BOTTOMRIGHT", bars[1], "BOTTOMLEFT", -3*border, 0)
elseif i == 6 then -- top
bars[i]:SetPoint("BOTTOM", bars[1], "TOP", 0, -spacing)
elseif i == 11 then -- stances
bars[i]:SetPoint("BOTTOM", bars[6], "TOP", 0, 3*border)
elseif i == 12 then -- pet
bars[i]:SetPoint("BOTTOM", bars[6], "TOP", 0, 3*border)
else -- others
bars[i]:SetPoint("TOP", 0, -i*50)
end
UpdateMovable(bars[i])
-- apply backdrop settings
if background == "1" then
CreateBackdrop(bars[i], border)
CreateBackdropShadow(bars[i])
bars[i].backdrop:Show()
-- share backdrop of main and top actionbar
if i == 6 then
bars[6].OnMove = bars[6].OnMove or function()
local _, a, _ = bars[6]:GetPoint()
if a == bars[1] and C.bars.bar1.enable == "1"
and C.bars.bar1.background == "1" and C.bars.bar6.background == "1"
and C.bars.bar1.autohide == "0" and C.bars.bar6.autohide == "0"
and C.bars.bar1.icon_size == C.bars.bar6.icon_size
and C.bars.bar1.spacing == C.bars.bar6.spacing
and C.bars.bar1.formfactor == C.bars.bar6.formfactor
and C.bars.bar1.buttons == C.bars.bar6.buttons
then
bars[1].backdrop:ClearAllPoints()
bars[1].backdrop:SetPoint("BOTTOMRIGHT", bars[1], "BOTTOMRIGHT", border, -border)
bars[1].backdrop:SetPoint("TOPLEFT", bars[6], "TOPLEFT", -border, border)
bars[6].backdrop:Hide()
else
if C.bars.bar1.background == "1" then
-- create/reset bar1 backdrop if required
CreateBackdrop(bars[1], border)
bars[1].backdrop:ClearAllPoints()
bars[1].backdrop:SetPoint("BOTTOMRIGHT", bars[1], "BOTTOMRIGHT", border, -border)
bars[1].backdrop:SetPoint("TOPLEFT", bars[1], "TOPLEFT", -border, border)
end
if C.bars.bar6.background == "1" then
bars[6].backdrop:Show()
end
end
end
bars[i].OnMove()
end
else
if bars[i].backdrop then
bars[i].backdrop:Hide()
end
if bars[i].shadow then
bars[i].shadow:Hide()
end
end
end
-- create actionbars
pfUI.bars = bars
pfUI.bars.update = updatecache
pfUI.bars.buttons = buttoncache
pfUI.bars.ButtonFullUpdate = ButtonFullUpdate
pfUI.bars.ButtonEnter = ButtonEnter
pfUI.bars.ButtonLeave = ButtonLeave
pfUI.bars.UpdateGrid = function(self, state, typ)
if not typ then
showgrid = state
for id in pairs(buttoncache) do
updatecache[id] = true
end
elseif typ == "PET" then
showgrid_pet = state
for slot=133,142 do
updatecache[slot] = true
end
end
end
pfUI.bars.UpdateConfig = function(self)
for i=1,12 do
CreateActionBar(i)
end
end
pfUI.bars:UpdateConfig()
-- Localize custom keybinds for additional actionbars (see Bindings.xml)
local names = {
["PAGING"] = T["Paging Actionbar"],
["STANCEONE"] = T["Stance Bar 1"],
["STANCETWO"] = T["Stance Bar 2"],
["STANCETHREE"] = T["Stance Bar 3"],
["STANCEFOUR"] = T["Stance Bar 4"],
}
for name, loc in pairs(names) do
_G["BINDING_HEADER_PFBAR"..name] = T["Action Bar"] .. " " .. loc
for i=1,12 do
_G["BINDING_NAME_PF" .. name .. i] = loc .. " " .. T["Button"] .. " " .. i
end
end
-- Map Keybinds to button clicks
function _G.pfActionButton(slot, slfcast, opt)
if ChatFrameEditBox:IsShown() then return end
local bar, button = 1, slot
-- determine the proper bar and button
if opt and blizzbarmapping[opt] then
bar = blizzbarmapping[opt]
elseif slot > 12 then
bar, button = ceil(slot/12), mod(slot, 12)
button = button == 0 and 12 or button
end
local frame = bars[bar][button]
if frame then
frame.slfcast = slfcast
frame:Click()
end
end
-- Set keybinds to all actionbuttons
if pfUI.client <= 11200 then
-- In order to be able to reuse already defined keybinds, we need to remap
-- existing button functions to pfUI. We need to get rid of the blizzard calls
-- to avoid having them call texture changes and errors due to missing buttons
_G.ActionButtonDown = pfActionButton
_G.ActionButtonUp = pfActionButton
_G.BonusActionButtonDown = function(slot) pfActionButton(slot, nil, "BonusActionBar") end
_G.BonusActionButtonUp = function(slot) pfActionButton(slot, nil, "BonusActionBar") end
_G.MultiActionButtonDown = function(bar, slot, slf) pfActionButton(slot, slf, bar) end
_G.MultiActionButtonUp = function(bar, slot, slf) pfActionButton(slot, slf, bar) end
_G.ShapeshiftBar_ChangeForm = function(slot) pfActionButton(slot, nil, "ShapeShiftBar") end
else
local bindwraps = {
["ACTIONBUTTON%d"] = 1,
["SHAPESHIFTBUTTON%d"] = 11, -- ShapeShiftBar
["BONUSACTIONBUTTON%d"] = 12, -- BonusActionBar
["MULTIACTIONBAR1BUTTON%d"] = 6, -- MultiBarBottomLeft
["MULTIACTIONBAR2BUTTON%d"] = 5, -- MultiBarBottomRight
["MULTIACTIONBAR3BUTTON%d"] = 3, -- MultiBarRight
["MULTIACTIONBAR4BUTTON%d"] = 4, -- MultiBarLeft
["PFPAGING%d"] = 2,
["PFSTANCEONE%d"] = 7,
["PFSTANCETWO%d"] = 8,
["PFSTANCETHREE%d"] = 9,
["PFSTANCEFOUR%d"] = 10,
}
-- rebind all existing bindings to our own buttons
local keybinder = CreateFrame("Frame")
keybinder:RegisterEvent("UPDATE_BINDINGS")
keybinder:SetScript("OnEvent", function()
for name, bar in pairs(bindwraps) do
for i=1,12 do
local key = GetBindingKey(format(name, i))
local button = bars[bar][i]
if key and button then
SetOverrideBindingClick(button, false, key, button:GetName(), 'LeftButton')
end
end
end
end)
end
-- handle drag-drop grid
local grid = CreateFrame("Frame")
grid:RegisterEvent("ACTIONBAR_SHOWGRID")
grid:RegisterEvent("ACTIONBAR_HIDEGRID")
grid:RegisterEvent("PET_BAR_SHOWGRID")
grid:RegisterEvent("PET_BAR_HIDEGRID")
grid:SetScript("OnEvent", function()
if event == "ACTIONBAR_SHOWGRID" then
pfUI.bars:UpdateGrid(1)
elseif event == "ACTIONBAR_HIDEGRID" then
pfUI.bars:UpdateGrid(0)
elseif event == "PET_BAR_SHOWGRID" then
pfUI.bars:UpdateGrid(1, "PET")
elseif event == "PET_BAR_HIDEGRID" then
pfUI.bars:UpdateGrid(0, "PET")
end
end)
-- reagent counter
if C.bars.reagents == "1" then
local reagent_slots = { }
local reagent_counts = { }
local reagent_capture = SPELL_REAGENTS.."(.+)"
local scanner = libtipscan:GetScanner("actionbar")
local UpdateSlot = function(slot)
local texture = GetActionTexture(slot)
-- update buttons that previously had an reagent
if reagent_slots[slot] and not HasAction(slot) then
reagent_slots[slot] = nil
updatecache[slot] = true
end
-- search for reagent requirements
if HasAction(slot) then
scanner:SetAction(slot)
local _, reagents = scanner:Find(reagent_capture)
-- remove reagent counts if existing
reagents = reagents and string.gsub(reagents, " %((.+)%)", "")
-- update on reagent requirement changes
if reagents and reagent_slots[slot] ~= reagents then
reagent_counts[reagents] = reagent_counts[reagents] or 0
reagent_slots[slot] = reagents
updatecache[slot] = true
end
end
end
local reagentcounter = CreateFrame("Frame", "pfReagentCounter", UIParent)
reagentcounter:RegisterEvent("PLAYER_ENTERING_WORLD")
reagentcounter:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
reagentcounter:RegisterEvent("BAG_UPDATE")
reagentcounter:SetScript("OnEvent", function()
if event == "BAG_UPDATE" then
this.event = true
else
this.scan = 1
end
end)
-- limit events to one per second and smoothen action scanning
reagentcounter:SetScript("OnUpdate", function()
-- scan one action slot per frame
if this.scan and this.scan <= 120 then
UpdateSlot(this.scan)
this.scan = this.scan + 1
end
-- trigger reagent count updates after action scans
if this.scan and this.scan >= 120 then
this.event = true
this.scan = nil
end
-- queue events to fire only once per second
if not this.event then return end
if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 1 end
-- scan for all reagent item counts
for item in pairs(reagent_counts) do
reagent_counts[item] = GetItemCount(item)
end
-- update all actionbar buttons
for slot in pairs(reagent_slots) do
updatecache[slot] = true
end
-- remove event trigger
this.event = nil
end)
function IsReagentAction(slot)
return reagent_slots[slot] and true or nil
end
function GetReagentCount(slot)
return reagent_counts[reagent_slots[slot]]
end
end
end)