enUS Localization Update Announcement / localization-update-announcement (push) Canceled after 0s
700 lines
30 KiB
Lua
700 lines
30 KiB
Lua
-- Bagshui Inventory Prototype: Settings Menu
|
|
|
|
Bagshui:AddComponent(function()
|
|
local Inventory = Bagshui.prototypes.Inventory
|
|
|
|
-- Maximum number of previously selected colors to store.
|
|
local COLOR_HISTORY_LIMIT = 10
|
|
|
|
-- Do-nothing function to be used when a setting doesn't have an update function.
|
|
local function emptyFunction() end
|
|
|
|
--- Show the Inventory settings menu.
|
|
---@param menu table Menu table.
|
|
function Inventory:OpenSettingsMenu(menu)
|
|
-- Docked frames should show the parent frame's menu.
|
|
if self.dockTo then
|
|
Bagshui.components[self.dockTo].menus:OpenMenu("Settings")
|
|
return
|
|
end
|
|
|
|
-- This is where the menu should anchor, in theory. See comments on
|
|
-- Inventory:FixSettingsMenuPosition() for more.
|
|
self.lastSettingsAnchor = self.settings.windowAnchorYPoint .. self.settings.windowAnchorXPoint
|
|
self.lastSettingsXOffset = BsSkin.menuShiftRight * (self.settings.windowAnchorXPoint == "LEFT" and 1 or -1)
|
|
|
|
-- Special property
|
|
Bagshui.menuFrame.bagshuiData.noFirstLevelRepositionNeeded = true
|
|
|
|
-- Open the menu.
|
|
self.menus:ShowMenu(
|
|
"Settings",
|
|
self.uiFrame,
|
|
self.lastSettingsXOffset,
|
|
0,
|
|
self.lastSettingsAnchor,
|
|
BsUtil.FlipAnchorPointComponent(self.lastSettingsAnchor, 2)
|
|
)
|
|
|
|
-- Anchor the menu to the side of the main window.
|
|
self:FixSettingsMenuPosition()
|
|
|
|
-- Prevent the settings menu from disappearing after 2 seconds.
|
|
self.menus:BlockAutoMenuClose(1, 3, "Settings")
|
|
end
|
|
|
|
--- The goal is to keep the settings menu anchored to the corner of the main window.
|
|
--- This is initially done naively by simply anchoring it to the opposite side of the window anchor.
|
|
--- Most of the time, it's probably ok, but if the window has been moved to the opposite side without changing
|
|
--- the anchor, the menu could be offscreen. This is addressed by a second pass where the menu is checked
|
|
--- to see if an X-adjustment would be necessary to bring it back onscreen. If so, move it to the other side.
|
|
--- There's also a bug in Blizzard's ToggleDropDownMenu() where custom menu positions aren't truly respected,
|
|
--- so we end up working around that here as well. It could probably be generalized into the
|
|
--- `Bagshui:ToggleDropDownMenu()` hook by checking the menu frame's anchor as compared to what was desired,
|
|
--- but since this is the only time we're trying for something other than `TOPLEFT` as the menu anchor it's
|
|
--- fine for now.
|
|
function Inventory:FixSettingsMenuPosition(secondPass)
|
|
if not self.menus then
|
|
return
|
|
end
|
|
if self.menus:IsMenuOpen("Settings") then
|
|
local menu = _G.DropDownList1 -- Grab the dropdown menu reference.
|
|
|
|
if not secondPass then
|
|
menu:ClearAllPoints()
|
|
menu:SetPoint(
|
|
self.lastSettingsAnchor,
|
|
self.uiFrame,
|
|
BsUtil.FlipAnchorPointComponent(self.lastSettingsAnchor, 2),
|
|
self.lastSettingsXOffset,
|
|
0
|
|
)
|
|
|
|
-- Trigger second pass position check on next frame update.
|
|
Bagshui:QueueClassCallback(self, self.FixSettingsMenuPosition, nil, nil, true)
|
|
else
|
|
local positionChanged = false
|
|
|
|
-- Check to see if the Settings menu has been positioned offscreen horizontally
|
|
-- or is overlapping the Inventory window, and if so, move it to the other side.
|
|
if
|
|
(BsUtil.GetFrameOffscreenAmount(menu, "x") ~= 0)
|
|
or (
|
|
(menu:GetLeft() or 0) >= (self.uiFrame:GetLeft() or 0)
|
|
and (menu:GetRight() or 0) <= (self.uiFrame:GetRight() or 0)
|
|
)
|
|
then
|
|
self.lastSettingsAnchor = BsUtil.FlipAnchorPointComponent(self.lastSettingsAnchor, 2)
|
|
self.lastSettingsXOffset = -self.lastSettingsXOffset
|
|
positionChanged = true
|
|
end
|
|
|
|
-- Vertical adjustment to keep the entire menu onscreen.
|
|
local yOffset = BsUtil.GetFrameOffscreenAmount(menu, "y")
|
|
|
|
if positionChanged or yOffset ~= 0 then
|
|
menu:ClearAllPoints()
|
|
menu:SetPoint(
|
|
self.lastSettingsAnchor,
|
|
self.uiFrame,
|
|
BsUtil.FlipAnchorPointComponent(self.lastSettingsAnchor, 2),
|
|
self.lastSettingsXOffset,
|
|
yOffset
|
|
)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Construct the Settings menu table based on the Settings configuration. Can be called recursively for nested settings.
|
|
---@param configTable table Settings configuration table from Config\Settings.lua.
|
|
---@param menuBaseTable table Menu table to place the items in as generated by `Menus:AddMenu()`.
|
|
---@param menuLevel number Level in which to place items (1-3).
|
|
---@param menuValue any Used to set the `value` property of the menu item.
|
|
function Inventory:BuildSettingsMenuFromConfig(configTable, menuBaseTable, menuLevel, menuValue)
|
|
assert((menuLevel > 1 and menuValue ~= nil) or menuLevel <= 1, "menuValue must be provided when menuLevel > 1")
|
|
|
|
-- The menu level default is 1.
|
|
local level = menuLevel or 1
|
|
-- Level 1 of menu tables is flat, but submenu tables all have a value key.
|
|
local menuTable = level > 1 and menuBaseTable.levels[level][menuValue] or menuBaseTable.levels[level]
|
|
|
|
-- Pre-colored Control+Alt+Shift+Click hint.
|
|
local settingResetHint = GRAY_FONT_COLOR_CODE .. L.Setting_Reset_TooltipText .. FONT_COLOR_CODE_CLOSE
|
|
|
|
-- Loop through the given settings configuration table.
|
|
for _, settingInfo in ipairs(configTable) do
|
|
-- Omit hidden settings.
|
|
if not settingInfo.hidden and (type(settingInfo.hideFunc) ~= "function" or not settingInfo.hideFunc()) then
|
|
if type(settingInfo.settings) == "table" then
|
|
-- Recurse for nested submenu, indicated by the presence of settingInfo.settings.
|
|
-- However, if there's no submenuName or we've reached the cap of menu levels, nothing can be done with it.
|
|
if settingInfo.submenuName and level < _G.UIDROPDOWNMENU_MAXLEVELS then
|
|
local submenuValue = settingInfo.submenuValue or settingInfo.submenuName
|
|
-- Create a parent item to open the submenu.
|
|
table.insert(menuTable, {
|
|
text = settingInfo.submenuName,
|
|
tooltipTitle = settingInfo.tooltipTitle or settingInfo.submenuName,
|
|
tooltipText = settingInfo.tooltipText,
|
|
value = submenuValue,
|
|
hasArrow = true,
|
|
})
|
|
-- Initialize the submenu table.
|
|
menuBaseTable.levels[level + 1][submenuValue] = {}
|
|
-- Recurse to build it.
|
|
self:BuildSettingsMenuFromConfig(settingInfo.settings, menuBaseTable, level + 1, submenuValue)
|
|
end
|
|
elseif settingInfo.mainTitle then
|
|
-- The mainTitle property creates an automatically-named menu item
|
|
-- with the Close button graphic as its icon, providing an obvious
|
|
-- way to dismiss the menu.
|
|
local menuItem = {
|
|
text = BS_FONT_COLOR.BAGSHUI
|
|
.. string.format(L.Menu_Settings, self.inventoryTypeLocalized)
|
|
.. FONT_COLOR_CODE_CLOSE,
|
|
_bagshuiFakeTitle = true,
|
|
func = function()
|
|
self:CloseMenusAndClearFocuses()
|
|
end,
|
|
}
|
|
BsSkin.closeButtonSkinFunc(menuItem)
|
|
table.insert(menuTable, menuItem)
|
|
elseif settingInfo.menuTitle then
|
|
-- This is just a title, not a setting.
|
|
table.insert(menuTable, {
|
|
text = settingInfo.menuTitle,
|
|
isTitle = true,
|
|
notCheckable = true,
|
|
keepShownOnClick = true,
|
|
})
|
|
else
|
|
assert(
|
|
BsUtil.TableContainsValue(BS_SETTING_TYPE, settingInfo.type),
|
|
tostring(settingInfo.name) .. " does not have a valid type."
|
|
)
|
|
|
|
-- Now we've found a setting.
|
|
local settingName = settingInfo.name or ""
|
|
local settingFriendlyName = settingInfo.title or L[settingInfo.name] or settingInfo.name
|
|
|
|
-- There are situations (like an inline CHOICES setting) where we don't actually
|
|
-- want `menuItem` added because it will be taken care of already.
|
|
local skipAddingToMenu = false
|
|
|
|
-- Base menu item.
|
|
local menuItem = {
|
|
_bagshuiSettingName = settingInfo.name,
|
|
_bagshuiSettingFriendlyName = settingFriendlyName, -- Store the base friendly name so we can manipulate the text property later.
|
|
_bagshuiFakeTitle = settingInfo.fakeTitle, -- Fake titles are styled like titles but are can be clicked and can have submenus.
|
|
_bagshuiAlpha = (settingInfo.faded and 0.6 or 1),
|
|
text = settingFriendlyName,
|
|
notCheckable = settingInfo.notCheckable,
|
|
notClickable = settingInfo.notClickable,
|
|
disabled = settingInfo.disabled,
|
|
tooltipTitle = L_nil[settingName .. "_TooltipTitle"] or settingInfo.tooltipTitle or settingFriendlyName,
|
|
tooltipText = (L_nil[settingName .. "_TooltipText"] or settingInfo.tooltipText),
|
|
keepShownOnClick = true,
|
|
}
|
|
|
|
-- Add scope indicators.
|
|
local scopeTooltipText = ""
|
|
if settingInfo.scope == BS_SETTING_SCOPE.ACCOUNT then
|
|
scopeTooltipText = L.SettingScope_Account
|
|
menuItem.icon = BsUtil.GetFullTexturePath("Icons\\Characters")
|
|
menuItem._bagshuiTextureA = 0.45
|
|
elseif settingInfo.scope == BS_SETTING_SCOPE.CHARACTER then
|
|
scopeTooltipText = L.SettingScope_Character
|
|
menuItem.icon = BsUtil.GetFullTexturePath("Icons\\Character")
|
|
menuItem._bagshuiTextureA = 0.45
|
|
end
|
|
|
|
if string.len(scopeTooltipText) > 0 then
|
|
scopeTooltipText = GRAY_FONT_COLOR_CODE .. scopeTooltipText .. FONT_COLOR_CODE_CLOSE
|
|
menuItem.tooltipText = (menuItem.tooltipText and (menuItem.tooltipText .. BS_NEWLINE) or "")
|
|
.. scopeTooltipText
|
|
end
|
|
|
|
-- Choices, numbers, and colors need submenus.
|
|
if
|
|
settingInfo.type == BS_SETTING_TYPE.CHOICES
|
|
or settingInfo.type == BS_SETTING_TYPE.NUMBER
|
|
or settingInfo.type == BS_SETTING_TYPE.COLOR
|
|
then
|
|
menuItem.hasArrow = true
|
|
local subLevel = level + 1
|
|
local subMenu
|
|
|
|
if not settingInfo.inline then
|
|
menuBaseTable.levels[subLevel][settingInfo.name] = {}
|
|
subMenu = menuBaseTable.levels[subLevel][settingInfo.name]
|
|
end
|
|
|
|
if
|
|
settingInfo.type == BS_SETTING_TYPE.CHOICES
|
|
or (settingInfo.type == BS_SETTING_TYPE.NUMBER and settingInfo.choices)
|
|
then
|
|
-- Choices / Numbers with a static list of choices.
|
|
|
|
if settingInfo.choicesAutoSplitMenuType then
|
|
-- This setting has an auto-split menu instead of a static list of choices.
|
|
|
|
-- Upvalues here for auto-split menu functions.
|
|
local settings = self.settings
|
|
local settingName = settingInfo.name
|
|
local func = settingInfo.choicesAutoSplitMenuFunc
|
|
local tooltipTextFunc = settingInfo.choicesAutoSplitMenuTooltipTextFunc
|
|
|
|
-- Triggering value and parameters for auto-split menu.
|
|
menuItem.value = {
|
|
autoSplitMenuType = settingInfo.choicesAutoSplitMenuType,
|
|
menuLevel = 1,
|
|
func = function(menuLevel, settingValue)
|
|
if type(func) == "function" then
|
|
func(settings, settingName, settingValue)
|
|
end
|
|
self.settings[settingName] = settingValue
|
|
self.menus:Refresh(menuLevel)
|
|
end,
|
|
checkFunc = function(menuOption)
|
|
return self.settings[settingName] == menuOption
|
|
end,
|
|
tooltipTitleFunc = settingInfo.choicesAutoSplitMenuTooltipTitleFunc or function(_, defaultTitle)
|
|
-- Only provide a tooltip title if none was provided by the menu.
|
|
return defaultTitle or menuItem.tooltipTitle
|
|
end,
|
|
tooltipTextFunc = function(objectId, tooltipText)
|
|
if tooltipTextFunc then
|
|
tooltipText = tooltipTextFunc(objectId, tooltipText, self)
|
|
end
|
|
return tooltipText
|
|
end,
|
|
omitFunc = settingInfo.choicesAutoSplitMenuOmitFunc,
|
|
keepShownOnClick = true,
|
|
}
|
|
menuItem.hasArrow = true
|
|
elseif settingInfo.choices then
|
|
-- Static list of choices.
|
|
|
|
for _, choice in ipairs(settingInfo.choices) do
|
|
local choiceTooltipText = choice.tooltipText
|
|
and (choice.tooltipText .. BS_NEWLINE .. scopeTooltipText)
|
|
or ((menuItem.tooltipText or "") .. (choice.tooltip and " " .. choice.tooltip or ""))
|
|
choiceTooltipText = (
|
|
string.len(choiceTooltipText or "") > 0 and choiceTooltipText .. BS_NEWLINE or ""
|
|
) .. settingResetHint
|
|
table.insert(
|
|
-- Add at current level or to submenu.
|
|
|
|
settingInfo.inline and menuTable or subMenu,
|
|
{
|
|
_bagshuiSettingName = settingInfo.name,
|
|
text = choice.text or choice.value,
|
|
value = choice.value,
|
|
tooltipTitle = choice.tooltipTitle or menuItem.tooltipTitle,
|
|
tooltipText = choiceTooltipText,
|
|
textR = choice.textR,
|
|
textG = choice.textG,
|
|
textB = choice.textB,
|
|
-- Copy scope indicators.
|
|
icon = menuItem.icon,
|
|
_bagshuiTextureA = menuItem._bagshuiTextureA,
|
|
}
|
|
)
|
|
end
|
|
|
|
-- When inline, don't add the parent menu item because everything is already done.
|
|
skipAddingToMenu = settingInfo.inline
|
|
end
|
|
elseif settingInfo.type == BS_SETTING_TYPE.NUMBER then
|
|
-- Numbers.
|
|
|
|
-- Range of values for the submenu.
|
|
if type(settingInfo.min) == "number" and type(settingInfo.max) == "number" then
|
|
for i = settingInfo.min, settingInfo.max, (settingInfo.step or 1) do
|
|
table.insert(subMenu, {
|
|
_bagshuiSettingName = settingInfo.name,
|
|
text = type(settingInfo.valueDisplayFunc) == "function" and settingInfo.valueDisplayFunc(i) or i,
|
|
value = i,
|
|
tooltipTitle = menuItem.tooltipTitle,
|
|
tooltipText = (menuItem.tooltipText and menuItem.tooltipText .. BS_NEWLINE or "")
|
|
.. settingResetHint,
|
|
-- Copy scope indicators.
|
|
icon = menuItem.icon,
|
|
_bagshuiTextureA = menuItem._bagshuiTextureA,
|
|
})
|
|
end
|
|
end
|
|
elseif settingInfo.type == BS_SETTING_TYPE.COLOR then
|
|
-- Colors.
|
|
|
|
-- Create submenu for color history.
|
|
self.menus:InitializeEmptyMenu(subMenu, {
|
|
_bagshuiSettingName = settingInfo.name,
|
|
_bagshuiSettingUpdateFunction = menuItem._bagshuiSettingUpdateFunction,
|
|
})
|
|
end
|
|
end
|
|
|
|
-- Apply text modifications.
|
|
if type(settingInfo.nameFunc) == "function" then
|
|
menuItem.text = settingInfo.nameFunc(menuItem.text)
|
|
menuItem.tooltipTitle = settingInfo.nameFunc(menuItem.tooltipTitle)
|
|
menuItem.tooltipText = settingInfo.nameFunc(menuItem.tooltipText)
|
|
end
|
|
|
|
-- Add the reset hint last because submenu items get it as needed.
|
|
if settingInfo.type ~= BS_SETTING_TYPE.TRIGGER then
|
|
menuItem.tooltipText = (menuItem.tooltipText and (menuItem.tooltipText .. BS_NEWLINE) or "")
|
|
.. "~1~" -- Insertion point for tooltip modifications.
|
|
.. GRAY_FONT_COLOR_CODE
|
|
.. L.Setting_Reset_TooltipText
|
|
.. FONT_COLOR_CODE_CLOSE
|
|
end
|
|
|
|
-- Store a backup copy of menu texts so they can be modified at display-time.
|
|
-- This probably could have been done in a more sane way but a quick hack is good enough.
|
|
menuItem._bagshuiOriginalText = menuItem.text
|
|
menuItem._bagshuiOriginalTooltipTitle = menuItem.tooltipTitle
|
|
menuItem._bagshuiOriginalTooltipText = menuItem.tooltipText
|
|
|
|
if not skipAddingToMenu then
|
|
table.insert(menuTable, menuItem)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Prepare a Settings menu item for display. Called from `Menus:LoadMenu()` when a menu item
|
|
--- has a `_bagshuiSettingName` property to build out the menu item properties.
|
|
---@param menuItem table Properties for the menu item, which will be modified in-place.
|
|
---@param menu table[] Parent table of `menuItem`.
|
|
---@param menuLevel number Menu level, 1-3.
|
|
---@param itemNum number Index of `menuItem` within `menu`.
|
|
---@param menuType string Identifier for a menu that has been registered via `AddMenu()`.
|
|
function Inventory:GenerateSettingsMenuItem(menuItem, menu, menuLevel, itemNum, menuType)
|
|
local settingName = menuItem._bagshuiSettingName
|
|
local settingsStorage = menuItem._bagshuiSettingsStorage or self.settings
|
|
local settingInfo = menuItem._bagshuiSettingInfo or self.settings:GetSettingInfo(settingName)
|
|
local currentSettingValue = settingsStorage[settingName]
|
|
local defaultValue = settingInfo.defaultValue
|
|
local settingUpdateFunction = menuItem._bagshuiSettingUpdateFunction or emptyFunction
|
|
|
|
local disabledByFunc
|
|
if type(settingInfo.disableFunc) == "function" then
|
|
disabledByFunc = settingInfo.disableFunc(settingName, settingsStorage)
|
|
end
|
|
|
|
if not self._generateSettingsMenuItem_ResetOnModifierKeys then
|
|
--- Wrapper for `self:ResetSettingOnModifierKeys()`.
|
|
---@param arg1 table Argument table containing `settingName`, `settingStorage`, and `menuLevel`.
|
|
self._generateSettingsMenuItem_ResetOnModifierKeys = function(arg1)
|
|
self:ResetSettingOnModifierKeys(arg1)
|
|
end
|
|
end
|
|
|
|
-- Update texts at display-time.
|
|
if menuItem._bagshuiOriginalText then
|
|
menuItem.text = menuItem._bagshuiOriginalText
|
|
if type(settingInfo.textDisplayFunc) == "function" then
|
|
menuItem.text = settingInfo.textDisplayFunc(menuItem.text, settingInfo.name, self.settings)
|
|
end
|
|
end
|
|
if menuItem._bagshuiOriginalTooltipText then
|
|
menuItem.tooltipText = menuItem._bagshuiOriginalTooltipText
|
|
if type(settingInfo.tooltipTextDisplayFunc) == "function" then
|
|
menuItem.tooltipText = settingInfo.tooltipTextDisplayFunc(menuItem.tooltipText, settingInfo.name, self.settings)
|
|
end
|
|
menuItem.tooltipText = string.gsub(menuItem.tooltipText, "~1~", "")
|
|
end
|
|
|
|
-- Add arg1 for use with ResetSettingOnModifierKeys().
|
|
if type(menuItem.arg1) ~= "table" then
|
|
menuItem.arg1 = {}
|
|
end
|
|
menuItem.arg1.settingName = settingName
|
|
menuItem.arg1.settingsStorage = settingsStorage
|
|
-- Need to store menu level because the global menu level variable will be wrong
|
|
-- for items with submenus.
|
|
menuItem.arg1.menuLevel = menuLevel
|
|
|
|
-- Figure out what the display text for the setting should be, when a `text`
|
|
-- property is available for the selected value within a list of choices.
|
|
local currentSettingFriendlyValue = currentSettingValue
|
|
if
|
|
settingInfo.choices
|
|
and (
|
|
(settingInfo.type == BS_SETTING_TYPE.CHOICES and not settingInfo.autoSplitMenuType)
|
|
or settingInfo.type == BS_SETTING_TYPE.NUMBER
|
|
)
|
|
then
|
|
for _, choice in ipairs(settingInfo.choices) do
|
|
if choice.value == currentSettingValue then
|
|
currentSettingFriendlyValue = choice.text or choice.value
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Apply value display translation if available.
|
|
if type(settingInfo.valueDisplayFunc) == "function" then
|
|
currentSettingFriendlyValue = settingInfo.valueDisplayFunc(currentSettingFriendlyValue)
|
|
end
|
|
|
|
-- Process each type of setting into the appropriate menu item.
|
|
if settingInfo.choicesAutoSplitMenuType then
|
|
-- Stupid hack on our own code to pass menuLevel through to `arg1 of the
|
|
-- auto-split menu `func`'set up in `BuildSettingsMenuFromConfig()`.
|
|
menuItem.value.objectId = menuLevel
|
|
elseif settingInfo.type == BS_SETTING_TYPE.BOOLEAN then
|
|
-- Boolean -- checked/unchecked, toggle setting on click.
|
|
|
|
menuItem.checked = settingsStorage[settingName]
|
|
menuItem.keepShownOnClick = true
|
|
menuItem.func = function()
|
|
if not self:ResetSettingOnModifierKeys(menuItem.arg1, nil, true) then
|
|
settingsStorage[settingName] = not settingsStorage[settingName]
|
|
self.menus:Refresh(menuLevel)
|
|
end
|
|
end
|
|
elseif settingInfo.type == BS_SETTING_TYPE.CHOICES or settingInfo.type == BS_SETTING_TYPE.NUMBER then
|
|
-- Choices / Numbers -- submenu with choices, update setting to selected choice on click.
|
|
|
|
-- Determine whether this is INSIDE a submenu or whether an arrow to open the submenu is needed.
|
|
if menuItem.value and not menuItem.hasArrow then
|
|
-- Inside submenu -- checked/unchecked based on current value, change setting on click.
|
|
-- Need to use tostring() here so we don't get caught by float nonsense where 1 somehow doesn't equal 1.
|
|
menuItem.checked = type(settingInfo.choicesCheckedFunc) == "function"
|
|
and settingInfo.choicesCheckedFunc(settingName, settingsStorage, menuItem.value)
|
|
or tostring(menuItem.value) == tostring(currentSettingValue)
|
|
menuItem.keepShownOnClick = true
|
|
menuItem.func = function()
|
|
if not self:ResetSettingOnModifierKeys(menuItem.arg1, nil, true) then
|
|
settingsStorage[settingName] = _G.this.value
|
|
settingUpdateFunction()
|
|
self.menus:Refresh()
|
|
self.menus:Refresh(menuLevel, true)
|
|
end
|
|
end
|
|
if disabledByFunc ~= nil then
|
|
menuItem.disabled = true
|
|
end
|
|
else
|
|
-- Parent menu item to open the submenu.
|
|
menuItem.value = settingName
|
|
menuItem.hasArrow = true
|
|
-- Append current value to menu text.
|
|
menuItem.text = menuItem._bagshuiSettingFriendlyName
|
|
.. GRAY_FONT_COLOR_CODE
|
|
.. " ["
|
|
.. currentSettingFriendlyValue
|
|
.. "]"
|
|
.. FONT_COLOR_CODE_CLOSE
|
|
menuItem.func = self._generateSettingsMenuItem_ResetOnModifierKeys
|
|
end
|
|
elseif settingInfo.type == BS_SETTING_TYPE.COLOR then
|
|
-- Colors -- display swatch and prepare color history.
|
|
|
|
menuItem.opacity = nil
|
|
|
|
-- Determine whether this is INSIDE a submenu or whether an arrow to open the submenu is needed.
|
|
if menuItem.value and not menuItem.hasArrow then
|
|
-- Inside submenu -- populate color history, change setting on click.
|
|
|
|
if Bagshui.colorHistory[itemNum] and itemNum < COLOR_HISTORY_LIMIT then
|
|
local color = Bagshui.colorHistory[itemNum]
|
|
menuItem.text = " "
|
|
menuItem.tooltipTitle = L.Menu_Settings_ColorHistory_TooltipTitle
|
|
menuItem._bagshuiHide = false
|
|
menuItem._bagshuiColorSwatchRightAnchor = -20
|
|
menuItem.hasColorSwatch = true
|
|
menuItem.notCheckable = true
|
|
menuItem.r = color[1]
|
|
menuItem.g = color[2]
|
|
menuItem.b = color[3]
|
|
menuItem.opacity = color[4]
|
|
menuItem.func = function()
|
|
Bagshui:CloseMenus(_G.UIDROPDOWNMENU_MENU_LEVEL, nil, true)
|
|
settingsStorage[settingName] = color
|
|
settingUpdateFunction()
|
|
self.menus:Refresh(menuLevel, true)
|
|
self:AddToColorHistory(color)
|
|
end
|
|
menuItem._bagshuiColorSwatchFunc = menuItem.func
|
|
else
|
|
menuItem._bagshuiHide = true
|
|
end
|
|
else
|
|
-- Parent menu item to open the submenu -- add color swatch and related functions
|
|
-- to properly update colors as the color picker is changed, while handling things
|
|
-- correctly so that the value is only saved if Okay is clicked.
|
|
|
|
-- Opacity management variables that will be captured into the cancelFunc closure below.
|
|
-- This is necessary because since we don't receive opacity as a parameter to cancelFunc.
|
|
local hasOpacity = false
|
|
local currentOpacity = (currentSettingValue and currentSettingValue[4])
|
|
or (defaultValue and defaultValue[4])
|
|
or 1
|
|
|
|
-- Menu item updates
|
|
menuItem.hasArrow = true
|
|
menuItem.value = settingName
|
|
menuItem.hasColorSwatch = true
|
|
menuItem.r = (currentSettingValue and currentSettingValue[1]) or (defaultValue and defaultValue[1]) or 1
|
|
menuItem.g = (currentSettingValue and currentSettingValue[2]) or (defaultValue and defaultValue[2]) or 1
|
|
menuItem.b = (currentSettingValue and currentSettingValue[3]) or (defaultValue and defaultValue[3]) or 1
|
|
if settingInfo.hasOpacity then
|
|
hasOpacity = true
|
|
menuItem.hasOpacity = true
|
|
-- Inverting opacity slider because it's insane that 100% means transparent and 0% means opaque.
|
|
menuItem.opacity = 1.0 - currentOpacity
|
|
end
|
|
|
|
local oldColor = { menuItem.r, menuItem.g, menuItem.b, menuItem.opacity }
|
|
|
|
-- Shared function to reopen the menu that triggered the color picker.
|
|
-- Getting submenus to open would take more digging than is worth it.
|
|
local function reopenMenu()
|
|
if
|
|
self.menus._openMenu_last_MenuType == menuType
|
|
and _G.UIDROPDOWNMENU_OPEN_MENU == Bagshui.menuFrame.bagshuiData.name
|
|
then
|
|
self.menus:OpenMenu(
|
|
menuType,
|
|
self.menus._openMenu_last_Arg1,
|
|
self.menus._openMenu_last_Arg2,
|
|
_G.UIParent,
|
|
self.menus._openMenu_last_UIParentXOffset,
|
|
self.menus._openMenu_last_UIParentYOffset
|
|
)
|
|
end
|
|
end
|
|
|
|
-- Change setting on color / opacity change.
|
|
local swatchFuncCallCount = 0
|
|
menuItem.swatchFunc = function()
|
|
local color = { _G.ColorPickerFrame:GetColorRGB() }
|
|
if hasOpacity then
|
|
-- Un-invert opacity value since we're inverting it for the UI (see menuItem.opacity note above).
|
|
table.insert(color, 1.0 - _G.OpacitySliderFrame:GetValue())
|
|
end
|
|
settingsStorage[settingName] = color
|
|
settingUpdateFunction()
|
|
|
|
-- Only perform actions when Okay is clicked. swatchFunc() gets called
|
|
-- immediately when the ColorPickerFrame is opened, so we skip it the
|
|
-- first time. After that, we can tell whether Okay was clicked by
|
|
-- checking whether ColorPickerFrame is still visible.
|
|
if swatchFuncCallCount > 0 and not _G.ColorPickerFrame:IsVisible() then
|
|
self:AddToColorHistory(oldColor)
|
|
self:AddToColorHistory(color)
|
|
|
|
reopenMenu()
|
|
end
|
|
|
|
swatchFuncCallCount = swatchFuncCallCount + 1
|
|
end
|
|
menuItem.opacityFunc = menuItem.swatchFunc
|
|
|
|
-- Color picker Cancel button click -- revert the setting.
|
|
menuItem.cancelFunc = function(previousValues)
|
|
local color
|
|
-- Allow reverting a color setting to nil for Groups, which need
|
|
-- nil to indicate the default color should be used.
|
|
if currentSettingValue ~= nil then
|
|
color = {
|
|
previousValues.r,
|
|
previousValues.g,
|
|
previousValues.b,
|
|
}
|
|
-- Use upvalues that were created above since previousValues doesn't contain opacity.
|
|
if hasOpacity then
|
|
table.insert(color, currentOpacity)
|
|
end
|
|
end
|
|
settingsStorage[settingName] = color
|
|
settingUpdateFunction()
|
|
reopenMenu()
|
|
end
|
|
|
|
menuItem.func = self._generateSettingsMenuItem_ResetOnModifierKeys
|
|
end
|
|
elseif settingInfo.type == BS_SETTING_TYPE.TRIGGER then
|
|
-- Triggers -- just update the setting to true and the Settings class takes care of the rest.
|
|
|
|
menuItem.checked = false
|
|
menuItem.keepShownOnClick = false
|
|
menuItem.func = function()
|
|
settingsStorage[settingName] = true
|
|
end
|
|
end
|
|
|
|
-- Decide whether the menu item should be disabled.
|
|
if disabledByFunc ~= nil then
|
|
menuItem.disabled = disabledByFunc
|
|
end
|
|
end
|
|
|
|
--- Add the given color to the global Bagshui color picker history.
|
|
--- @param color table Color to add: `{ r, g, b, [a] }`.
|
|
function Inventory:AddToColorHistory(color)
|
|
-- Due to float shenanigans, colors values may not be seen as equal unless we round them.
|
|
for i = 1, 4 do
|
|
color[i] = BsUtil.Round(color[i], 4)
|
|
end
|
|
|
|
-- Add color to first position if it's not already there.
|
|
if
|
|
not Bagshui.colorHistory[1]
|
|
or (
|
|
Bagshui.colorHistory[1][1] ~= color[1]
|
|
or Bagshui.colorHistory[1][2] ~= color[2]
|
|
or Bagshui.colorHistory[1][3] ~= color[3]
|
|
or Bagshui.colorHistory[1][4] ~= color[4]
|
|
)
|
|
then
|
|
table.insert(Bagshui.colorHistory, 1, color)
|
|
end
|
|
|
|
-- Remove any duplicates.
|
|
for i = table.getn(Bagshui.colorHistory), 2, -1 do
|
|
if
|
|
Bagshui.colorHistory[i][1] == color[1]
|
|
and Bagshui.colorHistory[i][2] == color[2]
|
|
and Bagshui.colorHistory[i][3] == color[3]
|
|
and Bagshui.colorHistory[i][4] == color[4]
|
|
then
|
|
table.remove(Bagshui.colorHistory, i)
|
|
end
|
|
end
|
|
|
|
-- Trim history if needed.
|
|
while table.getn(Bagshui.colorHistory) > COLOR_HISTORY_LIMIT do
|
|
table.remove(Bagshui.colorHistory)
|
|
end
|
|
end
|
|
|
|
--- When certain modifier keys are held down, reset the setting provided in the
|
|
--- arg1 table to default.
|
|
---@param arg1 table Menu item information for setting:
|
|
--- ```
|
|
--- {
|
|
--- settingName [string] = name of setting,
|
|
--- settingsStorage [table] = Settings class instance,
|
|
--- menuLevel [number] = Level of menu item,
|
|
--- }
|
|
--- ```
|
|
---@param arg2 any? Ignored.
|
|
---@param onlyRefreshOnReset boolean? Don't refresh the menu unless the setting was reset.
|
|
---@return boolean settingWasReset
|
|
function Inventory:ResetSettingOnModifierKeys(arg1, arg2, onlyRefreshOnReset)
|
|
if _G.IsAltKeyDown() and _G.IsControlKeyDown() and _G.IsShiftKeyDown() then
|
|
arg1.settingsStorage:SetDefaults(true, nil, nil, arg1.settingName)
|
|
self.menus:Refresh(arg1.menuLevel)
|
|
return true
|
|
elseif not onlyRefreshOnReset then
|
|
self.menus:Refresh(arg1.menuLevel)
|
|
end
|
|
return false
|
|
end
|
|
end)
|