if not WeakAuras.IsCorrectVersion() then return end local AddonName, OptionsPrivate = ... local L = WeakAuras.L local regionOptions = WeakAuras.regionOptions local commonOptionsCache = {} OptionsPrivate.commonOptionsCache = commonOptionsCache commonOptionsCache.data = {} commonOptionsCache.GetOrCreateData = function(self, info) local base = self.data for i, key in ipairs(info) do base[key] = base[key] or {} base = base[key] end return base end commonOptionsCache.GetData = function(self, info) local base = self.data for i, key in ipairs(info) do if base[key] and type(base[key]) == "table" then base = base[key] else return nil end end return base end commonOptionsCache.SetSameAll = function(self, info, value) local base = self:GetOrCreateData(info) base.sameAll = value end commonOptionsCache.GetSameAll = function(self, info) local base = self:GetData(info) if base then return base.sameAll end end commonOptionsCache.Clear = function(self) self.data = {} end local parsePrefix = function(input, data, create) local subRegionIndex, property = string.match(input, "^sub%.(%d+)%..-%.(.+)") subRegionIndex = tonumber(subRegionIndex) if subRegionIndex then if create then data.subRegions = data.subRegions or {} data.subRegions[subRegionIndex] = data.subRegions[subRegionIndex] or {} else if not data.subRegions or not data.subRegions[subRegionIndex] then return nil end end return data.subRegions[subRegionIndex], property end local index = string.find(input, ".", 1, true); if (index) then return data, string.sub(input, index + 1); end return data, input end local function setFuncs(option, input) if type(input) == "function" then option.func = input else option.func = input.func option.disabled = input.disabled end end local function addCollapsibleHeader(options, key, input, order, isGroupTab) if input.__noHeader then return end local title = input.__title local hasAdd = input.__add local hasDelete = input.__delete local hasUp = input.__up local hasDown = input.__down local hasDuplicate = input.__duplicate local hasApplyTemplate = input.__applyTemplate local defaultCollapsed = input.__collapsed local hiddenFunc = input.__hidden local notcollapsable = input.__notcollapsable local marginTop = input.__topLine local withoutheader = input.__withoutheader local isCollapsed = input.__isCollapsed local setCollapsed = input.__setCollapsed if not isCollapsed then isCollapsed = function() return OptionsPrivate.IsCollapsed("collapse", "region", key, defaultCollapsed) end end if not setCollapsed then setCollapsed = function(info, button, secondCall) if not notcollapsable and not secondCall then local isCollapsed = OptionsPrivate.IsCollapsed("collapse", "region", key, defaultCollapsed) OptionsPrivate.SetCollapsed("collapse", "region", key, not isCollapsed) end end end local titleWidth = WeakAuras.doubleWidth - (hasAdd and 0.15 or 0) - (hasDelete and 0.15 or 0) - (hasUp and 0.15 or 0) - (hasDown and 0.15 or 0) - (hasDuplicate and 0.15 or 0) - (hasApplyTemplate and 0.15 or 0) options[key .. "collapseSpacer"] = { type = marginTop and "header" or "description", name = "", order = order, width = "full", hidden = hiddenFunc, } if not withoutheader then options[key .. "collapseButton"] = { type = "execute", name = title, order = order + 0.1, width = titleWidth, func = setCollapsed, image = function() if notcollapsable then return "Interface\\AddOns\\WeakAuras\\Media\\Textures\\bullet1", 18, 18 else return isCollapsed() and "Interface\\AddOns\\WeakAuras\\Media\\Textures\\expand" or "Interface\\AddOns\\WeakAuras\\Media\\Textures\\collapse", 18, 18 end end, control = "WeakAurasExpand", hidden = hiddenFunc } if hasAdd then options[key .. "addButton"] = { type = "execute", name = L["Add"], order = order + 0.2, width = 0.15, image = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\add", imageWidth = 24, imageHeight = 24, control = "WeakAurasIcon", hidden = hiddenFunc } setFuncs(options[key .. "addButton"], input.__add) end if hasUp then options[key .. "upButton"] = { type = "execute", name = L["Move Up"], order = order + 0.3, width = 0.15, image = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\moveup", imageWidth = 24, imageHeight = 24, control = "WeakAurasIcon", hidden = hiddenFunc } setFuncs(options[key .. "upButton"], input.__up) end if hasDown then options[key .. "downButton"] = { type = "execute", name = L["Move Down"], order = order + 0.4, width = 0.15, image = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\movedown", imageWidth = 24, imageHeight = 24, control = "WeakAurasIcon", hidden = hiddenFunc } setFuncs(options[key .. "downButton"], input.__down) end if hasDuplicate then options[key .. "duplicateButton"] = { type = "execute", name = L["Duplicate"], order = order + 0.5, width = 0.15, image = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\duplicate", imageWidth = 24, imageHeight = 24, control = "WeakAurasIcon", hidden = hiddenFunc } setFuncs(options[key .. "duplicateButton"], input.__duplicate) end if hasDelete then options[key .. "deleteButton"] = { type = "execute", name = L["Delete"], order = order + 0.6, width = 0.15, image = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\delete", imageWidth = 24, imageHeight = 24, control = "WeakAurasIcon", hidden = hiddenFunc } setFuncs(options[key .. "deleteButton"], input.__delete) end if hasApplyTemplate then options[key .. "applyTemplate"] = { type = "execute", name = L["Apply Template"], order = order + 0.7, width = 0.15, image = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\template", imageWidth = 24, imageHeight = 24, control = "WeakAurasIcon", hidden = hiddenFunc } setFuncs(options[key .. "applyTemplate"], input.__applyTemplate) end end if hiddenFunc then return function() return hiddenFunc() or isCollapsed() end else return isCollapsed end end local function copyOptionTable(input, orderAdjustment, collapsedFunc) local resultOption = CopyTable(input); resultOption.order = orderAdjustment + resultOption.order; if collapsedFunc then local oldHidden = resultOption.hidden; if oldHidden ~= nil then local oldFunc if type(oldHidden) ~= "function" then oldFunc = function(...) return oldHidden end else oldFunc = oldHidden end resultOption.hidden = function(...) if collapsedFunc() then return true else return oldFunc(...) end end else resultOption.hidden = collapsedFunc; end end return resultOption; end local flattenRegionOptions = function(allOptions, isGroupTab) local result = {}; local base = 1000; for optionGroup, options in pairs(allOptions) do local groupBase = base * options.__order local collapsedFunc = addCollapsibleHeader(result, optionGroup, options, groupBase, isGroupTab) for optionName, option in pairs(options) do if not optionName:find("^__") then result[optionGroup .. "." .. optionName] = copyOptionTable(option, groupBase, collapsedFunc); end end end return result; end local function fixMetaOrders(allOptions) -- assumes that the results from create methods are contiguous in __order fields -- shifts __order fields such that each optionGroup is ordered correctly relative -- to its peers, but has a unique __order number in the combined option table. local groupOrders = {} local maxGroupOrder = 0 for optionGroup, options in pairs(allOptions) do local metaOrder = options.__order groupOrders[metaOrder] = groupOrders[metaOrder] or {} maxGroupOrder = max(maxGroupOrder, metaOrder) tinsert(groupOrders[metaOrder], optionGroup) end local index = 0 local newOrder = 1 while index <= maxGroupOrder do index = index + 1 if groupOrders[index] then table.sort(groupOrders[index]) for _, optionGroup in ipairs(groupOrders[index]) do allOptions[optionGroup].__order = newOrder newOrder = newOrder + 1 end end end end local function removeFuncs(intable, removeFunc) for i,v in pairs(intable) do if(i == "get" or i == "set" or i == "hidden" or i == "disabled") then intable[i] = nil; elseif (i == "func" and removeFunc) then intable[i] = nil elseif(type(v) == "table" and i ~= "values" and i ~= "extraFunctions") then removeFuncs(v, removeFunc) end end end local function getChildOption(options, info) for i=1,#info do options = options.args[info[i]]; if not(options) then return nil; end if (options.hidden) then local type = type(options.hidden); if (type == "bool") then if (options.hidden) then return nil; end elseif (type == "function") then if (options.hidden(info)) then return nil; end end end end return options end local function hiddenChild(childOptionTable, info) for i=#childOptionTable,0,-1 do if(childOptionTable[i].hidden ~= nil) then if(type(childOptionTable[i].hidden) == "boolean") then return childOptionTable[i].hidden; elseif(type(childOptionTable[i].hidden) == "function") then return childOptionTable[i].hidden(info); end end end return false; end local function CreateHiddenAll(subOption) return function(data, info) if(#data.controlledChildren == 0) then return true; end for child in OptionsPrivate.Private.TraverseLeafs(data) do local childOptions = OptionsPrivate.EnsureOptions(child, subOption) local childOption = childOptions; local childOptionTable = {[0] = childOption}; for i=1,#info do childOption = childOption.args[info[i]]; childOptionTable[i] = childOption; end if (childOption) then if (not hiddenChild(childOptionTable, info)) then return false; end end end return true; end end local function disabledChild(childOptionTable, info) for i=#childOptionTable,0,-1 do if(childOptionTable[i].disabled ~= nil) then if(type(childOptionTable[i].disabled) == "boolean") then return childOptionTable[i].disabled; elseif(type(childOptionTable[i].disabled) == "function") then return childOptionTable[i].disabled(info); end end end return false; end local function CreateDisabledAll(subOption) return function(data, info) for child in OptionsPrivate.Private.TraverseLeafs(data) do local childOptions = OptionsPrivate.EnsureOptions(child, subOption); local childOption = childOptions; local childOptionTable = {[0] = childOption}; for i=1,#info do childOption = childOption.args[info[i]]; childOptionTable[i] = childOption; end if (childOption) then if (not disabledChild(childOptionTable, info)) then return false; end end end return true; end end local function disabledOrHiddenChild(childOptionTable, info) return hiddenChild(childOptionTable, info) or disabledChild(childOptionTable, info); end local function replaceNameDescFuncs(intable, data, subOption) local function compareTables(tableA, tableB) if(#tableA == #tableB) then for j=1,#tableA do if(type(tableA[j]) == "number" and type(tableB[j]) == "number") then if((math.floor(tableA[j] * 100) / 100) ~= (math.floor(tableB[j] * 100) / 100)) then return false; end else if(tableA[j] ~= tableB[j]) then return false; end end end else return false; end return true; end local function getValueFor(options, info, key) local childOptionTable = {[0] = options}; for i=1,#info do options = options.args[info[i]]; if (not options) then return nil; end childOptionTable[i] = options; end if (disabledOrHiddenChild(childOptionTable, info)) then return nil; end for i=#childOptionTable,0,-1 do if(childOptionTable[i][key]) then return childOptionTable[i][key]; end end return nil; end local function combineKeys(info) local combinedKeys = nil; for child in OptionsPrivate.Private.TraverseLeafs(data) do local values = getValueFor(OptionsPrivate.EnsureOptions(child, subOption), info, "values"); if (values) then if (type(values) == "function") then values = values(info); end if (type(values) == "table") then combinedKeys = combinedKeys or {}; for k, v in pairs(values) do combinedKeys[k] = v; end end end end return combinedKeys; end local function regionPrefix(input) local index = string.find(input, ".", 1, true); if (index) then local regionType = string.sub(input, 1, index - 1); return regionOptions[regionType] and regionType; end return nil; end local function sameAll(info) local cached = commonOptionsCache:GetSameAll(info) if (cached ~= nil) then return cached end local combinedValues = {}; local first = true; local combinedKeys = combineKeys(info); local isToggle = nil for child in OptionsPrivate.Private.TraverseLeafs(data) do if isToggle == nil then local childOption = getChildOption(OptionsPrivate.EnsureOptions(child, subOption), info) isToggle = childOption and childOption.type == "toggle" end local regionType = regionPrefix(info[#info]); if(child and (not regionType or child.regionType == regionType or regionType == "sub")) then local childOptions = OptionsPrivate.EnsureOptions(child, subOption) local get = getValueFor(childOptions, info, "get"); if (combinedKeys) then for key, _ in pairs(combinedKeys) do local values = {}; if (get) then values = { get(info, key) }; end if (combinedValues[key] == nil) then combinedValues[key] = values; else if (not compareTables(combinedValues[key], values)) then commonOptionsCache:SetSameAll(info, false) return nil; end end end else local values = {}; if (get) then values = { get(info) }; local childOption = getChildOption(childOptions, info) if isToggle and values[1] == nil then values[1] = false end end if(first) then combinedValues = values; first = false; else if (not compareTables(combinedValues, values)) then commonOptionsCache:SetSameAll(info, false) return nil; end end end end end commonOptionsCache:SetSameAll(info, true) return true; end local function nameAll(info) local combinedName; local first = true; local foundNames = {}; for child in OptionsPrivate.Private.TraverseLeafs(data) do local childOption = getChildOption(OptionsPrivate.EnsureOptions(child, subOption), info); if (childOption) then local name; if(type(childOption.name) == "function") then name = childOption.name(info); else name = childOption.name; end if (not name) then -- Do nothing elseif(first) then if (name ~= "") then combinedName = name; first = false; end foundNames[name] = true; elseif not(foundNames[name]) then if (name ~= "") then if (childOption.type == "description") then combinedName = combinedName .. "\n\n" .. name; else combinedName = combinedName .. " / " .. name; end end foundNames[name] = true; end end end return combinedName or ""; end local function descAll(info) local combinedDesc; local first = true; for child in OptionsPrivate.Private.TraverseLeafs(data) do local childOption = getChildOption(OptionsPrivate.EnsureOptions(child, subOption), info); if (childOption) then local desc; if(type(childOption.desc) == "function") then desc = childOption.desc(info); else desc = childOption.desc; end if(first) then combinedDesc = desc; first = false; elseif not(combinedDesc == desc) then return L["Not all children have the same value for this option"]; end end end return combinedDesc; end local function recurse(intable) for i,v in pairs(intable) do if(i == "name" and type(v) ~= "table") then intable.name = function(info) local name = nameAll(info); if(sameAll(info)) then return name; else if(name == "") then return name; else return "|cFF4080FF"..(name or "error"); end end end intable.desc = function(info) if(sameAll(info)) then return descAll(info); else local combinedKeys = nil; if (intable.type == "multiselect") then combinedKeys = combineKeys(info) end local values = {}; for child in OptionsPrivate.Private.TraverseLeafs(data) do local childOptions = OptionsPrivate.EnsureOptions(child, subOption) local childOption = childOptions; local childOptionTable = {[0] = childOption}; for i=1,#info do childOption = childOption.args[info[i]]; childOptionTable[i] = childOption; end if (childOption and not hiddenChild(childOptionTable, info)) then for i=#childOptionTable,0,-1 do if(childOptionTable[i].get) then if(intable.type == "toggle") then local name, tri; if(type(childOption.name) == "function") then name = childOption.name(info); tri = true; else name = childOption.name; end if(tri and childOptionTable[i].get(info)) then tinsert(values, "|cFFE0E000"..child.id..": |r"..name); elseif(tri) then tinsert(values, "|cFFE0E000"..child.id..": |r"..L["Ignored"]); elseif(childOptionTable[i].get(info)) then tinsert(values, "|cFFE0E000"..child.id..": |r|cFF00FF00"..L["Enabled"]); else tinsert(values, "|cFFE0E000"..child.id..": |r|cFFFF0000"..L["Disabled"]); end elseif(intable.type == "color") then local r, g, b = childOptionTable[i].get(info); r, g, b = r or 1, g or 1, b or 1; tinsert(values, ("|cFF%2x%2x%2x%s"):format(r * 220 + 35, g * 220 + 35, b * 220 + 35, child.id)); elseif(intable.type == "select") then local selectValues = type(intable.values) == "table" and intable.values or intable.values(info); local key = childOptionTable[i].get(info); local display = key and selectValues[key] or L["None"]; if intable.dialogControl == "LSM30_Font" then tinsert(values, "|cFFE0E000"..child.id..": |r" .. key); else tinsert(values, "|cFFE0E000"..child.id..": |r"..display); end elseif(intable.type == "multiselect") then local selectedValues = {}; for k, v in pairs(combinedKeys) do if (childOptionTable[i].get(info, k)) then tinsert(selectedValues, tostring(v)) end end tinsert(values, "|cFFE0E000"..child.id..": |r"..table.concat(selectedValues, ",")); else local display = childOptionTable[i].get(info) or L["None"]; if(type(display) == "number") then display = math.floor(display * 100) / 100; else if #display > 50 then display = display:sub(1, 50) .. "..." end end tinsert(values, "|cFFE0E000"..child.id..": |r"..display); end break; end end end end return table.concat(values, "\n"); end end elseif(type(v) == "table" and i ~= "values") then recurse(v); end end end recurse(intable); end local function replaceImageFuncs(intable, data, subOption) local function imageAll(info) local combinedImage = {}; local first = true; for child in OptionsPrivate.Private.TraverseLeafs(data) do local childOption = OptionsPrivate.EnsureOptions(child, subOption) if not(childOption) then return "error" end childOption = getChildOption(childOption, info); if childOption and childOption.image then local image = {childOption.image(info)}; if(first) then combinedImage = image; first = false; else if not(combinedImage[1] == image[1]) then return "", 0, 0; end end end end return unpack(combinedImage); end local function recurse(intable) for i,v in pairs(intable) do if(i == "image" and type(v) == "function") then intable[i] = imageAll; elseif(type(v) == "table" and i ~= "values") then recurse(v); end end end recurse(intable); end local function replaceValuesFuncs(intable, data, subOption) local function valuesAll(info) local combinedValues = {}; local handledValues = {}; local first = true; for child in OptionsPrivate.Private.TraverseLeafs(data) do local childOption = OptionsPrivate.EnsureOptions(child, subOption) if not(childOption) then return "error" end childOption = getChildOption(childOption, info); if (childOption) then local values = childOption.values; if (type(values) == "function") then values = values(info); end if(first) then for k, v in pairs(values) do handledValues[k] = handledValues[k] or {}; handledValues[k][v] = true; combinedValues[k] = v; end first = false; else for k, v in pairs(values) do if (handledValues[k] and handledValues[k][v]) then -- Already known key/value pair else if (combinedValues[k]) then combinedValues[k] = combinedValues[k] .. "/" .. v; else combinedValues[k] = v; end handledValues[k] = handledValues[k] or {}; handledValues[k][v] = true; end end end end end return combinedValues; end local function recurse(intable) for i,v in pairs(intable) do if(i == "values" and type(v) == "function") then intable[i] = valuesAll; elseif(type(v) == "table" and i ~= "values") then recurse(v); end end end recurse(intable); end local getHelper = { first = true, combinedValues = {}, same = true, Set = function(self, values) if self.same == false then return false end if(self.first) then self.combinedValues = values; self.first = false; return true else if(#self.combinedValues == #values) then for j=1,#self.combinedValues do if(type(self.combinedValues[j]) == "number" and type(values[j]) == "number") then if((math.floor(self.combinedValues[j] * 100) / 100) ~= (math.floor(values[j] * 100) / 100)) then self.same = false; break; end else if(self.combinedValues[j] ~= values[j]) then self.same = false; break; end end end else self.same = false; end return self.same end end, Get = function(self) return self.combinedValues end, GetSame = function(self) return self.same end, HasValue = function(self) return not self.first end } local function CreateGetAll(subOption) return function(data, info, ...) local isToggle = nil local allChildren = CopyTable(getHelper) local enabledChildren = CopyTable(getHelper) for child in OptionsPrivate.Private.TraverseLeafs(data) do if isToggle == nil then local childOptions = getChildOption(OptionsPrivate.EnsureOptions(child, subOption), info) isToggle = childOptions and childOptions.type == "toggle" end local childOptions = OptionsPrivate.EnsureOptions(child, subOption) local childOption = childOptions; local childOptionTable = {[0] = childOption}; for i=1,#info do childOption = childOption.args[info[i]]; childOptionTable[i] = childOption; end if (childOption) then for i=#childOptionTable,0,-1 do if(childOptionTable[i].get) then local values = {childOptionTable[i].get(info, ...)}; if isToggle and values[1] == nil then values[1] = false end allChildren:Set(values) if not disabledOrHiddenChild(childOptionTable, info) then enabledChildren:Set(values) end if not allChildren:GetSame() and not enabledChildren:GetSame() then return nil; end break; end end end end if enabledChildren:HasValue() then return unpack(enabledChildren:Get()) else -- This can happen if all children are disabled return unpack(allChildren:Get()) end end end local function CreateSetAll(subOption, getAll) return function(data, info, ...) OptionsPrivate.Private.pauseOptionsProcessing(true); OptionsPrivate.Private.PauseAllDynamicGroups() local before = getAll(data, info, ...) for child in OptionsPrivate.Private.TraverseLeafs(data) do local childOptions = OptionsPrivate.EnsureOptions(child, subOption) local childOption = childOptions; local childOptionTable = {[0] = childOption}; for i=1,#info do childOption = childOption.args[info[i]]; childOptionTable[i] = childOption; end if (childOption and not disabledOrHiddenChild(childOptionTable, info)) then for i=#childOptionTable,0,-1 do if(childOptionTable[i].set) then if (childOptionTable[i].type == "multiselect") then childOptionTable[i].set(info, ..., not before); else childOptionTable[i].set(info, ...); end break; end end end end OptionsPrivate.Private.ResumeAllDynamicGroups() OptionsPrivate.Private.pauseOptionsProcessing(false); OptionsPrivate.Private.ScanForLoads(); OptionsPrivate.SortDisplayButtons(nil, true); OptionsPrivate.UpdateOptions() end end local function CreateExecuteAll(subOption) return function(data, info, button) local secondCall = nil for child in OptionsPrivate.Private.TraverseLeafs(data) do local childOptions = OptionsPrivate.EnsureOptions(child, subOption) local childOption = childOptions; local childOptionTable = {[0] = childOption}; for i=1,#info do childOption = childOption.args[info[i]]; childOptionTable[i] = childOption; end if (childOption and not disabledOrHiddenChild(childOptionTable, info)) then -- Some functions, that is the expand/collapse functions need to be -- effectively called only once. Passing in the secondCall parameter allows -- them to distinguish between the first and every other call childOption.func(info, button, secondCall) secondCall = true end end WeakAuras.ClearAndUpdateOptions(data.id) end end local function PositionOptions(id, data, _, hideWidthHeight, disableSelfPoint, group) local metaOrder = 99 local function IsParentDynamicGroup() if data.parent then local parentData = WeakAuras.GetData(data.parent) return parentData and parentData.regionType == "dynamicgroup" end end local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20; local positionOptions = { __title = L["Position Settings"], __order = metaOrder, width = { type = "range", width = WeakAuras.normalWidth, name = L["Width"], order = 60, min = 1, softMax = screenWidth, max = 4 * screenWidth, bigStep = 1, hidden = hideWidthHeight, }, height = { type = "range", width = WeakAuras.normalWidth, name = L["Height"], order = 61, min = 1, softMax = screenHeight, max = 4 * screenHeight, bigStep = 1, hidden = hideWidthHeight, }, xOffset = { type = "range", width = WeakAuras.normalWidth, name = L["X Offset"], order = 62, softMin = (-1 * screenWidth), min = (-4 * screenWidth), softMax = screenWidth, max = 4 * screenWidth, bigStep = 10, get = function() return data.xOffset end, set = function(info, v) data.xOffset = v; WeakAuras.Add(data); WeakAuras.UpdateThumbnail(data); OptionsPrivate.ResetMoverSizer(); if(data.parent) then local parentData = WeakAuras.GetData(data.parent); if(parentData) then WeakAuras.Add(parentData); end end end }, yOffset = { type = "range", width = WeakAuras.normalWidth, name = L["Y Offset"], order = 63, softMin = (-1 * screenHeight), min = (-4 * screenHeight), softMax = screenHeight, max = 4 * screenHeight, bigStep = 10, get = function() return data.yOffset end, set = function(info, v) data.yOffset = v; WeakAuras.Add(data); WeakAuras.UpdateThumbnail(data); OptionsPrivate.ResetMoverSizer(); if(data.parent) then local parentData = WeakAuras.GetData(data.parent); if(parentData) then WeakAuras.Add(parentData); end end end }, selfPoint = { type = "select", width = WeakAuras.normalWidth, name = L["Anchor"], order = 70, hidden = IsParentDynamicGroup, values = OptionsPrivate.Private.point_types, disabled = disableSelfPoint, }, anchorFrameType = { type = "select", width = WeakAuras.normalWidth, name = L["Anchored To"], order = 72, hidden = IsParentDynamicGroup, values = (data.regionType == "group" or data.regionType == "dynamicgroup") and OptionsPrivate.Private.anchor_frame_types_group or OptionsPrivate.Private.anchor_frame_types, }, -- Input field to select frame to anchor on anchorFrameFrame = { type = "input", width = WeakAuras.normalWidth, name = L["Frame"], order = 72.2, hidden = function() if (IsParentDynamicGroup()) then return true; end return not (data.anchorFrameType == "SELECTFRAME") end }, -- Button to select frame to anchor on chooseAnchorFrameFrame = { type = "execute", width = WeakAuras.normalWidth, name = L["Choose"], order = 72.4, hidden = function() if (IsParentDynamicGroup()) then return true; end return not (data.anchorFrameType == "SELECTFRAME") end, func = function() OptionsPrivate.StartFrameChooser(data, {"anchorFrameFrame"}); end }, anchorPoint = { type = "select", width = WeakAuras.normalWidth, name = function() if (data.anchorFrameType == "SCREEN") then return L["To Screen's"] elseif (data.anchorFrameType == "PRD") then return L["To Personal Ressource Display's"]; else return L["To Frame's"]; end end, order = 75, hidden = function() if (data.parent) then --if (IsParentDynamicGroup()) then -- return true; --end return data.anchorFrameType == "SCREEN" or data.anchorFrameType == "MOUSE"; else return data.anchorFrameType == "MOUSE"; end end, values = OptionsPrivate.Private.point_types }, anchorPointGroup = { type = "select", width = WeakAuras.normalWidth, name = L["To Group's"], order = 76, hidden = function() if (data.anchorFrameType ~= "SCREEN") then return true; end if (data.parent) then return IsParentDynamicGroup(); end return true; end, disabled = true, values = {["CENTER"] = L["Anchor Point"]}, get = function() return "CENTER"; end }, anchorFrameParent = { type = "toggle", width = WeakAuras.normalWidth, name = L["Set Parent to Anchor"], desc = L["Sets the anchored frame as the aura's parent, causing the aura to inherit attributes such as visibility and scale."], order = 77, get = function() return data.anchorFrameParent or data.anchorFrameParent == nil; end, hidden = function() return (data.anchorFrameType == "SCREEN" or data.anchorFrameType == "MOUSE" or IsParentDynamicGroup()); end, }, frameStrata = { type = "select", width = WeakAuras.normalWidth, name = L["Frame Strata"], order = 78, values = OptionsPrivate.Private.frame_strata_types }, anchorFrameSpace = { type = "execute", width = WeakAuras.normalWidth, name = "", order = 79, image = function() return "", 0, 0 end, hidden = function() return not (data.anchorFrameType ~= "SCREEN" or IsParentDynamicGroup()); end }, }; OptionsPrivate.commonOptions.AddCodeOption(positionOptions, data, L["Custom Anchor"], "custom_anchor", "https://github.com/WeakAuras/WeakAuras2/wiki/Custom-Code-Blocks#custom-anchor-function", 72.1, function() return not(data.anchorFrameType == "CUSTOM" and not IsParentDynamicGroup()) end, {"customAnchor"}, false, { setOnParent = group }) return positionOptions; end local function BorderOptions(id, data, showBackDropOptions, hiddenFunc, order) local borderOptions = { borderHeader = { type = "header", order = order, name = L["Border Settings"], hidden = hiddenFunc, }, border = { type = "toggle", width = WeakAuras.doubleWidth, name = L["Show Border"], order = order + 0.1, hidden = hiddenFunc, }, borderEdge = { type = "select", width = WeakAuras.normalWidth, dialogControl = "LSM30_Border", name = L["Border Style"], order = order + 0.2, values = AceGUIWidgetLSMlists.border, hidden = function() return hiddenFunc and hiddenFunc() or not data.border end, }, borderBackdrop = { type = "select", width = WeakAuras.normalWidth, dialogControl = "LSM30_Background", name = L["Backdrop Style"], order = order + 0.3, values = AceGUIWidgetLSMlists.background, hidden = function() return hiddenFunc and hiddenFunc() or not data.border end, }, borderOffset = { type = "range", width = WeakAuras.normalWidth, name = L["Border Offset"], order = order + 0.3, softMin = 0, softMax = 32, bigStep = 1, hidden = function() return hiddenFunc and hiddenFunc() or not data.border end, }, borderSize = { type = "range", width = WeakAuras.normalWidth, name = L["Border Size"], order = order + 0.4, min = 1, softMax = 64, bigStep = 1, hidden = function() return hiddenFunc and hiddenFunc() or not data.border end, }, borderInset = { type = "range", width = WeakAuras.normalWidth, name = L["Border Inset"], order = order + 0.5, softMin = 1, softMax = 32, bigStep = 1, hidden = function() return hiddenFunc and hiddenFunc() or not data.border end, }, border_spacer = { type = "description", name = "", width = WeakAuras.normalWidth, hidden = function() return hiddenFunc and hiddenFunc() or not data.border end, order = order + 0.6 }, borderColor = { type = "color", width = WeakAuras.normalWidth, name = L["Border Color"], hasAlpha = true, order = order + 0.7, hidden = function() return hiddenFunc and hiddenFunc() or not data.border end, }, borderInFront = { type = "toggle", width = WeakAuras.normalWidth, name = L["Border in Front"], order = order + 0.8, hidden = function() return hiddenFunc and hiddenFunc() or not data.border or not showBackDropOptions end, }, backdropColor = { type = "color", width = WeakAuras.normalWidth, name = L["Backdrop Color"], hasAlpha = true, order = order + 0.9, hidden = function() return hiddenFunc and hiddenFunc() or not data.border end, }, backdropInFront = { type = "toggle", width = WeakAuras.normalWidth, name = L["Backdrop in Front"], order = order + 1, hidden = function() return hiddenFunc and hiddenFunc() or not data.border or not showBackDropOptions end, }, } return borderOptions; end local function noop() end local function GetCustomCode(data, path) for _, key in ipairs(path) do if (not data or not data[key]) then return nil; end data = data[key]; end return data; end local function AddCodeOption(args, data, name, prefix, url, order, hiddenFunc, path, encloseInFunction, options) options = options and CopyTable(options) or {} options.extraFunctions = options.extraFunctions or {}; tinsert(options.extraFunctions, 1, { buttonLabel = L["Expand"], func = function(info) OptionsPrivate.OpenTextEditor(OptionsPrivate.GetPickedDisplay(), path, encloseInFunction, options.multipath, options.reloadOptions, options.setOnParent, url, options.validator) end }); args[prefix .. "_custom"] = { type = "input", width = WeakAuras.doubleWidth, name = name, order = order, multiline = true, hidden = hiddenFunc, control = "WeakAurasMultiLineEditBox", arg = { extraFunctions = options.extraFunctions, }, set = function(info, v) local subdata = data; for i = 1, #path -1 do local key = path[i]; subdata[key] = subdata[key] or {}; subdata = subdata[key]; end subdata[path[#path]] = v; WeakAuras.Add(data); if (options.extraSetFunction) then options.extraSetFunction(); end if (options.reloadOptions) then OptionsPrivate.ClearOptions(data.id) end end, get = function(info) return GetCustomCode(data, path); end }; args[prefix .. "_customError"] = { type = "description", name = function() if hiddenFunc() then return ""; end local code = GetCustomCode(data, path); if (not code or code:trim() == "") then return "" end if (encloseInFunction) then code = "function() "..code.."\n end"; end code = "return " .. code; local loadedFunction, errorString = loadstring(code); if not errorString then if options.validator then local ok, validate = xpcall(loadedFunction, function(err) errorString = err end) if ok then errorString = options.validator(validate) end end end return errorString and "|cFFFF0000"..errorString or ""; end, width = WeakAuras.doubleWidth, order = order + 0.002, hidden = function() if (hiddenFunc()) then return true; end local code = GetCustomCode(data, path); if (not code or code:trim() == "") then return true; end if (encloseInFunction) then code = "function() "..code.."\n end"; end code = "return " .. code; local loadedFunction, errorString = loadstring(code); if(errorString and not loadedFunction) then return false; else if options.validator then local ok, validate = xpcall(loadedFunction, noop) if ok then return options.validator(validate) end return false end return true; end end }; end local function AddCommonTriggerOptions(options, data, triggernum, doubleWidth) local trigger = data.triggers[triggernum].trigger local trigger_types = {}; for type, triggerSystem in pairs(OptionsPrivate.Private.triggerTypes) do trigger_types[type] = triggerSystem.GetName(type); end options.type = { type = "select", width = doubleWidth and WeakAuras.doubleWidth or WeakAuras.normalWidth, name = L["Type"], desc = L["The type of trigger"], order = 1.1, values = trigger_types, get = function(info) return trigger.type end, set = function(info, v) trigger.type = v; local prototype = trigger.event and OptionsPrivate.Private.event_prototypes[trigger.event]; if OptionsPrivate.Private.event_categories[v] and OptionsPrivate.Private.event_categories[v].default then if not prototype or prototype.type ~= v then trigger.event = OptionsPrivate.Private.event_categories[v].default end end WeakAuras.Add(data); WeakAuras.UpdateThumbnail(data); WeakAuras.UpdateDisplayButton(data); WeakAuras.ClearAndUpdateOptions(data.id); end, control = "WeakAurasSortedDropdown" } end -- Adds setters/getters to trigger options -- This is used by both aura triggers local function AddTriggerGetterSetter(options, data, triggernum) local trigger = data.triggers[triggernum].trigger for key, option in pairs(options) do if type(option) == "table" and not option.get then if option.type == "multiselect" then option.get = function(info, index) return trigger[key] and trigger[key][index] end else option.get = function(info) return trigger[key] end end end if type(option) == "table" and not option.set then if option.type == "multiselect" then option.set = function(info, index, value) if type(trigger[key]) ~= "table" then trigger[key] = {} end if value ~= nil then if value then trigger[key][index] = true else trigger[key][index] = nil end else if trigger[key][index] then trigger[key][index] = nil else trigger[key][index] = true end end if next(trigger[key]) == nil then trigger[key] = nil end WeakAuras.Add(data) WeakAuras.ClearAndUpdateOptions(data.id) end else option.set = function(info, v) trigger[key] = v WeakAuras.Add(data) WeakAuras.ClearAndUpdateOptions(data.id) end end end end end OptionsPrivate.commonOptions = {} OptionsPrivate.commonOptions.parsePrefix = parsePrefix OptionsPrivate.commonOptions.flattenRegionOptions = flattenRegionOptions OptionsPrivate.commonOptions.fixMetaOrders = fixMetaOrders OptionsPrivate.commonOptions.removeFuncs = removeFuncs OptionsPrivate.commonOptions.CreateHiddenAll = CreateHiddenAll OptionsPrivate.commonOptions.CreateDisabledAll = CreateDisabledAll OptionsPrivate.commonOptions.replaceNameDescFuncs = replaceNameDescFuncs OptionsPrivate.commonOptions.replaceImageFuncs = replaceImageFuncs OptionsPrivate.commonOptions.replaceValuesFuncs = replaceValuesFuncs OptionsPrivate.commonOptions.CreateGetAll = CreateGetAll OptionsPrivate.commonOptions.CreateSetAll = CreateSetAll OptionsPrivate.commonOptions.CreateExecuteAll = CreateExecuteAll OptionsPrivate.commonOptions.PositionOptions = PositionOptions OptionsPrivate.commonOptions.BorderOptions = BorderOptions OptionsPrivate.commonOptions.AddCodeOption = AddCodeOption OptionsPrivate.commonOptions.AddCommonTriggerOptions = AddCommonTriggerOptions OptionsPrivate.commonOptions.AddTriggerGetterSetter = AddTriggerGetterSetter