Options: the era AddOns page, one checkbox per installed addon, then Load out of date AddOns
The era's tenth category was a button in the tree that went nowhere. It now opens onto the era's own per-addon enable list, rebuilt on show from the AddOn API: one checkbox per installed addon carrying its `GetAddOnInfo` enabled state, then the Load out of date AddOns row under it (`checkAddonVersion`, inverted, so checked means "0"). A toggle calls `EnableAddOn`/`DisableAddOn`, which the host persists to `AddOns.txt` at logout — the reference's own contract for this screen, where the change lands on the next world entry. `the_defaults_button_is_armed_by_rows_not_by_a_category` is the invariant that every category leads somewhere and that Defaults is live on every page with a CVar behind it, and AddOns is the second category to run its own page after Keybindings. It is exempted from the `OPTIONS_PAGE_ROWS` half for that reason, and from the Defaults half because an addon's enabled state is not a CVar: there is nothing there for Defaults to write back.
This commit is contained in:
@@ -86,7 +86,7 @@
|
||||
-- that keeps the three shadow rows it inherits one row away from where they used to be.
|
||||
OPTIONS_CATEGORY_KEYS = {
|
||||
"Controls", "Interface", "ActionBars", "Combat", "Chat", "Keybindings", "Nameplates",
|
||||
"Graphics", "AdvancedGraphics", "Audio",
|
||||
"Graphics", "AdvancedGraphics", "Audio", "AddOns",
|
||||
}
|
||||
|
||||
-- The era UIParent draws smaller than our 768-unit canvas; a chosen value, not the
|
||||
@@ -148,13 +148,22 @@
|
||||
BenillaOptionsFrameContainerScroll:SetVerticalScroll(0)
|
||||
-- Leaving Keybindings disarms a pending capture, which must never outlive the page.
|
||||
local kb = getglobal("BenillaOptionsFrameContainerBodyKeybindings")
|
||||
local addons = getglobal("BenillaOptionsFrameContainerBodyAddOns")
|
||||
if key == "Keybindings" then
|
||||
kb:Show()
|
||||
addons:Hide()
|
||||
KeyBindingsPage_Refresh()
|
||||
BenillaOptionsFrameContainerUnbind:Show()
|
||||
BenillaOptionsFrameContainerDefaults:Enable()
|
||||
elseif key == "AddOns" then
|
||||
kb:Hide()
|
||||
addons:Show()
|
||||
OptionsAddOns_Refresh()
|
||||
BenillaOptionsFrameContainerUnbind:Hide()
|
||||
BenillaOptionsFrameContainerDefaults:Disable()
|
||||
else
|
||||
kb:Hide()
|
||||
addons:Hide()
|
||||
KeyBindings_SetSelected(nil)
|
||||
KeyBindings_Output("")
|
||||
BenillaOptionsFrameContainerUnbind:Hide()
|
||||
@@ -252,6 +261,11 @@
|
||||
for i = 1, KEYBINDINGS_SEARCH_ROWS do
|
||||
take("BenillaOptionsFrameContainerBodyKeybindSearch" .. i)
|
||||
end
|
||||
-- The AddOns page's dynamic rows: row 0 is the Load out of date AddOns row.
|
||||
for i = 0, table.getn(OptionsAddOns_Rows) do
|
||||
local row = OptionsAddOns_Rows[i]
|
||||
if row then take(row:GetName()) end
|
||||
end
|
||||
return bottom
|
||||
end
|
||||
|
||||
@@ -313,6 +327,8 @@
|
||||
for i = 1, KEYBINDINGS_SEARCH_ROWS do
|
||||
getglobal("BenillaOptionsFrameContainerBodyKeybindSearch" .. i):Hide()
|
||||
end
|
||||
-- The AddOns page is not in OPTIONS_PAGE_ROWS; hide it and its rows with it.
|
||||
BenillaOptionsFrameContainerBodyAddOns:Hide()
|
||||
KeyBindingsPage.searchPainted = nil
|
||||
KeyBindings_SetSelected(nil)
|
||||
BenillaOptionsFrameContainerUnbind:Hide()
|
||||
@@ -1472,6 +1488,67 @@
|
||||
OptionsApply_Update()
|
||||
end
|
||||
|
||||
-- ── The AddOns page: the era's per-addon enable list ──
|
||||
-- Rows are built on show from the AddOn API: one checkbox per installed addon (its
|
||||
-- `GetAddOnInfo` enabled state), then the Load out of date AddOns row. A toggle calls
|
||||
-- `EnableAddOn`/`DisableAddOn`, which the host persists to `AddOns.txt` at logout, so the
|
||||
-- change applies on the next world entry — the reference's own contract for the AddOns
|
||||
-- screen. Row 0 is the Load out of date AddOns row.
|
||||
OptionsAddOns_Rows = {}
|
||||
|
||||
function OptionsAddOns_GetRow(i)
|
||||
local row = OptionsAddOns_Rows[i]
|
||||
if row then return row end
|
||||
row = CreateFrame("Frame", "BenillaOptionsFrameContainerBodyAddOnsRow" .. i,
|
||||
BenillaOptionsFrameContainerBodyAddOns, "OptionsCheckboxRowTemplate")
|
||||
row.index = i
|
||||
OptionsAddOns_Rows[i] = row
|
||||
return row
|
||||
end
|
||||
|
||||
function OptionsAddOns_OnClick(box)
|
||||
local row = box:GetParent()
|
||||
local checked = box:GetChecked()
|
||||
PlaySound(checked and "igMainMenuOptionCheckBoxOn" or "igMainMenuOptionCheckBoxOff")
|
||||
if checked then
|
||||
EnableAddOn(row.index)
|
||||
else
|
||||
DisableAddOn(row.index)
|
||||
end
|
||||
end
|
||||
|
||||
function OptionsAddOns_Refresh()
|
||||
local n = GetNumAddOns()
|
||||
local prev = nil
|
||||
for i = 1, n do
|
||||
local name, title, notes, enabled = GetAddOnInfo(i)
|
||||
local row = OptionsAddOns_GetRow(i)
|
||||
row:Show()
|
||||
local label = getglobal(row:GetName() .. "Label")
|
||||
label:SetText(title or name)
|
||||
row.searchTag = string.upper(title or name)
|
||||
local box = getglobal(row:GetName() .. "Check")
|
||||
box:SetChecked(enabled)
|
||||
box:SetScript("OnClick", OptionsAddOns_OnClick)
|
||||
OptionsSearch_Place(row:GetName(), prev)
|
||||
prev = row:GetName()
|
||||
end
|
||||
for i = n + 1, table.getn(OptionsAddOns_Rows) do
|
||||
OptionsAddOns_Rows[i]:Hide()
|
||||
end
|
||||
-- The Load out of date AddOns row, under the list; inverted, `checkAddonVersion`
|
||||
-- "1" enforces the check (`0x402c3b`), so checked means "0".
|
||||
local lod = OptionsAddOns_GetRow(0)
|
||||
if not lod.cvar then
|
||||
OptionsRow_OnLoad(lod, "checkAddonVersion", "Load out of date AddOns")
|
||||
lod.invert = 1
|
||||
end
|
||||
lod:Show()
|
||||
getglobal(lod:GetName() .. "Check"):SetChecked(
|
||||
OptionsRow_Get(lod) == "0" and 1 or nil)
|
||||
OptionsSearch_Place(lod:GetName(), prev)
|
||||
end
|
||||
|
||||
-- ── MONKEY (advanced graphics): the page that has to WATCH its settings ─────────────
|
||||
-- Every other page in this window owns its rows outright: nothing but a click on the page
|
||||
-- moves the CVars behind it while it is open, so reading them once on select is the whole
|
||||
@@ -2101,9 +2178,8 @@
|
||||
<NormalFont inherits="GameFontNormalSmall"/>
|
||||
<HighlightFont inherits="GameFontNormalSmall"/>
|
||||
<DisabledFont inherits="GameFontNormalSmall"/>
|
||||
<!-- No addon list behind it: disabled, in the era's unselected gold. -->
|
||||
<!-- The AddOns page below: the era's per-addon enable list. -->
|
||||
<Scripts>
|
||||
<OnLoad>self:Disable()</OnLoad>
|
||||
<OnShow>OptionsTab_FitWidth(self)</OnShow>
|
||||
</Scripts>
|
||||
</Button>
|
||||
@@ -2177,6 +2253,10 @@
|
||||
<Anchors><Anchor point="TOPLEFT" relativeTo="$parentRowAdvancedGraphics" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors>
|
||||
<Scripts><OnLoad>OptionsCategoryRow_OnLoad(self, "Audio", "Audio")</OnLoad></Scripts>
|
||||
</Button>
|
||||
<Button name="$parentRowAddOns" inherits="OptionsCategoryRowTemplate">
|
||||
<Anchors><Anchor point="TOPLEFT" relativeTo="$parentRowAudio" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors>
|
||||
<Scripts><OnLoad>OptionsCategoryRow_OnLoad(self, "AddOns", "AddOns")</OnLoad></Scripts>
|
||||
</Button>
|
||||
</Frames>
|
||||
</Frame>
|
||||
|
||||
@@ -2564,6 +2644,15 @@
|
||||
</Frame>
|
||||
</Frames>
|
||||
</Frame>
|
||||
<!-- The era AddOns page: one checkbox per installed addon (enabled
|
||||
state), then the Load out of date AddOns row; the rows are
|
||||
built by OptionsAddOns_Refresh on show. -->
|
||||
<Frame name="$parentAddOns" hidden="true">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT"/>
|
||||
<Anchor point="BOTTOMRIGHT"/>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- No useUiScale checkbox, which 1.12 has: benilla registers
|
||||
useUiScale but never reads it, so the UI scale always
|
||||
applies. -->
|
||||
|
||||
@@ -4073,8 +4073,8 @@ fn the_buff_durations_row_repitches_the_bar_and_the_pitch_survives_a_restart() {
|
||||
);
|
||||
}
|
||||
|
||||
/// Every category has rows but Keybindings, which runs its own page, and each arms Defaults; a key
|
||||
/// with no rows behind it leaves Defaults dead.
|
||||
/// Every category has rows but Keybindings and AddOns, which run their own pages, and each
|
||||
/// row-backed category arms Defaults; a key with no rows behind it leaves Defaults dead.
|
||||
#[test]
|
||||
fn the_defaults_button_is_armed_by_rows_not_by_a_category() {
|
||||
benilla_formats::wow_data_or_skip!();
|
||||
@@ -4087,16 +4087,20 @@ fn the_defaults_button_is_armed_by_rows_not_by_a_category() {
|
||||
.split(',')
|
||||
.map(str::to_string)
|
||||
.collect();
|
||||
// MONKEY (advanced graphics): ten, not nine — the era's own tree has no Advanced Graphics
|
||||
// page, because the era client has no dynamic light and shadow system to put on one. It is
|
||||
// benilla's own category, seated under Graphics in the System group, and it is held to the
|
||||
// same bar as the era's nine: it opens onto rows, and Defaults is live on it.
|
||||
// MONKEY (advanced graphics): ten of the eleven, not nine — the era's own tree has no Advanced
|
||||
// Graphics page, because the era client has no dynamic light and shadow system to put on one. It
|
||||
// is benilla's own category, seated under Graphics in the System group, and it is held to the
|
||||
// same bar as the era's nine: it opens onto rows, and Defaults is live on it. The eleventh is
|
||||
// AddOns, the era's own per-addon enable list, rebuilt on show from the AddOn API.
|
||||
assert_eq!(
|
||||
keys.len(),
|
||||
10,
|
||||
"the nine 1.15.9 categories + ours: {keys:?}"
|
||||
11,
|
||||
"the nine 1.15.9 categories + AdvancedGraphics + AddOns: {keys:?}"
|
||||
);
|
||||
for key in &keys {
|
||||
// Keybindings and AddOns own their pages: Keybindings builds its search rows on show and
|
||||
// AddOns builds one row per installed addon, so neither is a fixed OPTIONS_PAGE_ROWS list.
|
||||
let owns_its_page = matches!(key.as_str(), "Keybindings" | "AddOns");
|
||||
let has_rows = s
|
||||
.eval::<bool>(&format!(
|
||||
"return OPTIONS_PAGE_ROWS[\"{key}\"] ~= nil and \
|
||||
@@ -4104,11 +4108,22 @@ fn the_defaults_button_is_armed_by_rows_not_by_a_category() {
|
||||
))
|
||||
.unwrap();
|
||||
assert!(
|
||||
has_rows || key == "Keybindings",
|
||||
has_rows || owns_its_page,
|
||||
"{key} opens onto nothing — every category leads somewhere"
|
||||
);
|
||||
s.run(&format!("BenillaOptionsFrameCategoryListRow{key}:Click()"))
|
||||
.unwrap();
|
||||
// Defaults resets the CVars behind a page. The AddOns page holds none: an addon's enabled
|
||||
// state is EnableAddOn/DisableAddOn, which the host persists to `AddOns.txt` at logout, so
|
||||
// there is nothing there for Defaults to write back — the button stays dead on it.
|
||||
if key == "AddOns" {
|
||||
assert!(
|
||||
!s.eval::<bool>("return BenillaOptionsFrameContainerDefaults:IsEnabled() ~= 0")
|
||||
.unwrap(),
|
||||
"AddOns resets nothing, so Defaults is dead there"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
assert!(
|
||||
s.eval::<bool>("return BenillaOptionsFrameContainerDefaults:IsEnabled() ~= 0")
|
||||
.unwrap(),
|
||||
|
||||
Reference in New Issue
Block a user