聊天重做前缓存

This commit is contained in:
rucky
2026-04-09 09:46:47 +08:00
parent 6e18269bfd
commit e915bbd74a
39 changed files with 8501 additions and 2308 deletions

792
ExtraBar.lua Normal file
View File

@@ -0,0 +1,792 @@
--------------------------------------------------------------------------------
-- Nanami-UI: ExtraBar
--
-- A fully configurable extra action bar using action slots from page 7+
-- (slots 73-120). Buttons are created from scratch since no spare Blizzard
-- ActionButton frames exist.
--
-- Supports: grid layout, per-row count, alignment, drag-and-drop, cooldown,
-- range coloring, tooltip, and Mover integration for position saving.
--------------------------------------------------------------------------------
SFrames.ExtraBar = {}
local EB = SFrames.ExtraBar
local DEFAULTS = {
enable = false,
buttonCount = 12,
perRow = 12,
buttonSize = 36,
buttonGap = 2,
align = "center",
startSlot = 73,
alpha = 1.0,
showHotkey = true,
showCount = true,
buttonRounded = false,
buttonInnerShadow = false,
}
local MAX_BUTTONS = 48
function EB:GetDB()
if not SFramesDB then SFramesDB = {} end
if type(SFramesDB.ExtraBar) ~= "table" then SFramesDB.ExtraBar = {} end
local db = SFramesDB.ExtraBar
for k, v in pairs(DEFAULTS) do
if db[k] == nil then db[k] = v end
end
return db
end
--------------------------------------------------------------------------------
-- Layout helper (local LayoutGrid equivalent)
--------------------------------------------------------------------------------
local function LayoutGrid(buttons, parent, size, gap, perRow, count)
if count == 0 then return end
local numCols = math.min(perRow, count)
local numRows = math.ceil(count / perRow)
parent:SetWidth(numCols * size + math.max(numCols - 1, 0) * gap)
parent:SetHeight(numRows * size + math.max(numRows - 1, 0) * gap)
for i = 1, count do
local b = buttons[i]
if b then
b:SetWidth(size)
b:SetHeight(size)
b:ClearAllPoints()
local col = math.fmod(i - 1, perRow)
local row = math.floor((i - 1) / perRow)
b:SetPoint("TOPLEFT", parent, "TOPLEFT", col * (size + gap), -row * (size + gap))
b:Show()
end
end
for i = count + 1, MAX_BUTTONS do
if buttons[i] then buttons[i]:Hide() end
end
end
--------------------------------------------------------------------------------
-- Button visual helpers (mirrors ActionBars.lua approach)
--------------------------------------------------------------------------------
local function CreateBackdropFor(btn)
if btn.sfBackdrop then return end
local level = btn:GetFrameLevel()
local bd = CreateFrame("Frame", nil, btn)
bd:SetFrameLevel(level > 0 and (level - 1) or 0)
bd:SetAllPoints(btn)
SFrames:CreateBackdrop(bd)
btn.sfBackdrop = bd
end
local function CreateInnerShadow(btn)
if btn.sfInnerShadow then return btn.sfInnerShadow end
local shadow = {}
local thickness = 4
local top = btn:CreateTexture(nil, "OVERLAY")
top:SetTexture("Interface\\Buttons\\WHITE8X8")
top:SetHeight(thickness)
top:SetGradientAlpha("VERTICAL", 0, 0, 0, 0, 0, 0, 0, 0.5)
shadow.top = top
local bot = btn:CreateTexture(nil, "OVERLAY")
bot:SetTexture("Interface\\Buttons\\WHITE8X8")
bot:SetHeight(thickness)
bot:SetGradientAlpha("VERTICAL", 0, 0, 0, 0.5, 0, 0, 0, 0)
shadow.bottom = bot
local left = btn:CreateTexture(nil, "OVERLAY")
left:SetTexture("Interface\\Buttons\\WHITE8X8")
left:SetWidth(thickness)
left:SetGradientAlpha("HORIZONTAL", 0, 0, 0, 0.5, 0, 0, 0, 0)
shadow.left = left
local right = btn:CreateTexture(nil, "OVERLAY")
right:SetTexture("Interface\\Buttons\\WHITE8X8")
right:SetWidth(thickness)
right:SetGradientAlpha("HORIZONTAL", 0, 0, 0, 0, 0, 0, 0, 0.5)
shadow.right = right
btn.sfInnerShadow = shadow
return shadow
end
local function ApplyButtonVisuals(btn, rounded, innerShadow)
local bd = btn.sfBackdrop
if not bd then return end
local inset = rounded and 3 or 2
btn.sfIconInset = inset
if rounded then
bd:SetBackdrop({
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 12,
insets = { left = 3, right = 3, top = 3, bottom = 3 }
})
else
bd:SetBackdrop({
bgFile = "Interface\\Buttons\\WHITE8X8",
edgeFile = "Interface\\Buttons\\WHITE8X8",
tile = false, tileSize = 0, edgeSize = 1,
insets = { left = 1, right = 1, top = 1, bottom = 1 }
})
end
local A = SFrames.ActiveTheme
if A and A.panelBg then
bd:SetBackdropColor(A.panelBg[1], A.panelBg[2], A.panelBg[3], A.panelBg[4] or 0.9)
bd:SetBackdropBorderColor(A.panelBorder[1], A.panelBorder[2], A.panelBorder[3], A.panelBorder[4] or 1)
else
bd:SetBackdropColor(0.1, 0.1, 0.1, 0.9)
bd:SetBackdropBorderColor(0, 0, 0, 1)
end
local icon = btn.sfIcon
if icon then
icon:ClearAllPoints()
icon:SetPoint("TOPLEFT", btn, "TOPLEFT", inset, -inset)
icon:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -inset, inset)
end
if btn.sfCdOverlay then
btn.sfCdOverlay:ClearAllPoints()
btn.sfCdOverlay:SetPoint("TOPLEFT", btn, "TOPLEFT", inset, -inset)
btn.sfCdOverlay:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -inset, inset)
end
if btn.sfRangeOverlay then
btn.sfRangeOverlay:ClearAllPoints()
btn.sfRangeOverlay:SetPoint("TOPLEFT", btn, "TOPLEFT", inset, -inset)
btn.sfRangeOverlay:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -inset, inset)
end
if innerShadow then
if not btn.sfInnerShadow then CreateInnerShadow(btn) end
local s = btn.sfInnerShadow
s.top:ClearAllPoints()
s.top:SetPoint("TOPLEFT", btn, "TOPLEFT", inset, -inset)
s.top:SetPoint("TOPRIGHT", btn, "TOPRIGHT", -inset, -inset)
s.bottom:ClearAllPoints()
s.bottom:SetPoint("BOTTOMLEFT", btn, "BOTTOMLEFT", inset, inset)
s.bottom:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -inset, inset)
s.left:ClearAllPoints()
s.left:SetPoint("TOPLEFT", btn, "TOPLEFT", inset, -inset)
s.left:SetPoint("BOTTOMLEFT", btn, "BOTTOMLEFT", inset, inset)
s.right:ClearAllPoints()
s.right:SetPoint("TOPRIGHT", btn, "TOPRIGHT", -inset, -inset)
s.right:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -inset, inset)
s.top:Show(); s.bottom:Show(); s.left:Show(); s.right:Show()
else
if btn.sfInnerShadow then
local s = btn.sfInnerShadow
s.top:Hide(); s.bottom:Hide(); s.left:Hide(); s.right:Hide()
end
end
end
--------------------------------------------------------------------------------
-- Single-button refresh helpers
--------------------------------------------------------------------------------
local function RefreshButtonIcon(btn)
local slot = btn.sfActionSlot
if not slot then return end
if HasAction(slot) then
local tex = GetActionTexture(slot)
btn.sfIcon:SetTexture(tex)
btn.sfIcon:Show()
btn.sfIcon:SetVertexColor(1, 1, 1, 1)
btn:SetAlpha(1)
else
btn.sfIcon:SetTexture(nil)
btn.sfIcon:Hide()
end
end
local function RefreshButtonCooldown(btn)
local slot = btn.sfActionSlot
if not slot or not HasAction(slot) then
if btn.sfCdOverlay then btn.sfCdOverlay:Hide() end
if btn.sfCdText then btn.sfCdText:SetText("") end
btn.sfCdStart = 0
btn.sfCdDuration = 0
return
end
local start, duration, enable = GetActionCooldown(slot)
if not start or not duration or duration == 0 or enable == 0 then
if btn.sfCdOverlay then btn.sfCdOverlay:Hide() end
if btn.sfCdText then btn.sfCdText:SetText("") end
btn.sfCdStart = 0
btn.sfCdDuration = 0
return
end
btn.sfCdStart = start
btn.sfCdDuration = duration
local now = GetTime()
local remaining = (start + duration) - now
if remaining > 0 then
if btn.sfCdOverlay then btn.sfCdOverlay:Show() end
if btn.sfCdText then
if remaining >= 60 then
btn.sfCdText:SetText(math.floor(remaining / 60) .. "m")
else
btn.sfCdText:SetText(math.floor(remaining + 0.5) .. "")
end
end
else
if btn.sfCdOverlay then btn.sfCdOverlay:Hide() end
if btn.sfCdText then btn.sfCdText:SetText("") end
btn.sfCdStart = 0
btn.sfCdDuration = 0
end
end
local function RefreshButtonUsable(btn)
local slot = btn.sfActionSlot
if not slot or not HasAction(slot) then return end
local isUsable, notEnoughMana = IsUsableAction(slot)
if isUsable then
btn.sfIcon:SetVertexColor(1, 1, 1, 1)
elseif notEnoughMana then
btn.sfIcon:SetVertexColor(0.2, 0.2, 0.8, 1)
else
btn.sfIcon:SetVertexColor(0.4, 0.4, 0.4, 1)
end
end
local function RefreshButtonCount(btn)
local slot = btn.sfActionSlot
if not slot or not HasAction(slot) then
btn.sfCount:SetText("")
return
end
local count = GetActionCount(slot)
if count and count > 0 then
btn.sfCount:SetText(tostring(count))
else
btn.sfCount:SetText("")
end
end
local function RefreshButtonRange(btn)
local slot = btn.sfActionSlot
if not slot or not HasAction(slot) then
if btn.sfRangeOverlay then btn.sfRangeOverlay:Hide() end
return
end
local inRange = IsActionInRange(slot)
if not btn.sfRangeOverlay then
local inset = btn.sfIconInset or 2
local ov = btn:CreateTexture(nil, "OVERLAY")
ov:SetTexture("Interface\\Buttons\\WHITE8X8")
ov:SetPoint("TOPLEFT", btn, "TOPLEFT", inset, -inset)
ov:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -inset, inset)
ov:SetVertexColor(1.0, 0.1, 0.1, 0.35)
ov:Hide()
btn.sfRangeOverlay = ov
end
if inRange == 0 then
btn.sfRangeOverlay:Show()
else
btn.sfRangeOverlay:Hide()
end
end
local function RefreshButtonState(btn)
local slot = btn.sfActionSlot
if not slot or not HasAction(slot) then return end
if IsCurrentAction(slot) then
if btn.sfBackdrop then
btn.sfBackdrop:SetBackdropBorderColor(1, 1, 1, 0.8)
end
else
local A = SFrames.ActiveTheme
if btn.sfBackdrop then
if A and A.panelBorder then
btn.sfBackdrop:SetBackdropBorderColor(A.panelBorder[1], A.panelBorder[2], A.panelBorder[3], A.panelBorder[4] or 1)
else
btn.sfBackdrop:SetBackdropBorderColor(0, 0, 0, 1)
end
end
end
end
local function RefreshButtonAll(btn)
RefreshButtonIcon(btn)
RefreshButtonCooldown(btn)
RefreshButtonUsable(btn)
RefreshButtonCount(btn)
RefreshButtonState(btn)
end
--------------------------------------------------------------------------------
-- Custom action button factory
--------------------------------------------------------------------------------
local btnIndex = 0
local function CreateExtraButton(parent)
btnIndex = btnIndex + 1
local name = "SFramesExtraBarButton" .. btnIndex
local btn = CreateFrame("Button", name, parent)
btn:SetWidth(36)
btn:SetHeight(36)
btn:RegisterForClicks("LeftButtonUp", "RightButtonUp")
btn:RegisterForDrag("LeftButton")
CreateBackdropFor(btn)
local icon = btn:CreateTexture(name .. "Icon", "ARTWORK")
icon:SetPoint("TOPLEFT", btn, "TOPLEFT", 2, -2)
icon:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -2, 2)
icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
btn.sfIcon = icon
local cdOverlay = btn:CreateTexture(nil, "OVERLAY")
cdOverlay:SetTexture("Interface\\Buttons\\WHITE8X8")
cdOverlay:SetAllPoints(icon)
cdOverlay:SetVertexColor(0, 0, 0, 0.6)
cdOverlay:Hide()
btn.sfCdOverlay = cdOverlay
local cdText = btn:CreateFontString(nil, "OVERLAY")
cdText:SetFont(SFrames:GetFont(), 12, "OUTLINE")
cdText:SetPoint("CENTER", btn, "CENTER", 0, 0)
cdText:SetTextColor(1, 1, 0.2)
cdText:SetText("")
btn.sfCdText = cdText
btn.sfCdStart = 0
btn.sfCdDuration = 0
local font = SFrames:GetFont()
local hotkey = btn:CreateFontString(name .. "HotKey", "OVERLAY")
hotkey:SetFont(font, 9, "OUTLINE")
hotkey:SetPoint("TOPRIGHT", btn, "TOPRIGHT", -2, -2)
hotkey:SetJustifyH("RIGHT")
btn.sfHotKey = hotkey
local count = btn:CreateFontString(name .. "Count", "OVERLAY")
count:SetFont(font, 9, "OUTLINE")
count:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -2, 2)
count:SetJustifyH("RIGHT")
btn.sfCount = count
-- Highlight texture
local hl = btn:CreateTexture(nil, "HIGHLIGHT")
hl:SetTexture("Interface\\Buttons\\ButtonHilight-Square")
hl:SetBlendMode("ADD")
hl:SetPoint("TOPLEFT", btn, "TOPLEFT", 2, -2)
hl:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -2, 2)
hl:SetAlpha(0.3)
-- Pushed texture overlay
local pushed = btn:CreateTexture(nil, "OVERLAY")
pushed:SetTexture("Interface\\Buttons\\WHITE8X8")
pushed:SetPoint("TOPLEFT", btn, "TOPLEFT", 2, -2)
pushed:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -2, 2)
pushed:SetVertexColor(1, 1, 1, 0.15)
pushed:Hide()
btn.sfPushed = pushed
btn.sfActionSlot = nil
btn:SetScript("OnClick", function()
local slot = this.sfActionSlot
if not slot then return end
if arg1 == "LeftButton" then
if IsShiftKeyDown() and ChatFrameEditBox and ChatFrameEditBox:IsVisible() then
-- Shift-click: link to chat (fallback: pickup)
pcall(PickupAction, slot)
else
UseAction(slot, 0, 1)
end
elseif arg1 == "RightButton" then
UseAction(slot, 0, 1)
end
RefreshButtonAll(this)
end)
btn:SetScript("OnDragStart", function()
local slot = this.sfActionSlot
if slot then
pcall(PickupAction, slot)
RefreshButtonAll(this)
end
end)
btn:SetScript("OnReceiveDrag", function()
local slot = this.sfActionSlot
if slot then
pcall(PlaceAction, slot)
RefreshButtonAll(this)
end
end)
btn:SetScript("OnEnter", function()
local slot = this.sfActionSlot
if slot and HasAction(slot) then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetAction(slot)
GameTooltip:Show()
end
end)
btn:SetScript("OnLeave", function()
GameTooltip:Hide()
end)
btn:SetScript("OnMouseDown", function()
if this.sfPushed then this.sfPushed:Show() end
end)
btn:SetScript("OnMouseUp", function()
if this.sfPushed then this.sfPushed:Hide() end
end)
btn:Hide()
return btn
end
--------------------------------------------------------------------------------
-- Create all buttons once
--------------------------------------------------------------------------------
function EB:CreateButtons()
local db = self:GetDB()
self.holder = CreateFrame("Frame", "SFramesExtraBarHolder", UIParent)
self.holder:SetWidth(200)
self.holder:SetHeight(40)
local pos = SFramesDB and SFramesDB.Positions and SFramesDB.Positions["ExtraBar"]
if pos and pos.point and pos.relativePoint then
self.holder:SetPoint(pos.point, UIParent, pos.relativePoint, pos.xOfs or 0, pos.yOfs or 0)
else
self.holder:SetPoint("CENTER", UIParent, "CENTER", 0, -200)
end
self.buttons = {}
for i = 1, MAX_BUTTONS do
local btn = CreateExtraButton(self.holder)
table.insert(self.buttons, btn)
end
if SFrames.ActionBars and SFrames.ActionBars.RegisterBindButton then
for i = 1, MAX_BUTTONS do
local bname = self.buttons[i]:GetName()
SFrames.ActionBars:RegisterBindButton(bname, "NANAMI_EXTRABAR" .. i)
end
end
end
--------------------------------------------------------------------------------
-- Apply configuration
--------------------------------------------------------------------------------
function EB:ApplyConfig()
if not self.holder then return end
local db = self:GetDB()
if not db.enable then
self.holder:Hide()
return
end
local count = math.min(db.buttonCount or 12, MAX_BUTTONS)
local perRow = db.perRow or 12
local size = db.buttonSize or 36
local gap = db.buttonGap or 2
local startSlot = db.startSlot or 73
-- Assign action slots
for i = 1, MAX_BUTTONS do
local btn = self.buttons[i]
btn.sfActionSlot = startSlot + i - 1
end
-- Layout
LayoutGrid(self.buttons, self.holder, size, gap, perRow, count)
-- Alignment via anchor
local positions = SFramesDB and SFramesDB.Positions
local pos = positions and positions["ExtraBar"]
if not (pos and pos.point and pos.relativePoint) then
self.holder:ClearAllPoints()
local align = db.align or "center"
if align == "left" then
self.holder:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", 20, 200)
elseif align == "right" then
self.holder:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -20, 200)
else
self.holder:SetPoint("CENTER", UIParent, "CENTER", 0, -200)
end
end
-- Alpha
local alpha = db.alpha or 1
if alpha < 0.1 then alpha = 0.1 end
if alpha > 1 then alpha = 1 end
self.holder:SetAlpha(alpha)
-- Scale (inherit from main action bars if available)
local abDb = SFrames.ActionBars and SFrames.ActionBars.GetDB and SFrames.ActionBars:GetDB()
local scale = abDb and abDb.scale or 1.0
self.holder:SetScale(scale)
-- Button visuals
local isRounded = db.buttonRounded
local isShadow = db.buttonInnerShadow
local showHK = db.showHotkey
local showCt = db.showCount
local font = SFrames:GetFont()
local fontSize = math.max(6, math.floor(size * 0.25 + 0.5))
for i = 1, count do
local btn = self.buttons[i]
ApplyButtonVisuals(btn, isRounded, isShadow)
if btn.sfHotKey then
btn.sfHotKey:SetFont(font, fontSize, "OUTLINE")
if showHK then btn.sfHotKey:Show() else btn.sfHotKey:Hide() end
end
if btn.sfCount then
btn.sfCount:SetFont(font, fontSize, "OUTLINE")
if showCt then btn.sfCount:Show() else btn.sfCount:Hide() end
end
if btn.sfCdText then
local cdFontSize = math.max(8, math.floor(size * 0.35 + 0.5))
btn.sfCdText:SetFont(font, cdFontSize, "OUTLINE")
end
RefreshButtonAll(btn)
end
self.holder:Show()
-- Update mover if in layout mode
if SFrames.Movers and SFrames.Movers:IsLayoutMode() then
SFrames.Movers:SyncMoverToFrame("ExtraBar")
end
end
--------------------------------------------------------------------------------
-- Refresh all visible buttons
--------------------------------------------------------------------------------
function EB:RefreshAll()
if not self.buttons then return end
local db = self:GetDB()
if not db.enable then return end
local count = math.min(db.buttonCount or 12, MAX_BUTTONS)
for i = 1, count do
RefreshButtonAll(self.buttons[i])
end
end
function EB:RefreshCooldowns()
if not self.buttons then return end
local db = self:GetDB()
if not db.enable then return end
local count = math.min(db.buttonCount or 12, MAX_BUTTONS)
for i = 1, count do
RefreshButtonCooldown(self.buttons[i])
end
end
function EB:RefreshUsable()
if not self.buttons then return end
local db = self:GetDB()
if not db.enable then return end
local count = math.min(db.buttonCount or 12, MAX_BUTTONS)
for i = 1, count do
RefreshButtonUsable(self.buttons[i])
end
end
function EB:RefreshStates()
if not self.buttons then return end
local db = self:GetDB()
if not db.enable then return end
local count = math.min(db.buttonCount or 12, MAX_BUTTONS)
for i = 1, count do
RefreshButtonState(self.buttons[i])
end
end
function EB:RefreshHotkeys()
if not self.buttons then return end
local db = self:GetDB()
if not db.enable then return end
local count = math.min(db.buttonCount or 12, MAX_BUTTONS)
for i = 1, count do
local btn = self.buttons[i]
local cmd = "NANAMI_EXTRABAR" .. i
local hotkey = btn.sfHotKey
if hotkey then
local key1 = GetBindingKey(cmd)
if key1 then
local text = key1
if GetBindingText then
text = GetBindingText(key1, "KEY_", 1) or key1
end
hotkey:SetText(text)
else
hotkey:SetText("")
end
end
end
end
--------------------------------------------------------------------------------
-- OnUpdate poller for cooldown / range / usability
--------------------------------------------------------------------------------
function EB:SetupPoller()
local poller = CreateFrame("Frame", "SFramesExtraBarPoller", UIParent)
poller.timer = 0
self.poller = poller
poller:SetScript("OnUpdate", function()
this.timer = this.timer + arg1
if this.timer < 0.2 then return end
this.timer = 0
local db = EB:GetDB()
if not db.enable then return end
local count = math.min(db.buttonCount or 12, MAX_BUTTONS)
for i = 1, count do
local btn = EB.buttons[i]
if btn and btn:IsShown() then
RefreshButtonCooldown(btn)
RefreshButtonUsable(btn)
RefreshButtonRange(btn)
RefreshButtonState(btn)
end
end
end)
end
--------------------------------------------------------------------------------
-- Initialize
--------------------------------------------------------------------------------
function EB:Initialize()
local db = self:GetDB()
if not db.enable then return end
self:CreateButtons()
self:ApplyConfig()
self:SetupPoller()
-- Events
SFrames:RegisterEvent("ACTIONBAR_SLOT_CHANGED", function()
if not EB.buttons then return end
local db = EB:GetDB()
if not db.enable then return end
local slot = arg1
local startSlot = db.startSlot or 73
local count = math.min(db.buttonCount or 12, MAX_BUTTONS)
if slot then
local idx = slot - startSlot + 1
if idx >= 1 and idx <= count then
RefreshButtonAll(EB.buttons[idx])
end
else
EB:RefreshAll()
end
end)
SFrames:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN", function()
EB:RefreshCooldowns()
end)
SFrames:RegisterEvent("ACTIONBAR_UPDATE_USABLE", function()
EB:RefreshUsable()
end)
SFrames:RegisterEvent("ACTIONBAR_UPDATE_STATE", function()
EB:RefreshStates()
end)
SFrames:RegisterEvent("PLAYER_ENTERING_WORLD", function()
EB:RefreshAll()
EB:RefreshHotkeys()
end)
SFrames:RegisterEvent("UPDATE_BINDINGS", function()
EB:RefreshHotkeys()
end)
-- Register mover
if SFrames.Movers and SFrames.Movers.RegisterMover then
SFrames.Movers:RegisterMover("ExtraBar", self.holder, "额外动作条",
"CENTER", "UIParent", "CENTER", 0, -200)
end
end
--------------------------------------------------------------------------------
-- Late enable: called from ConfigUI when user toggles enable on
--------------------------------------------------------------------------------
function EB:Enable()
local db = self:GetDB()
db.enable = true
if not self.holder then
self:CreateButtons()
self:SetupPoller()
SFrames:RegisterEvent("ACTIONBAR_SLOT_CHANGED", function()
if not EB.buttons then return end
local db2 = EB:GetDB()
if not db2.enable then return end
local slot = arg1
local startSlot = db2.startSlot or 73
local count = math.min(db2.buttonCount or 12, MAX_BUTTONS)
if slot then
local idx = slot - startSlot + 1
if idx >= 1 and idx <= count then
RefreshButtonAll(EB.buttons[idx])
end
else
EB:RefreshAll()
end
end)
SFrames:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN", function()
EB:RefreshCooldowns()
end)
SFrames:RegisterEvent("ACTIONBAR_UPDATE_USABLE", function()
EB:RefreshUsable()
end)
SFrames:RegisterEvent("ACTIONBAR_UPDATE_STATE", function()
EB:RefreshStates()
end)
SFrames:RegisterEvent("UPDATE_BINDINGS", function()
EB:RefreshHotkeys()
end)
if SFrames.Movers and SFrames.Movers.RegisterMover then
SFrames.Movers:RegisterMover("ExtraBar", self.holder, "额外动作条",
"CENTER", "UIParent", "CENTER", 0, -200)
end
end
self:ApplyConfig()
self:RefreshHotkeys()
end
function EB:Disable()
local db = self:GetDB()
db.enable = false
if self.holder then
self.holder:Hide()
end
if self.holder and SFrames.Movers and SFrames.Movers.IsLayoutMode
and SFrames.Movers:IsLayoutMode() then
pcall(SFrames.Movers.SyncMoverToFrame, SFrames.Movers, "ExtraBar")
end
end
function EB:RunButton(index)
if not self.buttons then return end
local db = self:GetDB()
if not db.enable then return end
if index < 1 or index > math.min(db.buttonCount or 12, MAX_BUTTONS) then return end
local btn = self.buttons[index]
if not btn or not btn:IsVisible() then return end
local slot = btn.sfActionSlot
if slot and HasAction(slot) then
UseAction(slot)
RefreshButtonAll(btn)
end
end