Files
coa-bartender/Bar.lua
T
florian.berthold 57a5cdabdf ascension: 4.4.2 → vendored 4.4.2-2-g3b02ee4 (in-game AddOns dir)
Imported from /srv/add01/wow-ascension/Interface/AddOns/Bartender4 — the
build Ascension's WotLK 3.3.5 client ships.

Single vendored drop: Ascension's build process bundles their custom
patches with the standard CurseForge packager output (embedded libs),
and the individual patches aren't published separately.

Net delta vs Nevcairiel 4.4.2, excluding bundled libs and CRLF
normalization: 21 files, 2213+/52- — the Ascension-specific
adaptations for WotLK 3.3.5 hero classes / custom action systems.

License: All rights reserved (per .toc).
2026-05-08 03:45:58 +02:00

520 lines
13 KiB
Lua

--[[
Copyright (c) 2009, Hendrik "Nevcairiel" Leppkes < h.leppkes at gmail dot com >
All rights reserved.
]]
--[[
Generic Bar Frame Template
]]
local Bar = CreateFrame("Button")
local Bar_MT = {__index = Bar}
local table_concat, table_insert = table.concat, table.insert
--[[===================================================================================
Universal Bar Contructor
===================================================================================]]--
local defaults = {
alpha = 1,
fadeout = false,
fadeoutalpha = 0.1,
fadeoutdelay = 0.2,
visibility = {
vehicleui = true,
stance = {},
},
position = {
scale = 1,
growVertical = "DOWN",
growHorizontal = "RIGHT",
},
clickthrough = false,
}
local Sticky = LibStub("LibSimpleSticky-1.0")
local LibWin = LibStub("LibWindow-1.1")
local snapBars = { WorldFrame, UIParent }
local barOnEnter, barOnLeave, barOnDragStart, barOnDragStop, barOnClick, barOnUpdateFunc, barOnAttributeChanged
do
function barOnEnter(self)
if not self:GetParent().isMoving then
self:SetBackdropBorderColor(0.5, 0.5, 0, 1)
end
end
function barOnLeave(self)
self:SetBackdropBorderColor(0, 0, 0, 0)
end
local function barReAnchorForSnap(self)
local x,y,anchor = nil, nil, self:GetAnchor()
x = (self.config.position.growHorizontal == "RIGHT") and self:GetLeft() or self:GetRight()
y = (self.config.position.growVertical == "DOWN") and self:GetTop() or self:GetBottom()
self:ClearSetPoint(anchor, UIParent, "BOTTOMLEFT", x, y)
self:SetWidth(self.overlay:GetWidth())
self:SetHeight(self.overlay:GetHeight())
end
local function barReAnchorNormal(self)
local x,y,anchor = nil, nil, self:GetAnchor()
x = (self.config.position.growHorizontal == "RIGHT") and self:GetLeft() or self:GetRight()
y = (self.config.position.growVertical == "DOWN") and self:GetTop() or self:GetBottom()
self:ClearSetPoint(anchor, UIParent, "BOTTOMLEFT", x, y)
self:SetWidth(1)
self:SetHeight(1)
end
function barOnDragStart(self)
local parent = self:GetParent()
if Bartender4.db.profile.snapping then
local offset = 8 - (parent.config.padding or 0)
-- we need to re-anchor the bar and set its proper width for snaping to work properly
barReAnchorForSnap(parent)
Sticky:StartMoving(parent, snapBars, offset, offset, offset, offset)
else
parent:StartMoving()
end
self:SetBackdropBorderColor(0, 0, 0, 0)
parent.isMoving = true
end
function barOnDragStop(self)
local parent = self:GetParent()
if parent.isMoving then
if Bartender4.db.profile.snapping then
local sticky, stickTo = Sticky:StopMoving(parent)
barReAnchorNormal(parent)
--Bartender4:Print(sticky, stickTo and stickTo:GetName() or nil)
else
parent:StopMovingOrSizing()
end
parent:SavePosition()
parent.isMoving = nil
end
end
function barOnClick(self)
-- TODO: Hide/Show bar on Click
-- TODO: Once dropdown config is stable, show dropdown on rightclick
end
function barOnUpdateFunc(self, elapsed)
self.elapsed = self.elapsed + elapsed
if self.elapsed > self.config.fadeoutdelay then
self:ControlFadeOut(self.elapsed)
self.elapsed = 0
end
end
function barOnAttributeChanged(self, attribute, value)
if attribute == "fade" then
if value then
self:SetScript("OnUpdate", barOnUpdateFunc)
self:ControlFadeOut()
else
self:SetScript("OnUpdate", nil)
self.faded = nil
self:SetConfigAlpha()
end
end
end
end
local barregistry = {}
Bartender4.Bar = {}
Bartender4.Bar.defaults = defaults
Bartender4.Bar.prototype = Bar
Bartender4.Bar.barregistry = barregistry
function Bartender4.Bar:Create(id, config, name)
id = tostring(id)
assert(not barregistry[id], "duplicated entry in barregistry.")
local bar = setmetatable(CreateFrame("Frame", ("BT4Bar%s"):format(id), UIParent, "SecureHandlerStateTemplate"), Bar_MT)
barregistry[id] = bar
bar.id = id
bar.name = name or id
bar.config = config
bar:SetMovable(true)
bar:HookScript("OnAttributeChanged", barOnAttributeChanged)
bar:SetWidth(1)
bar:SetHeight(1)
local overlay = CreateFrame("Button", bar:GetName() .. "Overlay", bar)
bar.overlay = overlay
overlay.bar = bar
table_insert(snapBars, overlay)
overlay:EnableMouse(true)
overlay:RegisterForDrag("LeftButton")
overlay:RegisterForClicks("LeftButtonUp")
overlay:SetBackdrop({
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
tile = true,
tileSize = 16,
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
edgeSize = 16,
insets = {left = 5, right = 3, top = 3, bottom = 5}
})
overlay:SetBackdropColor(0, 1, 0, 0.5)
overlay:SetBackdropBorderColor(0.5, 0.5, 0, 0)
overlay.Text = overlay:CreateFontString(nil, "ARTWORK")
overlay.Text:SetFontObject(GameFontNormal)
overlay.Text:SetText(name)
overlay.Text:Show()
overlay.Text:ClearAllPoints()
overlay.Text:SetPoint("CENTER", overlay, "CENTER")
overlay:SetScript("OnEnter", barOnEnter)
overlay:SetScript("OnLeave", barOnLeave)
overlay:SetScript("OnDragStart", barOnDragStart)
overlay:SetScript("OnDragStop", barOnDragStop)
overlay:SetScript("OnClick", barOnClick)
overlay:SetFrameLevel(bar:GetFrameLevel() + 10)
bar:AnchorOverlay()
overlay:Hide()
bar.elapsed = 0
bar.hidedriver = {}
return bar
end
function Bartender4.Bar:GetAll()
return pairs(barregistry)
end
function Bartender4.Bar:ForAll(method, ...)
for _,bar in self:GetAll() do
local func = bar[method]
if func then
func(bar, ...)
end
end
end
--[[===================================================================================
Universal Bar Prototype
===================================================================================]]--
Bar.BT4BarType = "Bar"
function Bar:ApplyConfig(config)
if config then
self.config = config
end
LibWin.RegisterConfig(self, self.config.position)
self:UpgradeConfig()
if self.disabled then return end
if Bartender4.Locked then
self:Lock()
else
self:Unlock()
end
self:LoadPosition()
self:SetConfigScale()
self:SetConfigAlpha()
self:SetClickThrough()
self:InitVisibilityDriver()
end
function Bar:GetAnchor()
return ((self.config.position.growVertical == "DOWN") and "TOP" or "BOTTOM") .. ((self.config.position.growHorizontal == "RIGHT") and "LEFT" or "RIGHT")
end
function Bar:AnchorOverlay()
self.overlay:ClearAllPoints()
local anchor = self:GetAnchor()
self.overlay:SetPoint(anchor, self, anchor)
end
function Bar:UpgradeConfig()
local version = self.config.version or 1
if version < 2 then
-- LibWindow migration, move scale into position
if self.config.scale then
self.config.position.scale = self.config.scale
self.config.scale = nil
end
-- LibWindow migration, update position data
do
local pos = self.config.position
self:SetScale(pos.scale)
local x, y, s = pos.x, pos.y, self:GetEffectiveScale()
local point, relPoint = pos.point, pos.relPoint
if x and y and point and relPoint then
x, y = x/s, y/s
self:ClearSetPoint(point, UIParent, relPoint, x, y)
self:SavePosition()
pos.relPoint = nil
end
end
end
if version < 3 then
-- Size adjustment is done in first SetSize
self.needSizeFix = true
end
self.config.version = Bartender4.CONFIG_VERSION
end
function Bar:Unlock()
if self.disabled or self.unlocked then return end
self.unlocked = true
self:DisableVisibilityDriver()
self:Show()
self.overlay:Show()
end
function Bar:Lock()
if self.disabled or not self.unlocked then return end
self.unlocked = nil
self:StopDragging()
self:ApplyVisibilityDriver()
self.overlay:Hide()
end
function Bar:StopDragging()
barOnDragStop(self.overlay)
end
function Bar:LoadPosition()
LibWin.RestorePosition(self)
end
function Bar:SavePosition()
LibWin.SavePosition(self)
end
function Bar:SetSize(width, height)
self.overlay:SetWidth(width)
self.overlay:SetHeight(height or width)
if self.needSizeFix then
self:SetWidth(width)
self:SetHeight(height or width)
local x, y = self:GetLeft(), self:GetTop()
self:ClearSetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
self:SetWidth(1)
self:SetHeight(1)
self:SavePosition()
self.needSizeFix = nil
end
end
function Bar:GetConfigAlpha()
return self.config.alpha
end
function Bar:SetConfigAlpha(alpha)
if alpha then
self.config.alpha = alpha
end
if not self.faded then
self:SetAlpha(self.config.alpha)
end
end
function Bar:GetConfigScale()
return self.config.position.scale
end
function Bar:SetConfigScale(scale)
if scale then
LibWin.SetScale(self, scale)
end
end
function Bar:GetClickThrough()
return self.config.clickthrough
end
function Bar:SetClickThrough(click)
if click ~= nil then
self.config.clickthrough = click
end
if self.ControlClickThrough then
self:ControlClickThrough()
end
end
function Bar:GetFadeOut()
return self.config.fadeout
end
function Bar:SetFadeOut(fadeout)
if fadeout ~= nil then
self.config.fadeout = fadeout
self:InitVisibilityDriver()
end
end
function Bar:GetFadeOutAlpha()
return self.config.fadeoutalpha
end
function Bar:SetFadeOutAlpha(fadealpha)
if fadealpha ~= nil then
self.config.fadeoutalpha = fadealpha
end
if self.faded then
self:SetAlpha(self.config.fadeoutalpha)
end
end
function Bar:GetFadeOutDelay()
return self.config.fadeoutdelay
end
function Bar:SetFadeOutDelay(delay)
if delay ~= nil then
self.config.fadeoutdelay = delay
end
end
function Bar:ControlFadeOut()
if self.faded and MouseIsOver(self.overlay) then
self:SetAlpha(self.config.alpha)
self.faded = nil
elseif not self.faded and not MouseIsOver(self.overlay) then
local fade = self:GetAttribute("fade")
if tonumber(fade) then
fade = min(max(fade, 0), 100) / 100
self:SetAlpha(fade)
else
self:SetAlpha(self.config.fadeoutalpha or 0)
end
self.faded = true
end
end
local directVisCond = {
pet = true,
nopet = true,
combat = true,
nocombat = true,
mounted = true,
}
function Bar:InitVisibilityDriver(returnOnly)
local tmpDriver
if returnOnly then
tmpDriver = self.hidedriver
else
UnregisterStateDriver(self, 'vis')
end
self.hidedriver = {}
self:SetAttribute("_onstate-vis", [[
if not newstate then return end
if newstate == "show" then
self:Show()
self:SetAttribute("fade", false)
elseif strsub(newstate, 1, 4) == "fade" then
self:Show()
self:SetAttribute("fade", (newstate == "fade") and true or strsub(newstate, 6))
elseif newstate == "hide" then
self:Hide()
end
]])
if self.config.visibility.custom and not returnOnly then
table_insert(self.hidedriver, self.config.visibility.customdata or "")
else
for key, value in pairs(self.config.visibility) do
if value then
if key == "always" then
table_insert(self.hidedriver, "hide")
elseif key == "possess" then
table_insert(self.hidedriver, "[bonusbar:5]hide")
elseif key == "vehicleui" then
table_insert(self.hidedriver, "[vehicleui]hide")
elseif key == "vehicle" then
table_insert(self.hidedriver, "[target=vehicle,exists]hide")
elseif directVisCond[key] then
table_insert(self.hidedriver, ("[%s]hide"):format(key))
elseif key == "stance" then
for k,v in pairs(value) do
if v then
table_insert(self.hidedriver, ("[stance:%d]hide"):format(k))
end
end
elseif key == "custom" or key == "customdata" then
-- do nothing
else
Bartender4:Print("Invalid visibility state: "..key)
end
end
end
end
table_insert(self.hidedriver, self.config.fadeout and "fade" or "show")
if not returnOnly then
self:ApplyVisibilityDriver()
else
self.hidedriver, tmpDriver = tmpDriver, self.hidedriver
return table_concat(tmpDriver, ";")
end
end
function Bar:ApplyVisibilityDriver()
if self.unlocked then return end
-- default state is shown
local driver = table_concat(self.hidedriver, ";")
RegisterStateDriver(self, "vis", driver)
end
function Bar:DisableVisibilityDriver()
UnregisterStateDriver(self, "vis")
self:SetAttribute("state-vis", "show")
self:Show()
end
function Bar:GetVisibilityOption(option, index)
if option == "stance" then
return self.config.visibility.stance[index]
else
return self.config.visibility[option]
end
end
function Bar:SetVisibilityOption(option, value, arg)
if option == "stance" then
self.config.visibility.stance[value] = arg
else
self.config.visibility[option] = value
end
self:InitVisibilityDriver()
end
function Bar:CopyCustomConditionals()
self.config.visibility.customdata = self:InitVisibilityDriver(true)
self:InitVisibilityDriver()
end
function Bar:Enable()
if not self.disabled then return end
self.disabled = nil
end
function Bar:Disable()
if self.disabled then return end
self:Lock()
self.disabled = true
self:UnregisterAllEvents()
self:DisableVisibilityDriver()
self:SetAttribute("state-vis", nil)
self:Hide()
end
--[[
Lazyness functions
]]
function Bar:ClearSetPoint(...)
self:ClearAllPoints()
self:SetPoint(...)
end