Unify all option panels through MTH_Layout engine

Add reusable MTH_Layout box/column layout engine (api/options-layout.lua) and route every option panel through it (shell, general, zButtons per-button config, zBar, chronometer, auto buy, profiles, credits, etc.) for consistent, auto-sizing layout. Restore realm gate. README note.
This commit is contained in:
DuvelCorp
2026-09-10 23:59:37 +02:00
parent adb21c336c
commit ccf9d8b0b6
16 changed files with 1770 additions and 1861 deletions
+137 -176
View File
@@ -358,25 +358,14 @@ local function MTH_CHRON_NormalizeSection(tabKey)
return "general"
end
local function MTH_CHRON_RenderTimerSection(container, profile, title, items, bucket, opts)
opts = opts or {}
local timerX = opts.x or 20
local timerY = opts.y or -84
local prefix = tostring(opts.prefix or "Main")
MTH_CHRON_MakeTitle(container, "MetaHuntOptionsChronometerTimersHeader" .. prefix, title, timerX, timerY)
timerY = timerY - 24
local function MTH_CHRON_RenderTimerBox(box, profile, items, bucket, prefix)
prefix = tostring(prefix or "Main")
if table.getn(items) == 0 then
MTH_CHRON_MakeSmall(container, "MetaHuntOptionsChronometerSectionEmpty" .. prefix, "(none)", timerX + 8, timerY)
box:Text("MetaHuntOptionsChronometerSectionEmpty" .. prefix, "(none)")
return
end
for i = 1, table.getn(items) do
if timerY < -560 then
MTH_CHRON_MakeSmall(container, "MetaHuntOptionsChronometerOverflow" .. prefix, "...more", timerX + 8, timerY)
break
end
local row = items[i]
local timerName = row
local label = row
@@ -387,11 +376,9 @@ local function MTH_CHRON_RenderTimerSection(container, profile, title, items, bu
timerName = tostring(timerName or "")
label = tostring(label or timerName)
local controlName = "MetaHuntOptionsChronometerTimer" .. prefix .. tostring(bucket) .. tostring(i)
local check = MTH_CreateCheckbox(container, controlName, label, timerY, timerX)
if check then
check:SetChecked(profile.disabledSpells[bucket][timerName] == nil and true or false)
check:SetScript("OnClick", function()
if not this then return end
box:Checkbox(controlName, label, {
checked = profile.disabledSpells[bucket][timerName] == nil,
onClick = function()
local currentlyDisabled = profile.disabledSpells[bucket][timerName] ~= nil
if currentlyDisabled then
profile.disabledSpells[bucket][timerName] = nil
@@ -402,9 +389,8 @@ local function MTH_CHRON_RenderTimerSection(container, profile, title, items, bu
end
MTH_CHRON_ApplyLiveProfile(profile)
end)
end
timerY = timerY - 20
end,
})
end
end
@@ -461,210 +447,185 @@ function MTH_SetupChronometerOptions(tabKey)
local container = MTH_GetFrame("MetaHuntOptionsChronometer")
if not container then return end
MTH_ClearContainer(container)
MTH_CHRON_STATE.controls = {}
local profile = MTH_CHRON_GetProfile()
local _, class = UnitClass("player")
class = class or "HUNTER"
MTH_CHRON_MakeTitle(container, "MetaHuntOptionsChronometerTitle", "Chronometer", 20, -10)
local panel = MTH_Layout.Panel(container)
panel:Title("Chronometer")
local moduleCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerEnabled", "Enable Chronometer module", -54)
if moduleCheck then
local moduleEnabled = false
do
local module = MTH and MTH:GetModule("chronometer")
moduleCheck:SetChecked(module and module.enabled and true or false)
moduleCheck:SetScript("OnClick", function()
if not this then return end
local enabled = MTH_CHRON_IsChecked(this)
moduleEnabled = module and module.enabled and true or false
end
panel:TopCheckbox("MetaHuntOptionsChronometerEnabled", "Enable Chronometer module", {
checked = moduleEnabled,
onClick = function()
local enabled = this:GetChecked() == 1
if MTH and MTH.SetModuleEnabled then
MTH:SetModuleEnabled("chronometer", enabled)
end
end)
end
end,
})
if section == "general" then
MTH_CHRON_MakeTitle(container, "MetaHuntOptionsChronometerGeneralHeader", "General", 20, -84)
local ghostSlider = MTH_CreateSlider(container, "MetaHuntOptionsChronometerGhost", "Ghost Duration", 0, 30, 1, -112)
if ghostSlider then
ghostSlider:SetValue(tonumber(profile.ghost) or 0)
ghostSlider.onChange = function(value)
local genBox = panel:Box("left", "MetaHuntOptionsChronometerGeneralBox", "General")
genBox:Slider("MetaHuntOptionsChronometerGhost", {
label = "Ghost Duration", min = 0, max = 30, step = 1,
value = tonumber(profile.ghost) or 0,
onChange = function(value)
profile.ghost = tonumber(value) or 0
MTH_CHRON_ApplyLiveProfile(profile)
end
end
local killCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerFadeOnKill", "Fade on kill", -154)
if killCheck then
killCheck:SetChecked(profile.fadeonkill and true or false)
killCheck:SetScript("OnClick", function()
if not this then return end
profile.fadeonkill = MTH_CHRON_IsChecked(this)
end)
end
local fadeCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerFadeOnFade", "Fade on aura fade", -179)
if fadeCheck then
fadeCheck:SetChecked(profile.fadeonfade and true or false)
fadeCheck:SetScript("OnClick", function()
if not this then return end
profile.fadeonfade = MTH_CHRON_IsChecked(this)
end)
end
local selfCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerSelfBars", "Show self bars", -204)
if selfCheck then
selfCheck:SetChecked(profile.selfbars and true or false)
selfCheck:SetScript("OnClick", function()
if not this then return end
profile.selfbars = MTH_CHRON_IsChecked(this)
end)
end
local onlySelfCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerOnlySelf", "Only self target", -229)
if onlySelfCheck then
onlySelfCheck:SetChecked(profile.onlyself and true or false)
onlySelfCheck:SetScript("OnClick", function()
if not this then return end
profile.onlyself = MTH_CHRON_IsChecked(this)
end)
end
end,
})
genBox:Checkbox("MetaHuntOptionsChronometerFadeOnKill", "Fade on kill", {
checked = profile.fadeonkill and true or false,
onClick = function() profile.fadeonkill = this:GetChecked() == 1 end,
})
genBox:Checkbox("MetaHuntOptionsChronometerFadeOnFade", "Fade on aura fade", {
checked = profile.fadeonfade and true or false,
onClick = function() profile.fadeonfade = this:GetChecked() == 1 end,
})
genBox:Checkbox("MetaHuntOptionsChronometerSelfBars", "Show self bars", {
checked = profile.selfbars and true or false,
onClick = function() profile.selfbars = this:GetChecked() == 1 end,
})
genBox:Checkbox("MetaHuntOptionsChronometerOnlySelf", "Only self target", {
checked = profile.onlyself and true or false,
onClick = function() profile.onlyself = this:GetChecked() == 1 end,
})
elseif section == "bar" then
MTH_CHRON_MakeTitle(container, "MetaHuntOptionsChronometerBarHeader", "Bars", 20, -84)
local runTestButton = MTH_CreateActionButton(container, "MetaHuntOptionsChronometerRunTest", "Run Test", 20, -112, 130, 22, function()
local engine = MTH_ChronometerHunter
if engine and engine.RunTest then
engine:RunTest()
end
end)
local anchorButton = MTH_CreateActionButton(container, "MetaHuntOptionsChronometerAnchor", "Toggle Anchor", 165, -112, 130, 22, function()
local engine = MTH_ChronometerHunter
if engine and engine.ToggleAnchor then
engine:ToggleAnchor()
end
end)
if runTestButton then runTestButton:Show() end
if anchorButton then anchorButton:Show() end
local ctrlBox = panel:Box("left", "MetaHuntOptionsChronometerControlsBox", "Controls")
ctrlBox:Buttons({
{ name = "MetaHuntOptionsChronometerRunTest", label = "Run Test", width = 120,
onClick = function()
local engine = MTH_ChronometerHunter
if engine and engine.RunTest then engine:RunTest() end
end },
{ name = "MetaHuntOptionsChronometerAnchor", label = "Toggle Anchor", width = 120,
onClick = function()
local engine = MTH_ChronometerHunter
if engine and engine.ToggleAnchor then engine:ToggleAnchor() end
end },
})
local anchorX = tonumber(profile.barposition and profile.barposition.x) or 0
local anchorY = tonumber(profile.barposition and profile.barposition.y) or 0
MTH_CHRON_MakeSmall(container, "MetaHuntOptionsChronometerAnchorPos", "Anchor: X " .. tostring(anchorX) .. " Y " .. tostring(anchorY), 20, -142)
ctrlBox:Note("MetaHuntOptionsChronometerAnchorPos",
"Anchor: X " .. tostring(anchorX) .. " Y " .. tostring(anchorY))
local widthSlider = MTH_CreateSlider(container, "MetaHuntOptionsChronometerBarWidth", "Bar Width", 80, 320, 1, -180)
if widthSlider then
widthSlider:SetValue(tonumber(profile.barwidth) or 220)
widthSlider.onChange = function(value)
local dimBox = panel:Box("left", "MetaHuntOptionsChronometerDimBox", "Dimensions")
dimBox:Slider("MetaHuntOptionsChronometerBarWidth", {
label = "Bar Width", min = 80, max = 320, step = 1,
value = tonumber(profile.barwidth) or 220,
onChange = function(value)
profile.barwidth = tonumber(value) or 220
MTH_CHRON_ApplyLiveProfile(profile)
end
end
local scaleSlider = MTH_CreateSlider(container, "MetaHuntOptionsChronometerBarScale", "Bar Scale", 0.5, 1.5, 0.1, -222)
if scaleSlider then
scaleSlider:SetValue(tonumber(profile.barscale) or 1)
scaleSlider.onChange = function(value)
end,
})
dimBox:Slider("MetaHuntOptionsChronometerBarScale", {
label = "Bar Scale", min = 0.5, max = 1.5, step = 0.1,
value = tonumber(profile.barscale) or 1,
format = function(v) return string.format("%.1f", v) end,
onChange = function(value)
profile.barscale = tonumber(value) or 1
MTH_CHRON_ApplyLiveProfile(profile)
end
end
local heightSlider = MTH_CreateSlider(container, "MetaHuntOptionsChronometerBarHeight", "Bar Height", 8, 30, 1, -264)
if heightSlider then
heightSlider:SetValue(tonumber(profile.barheight) or 16)
heightSlider.onChange = function(value)
end,
})
dimBox:Slider("MetaHuntOptionsChronometerBarHeight", {
label = "Bar Height", min = 8, max = 30, step = 1,
value = tonumber(profile.barheight) or 16,
onChange = function(value)
profile.barheight = tonumber(value) or 16
MTH_CHRON_ApplyLiveProfile(profile)
end
end
local spacingSlider = MTH_CreateSlider(container, "MetaHuntOptionsChronometerBarSpacing", "Bar Spacing", 0, 15, 1, -306)
if spacingSlider then
spacingSlider:SetValue(tonumber(profile.spacing) or 0)
spacingSlider.onChange = function(value)
end,
})
dimBox:Slider("MetaHuntOptionsChronometerBarSpacing", {
label = "Bar Spacing", min = 0, max = 15, step = 1,
value = tonumber(profile.spacing) or 0,
onChange = function(value)
profile.spacing = tonumber(value) or 0
MTH_CHRON_ApplyLiveProfile(profile)
end
end
local textSizeSlider = MTH_CreateSlider(container, "MetaHuntOptionsChronometerTextSize", "Text Size", 8, 20, 1, -348)
if textSizeSlider then
textSizeSlider:SetValue(tonumber(profile.textsize) or 10)
textSizeSlider.onChange = function(value)
end,
})
dimBox:Slider("MetaHuntOptionsChronometerTextSize", {
label = "Text Size", min = 8, max = 20, step = 1,
value = tonumber(profile.textsize) or 10,
onChange = function(value)
profile.textsize = tonumber(value) or 10
MTH_CHRON_ApplyLiveProfile(profile)
end
end
end,
})
MTH_CHRON_MakeSmall(container, "MetaHuntOptionsChronometerTextPatternLabel", "Bar Text ($s spell, $t target)", 20, -390)
MTH_CHRON_MakeInput(container, "MetaHuntOptionsChronometerTextPattern", 20, -408, 220, 20, profile.text or "$t", function(newText)
if not newText or newText == "" then
newText = "$t"
end
profile.text = tostring(newText)
MTH_CHRON_ApplyLiveProfile(profile)
end)
local growCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerGrowUp", "Grow bars upward", -438)
if growCheck then
growCheck:SetChecked(profile.growup and true or false)
growCheck:SetScript("OnClick", function()
if not this then return end
profile.growup = MTH_CHRON_IsChecked(this)
local textBox = panel:Box("right", "MetaHuntOptionsChronometerTextBox", "Text & Growth")
textBox:Note("MetaHuntOptionsChronometerTextPatternHint",
"Bar text tokens: $s = spell, $t = target", { lines = 2 })
local patternEdit = textBox:EditRow("MetaHuntOptionsChronometerTextPatternLabel", "Bar Text",
"MetaHuntOptionsChronometerTextPattern", 150, { height = 20 })
if patternEdit then
patternEdit:SetText(tostring(profile.text or "$t"))
patternEdit:SetScript("OnEnterPressed", function()
local newText = this:GetText() or ""
if newText == "" then newText = "$t" end
profile.text = tostring(newText)
MTH_CHRON_ApplyLiveProfile(profile)
this:ClearFocus()
end)
end
local reverseCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerReverse", "Reverse bars", -463)
if reverseCheck then
reverseCheck:SetChecked(profile.reverse and true or false)
reverseCheck:SetScript("OnClick", function()
if not this then return end
profile.reverse = MTH_CHRON_IsChecked(this)
textBox:Checkbox("MetaHuntOptionsChronometerGrowUp", "Grow bars upward", {
checked = profile.growup and true or false,
onClick = function()
profile.growup = this:GetChecked() == 1
MTH_CHRON_ApplyLiveProfile(profile)
end)
end
end,
})
textBox:Checkbox("MetaHuntOptionsChronometerReverse", "Reverse bars", {
checked = profile.reverse and true or false,
onClick = function()
profile.reverse = this:GetChecked() == 1
MTH_CHRON_ApplyLiveProfile(profile)
end,
})
MTH_CHRON_MakeSmall(container, "MetaHuntOptionsChronometerIconPosLabel", "Icon Position", 20, -494)
local iconLeft = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerIconLeft", "Left", -514)
local iconRight = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerIconRight", "Right", -538)
if iconLeft and iconRight then
iconLeft:SetChecked(profile.iconposition ~= "RIGHT")
iconRight:SetChecked(profile.iconposition == "RIGHT")
iconLeft:SetScript("OnClick", function()
local iconBox = panel:Box("right", "MetaHuntOptionsChronometerIconBox", "Icon Position")
local iconLeft, iconRight
iconLeft = iconBox:Checkbox("MetaHuntOptionsChronometerIconLeft", "Left", {
checked = profile.iconposition ~= "RIGHT",
onClick = function()
profile.iconposition = "LEFT"
iconLeft:SetChecked(true)
iconRight:SetChecked(nil)
MTH_CHRON_ApplyLiveProfile(profile)
end)
iconRight:SetScript("OnClick", function()
end,
})
iconRight = iconBox:Checkbox("MetaHuntOptionsChronometerIconRight", "Right", {
checked = profile.iconposition == "RIGHT",
onClick = function()
profile.iconposition = "RIGHT"
iconRight:SetChecked(true)
iconLeft:SetChecked(nil)
MTH_CHRON_ApplyLiveProfile(profile)
end)
end
end,
})
else
local classSpells, classEvents, racial = MTH_CHRON_BuildTimerLists()
if section == "classspells" then
MTH_CHRON_RenderTimerSection(container, profile, "Hunter Spells", classSpells, class, {
x = 20,
y = -84,
prefix = "ClassSpells",
})
MTH_CHRON_RenderTimerSection(container, profile, "Hunter Trinkets", MTH_CHRON_BuildHunterTrinketItems(classEvents), class, {
x = 300,
y = -84,
prefix = "ClassTrinkets",
})
local spellsBox = panel:Box("left", "MetaHuntOptionsChronometerSpellsBox", "Hunter Spells")
MTH_CHRON_RenderTimerBox(spellsBox, profile, classSpells, class, "ClassSpells")
local trinketBox = panel:Box("right", "MetaHuntOptionsChronometerTrinketsBox", "Hunter Trinkets")
MTH_CHRON_RenderTimerBox(trinketBox, profile, MTH_CHRON_BuildHunterTrinketItems(classEvents), class, "ClassTrinkets")
elseif section == "classevents" then
MTH_CHRON_RenderTimerSection(container, profile, "Hunter Events", classEvents, class, { prefix = "ClassEvents" })
local eventsBox = panel:Box("left", "MetaHuntOptionsChronometerEventsBox", "Hunter Events")
MTH_CHRON_RenderTimerBox(eventsBox, profile, classEvents, class, "ClassEvents")
elseif section == "racial" then
MTH_CHRON_RenderTimerSection(container, profile, "Racial", racial, "RACIAL", { prefix = "Racial" })
local racialBox = panel:Box("left", "MetaHuntOptionsChronometerRacialBox", "Racial")
MTH_CHRON_RenderTimerBox(racialBox, profile, racial, "RACIAL", "Racial")
end
end
panel:Finish()
end
if _G then