BulwarkFrame v0.3.0

This commit is contained in:
2026-08-30 15:37:07 +02:00
parent 2b6de41d9a
commit dca4228c85
5 changed files with 201 additions and 10 deletions
+146 -3
View File
@@ -14,7 +14,7 @@ local PANEL_W = 430
-- Content width of one column: panel minus both outer margins minus the gutter, halved.
local COL_W = (PANEL_W - 48 - 12) / 2
local panel = nil
local cbIndex, slIndex, swIndex = 0, 0, 0
local cbIndex, slIndex, swIndex, ebIndex = 0, 0, 0, 0
local refreshers = {}
local function db() return BulwarkFrameDB end
@@ -81,6 +81,8 @@ local function CreateCheckbox(parent, label, tip, getter, setter)
local lbl = getglobal(name .. "Text")
if lbl then lbl:SetText(label); ApplyFont(lbl) end
cb.bfSet = setter
cb.bfLabel = label -- scratch field for the offline stub; the real client's own label
-- text lives in the $parentText template region instead.
cb:SetScript("OnClick", function()
this.bfSet(this:GetChecked() == 1)
Applied()
@@ -188,6 +190,56 @@ local function CreateSwatch(parent, label, key, tip)
return holder
end
-- A numeric edit box: a label above a small InputBoxTemplate field. Used for the two spell ids,
-- which are not on any slider scale -- typing the exact id is the only sane input for one.
-- Applies on Enter or on losing focus (tabbing/clicking away), the same "commit, don't live-type"
-- behaviour InputBoxTemplate users get everywhere else in the default UI. An unparsable entry is
-- reverted to the current stored value rather than silently written as nil.
local function CreateEditBox(parent, label, tip, getter, setter)
ebIndex = ebIndex + 1
local name = "BulwarkFrameOptEdit" .. ebIndex
local holder = CreateFrame("Frame", name .. "Holder", parent)
holder:SetWidth(COL_W)
holder:SetHeight(34)
local lbl = holder:CreateFontString(name .. "Label", "OVERLAY", "GameFontNormalSmall")
lbl:SetPoint("TOPLEFT", holder, "TOPLEFT", 0, 0)
lbl:SetJustifyH("LEFT")
lbl:SetText(label)
ApplyFont(lbl, 11)
local eb = CreateFrame("EditBox", name, holder, "InputBoxTemplate")
eb:SetWidth(90)
eb:SetHeight(18)
eb:SetAutoFocus(false)
eb:SetMaxLetters(6)
if eb.SetNumeric then eb:SetNumeric(true) end
eb:SetPoint("TOPLEFT", holder, "TOPLEFT", 4, -16)
local function commit()
local v = tonumber(eb:GetText())
if v then
eb.bfSet(math.floor(v))
else
eb:SetText(tostring(getter()))
end
eb:ClearFocus()
Applied()
end
eb.bfSet = setter
eb:SetScript("OnEnterPressed", commit)
eb:SetScript("OnEscapePressed", function() eb:SetText(tostring(getter())); eb:ClearFocus() end)
eb:SetScript("OnEditFocusLost", commit)
-- No AddRowHover here: an overlay button covering the row would sit above the edit box and
-- eat the click meant to focus it. The tooltip is on the field and the label only.
AddTooltip(eb, tip)
holder:EnableMouse(true)
AddTooltip(holder, tip)
table.insert(refreshers, function() eb:SetText(tostring(getter())) end)
return holder
end
local function CreateButton(parent, label, tip, onClick)
local b = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
b:SetWidth(110)
@@ -333,6 +385,12 @@ local function BuildPanel()
function(v) db().swingHeight = math.floor(v) end)
sliderL(swingH)
local spacing = CreateSlider(panel, "Bar spacing", 0, 10, 1, "Bar spacing: %d px",
"Vertical gap between the threshold bar, the expiry bar, and the swing line.",
function() return db().spacing end,
function(v) db().spacing = math.floor(v) end)
sliderL(spacing)
-- right column: elements, colours, model ----------------------------------------------
local ry = -46
headR("Elements")
@@ -383,7 +441,20 @@ local function BuildPanel()
local e5 = CreateCheckbox(panel, "Expiry text", "Show the remaining seconds as a number.",
function() return db().showExpiryText end,
function(v) db().showExpiryText = v end)
placeR(e5, 40)
placeR(e5, 28)
local e6 = CreateCheckbox(panel, "Attack speed text",
"Show the current weapon attack speed on the left of the expiry bar.",
function() return db().showSpeedText end,
function(v) db().showSpeedText = v end)
placeR(e6, 28)
local expiryAlpha = CreateSlider(panel, "Expiry bar opacity", 0, 1, 0.05, "Expiry bar opacity: %.2f",
"Alpha of the expiry bar. Kept lower than the threshold bar by default so it reads as the "
.. "secondary readout.",
function() return db().expiryAlpha end,
function(v) db().expiryAlpha = v end)
sliderR(expiryAlpha)
headR("Colours")
@@ -394,7 +465,47 @@ local function BuildPanel()
local sw3 = CreateSwatch(panel, "High", "colorGreen", "Colour above the high threshold.")
placeR(sw3, 24)
local sw4 = CreateSwatch(panel, "Swing marker", "colorSwing", "Colour of the swing marker.")
placeR(sw4, 34)
placeR(sw4, 24)
-- Background colour is a 4-element {r,g,b,a} table; CreateSwatch only ever touches indices
-- 1..3, so the alpha channel gets its own slider straight onto the same table rather than a
-- second colour-helper -- there is no opacity-capable picker in this file to reuse.
local sw5 = CreateSwatch(panel, "Background", "colorBg", "Background colour of the frame.")
placeR(sw5, 24)
local bgAlpha = CreateSlider(panel, "Background opacity", 0, 1, 0.05, "Background opacity: %.2f",
"Opacity of the frame's background panel.",
function() return (db().colorBg or {})[4] or 0.8 end,
function(v) local c = db().colorBg; if c then c[4] = v end end)
sliderR(bgAlpha)
headR("Thresholds")
local poolRed = CreateSlider(panel, "Pool red threshold", 0, 100, 5, "Pool turns red below: %.0f%%",
"The threshold bar turns red at or below this fraction of the pool.",
function() return (db().poolRed or 0.30) * 100 end,
function(v) db().poolRed = v / 100 end)
sliderR(poolRed)
local poolYellow = CreateSlider(panel, "Pool yellow threshold", 0, 100, 5, "Pool turns green above: %.0f%%",
"The threshold bar turns green above this fraction of the pool (yellow in between).",
function() return (db().poolYellow or 0.70) * 100 end,
function(v) db().poolYellow = v / 100 end)
sliderR(poolYellow)
local timeRed = CreateSlider(panel, "Expiry red threshold", 0, BF.BUFFER_DURATION, 0.5,
"Expiry turns red below: %.1fs",
"The expiry bar turns red once fewer than this many seconds remain.",
function() return db().timeRed or 2.0 end,
function(v) db().timeRed = v end)
sliderR(timeRed)
local timeYellow = CreateSlider(panel, "Expiry yellow threshold", 0, BF.BUFFER_DURATION, 0.5,
"Expiry turns green above: %.1fs",
"The expiry bar turns green once more than this many seconds remain (yellow in between).",
function() return db().timeYellow or 5.0 end,
function(v) db().timeYellow = v end)
sliderR(timeYellow)
headR("Absorb model")
@@ -420,6 +531,13 @@ local function BuildPanel()
placeR(setBtn, 28)
table.insert(refreshers, function() setBtn:SetText("Set bonus: " .. (db().setBonusMode or "none")) end)
local setVal = CreateSlider(panel, "Set bonus value", 0, 20, 1, "Set bonus value: %d%%",
"The set bonus percentage the reading above applies. Only used while the set bonus reading "
.. "is 'add' or 'mult'.",
function() return db().setBonusValue end,
function(v) db().setBonusValue = math.floor(v) end)
sliderR(setVal)
local latency = CreateCheckbox(panel, "Latency-adjust swing",
"Shift the swing marker by your round-trip time, so it shows when to press rather than "
.. "when the server swung.",
@@ -427,6 +545,31 @@ local function BuildPanel()
function(v) db().swingUseLatency = v; BF.RefreshSwingInputs() end)
placeR(latency, 28)
local latencyShare = CreateSlider(panel, "Latency share", 0, 1, 0.05, "Latency share: %.2f",
"How much of the round-trip time to shift the swing marker by: 1.00 = the full round trip, "
.. "0.50 = downstream only. Only used while latency-adjust is on.",
function() return db().swingLatencyShare end,
function(v) db().swingLatencyShare = v; BF.RefreshSwingInputs() end)
sliderR(latencyShare)
headR("Aura IDs")
local poolAuraBox = CreateEditBox(panel, "Pool aura spell id",
"Spell id of the Earthen Bulwark Durability debuff, whose stack count is the pool level. "
.. "TurtleWoW can renumber a custom spell between patches -- if the readout goes blank after "
.. "an update, /bulwark probe to find the new id and enter it here.",
function() return db().poolAura end,
function(v) db().poolAura = v end)
placeR(poolAuraBox, 36)
local timeAuraBox = CreateEditBox(panel, "Time aura spell id",
"Spell id of the Earthen Bulwark buff, whose remaining duration drives the expiry bar. "
.. "TurtleWoW can renumber a custom spell between patches -- if the readout goes blank after "
.. "an update, /bulwark probe to find the new id and enter it here.",
function() return db().timeAura end,
function(v) db().timeAura = v end)
placeR(timeAuraBox, 40)
-- footer -------------------------------------------------------------------------------
local demoBtn = CreateButton(panel, "Demo", "Run the display off a synthetic cycle so colours "
.. "and sizes can be judged without a fight.", function()