Files
coa-bartender/Bartender4/Options/Bar.lua
T
florian.berthold 3fb81c08a0 fix: enable stance/state bars for CoA custom classes with shapeshift forms
Vanilla Bartender4 assumes only DRUID/WARRIOR/WARLOCK/PRIEST/ROGUE/HERO have
shapeshift forms. CoA custom classes (Witchdoctor, Templar, …) can register
forms late at runtime and aren't in the whitelist, so the stance/state bar
never came up for them.

StanceBar.lua:
  - ApplyConfig() no longer Disable()s the module when GetNumShapeshiftForms()
    is 0 at config time. A disabled module never re-enables on
    UPDATE_SHAPESHIFT_FORMS, so late-registered forms were lost. We now just
    hide the bar frame.
  - Register UPDATE_SHAPESHIFT_FORMS and PLAYER_ENTERING_WORLD on the module
    itself and re-Enable() / show the bar when forms appear after the fact.

Options/Bar.lua:
  - The 'Hide in Stance/Form' visibility option was gated by a hard-coded
    stanceClasses whitelist. Add an OR-fallback on GetNumShapeshiftForms() > 0
    so CoA classes with forms get the UI.

StateBar.lua:
  - DefaultStanceMap only had vanilla entries. For unknown classes with live
    forms, synthesise a generic { id="formN", index=N } map at runtime so
    UpdateStates() can wire stance-based action bar swaps.
2026-05-24 17:39:15 +02:00

479 lines
13 KiB
Lua

--[[
Copyright (c) 2009, Hendrik "Nevcairiel" Leppkes < h.leppkes at gmail dot com >
All rights reserved.
]]
local L = LibStub("AceLocale-3.0"):GetLocale("Bartender4")
local Bar = Bartender4.Bar.prototype
--[[===================================================================================
Bar Options
===================================================================================]]--
local barregistry = Bartender4.Bar.barregistry
local function round(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
-- option utilty functions
local optGetter, optSetter, visibilityGetter, visibilitySetter, customEnabled, customDisabled, customCopy, clickThroughVis, posGet, posSet, centerHorz, centerVert, resetPos
do
local getBar, optionMap, callFunc
-- maps option keys to function names
optionMap = {
alpha = "ConfigAlpha",
scale = "ConfigScale",
fadeout = "FadeOut",
fadeoutalpha = "FadeOutAlpha",
fadeoutdelay = "FadeOutDelay",
clickthrough = "ClickThrough",
}
-- retrieves a valid bar object from the barregistry table
function getBar(id)
local bar = barregistry[tostring(id)]
assert(bar, ("Invalid bar id in options table. (%s)"):format(id))
return bar
end
-- calls a function on the bar
function callFunc(bar, type, option, ...)
local func = type .. (optionMap[option] or option)
assert(bar[func], ("Invalid get/set function %s in bar %s."):format(func, bar.id))
return bar[func](bar, ...)
end
-- universal function to get a option
function optGetter(info)
local bar = getBar(info[2])
local option = info[#info]
return callFunc(bar, "Get", option)
end
-- universal function to set a option
function optSetter(info, ...)
local bar = getBar(info[2])
local option = info[#info]
return callFunc(bar, "Set", option, ...)
end
function visibilityGetter(info, ...)
local bar = getBar(info[2])
local option = info[#info]
return bar:GetVisibilityOption(option, ...)
end
function visibilitySetter(info, ...)
local bar = getBar(info[2])
local option = info[#info]
bar:SetVisibilityOption(option, ...)
end
function customEnabled(info)
local bar = getBar(info[2])
return bar:GetVisibilityOption("custom")
end
function customDisabled(info)
local bar = getBar(info[2])
return not bar:GetVisibilityOption("custom")
end
function customCopy(info)
local bar = getBar(info[2])
bar:CopyCustomConditionals()
end
function clickThroughVis(info)
local bar = getBar(info[2])
return (not bar.ClickThroughSupport)
end
function posGet(info)
local bar = getBar(info[2])
local opt = info.arg or info[#info]
if opt == "x" or opt == "y" then
local v = bar.config.position[opt]
return tostring(round(v, 5))
end
return bar.config.position[opt]
end
function posSet(info, value)
local bar = getBar(info[2])
local opt = info.arg or info[#info]
if opt == "x" or opt == "y" then
value = tonumber(value)
end
bar.config.position[opt] = value
bar:LoadPosition()
end
function centerHorz(info)
local bar = getBar(info[2])
local pos = bar.config.position
local x_mod = (pos.growHorizontal == "RIGHT") and -1 or 1
pos.x = (bar.overlay:GetWidth() / 2) * pos.scale * x_mod
if pos.point == "CENTER" or pos.point == "LEFT" or pos.point == "RIGHT" then -- no special handling
pos.point = "CENTER"
else
pos.point = pos.point:gsub("LEFT", ""):gsub("RIGHT", "")
end
bar:LoadPosition()
end
function centerVert(info)
local bar = getBar(info[2])
local pos = bar.config.position
local y_mod = (pos.growVertical == "DOWN") and 1 or -1
pos.y = (bar.overlay:GetHeight() / 2) * pos.scale * y_mod
if pos.point == "CENTER" or pos.point == "TOP" or pos.point == "BOTTOM" then -- no special handling
pos.point = "CENTER"
else
pos.point = pos.point:gsub("TOP", ""):gsub("BOTTOM", "")
end
bar:LoadPosition()
end
function resetPos(info)
local bar = getBar(info[2])
local pos = bar.config.position
local x_mod = (pos.growHorizontal == "RIGHT") and -1 or 1
local y_mod = (pos.growVertical == "DOWN") and 1 or -1
pos.x = (bar.overlay:GetWidth() / 2) * pos.scale * x_mod
pos.y = (bar.overlay:GetHeight() / 2) * pos.scale * y_mod
pos.point = "CENTER"
bar:LoadPosition()
end
end
local _, class = UnitClass("player")
local stanceClasses = {
DRUID = true,
HERO = true,
WARRIOR = true,
WARLOCK = true,
PRIEST = true,
ROGUE = true,
}
local function getStanceTable()
local tbl = {}
if class ~= "WARRIOR" then
tbl[0] = L["No Stance/Form"]
end
local num = GetNumShapeshiftForms()
for i = 1, num do
tbl[i] = select(2, GetShapeshiftFormInfo(i))
end
-- HACK: Metamorphosis work around, it is on slot 1 in GetShapeshiftFormInfo() but stance:2 is active..
if class == "WARLOCK" and tbl[1] == GetSpellInfo(59672) then
tbl[2], tbl[1] = tbl[1], nil
end
if class == "ROGUE" and tbl[1] == GetSpellInfo(51713) then -- shadow dance hack
tbl[3], tbl[1] = tbl[1], nil
end
return tbl
end
local validAnchors = {
CENTER = "CENTER",
LEFT = "LEFT",
RIGHT = "RIGHT",
TOP = "TOP",
TOPLEFT = "TOPLEFT",
TOPRIGHT = "TOPRIGHT",
BOTTOM = "BOTTOM",
BOTTOMLEFT = "BOTTOMLEFT",
BOTTOMRIGHT = "BOTTOMRIGHT",
}
local options
function Bar:GetOptionObject()
local otbl = {
general = {
type = "group",
cmdInline = true,
name = L["General Settings"],
order = 1,
args = {
styleheader = {
order = 10,
type = "header",
name = L["Bar Style & Layout"],
},
alpha = {
order = 20,
name = L["Alpha"],
desc = L["Configure the alpha of the bar."],
type = "range",
min = 0, max = 1, bigStep = 0.05,
isPercent = true,
get = optGetter,
set = optSetter,
},
scale = {
order = 30,
name = L["Scale"],
desc = L["Configure the scale of the bar."],
type = "range",
min = 0, softMin = .1, softMax = 2, bigStep = 0.05,
get = optGetter,
set = optSetter,
},
clickthrough = {
order = 200,
name = L["Click-Through"],
desc = L["Disable any reaction to mouse events on this bar, making the bar click-through."],
type = "toggle",
get = optGetter,
set = optSetter,
hidden = clickThroughVis,
width = "full",
},
},
},
visibility = {
type = "group",
name = L["Visibility"],
order = 2,
get = visibilityGetter,
set = visibilitySetter,
args = {
info = {
order = 1,
type = "description",
name = L["The bar default is to be visible all the time, you can configure conditions here to control when the bar should be hidden."] .. "\n",
},
fadeout = {
order = 5,
name = L["Fade Out"],
desc = L["Enable the FadeOut mode"],
type = "toggle",
get = optGetter,
set = optSetter,
width = "full",
},
fadeoutalpha = {
order = 6,
name = L["Fade Out Alpha"],
desc = L["Configure the Fade Out Alpha"],
type = "range",
min = 0, max = 1, bigStep = 0.05,
isPercent = true,
get = optGetter,
set = optSetter,
},
fadeoutdelay = {
order = 7,
name = L["Fade Out Delay"],
desc = L["Configure the Fade Out Delay"],
type = "range",
min = 0, softMax = 1, bigStep = 0.01,
get = optGetter,
set = optSetter,
},
fadeNl = {
order = 8,
type = "description",
name = "",
},
always = {
order = 10,
type = "toggle",
name = L["Always Hide"],
desc = L["You can set the bar to be always hidden, if you only wish to access it using key-bindings."],
disabled = customEnabled,
},
possess = {
order = 15,
type = "toggle",
name = L["Hide when Possessing"],
desc = L["Hide this bar when you are possessing a NPC."],
disabled = customEnabled,
},
vehicle = {
order = 16,
type = "toggle",
name = L["Hide on Vehicle"],
desc = L["Hide this bar when you are riding on a vehicle."],
disabled = customEnabled,
},
vehicleui = {
order = 17,
type = "toggle",
name = L["Hide with Vehicle UI"],
desc = L["Hide this bar when the game wants to show a vehicle UI."],
disabled = customEnabled,
},
combat = {
order = 20,
type = "toggle",
name = L["Hide in Combat"],
desc = L["This bar will be hidden once you enter combat."],
disabled = customEnabled,
},
nocombat = {
order = 21,
type = "toggle",
name = L["Hide out of Combat"],
desc = L["This bar will be hidden whenever you are not in combat."],
disabled = customEnabled,
},
pet = {
order = 30,
type = "toggle",
name = L["Hide with pet"],
desc = L["Hide this bar when you have a pet."],
disabled = customEnabled,
},
nopet = {
order = 31,
type = "toggle",
name = L["Hide without pet"],
desc = L["Hide this bar when you have no pet."],
disabled = customEnabled,
},
stance = {
order = 50,
type = "multiselect",
name = L["Hide in Stance/Form"],
desc = L["Hide this bar in a specific Stance or Form."],
values = getStanceTable,
-- CoA: custom classes (Witchdoctor, Templar, …) may have forms
-- but aren't in the vanilla stanceClasses whitelist. Show the
-- option whenever the player currently has any form available.
hidden = function() return (not (stanceClasses[class] or GetNumShapeshiftForms() > 0)) end,
disabled = customEnabled,
},
customNl = {
order = 98,
type = "description",
name = "\n",
},
customHeader = {
order = 99,
type = "header",
name = L["Custom Conditionals"],
},
custom = {
order = 100,
type = "toggle",
name = L["Use Custom Condition"],
desc = L["Enable the use of a custom condition, disabling all of the above."],
},
customCopy = {
order = 101,
type = "execute",
name = L["Copy Conditionals"],
desc = L["Create a copy of the auto-generated conditionals in the custom configuration as a base template."],
func = customCopy,
},
customDesc = {
order = 102,
type = "description",
name = L["Note: Enabling Custom Conditionals will disable all of the above settings!"],
},
customdata = {
order = 103,
type = "input",
name = L["Custom Conditionals"],
desc = L["You can use any macro conditionals in the custom string, using \"show\" and \"hide\" as values.\n\nExample: [combat]hide;show"],
width = "full",
multiline = true,
disabled = customDisabled,
},
},
},
position = {
type = "group",
name = L["Positioning"],
order = 20,
args = {
info = {
order = 1,
type = "description",
name = L["The Positioning options here will allow you to position the bar to your liking and with an absolute precision."],
},
point = {
order = 10,
type = "select",
name = L["Anchor"],
desc = L["Change the current anchor point of the bar."],
values = validAnchors,
get = posGet,
set = posSet,
},
scale = {
order = 11,
name = L["Scale"],
desc = L["Configure the scale of the bar."],
type = "range",
min = 0, softMin = .1, softMax = 2, bigStep = 0.05,
get = optGetter,
set = optSetter,
},
nl1 = {
order = 12,
type = "description",
name = "",
},
x = {
order = 20,
type = "input",
name = L["X Offset"],
desc = L["Offset in X direction (horizontal) from the given anchor point."],
get = posGet,
set = posSet,
dialogControl = "NumberEditBox",
},
y = {
order = 21,
type = "input",
name = L["Y Offset"],
desc = L["Offset in Y direction (vertical) from the given anchor point."],
get = posGet,
set = posSet,
dialogControl = "NumberEditBox",
},
nl2 = {
order = 25,
type = "description",
name = "",
},
centerhorz = {
order = 31,
type = "execute",
name = L["Center Horizontally"],
desc = L["Centers the bar horizontally on screen."],
func = centerHorz,
},
centervert = {
order = 31,
type = "execute",
name = L["Center Vertically"],
desc = L["Centers the bar vertically on screen."],
func = centerVert,
},
nl2 = {
order = 35,
type = "description",
name = " ",
},
reset = {
order = 40,
type = "execute",
name = L["Reset Position"],
desc = L["Reset the position of this bar completly if it ended up off-screen and you cannot reach it anymore."],
func = resetPos,
},
},
}
}
return Bartender4:NewOptionObject(otbl)
end