fix(libs): restore ElvUI-namespaced Ace3 stack clobbered by sweep

The coa-ace3 sweep (commits 0c130e0..5ea6e44, before coa-elvui was added to
EXCLUDED_FORKS in coa-ace3 tools/sweep.py) overwrote ElvUI's customized,
-ElvUI-namespaced Ace3 libs with plain canonical ones. ElvUI registers libs
as AceLocale-3.0-ElvUI and the AceConfig-3.0-ElvUI family (plus -ElvUI
widgets that don't exist in canonical), so the clobber left them
unregistered: ElvUI failed to init (16 locale 'L' errors) and /ec would not
open. Restores ElvUI/Libraries/Ace3/AceLocale-3.0 and the
ElvUI_OptionsUI/Libraries/Ace3 stack to their pre-sweep state (5021fd1).
coa-elvui is now in EXCLUDED_FORKS, so this won't be re-clobbered.
This commit is contained in:
2026-05-25 19:30:48 +02:00
parent 49a3d4c81c
commit 4a1cf548ef
28 changed files with 915 additions and 855 deletions
@@ -5,9 +5,9 @@
local LibStub = LibStub
local gui = LibStub("AceGUI-3.0")
local reg = LibStub("AceConfigRegistry-3.0")
local reg = LibStub("AceConfigRegistry-3.0-ElvUI")
local MAJOR, MINOR = "AceConfigDialog-3.0", 92
local MAJOR, MINOR = "AceConfigDialog-3.0-ElvUI", 79
local AceConfigDialog, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigDialog then return end
@@ -15,20 +15,25 @@ if not AceConfigDialog then return end
AceConfigDialog.OpenFrames = AceConfigDialog.OpenFrames or {}
AceConfigDialog.Status = AceConfigDialog.Status or {}
AceConfigDialog.frame = AceConfigDialog.frame or CreateFrame("Frame")
AceConfigDialog.tooltip = AceConfigDialog.tooltip or CreateFrame("GameTooltip", "AceConfigDialogTooltip", UIParent, "GameTooltipTemplate")
AceConfigDialog.frame.apps = AceConfigDialog.frame.apps or {}
AceConfigDialog.frame.closing = AceConfigDialog.frame.closing or {}
AceConfigDialog.frame.closeAllOverride = AceConfigDialog.frame.closeAllOverride or {}
-- Lua APIs
local tinsert, tsort, tremove, wipe = table.insert, table.sort, table.remove, table.wipe
local tconcat, tinsert, tsort, tremove = table.concat, table.insert, table.sort, table.remove
local strmatch, format = string.match, string.format
local error = error
local pairs, next, select, type, unpack, ipairs = pairs, next, select, type, unpack, ipairs
local tostring, tonumber = tostring, tonumber
local assert, loadstring, error = assert, loadstring, error
local pairs, next, select, type, unpack, wipe, ipairs = pairs, next, select, type, unpack, wipe, ipairs
local rawset, tostring, tonumber = rawset, tostring, tonumber
local math_min, math_max, math_floor = math.min, math.max, math.floor
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: NORMAL_FONT_COLOR, GameTooltip, StaticPopupDialogs, ACCEPT, CANCEL, StaticPopup_Show
-- GLOBALS: PlaySound, GameFontHighlight, GameFontHighlightSmall, GameFontHighlightLarge
-- GLOBALS: CloseSpecialWindows, InterfaceOptions_AddCategory, geterrorhandler
local emptyTbl = {}
--[[
@@ -40,10 +45,39 @@ local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local xpcall, eh = ...
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = ...
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = code:gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
Dispatchers[0] = function(func)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
if func then
return xpcall(func, errorhandler, ...)
end
return Dispatchers[select("#", ...)](func, ...)
end
local width_multiplier = 170
@@ -147,7 +181,6 @@ local stringIsLiteral = {
width = true,
image = true,
fontSize = true,
tooltipHyperlink = true
}
--Is Never a function or method
@@ -189,8 +222,9 @@ local function GetOptionsMemberValue(membername, option, options, path, appName,
--We have a function to call
local info = new()
--traverse the options table, picking up the handler and filling the info with the path
local handler
local group = options
local handler = group.handler
handler = group.handler or handler
for i = 1, #path do
group = GetSubOption(group, path[i])
@@ -208,21 +242,21 @@ local function GetOptionsMemberValue(membername, option, options, path, appName,
info.uiType = "dialog"
info.uiName = MAJOR
local a, b, c ,d
local a, b, c, d, e, f, g, h -- ElvUI adds e,f,g,h for default color
--using 4 returns for the get of a color type, increase if a type needs more
if type(member) == "function" then
--Call the function
a,b,c,d = member(info, ...)
a,b,c,d,e,f,g,h = member(info, ...)
else
--Call the method
if handler and handler[member] then
a,b,c,d = handler[member](handler, info, ...)
a,b,c,d,e,f,g,h = handler[member](handler, info, ...)
else
error(format("Method %s doesn't exist in handler for type %s", member, membername))
end
end
del(info)
return a,b,c,d
return a,b,c,d,e,f,g,h
else
--The value isnt a function to call, return it
return member
@@ -499,163 +533,137 @@ local function OptionOnMouseOver(widget, event)
local options = user.options
local path = user.path
local appName = user.appName
local tooltip = AceConfigDialog.tooltip
tooltip:SetOwner(widget.frame, "ANCHOR_TOPRIGHT")
local tooltipHyperlink = GetOptionsMemberValue("tooltipHyperlink", opt, options, path, appName)
if tooltipHyperlink then
tooltip:SetHyperlink(tooltipHyperlink)
tooltip:Show()
return
end
-- modified by ElvUI
if opt.descStyle and opt.descStyle ~= "tooltip" then return end
local name = GetOptionsMemberValue("name", opt, options, path, appName)
local desc = GetOptionsMemberValue("desc", opt, options, path, appName)
local usage = GetOptionsMemberValue("usage", opt, options, path, appName)
local descStyle = opt.descStyle
if descStyle and descStyle ~= "tooltip" then return end
local descText = type(desc) == "string"
local usageText = type(usage) == "string"
local userText = opt.type == "multiselect"
local softText = opt.softMin or opt.softMax
local bigText = opt.bigStep
local Min, Max, Step
tooltip:SetText(name, 1, .82, 0, 1, true)
if opt.type == "multiselect" then
tooltip:AddLine(user.text, 0.5, 0.5, 0.8, true)
if softText then
Min = (opt.min and "|cFFCCCCCCMin:|r "..(opt.isPercent and (opt.min*100).."%" or opt.min)) or ""
Max = (opt.max and "|cFFCCCCCCMax:|r "..(opt.isPercent and (opt.max*100).."%" or opt.max)) or ""
softText = Min ~= "" or Max ~= ""
end
if type(desc) == "string" then
tooltip:AddLine(desc, 1, 1, 1, true)
end
if type(usage) == "string" then
tooltip:AddLine(usage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true)
if bigText then
local dec = opt.step and format("%f", opt.step):gsub('%.?0-$','')
local num = dec and tonumber(dec)
Step = (num and num > 0 and "|cFFCCCCCCStep:|r "..dec) or ""
bigText = Step ~= ""
end
tooltip:Show()
if descText or usageText or userText or softText or bigText then
GameTooltip:SetOwner(widget.frame, "ANCHOR_TOPRIGHT")
GameTooltip:SetText(name, 1, .82, 0, true)
if userText then
GameTooltip:AddLine(user.text, 0.5, 0.5, 0.8, true)
end
if descText then
GameTooltip:AddLine(desc, 1, 1, 1, true)
end
if usageText then
GameTooltip:AddLine("Usage: "..usage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true)
end
if bigText or softText then
GameTooltip:AddLine(" ")
end
if bigText then
GameTooltip:AddLine(Step, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true)
end
if softText then
GameTooltip:AddDoubleLine(Min, Max)
end
GameTooltip:Show()
end
end
local function OptionOnMouseLeave(widget, event)
AceConfigDialog.tooltip:Hide()
GameTooltip:Hide()
end
local function GetFuncName(option)
if option.type == "execute" then
local type = option.type
if type == "execute" then
return "func"
else
return "set"
end
end
do
local InCombatLockdown = InCombatLockdown
local frame = AceConfigDialog.popup
if not frame or oldminor < 81 then
frame = CreateFrame("Frame", nil, UIParent)
AceConfigDialog.popup = frame
frame:Hide()
frame:SetPoint("CENTER", UIParent, "CENTER")
frame:SetSize(320, 72)
frame:EnableMouse(true) -- Do not allow click-through on the frame
frame:SetFrameStrata("TOOLTIP")
frame:SetFrameLevel(100) -- Lots of room to draw under it
frame:SetScript("OnKeyDown", function(self, key)
if key == "ESCAPE" then
if not InCombatLockdown() then
self:SetPropagateKeyboardInput(false)
end
if self.cancel:IsShown() then
self.cancel:Click()
else -- Showing a validation error
self:Hide()
end
elseif not InCombatLockdown() then
self:SetPropagateKeyboardInput(true)
end
end)
local border = CreateFrame("Frame", nil, frame, "DialogBorderOpaqueTemplate")
border:SetAllPoints(frame)
frame:SetFixedFrameStrata(true)
frame:SetFixedFrameLevel(true)
local text = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
text:SetSize(290, 0)
text:SetPoint("TOP", 0, -16)
frame.text = text
local function newButton(newText)
local button = CreateFrame("Button", nil, frame)
button:SetSize(128, 21)
button:SetNormalFontObject(GameFontNormal)
button:SetHighlightFontObject(GameFontHighlight)
button:SetNormalTexture("Interface\\Buttons\\UI-DialogBox-Button-Up")
button:GetNormalTexture():SetTexCoord(0.0, 1.0, 0.0, 0.71875)
button:SetPushedTexture("Interface\\Buttons\\UI-DialogBox-Button-Down")
button:GetPushedTexture():SetTexCoord(0.0, 1.0, 0.0, 0.71875)
button:SetHighlightTexture("Interface\\Buttons\\UI-DialogBox-Button-Highlight")
button:GetHighlightTexture():SetTexCoord(0.0, 1.0, 0.0, 0.71875)
button:SetText(newText)
return button
end
local accept = newButton(ACCEPT)
accept:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -6, 16)
frame.accept = accept
local cancel = newButton(CANCEL)
cancel:SetPoint("LEFT", accept, "RIGHT", 13, 0)
frame.cancel = cancel
end
end
local function confirmPopup(appName, rootframe, basepath, info, message, func, ...)
local frame = AceConfigDialog.popup
frame:Show()
frame.text:SetText(message)
-- From StaticPopup.lua
-- local height = 32 + text:GetHeight() + 2;
-- height = height + 6 + accept:GetHeight()
-- We add 32 + 2 + 6 + 21 (button height) == 61
local height = 61 + frame.text:GetHeight()
frame:SetHeight(height)
frame.accept:ClearAllPoints()
frame.accept:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -6, 16)
frame.cancel:Show()
local t = {...}
local tCount = select("#", ...)
frame.accept:SetScript("OnClick", function(self)
safecall(func, unpack(t, 1, tCount)) -- Manually set count as unpack() stops on nil (bug with #table)
if not StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"] then
StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"] = {}
end
local t = StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"]
for k in pairs(t) do
t[k] = nil
end
t.text = message
t.button1 = ACCEPT
t.button2 = CANCEL
t.preferredIndex = STATICPOPUP_NUMDIALOGS
local dialog, oldstrata
t.OnAccept = function()
safecall(func, unpack(t))
if dialog and oldstrata then
dialog:SetFrameStrata(oldstrata)
end
AceConfigDialog:Open(appName, rootframe, unpack(basepath or emptyTbl))
frame:Hide()
self:SetScript("OnClick", nil)
frame.cancel:SetScript("OnClick", nil)
del(info)
end)
frame.cancel:SetScript("OnClick", function(self)
end
t.OnCancel = function()
if dialog and oldstrata then
dialog:SetFrameStrata(oldstrata)
end
AceConfigDialog:Open(appName, rootframe, unpack(basepath or emptyTbl))
frame:Hide()
self:SetScript("OnClick", nil)
frame.accept:SetScript("OnClick", nil)
del(info)
end)
end
for i = 1, select("#", ...) do
t[i] = select(i, ...) or false
end
t.timeout = 0
t.whileDead = 1
t.hideOnEscape = 1
dialog = StaticPopup_Show("ACECONFIGDIALOG30_CONFIRM_DIALOG")
if dialog then
oldstrata = dialog:GetFrameStrata()
dialog:SetFrameStrata("TOOLTIP")
end
end
local function validationErrorPopup(message)
local frame = AceConfigDialog.popup
frame:Show()
frame.text:SetText(message)
-- From StaticPopup.lua
-- local height = 32 + text:GetHeight() + 2;
-- height = height + 6 + accept:GetHeight()
-- We add 32 + 2 + 6 + 21 (button height) == 61
local height = 61 + frame.text:GetHeight()
frame:SetHeight(height)
if not StaticPopupDialogs["ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG"] then
StaticPopupDialogs["ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG"] = {}
end
local t = StaticPopupDialogs["ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG"]
t.text = message
t.button1 = OKAY
t.preferredIndex = STATICPOPUP_NUMDIALOGS
local dialog, oldstrata
t.OnAccept = function()
if dialog and oldstrata then
dialog:SetFrameStrata(oldstrata)
end
end
t.timeout = 0
t.whileDead = 1
t.hideOnEscape = 1
frame.accept:ClearAllPoints()
frame.accept:SetPoint("BOTTOM", frame, "BOTTOM", 0, 16)
frame.cancel:Hide()
frame.accept:SetScript("OnClick", function()
frame:Hide()
end)
dialog = StaticPopup_Show("ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG")
if dialog then
oldstrata = dialog:GetFrameStrata()
dialog:SetFrameStrata("TOOLTIP")
end
end
local function ActivateControl(widget, event, ...)
@@ -678,7 +686,7 @@ local function ActivateControl(widget, event, ...)
if group[funcname] ~= nil then
func = group[funcname]
end
handler = group.handler
handler = group.handler or handler
confirm = group.confirm
validate = group.validate
for i = 1, #path do
@@ -742,6 +750,7 @@ local function ActivateControl(widget, event, ...)
end
end
local rootframe = user.rootframe
if not validated or type(validated) == "string" then
if not validated then
if usage then
@@ -756,12 +765,12 @@ local function ActivateControl(widget, event, ...)
end
-- show validate message
if user.rootframe.SetStatusText then
user.rootframe:SetStatusText(validated)
if not group.validatePopup and rootframe.SetStatusText then
rootframe:SetStatusText(validated)
else
validationErrorPopup(validated)
end
PlaySound(882) -- SOUNDKIT.IG_PLAYER_INVITE_DECLINE || _DECLINE is actually missing from the table
PlaySound("igPlayerInviteDecline")
del(info)
return true
else
@@ -794,14 +803,14 @@ local function ActivateControl(widget, event, ...)
if type(confirm) == "boolean" then
if confirm then
if not confirmText then
local option_name, desc = option.name, option.desc
if type(option_name) == "function" then
option_name = option_name(info)
local name, desc = option.name, option.desc
if type(name) == "function" then
name = name(info)
end
if type(desc) == "function" then
desc = desc(info)
end
confirmText = option_name
confirmText = name
if desc then
confirmText = confirmText.." - "..desc
end
@@ -879,6 +888,11 @@ end
local function ActivateSlider(widget, event, value)
local option = widget:GetUserData("option")
local min, max, step = option.min or (not option.softMin and 0 or nil), option.max or (not option.softMax and 100 or nil), option.step
-- checks added by elvui
if type(min) == 'function' then min = min() end
if type(max) == 'function' then max = max() end
if min then
if step then
value = math_floor((value - min) / step + 0.5) * step + min
@@ -1083,11 +1097,6 @@ local function InjectInfo(control, options, option, path, rootframe, appName)
control:SetCallback("OnRelease", CleanUserData)
control:SetCallback("OnLeave", OptionOnMouseLeave)
control:SetCallback("OnEnter", OptionOnMouseOver)
-- forward custom arg data directly
if control.SetCustomData and option.arg then
safecall(control.SetCustomData, control, option.arg)
end
end
local function CreateControl(userControlType, fallbackControlType)
@@ -1108,6 +1117,11 @@ local function sortTblAsStrings(x,y)
return tostring(x) < tostring(y) -- Support numbers as keys
end
-- added by ElvUI
local function sortTblByValue(x,y)
return x[2] < y[2]
end
--[[
options - root of the options table being fed
container - widget that controls will be placed in
@@ -1148,13 +1162,15 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
--Control to feed
local control
local name = GetOptionsMemberValue("name", v, options, path, appName)
if v.type == "execute" then
local imageCoords = GetOptionsMemberValue("imageCoords",v, options, path, appName)
local image, width, height = GetOptionsMemberValue("image",v, options, path, appName)
local iconControl = type(image) == "string" or type(image) == "number"
control = CreateControl(v.dialogControl or v.control, iconControl and "Icon" or "Button")
control = CreateControl(v.dialogControl or v.control, iconControl and "Icon" or "Button-ElvUI")
if iconControl then
if not width then
width = GetOptionsMemberValue("imageWidth",v, options, path, appName)
@@ -1197,6 +1213,11 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
elseif v.type == "toggle" then
control = CreateControl(v.dialogControl or v.control, "CheckBox")
control:SetLabel(name)
control.textWidth = GetOptionsMemberValue("textWidth",v,options,path,appName)
if control.textWidth and control.frame and control.text then
local textWidth = control.text:GetWidth()+30
control.customWidth = (textWidth>=width_multiplier and textWidth<=width_multiplier*1.5) and textWidth
end
control:SetTriState(v.tristate)
local value = GetOptionsMemberValue("get",v, options, path, appName)
control:SetValue(value)
@@ -1210,7 +1231,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
local image = GetOptionsMemberValue("image", v, options, path, appName)
local imageCoords = GetOptionsMemberValue("imageCoords", v, options, path, appName)
if type(image) == "string" or type(image) == "number" then
if type(image) == "string" then
if type(imageCoords) == "table" then
control:SetImage(image, unpack(imageCoords))
else
@@ -1250,7 +1271,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
end
tsort(sorting, sortTblAsStrings)
end
for _, value in ipairs(sorting) do
for k, value in ipairs(sorting) do
local text = values[value]
local radio = gui:Create("CheckBox")
radio:SetLabel(text)
@@ -1278,13 +1299,15 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
control:DoLayout()
else
control = CreateControl(v.dialogControl or v.control, "Dropdown")
local sortByValue = GetOptionsMemberValue("sortByValue",v,options,path,appName)
local itemType = v.itemControl
if itemType and not gui:GetWidgetVersion(itemType) then
geterrorhandler()(("Invalid Custom Item Type - %s"):format(tostring(itemType)))
itemType = nil
end
control:SetLabel(name)
control:SetList(values, sorting, itemType)
control:SetList(values, sorting, itemType, sortByValue)
local value = GetOptionsMemberValue("get",v, options, path, appName)
if not values[value] then
value = nil
@@ -1296,14 +1319,20 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
elseif v.type == "multiselect" then
local values = GetOptionsMemberValue("values", v, options, path, appName)
local disabled = CheckOptionDisabled(v, options, path, appName)
local sortByValue = GetOptionsMemberValue("sortByValue", v, options, path, appName)
local valuesort = new()
if values then
for value, text in pairs(values) do
tinsert(valuesort, value)
tinsert(valuesort, (sortByValue and {value, text}) or value)
end
end
tsort(valuesort)
if sortByValue then
tsort(valuesort, sortTblByValue)
else
tsort(valuesort)
end
local controlType = v.dialogControl or v.control
if controlType then
@@ -1332,42 +1361,76 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
control:SetWidth(width_multiplier)
end
--check:SetTriState(v.tristate)
for s = 1, #valuesort do
local key = valuesort[s]
for i = 1, #valuesort do
local key = (sortByValue and valuesort[i][1]) or valuesort[i]
local value = GetOptionsMemberValue("get",v, options, path, appName, key)
control:SetItemValue(key,value)
end
else
local width = GetOptionsMemberValue("width",v,options,path,appName)
local dragdrop = GetOptionsMemberValue("dragdrop",v,options,path,appName)
control = gui:Create("InlineGroup")
control:SetLayout("Flow")
control:SetTitle(name)
control.width = "fill"
control:PauseLayout()
local width = GetOptionsMemberValue("width",v,options,path,appName)
for s = 1, #valuesort do
local value = valuesort[s]
for i = 1, #valuesort do
local value = (sortByValue and valuesort[i][1]) or valuesort[i]
local text = values[value]
local check = gui:Create("CheckBox")
check:SetLabel(text)
check:SetUserData("value", value)
check:SetUserData("text", text)
check:SetDisabled(disabled)
check:SetTriState(v.tristate)
check:SetValue(GetOptionsMemberValue("get",v, options, path, appName, value))
check:SetCallback("OnValueChanged",ActivateMultiControl)
InjectInfo(check, options, v, path, rootframe, appName)
control:AddChild(check)
if width == "double" then
check:SetWidth(width_multiplier * 2)
elseif width == "half" then
check:SetWidth(width_multiplier / 2)
elseif (type(width) == "number") then
check:SetWidth(width_multiplier * width)
elseif width == "full" then
check.width = "fill"
if dragdrop then
local button = gui:Create("Button-ElvUI")
button:SetDisabled(disabled)
button:SetUserData("value", value)
button:SetUserData("text", text)
local state = v.stateSwitchGetText and v.stateSwitchGetText(button, text, value)
button:SetText(format("|cFF888888%d|r %s", i, state or text))
button.stateSwitchOnClick = v.stateSwitchOnClick
button.dragOnMouseDown = v.dragOnMouseDown
button.dragOnMouseUp = v.dragOnMouseUp
button.dragOnEnter = v.dragOnEnter
button.dragOnLeave = v.dragOnLeave
button.dragOnClick = v.dragOnClick
button.dragdrop = true
button.ActivateMultiControl = ActivateMultiControl
button.value = GetOptionsMemberValue("get",v, options, path, appName, value)
InjectInfo(button, options, v, path, rootframe, appName)
control:AddChild(button)
if width == "double" then
button:SetWidth(width_multiplier * 2)
elseif width == "half" then
button:SetWidth(width_multiplier / 2)
elseif (type(width) == "number") then
control:SetWidth(width_multiplier * width)
elseif width == "full" then
button.width = "fill"
else
button:SetWidth(width_multiplier)
end
else
check:SetWidth(width_multiplier)
local check = gui:Create("CheckBox")
check:SetLabel(text)
check:SetUserData("value", value)
check:SetUserData("text", text)
check:SetDisabled(disabled)
check:SetTriState(v.tristate)
check:SetValue(GetOptionsMemberValue("get",v, options, path, appName, value))
check:SetCallback("OnValueChanged",ActivateMultiControl)
InjectInfo(check, options, v, path, rootframe, appName)
control:AddChild(check)
if width == "double" then
check:SetWidth(width_multiplier * 2)
elseif width == "half" then
check:SetWidth(width_multiplier / 2)
elseif (type(width) == "number") then
control:SetWidth(width_multiplier * width)
elseif width == "full" then
check.width = "fill"
else
check:SetWidth(width_multiplier)
end
end
end
control:ResumeLayout()
@@ -1379,7 +1442,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
del(valuesort)
elseif v.type == "color" then
control = CreateControl(v.dialogControl or v.control, "ColorPicker")
control = CreateControl(v.dialogControl or v.control, "ColorPicker-ElvUI")
control:SetLabel(name)
control:SetHasAlpha(GetOptionsMemberValue("hasAlpha",v, options, path, appName))
control:SetColor(GetOptionsMemberValue("get",v, options, path, appName))
@@ -1413,7 +1476,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
local imageCoords = GetOptionsMemberValue("imageCoords",v, options, path, appName)
local image, width, height = GetOptionsMemberValue("image",v, options, path, appName)
if type(image) == "string" or type(image) == "number" then
if type(image) == "string" then
if not width then
width = GetOptionsMemberValue("imageWidth",v, options, path, appName)
end
@@ -1433,27 +1496,29 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
end
control:SetImageSize(width, height)
end
local controlWidth = GetOptionsMemberValue("width",v,options,path,appName)
control.width = not controlWidth and "fill"
local width = GetOptionsMemberValue("width",v,options,path,appName)
control.width = not width and "fill"
end
--Common Init
if control then
if control.width ~= "fill" then
local width = GetOptionsMemberValue("width",v,options,path,appName)
local relWidth = GetOptionsMemberValue("relWidth",v,options,path,appName)
if width == "double" then
control:SetWidth(width_multiplier * 2)
elseif width == "half" then
control:SetWidth(width_multiplier / 2)
elseif (type(width) == "number") then
control:SetWidth(width_multiplier * width)
elseif width == "relative" and relWidth then
control:SetRelativeWidth(relWidth)
elseif width == "full" then
control.width = "fill"
local customWidth = control.customWidth or GetOptionsMemberValue("customWidth",v,options,path,appName)
if control.width ~= "fill" or customWidth then
if customWidth then
control:SetWidth(customWidth)
else
control:SetWidth(width_multiplier)
local width = GetOptionsMemberValue("width",v,options,path,appName)
if width == "double" then
control:SetWidth(width_multiplier * 2)
elseif width == "half" then
control:SetWidth(width_multiplier / 2)
elseif (type(width) == "number") then
control:SetWidth(width_multiplier * width)
elseif width == "full" then
control.width = "fill"
else
control:SetWidth(width_multiplier)
end
end
end
if control.SetDisabled then
@@ -1489,7 +1554,6 @@ local function TreeOnButtonEnter(widget, event, uniquevalue, button)
local option = user.option
local path = user.path
local appName = user.appName
local tooltip = AceConfigDialog.tooltip
local feedpath = new()
for i = 1, #path do
@@ -1506,25 +1570,24 @@ local function TreeOnButtonEnter(widget, event, uniquevalue, button)
local name = GetOptionsMemberValue("name", group, options, feedpath, appName)
local desc = GetOptionsMemberValue("desc", group, options, feedpath, appName)
tooltip:SetOwner(button, "ANCHOR_NONE")
tooltip:ClearAllPoints()
if widget.type == "TabGroup" then
tooltip:SetPoint("BOTTOM",button,"TOP")
else
tooltip:SetPoint("LEFT",button,"RIGHT")
end
tooltip:SetText(name, 1, .82, 0, 1, true)
if type(desc) == "string" then
tooltip:AddLine(desc, 1, 1, 1, true)
end
GameTooltip:SetOwner(button, "ANCHOR_CURSOR")
if widget.type == "TabGroup" then
GameTooltip:SetPoint("BOTTOM",button,"TOP")
else
GameTooltip:SetPoint("LEFT",button,"RIGHT")
end
tooltip:Show()
GameTooltip:SetText(name, 1, .82, 0, 1)
GameTooltip:AddLine(desc, 1, 1, 1, 1)
GameTooltip:Show()
end
end
local function TreeOnButtonLeave(widget, event, value, button)
AceConfigDialog.tooltip:Hide()
GameTooltip:Hide()
end
@@ -1692,29 +1755,29 @@ function AceConfigDialog:FeedGroup(appName,options,container,rootframe,path, isR
elseif grouptype == "select" then
local selectGroup = gui:Create("DropdownGroup")
selectGroup:SetTitle(name)
InjectInfo(selectGroup, options, group, path, rootframe, appName)
selectGroup:SetCallback("OnGroupSelected", GroupSelected)
local select = gui:Create("DropdownGroup")
select:SetTitle(name)
InjectInfo(select, options, group, path, rootframe, appName)
select:SetCallback("OnGroupSelected", GroupSelected)
local status = AceConfigDialog:GetStatusTable(appName, path)
if not status.groups then
status.groups = {}
end
selectGroup:SetStatusTable(status.groups)
select:SetStatusTable(status.groups)
local grouplist, orderlist = BuildSelect(group, options, path, appName)
selectGroup:SetGroupList(grouplist, orderlist)
selectGroup:SetUserData("grouplist", grouplist)
selectGroup:SetUserData("orderlist", orderlist)
select:SetGroupList(grouplist, orderlist)
select:SetUserData("grouplist", grouplist)
select:SetUserData("orderlist", orderlist)
local firstgroup = orderlist[1]
if firstgroup then
selectGroup:SetGroup((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or firstgroup)
select:SetGroup((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or firstgroup)
end
selectGroup.width = "fill"
selectGroup.height = "fill"
select.width = "fill"
select.height = "fill"
container:AddChild(selectGroup)
container:AddChild(select)
--assume tree group by default
--if parenttype is tree then this group is already a node on that tree
@@ -1942,19 +2005,17 @@ end
-- convert pre-39 BlizOptions structure to the new format
if oldminor and oldminor < 39 and AceConfigDialog.BlizOptions then
local old = AceConfigDialog.BlizOptions
local newOpt = {}
local new = {}
for key, widget in pairs(old) do
local appName = widget:GetUserData("appName")
if not newOpt[appName] then newOpt[appName] = {} end
newOpt[appName][key] = widget
if not new[appName] then new[appName] = {} end
new[appName][key] = widget
end
AceConfigDialog.BlizOptions = newOpt
AceConfigDialog.BlizOptions = new
else
AceConfigDialog.BlizOptions = AceConfigDialog.BlizOptions or {}
end
AceConfigDialog.BlizOptionsIDMap = AceConfigDialog.BlizOptionsIDMap or {}
local function FeedToBlizPanel(widget, event)
local path = widget:GetUserData("path")
AceConfigDialog:Open(widget:GetUserData("appName"), widget, unpack(path or emptyTbl))
@@ -1976,17 +2037,15 @@ end
-- has to be a head-level note.
--
-- This function returns a reference to the container frame registered with the Interface
-- Options, as well as the registered ID. You can use the ID to open the options with
-- the API function `Settings.OpenToCategory`.
-- Options. You can use this reference to open the options with the API function
-- `InterfaceOptionsFrame_OpenToCategory`.
-- @param appName The application name as given to `:RegisterOptionsTable()`
-- @param name A descriptive name to display in the options tree (defaults to appName)
-- @param parent The parent to use in the interface options tree.
-- @param ... The path in the options table to feed into the interface options panel.
-- @return The reference to the frame registered into the Interface Options.
-- @return The category ID to pass to Settings.OpenToCategory
function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
local BlizOptions = AceConfigDialog.BlizOptions
local BlizOptionsIDMap = AceConfigDialog.BlizOptionsIDMap
local key = appName
for n = 1, select("#", ...) do
@@ -2000,6 +2059,7 @@ function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
if not BlizOptions[appName][key] then
local group = gui:Create("BlizOptionsGroup")
BlizOptions[appName][key] = group
group:SetName(name or appName, parent)
group:SetTitle(name or appName)
group:SetUserData("appName", appName)
@@ -2012,42 +2072,8 @@ function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
end
group:SetCallback("OnShow", FeedToBlizPanel)
group:SetCallback("OnHide", ClearBlizPanel)
local categoryName = name or appName
-- CoA-compat: the Settings.* API (GetCategory / RegisterCanvasLayoutCategory /
-- RegisterCanvasLayoutSubcategory / RegisterAddOnCategory) is a retail-only
-- (Dragonflight+) replacement for the WotLK-era InterfaceOptions_AddCategory.
-- On the 3.3.5-based CoA client Settings is nil, so fall back to the legacy API.
if Settings and Settings.GetCategory then
if parent then
local parentID = BlizOptionsIDMap[parent] or parent
local category = Settings.GetCategory(parentID)
if not category then
error(("The parent category '%s' was not found"):format(parent), 2)
end
local subcategory = Settings.RegisterCanvasLayoutSubcategory(category, group.frame, categoryName)
group:SetName(subcategory.ID, parentID)
else
if BlizOptionsIDMap[categoryName] then
error(("%s has already been added to the Blizzard Options Window with the given name: %s"):format(appName, categoryName), 2)
end
local category = Settings.RegisterCanvasLayoutCategory(group.frame, categoryName)
if not (C_SettingsUtil and C_SettingsUtil.OpenSettingsPanel) then
-- override the ID so the name can be used in Settings.OpenToCategory
-- unfortunately with incoming API changes in 12.0 (and likely classic at some point) this override is no longer possible
category.ID = categoryName
end
group:SetName(category.ID)
BlizOptionsIDMap[categoryName] = category.ID
Settings.RegisterAddOnCategory(category)
end
else
group:SetName(name or appName, parent)
InterfaceOptions_AddCategory(group.frame)
end
return group.frame, group.frame.name
InterfaceOptions_AddCategory(group.frame)
return group.frame
else
error(("%s has already been added to the Blizzard Options Window with the given path"):format(appName), 2)
end