Rewrite the options menu (#28389)

* Basic attempt at rewriting how the options menu works, move accessibility settings into their own tab.

* Audio tab uses the new options system.

* Rewrite Misc tab

* Clean up heading styling

* Rewrite options tab and other minor cleanup all over the place.

* Documentation comments and minor cleanup.

(cherry picked from commit 07fe1a6b5a0724a266e99781f697f423fe2badd5)
This commit is contained in:
Pieter-Jan Briers
2024-06-22 07:11:14 +03:00
committed by Spatison
parent 4e5b7e10c2
commit 610de8f4e6
24 changed files with 1242 additions and 1070 deletions

View File

@@ -30,7 +30,7 @@ public sealed class AnnouncerSystem : SharedAnnouncerSystem
AnnouncerVolume = _config.GetCVar(CCVars.AnnouncerVolume) * 100f / ContentAudioSystem.AnnouncerMultiplier;
_config.OnValueChanged(CCVars.AnnouncerVolume, OnAnnouncerVolumeChanged);
_config.OnValueChanged(CCVars.AnnouncerDisableMultipleSounds, OnAnnouncerDisableMultipleSounds);
_config.OnValueChanged(CCVars.AnnouncerDisableMultipleEnabled, OnAnnouncerDisableMultipleEnabled);
SubscribeNetworkEvent<AnnouncementSendEvent>(OnAnnouncementReceived);
}
@@ -40,7 +40,7 @@ public sealed class AnnouncerSystem : SharedAnnouncerSystem
base.Shutdown();
_config.UnsubValueChanged(CCVars.AnnouncerVolume, OnAnnouncerVolumeChanged);
_config.UnsubValueChanged(CCVars.AnnouncerDisableMultipleSounds, OnAnnouncerDisableMultipleSounds);
_config.UnsubValueChanged(CCVars.AnnouncerDisableMultipleEnabled, OnAnnouncerDisableMultipleEnabled);
}
@@ -52,7 +52,7 @@ public sealed class AnnouncerSystem : SharedAnnouncerSystem
source.Gain = AnnouncerVolume;
}
private void OnAnnouncerDisableMultipleSounds(bool value)
private void OnAnnouncerDisableMultipleEnabled(bool value)
{
if (!value)
return;
@@ -79,7 +79,7 @@ public sealed class AnnouncerSystem : SharedAnnouncerSystem
source.Gain = AnnouncerVolume * SharedAudioSystem.VolumeToGain(ev.AudioParams.Volume);
source.Global = true;
if (_config.GetCVar(CCVars.AnnouncerDisableMultipleSounds))
if (_config.GetCVar(CCVars.AnnouncerDisableMultipleEnabled))
{
foreach (var audioSource in AnnouncerSources.ToList())
{

View File

@@ -103,7 +103,7 @@ public sealed class CombatModeSystem : SharedCombatModeSystem
UpdateHud(entity);
// WD EDIT START
if (silent || !_cfg.GetCVar(WhiteCVars.ToggleCombatModeSound))
if (silent || !_cfg.GetCVar(WhiteCVars.CombatModeSoundEnabled))
return;
var soundToPlay = value

View File

@@ -0,0 +1,6 @@
<Control xmlns="https://spacestation14.io">
<BoxContainer Orientation="Horizontal">
<Label Name="NameLabel" MinWidth="400" />
<OptionButton Name="Button" Access="Public" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,21 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
namespace Content.Client.Options.UI;
/// <summary>
/// Standard UI control used for drop-downs in the options menu. Intended for use with <see cref="OptionsTabControlRow"/>.
/// </summary>
/// <seealso cref="OptionsTabControlRow.AddOptionDropDown{T}"/>
[GenerateTypedNameReferences]
public sealed partial class OptionDropDown : Control
{
/// <summary>
/// The text describing what this drop-down controls.
/// </summary>
public string? Title
{
get => NameLabel.Text;
set => NameLabel.Text = value;
}
}

View File

@@ -0,0 +1,7 @@
<Control xmlns="https://spacestation14.io">
<BoxContainer Orientation="Horizontal">
<Label Name="NameLabel" MinWidth="400" />
<Slider Name="Slider" Access="Public" HorizontalExpand="True" />
<Label Name="ValueLabel" Access="Public" Margin="8 0 4 0" MinWidth="48" Align="Right" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,22 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
namespace Content.Client.Options.UI;
/// <summary>
/// Standard UI control used for sliders in the options menu. Intended for use with <see cref="OptionsTabControlRow"/>.
/// </summary>
/// <seealso cref="OptionsTabControlRow.AddOptionSlider"/>
/// <seealso cref="OptionsTabControlRow.AddOptionPercentSlider"/>
[GenerateTypedNameReferences]
public sealed partial class OptionSlider : Control
{
/// <summary>
/// The text describing what this slider controls.
/// </summary>
public string? Title
{
get => NameLabel.Text;
set => NameLabel.Text = value;
}
}

View File

@@ -7,5 +7,6 @@
<tabs:GraphicsTab Name="GraphicsTab" />
<tabs:KeyRebindTab Name="KeyRebindTab" />
<tabs:AudioTab Name="AudioTab" />
<tabs:AccessibilityTab Name="AccessibilityTab" />
</TabContainer>
</DefaultWindow>

View File

@@ -1,9 +1,7 @@
using Content.Client.Options.UI.Tabs;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Options.UI
{
[GenerateTypedNameReferences]
@@ -18,13 +16,17 @@ namespace Content.Client.Options.UI
Tabs.SetTabTitle(1, Loc.GetString("ui-options-tab-graphics"));
Tabs.SetTabTitle(2, Loc.GetString("ui-options-tab-controls"));
Tabs.SetTabTitle(3, Loc.GetString("ui-options-tab-audio"));
Tabs.SetTabTitle(4, Loc.GetString("ui-options-tab-accessibility"));
UpdateTabs();
}
public void UpdateTabs()
{
GraphicsTab.UpdateProperties();
GraphicsTab.Control.ReloadValues();
MiscTab.Control.ReloadValues();
AccessibilityTab.Control.ReloadValues();
AudioTab.Control.ReloadValues();
}
}
}

View File

@@ -0,0 +1,18 @@
<Control xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
<controls:StripeBack HasBottomEdge="False">
<BoxContainer Orientation="Horizontal" Align="End" Margin="2">
<Button Name="DefaultButton"
Text="{Loc 'ui-options-default'}"
TextAlign="Center"
Margin="8 0" />
<Button Name="ResetButton"
Text="{Loc 'ui-options-reset-all'}"
StyleClasses="Caution" />
<Button Name="ApplyButton"
Text="{Loc 'ui-options-apply'}"
StyleClasses="OpenLeft" />
</BoxContainer>
</controls:StripeBack>
</Control>

View File

@@ -0,0 +1,684 @@
using System.Linq;
using Content.Client.Stylesheets;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Collections;
using Robust.Shared.Configuration;
namespace Content.Client.Options.UI;
/// <summary>
/// Control used on all tabs of the in-game options menu,
/// contains the "save" and "reset" buttons and controls the entire logic.
/// </summary>
/// <remarks>
/// <para>
/// Basic operation is simple: options tabs put this control at the bottom of the tab,
/// they bind UI controls to it with calls such as <see cref="AddOptionCheckBox"/>,
/// then they call <see cref="Initialize"/>. The rest is all handled by the control.
/// </para>
/// <para>
/// Individual options are implementations of <see cref="BaseOption"/>. See the type for details.
/// Common implementations for building on top of CVars are already exist,
/// but tabs can define their own if they need to.
/// </para>
/// <para>
/// Generally, options are added via helper methods such as <see cref="AddOptionCheckBox"/>,
/// however it is totally possible to directly instantiate the backing types
/// and add them via <see cref="AddOption{T}"/>.
/// </para>
/// <para>
/// The options system is general purpose enough that <see cref="OptionsTabControlRow"/> does not, itself,
/// know what a CVar is. It does automatically save CVars to config when save is pressed, but otherwise CVar interaction
/// is handled by <see cref="BaseOption"/> implementations.
/// </para>
/// <para>
/// Behaviorally, the row has 3 control buttons: save, reset changed, and reset to default.
/// "Save" writes the configuration changes and saves the configuration.
/// "Reset changed" discards changes made in the menu and re-loads the saved settings.
/// "Reset to default" resets the settings on the menu to be the default, out-of-the-box values.
/// Note that "Reset to default" does not save immediately, the user must still press save manually.
/// </para>
/// <para>
/// The disabled state of the 3 buttons is updated dynamically based on the values of the options.
/// </para>
/// </remarks>
[GenerateTypedNameReferences]
public sealed partial class OptionsTabControlRow : Control
{
[Dependency] private readonly ILocalizationManager _loc = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private ValueList<BaseOption> _options;
public OptionsTabControlRow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
ResetButton.StyleClasses.Add(StyleBase.ButtonOpenRight);
ApplyButton.OnPressed += ApplyButtonPressed;
ResetButton.OnPressed += ResetButtonPressed;
DefaultButton.OnPressed += DefaultButtonPressed;
}
/// <summary>
/// Add a new option to be tracked by the control.
/// </summary>
/// <param name="option">The option object that manages this object's logic</param>
/// <typeparam name="T">
/// The type of option being passed in. Necessary to allow the return type to match the parameter type
/// for easy chaining.
/// </typeparam>
/// <returns>The same <paramref name="option"/> as passed in, for easy chaining.</returns>
public T AddOption<T>(T option) where T : BaseOption
{
_options.Add(option);
return option;
}
/// <summary>
/// Add a checkbox option backed by a simple boolean CVar.
/// </summary>
/// <param name="cVar">The CVar represented by the checkbox.</param>
/// <param name="checkBox">The UI control for the option.</param>
/// <param name="invert">
/// If true, the checkbox is inverted relative to the CVar: if the CVar is true, the checkbox will be unchecked.
/// </param>
/// <returns>The option instance backing the added option.</returns>
/// <seealso cref="OptionCheckboxCVar"/>
public OptionCheckboxCVar AddOptionCheckBox(CVarDef<bool> cVar, CheckBox checkBox, bool invert = false)
{
return AddOption(new OptionCheckboxCVar(this, _cfg, cVar, checkBox, invert));
}
/// <summary>
/// Add a slider option, displayed in percent, backed by a simple float CVar.
/// </summary>
/// <param name="cVar">The CVar represented by the slider.</param>
/// <param name="slider">The UI control for the option.</param>
/// <param name="min">The minimum value the slider should allow. The default value represents "0%"</param>
/// <param name="max">The maximum value the slider should allow. The default value represents "100%"</param>
/// <param name="scale">
/// Scale with which to multiply slider values when mapped to the backing CVar.
/// For example, if a scale of 2 is set, a slider at 75% writes a value of 1.5 to the CVar.
/// </param>
/// <returns>The option instance backing the added option.</returns>
/// <remarks>
/// <para>
/// Note that percentage values are represented as ratios in code, i.e. a value of 100% is "1".
/// </para>
/// </remarks>
public OptionSliderFloatCVar AddOptionPercentSlider(
CVarDef<float> cVar,
OptionSlider slider,
float min = 0,
float max = 1,
float scale = 1)
{
return AddOption(new OptionSliderFloatCVar(this, _cfg, cVar, slider, min, max, scale, FormatPercent));
}
/// <summary>
/// Add a slider option, backed by a simple integer CVar.
/// </summary>
/// <param name="cVar">The CVar represented by the slider.</param>
/// <param name="slider">The UI control for the option.</param>
/// <param name="min">The minimum value the slider should allow.</param>
/// <param name="max">The maximum value the slider should allow.</param>
/// <param name="format">
/// An optional delegate used to format the textual value display of the slider.
/// If not provided, the default behavior is to directly format the integer value as text.
/// </param>
/// <returns>The option instance backing the added option.</returns>
public OptionSliderIntCVar AddOptionSlider(
CVarDef<int> cVar,
OptionSlider slider,
int min,
int max,
Func<OptionSliderIntCVar, int, string>? format = null)
{
return AddOption(new OptionSliderIntCVar(this, _cfg, cVar, slider, min, max, format ?? FormatInt));
}
/// <summary>
/// Add a drop-down option, backed by a CVar.
/// </summary>
/// <param name="cVar">The CVar represented by the drop-down.</param>
/// <param name="dropDown">The UI control for the option.</param>
/// <param name="options">
/// The set of options that will be shown in the drop-down. Items are ordered as provided.
/// </param>
/// <typeparam name="T">The type of the CVar being controlled.</typeparam>
/// <returns>The option instance backing the added option.</returns>
public OptionDropDownCVar<T> AddOptionDropDown<T>(
CVarDef<T> cVar,
OptionDropDown dropDown,
IReadOnlyCollection<OptionDropDownCVar<T>.ValueOption> options)
where T : notnull
{
return AddOption(new OptionDropDownCVar<T>(this, _cfg, cVar, dropDown, options));
}
/// <summary>
/// Initializes the control row. This should be called after all options have been added.
/// </summary>
public void Initialize()
{
foreach (var option in _options)
{
option.LoadValue();
}
UpdateButtonState();
}
/// <summary>
/// Re-loads options in the settings from backing values.
/// Should be called when the options window is opened to make sure all values are up-to-date.
/// </summary>
public void ReloadValues()
{
Initialize();
}
/// <summary>
/// Called by <see cref="BaseOption"/> to signal that an option's value changed through user interaction.
/// </summary>
/// <remarks>
/// <see cref="BaseOption"/> implementations should not call this function directly,
/// instead they should call <see cref="BaseOption.ValueChanged"/>.
/// </remarks>
public void ValueChanged()
{
UpdateButtonState();
}
private void UpdateButtonState()
{
var anyModified = _options.Any(option => option.IsModified());
var anyModifiedFromDefault = _options.Any(option => option.IsModifiedFromDefault());
DefaultButton.Disabled = !anyModifiedFromDefault;
ApplyButton.Disabled = !anyModified;
ResetButton.Disabled = !anyModified;
}
private void ApplyButtonPressed(BaseButton.ButtonEventArgs obj)
{
foreach (var option in _options)
{
if (option.IsModified())
option.SaveValue();
}
_cfg.SaveToFile();
UpdateButtonState();
}
private void ResetButtonPressed(BaseButton.ButtonEventArgs obj)
{
foreach (var option in _options)
{
option.LoadValue();
}
UpdateButtonState();
}
private void DefaultButtonPressed(BaseButton.ButtonEventArgs obj)
{
foreach (var option in _options)
{
option.ResetToDefault();
}
UpdateButtonState();
}
private string FormatPercent(OptionSliderFloatCVar slider, float value)
{
return _loc.GetString("ui-options-value-percent", ("value", value));
}
private static string FormatInt(OptionSliderIntCVar slider, int value)
{
return value.ToString();
}
}
/// <summary>
/// Base class of a single "option" for <see cref="OptionsTabControlRow"/>.
/// </summary>
/// <remarks>
/// <para>
/// Implementations of this class handle loading values from backing storage or defaults,
/// handling UI controls, and saving. The main <see cref="OptionsTabControlRow"/> does not know what a CVar is.
/// </para>
/// <para>
/// <see cref="BaseOptionCVar{TValue}"/> is a derived class that makes it easier to work with options
/// backed by a single CVar.
/// </para>
/// </remarks>
/// <param name="controller">The control row that owns this option.</param>
/// <seealso cref="OptionsTabControlRow"/>
public abstract class BaseOption(OptionsTabControlRow controller)
{
/// <summary>
/// Should be called by derived implementations to indicate that their value changed, due to user interaction.
/// </summary>
protected virtual void ValueChanged()
{
controller.ValueChanged();
}
/// <summary>
/// Loads the value represented by this option from its backing store, into the UI state.
/// </summary>
public abstract void LoadValue();
/// <summary>
/// Saves the value in the UI state to the backing store.
/// </summary>
public abstract void SaveValue();
/// <summary>
/// Resets the UI state to that of the factory-default value. This should not write to the backing store.
/// </summary>
public abstract void ResetToDefault();
/// <summary>
/// Called to check if this option's UI value is different from the backing store value.
/// </summary>
/// <returns>If true, the UI value is different and was modified by the user.</returns>
public abstract bool IsModified();
/// <summary>
/// Called to check if this option's UI value is different from the backing store's default value.
/// </summary>
/// <returns>If true, the UI value is different.</returns>
public abstract bool IsModifiedFromDefault();
}
/// <summary>
/// Derived class of <see cref="BaseOption"/> intended for making mappings to simple CVars easier.
/// </summary>
/// <typeparam name="TValue">The type of the CVar.</typeparam>
/// <seealso cref="OptionsTabControlRow"/>
public abstract class BaseOptionCVar<TValue> : BaseOption
where TValue : notnull
{
/// <summary>
/// Raised immediately when the UI value of this option is changed by the user, even before saving.
/// </summary>
/// <remarks>
/// <para>
/// This can be used to update parts of the options UI based on the state of a checkbox.
/// </para>
/// </remarks>
public event Action<TValue>? ImmediateValueChanged;
private readonly IConfigurationManager _cfg;
private readonly CVarDef<TValue> _cVar;
/// <summary>
/// Sets and gets the actual CVar value to/from the frontend UI state or control.
/// </summary>
/// <remarks>
/// <para>
/// In the simplest case, this function should set a UI control's state to represent the CVar,
/// and inversely conver the UI control's state to the CVar value. For simple controls like a checkbox or slider,
/// this just means passing through their value property.
/// </para>
/// </remarks>
protected abstract TValue Value { get; set; }
protected BaseOptionCVar(
OptionsTabControlRow controller,
IConfigurationManager cfg,
CVarDef<TValue> cVar)
: base(controller)
{
_cfg = cfg;
_cVar = cVar;
}
public override void LoadValue()
{
Value = _cfg.GetCVar(_cVar);
}
public override void SaveValue()
{
_cfg.SetCVar(_cVar, Value);
}
public override void ResetToDefault()
{
Value = _cVar.DefaultValue;
}
public override bool IsModified()
{
return !IsValueEqual(Value, _cfg.GetCVar(_cVar));
}
public override bool IsModifiedFromDefault()
{
return !IsValueEqual(Value, _cVar.DefaultValue);
}
protected virtual bool IsValueEqual(TValue a, TValue b)
{
// Use different logic for floats so there's some error margin.
// This check is handled cleanly at compile-time by the JIT.
if (typeof(TValue) == typeof(float))
return MathHelper.CloseToPercent((float) (object) a, (float) (object) b);
return EqualityComparer<TValue>.Default.Equals(a, b);
}
protected override void ValueChanged()
{
base.ValueChanged();
ImmediateValueChanged?.Invoke(Value);
}
}
/// <summary>
/// Implementation of a CVar option that simply corresponds with a <see cref="CheckBox"/>.
/// </summary>
/// <remarks>
/// <para>
/// Generally, you should just call <c>AddOption</c> methods on <see cref="OptionsTabControlRow"/>
/// instead of instantiating this type directly.
/// </para>
/// </remarks>
/// <seealso cref="OptionsTabControlRow"/>
public sealed class OptionCheckboxCVar : BaseOptionCVar<bool>
{
private readonly CheckBox _checkBox;
private readonly bool _invert;
protected override bool Value
{
get => _checkBox.Pressed ^ _invert;
set => _checkBox.Pressed = value ^ _invert;
}
/// <summary>
/// Creates a new instance of this type.
/// </summary>
/// <param name="controller">The control row that owns this option.</param>
/// <param name="cfg">The configuration manager to get and set values from.</param>
/// <param name="cVar">The CVar that is being controlled by this option.</param>
/// <param name="checkBox">The UI control for the option.</param>
/// <param name="invert">
/// If true, the checkbox is inverted relative to the CVar: if the CVar is true, the checkbox will be unchecked.
/// </param>
/// <remarks>
/// <para>
/// It is generally more convenient to call overloads on <see cref="OptionsTabControlRow"/>
/// such as <see cref="OptionsTabControlRow.AddOptionCheckBox"/> instead of instantiating this type directly.
/// </para>
/// </remarks>
public OptionCheckboxCVar(
OptionsTabControlRow controller,
IConfigurationManager cfg,
CVarDef<bool> cVar,
CheckBox checkBox,
bool invert)
: base(controller, cfg, cVar)
{
_checkBox = checkBox;
_invert = invert;
checkBox.OnToggled += _ =>
{
ValueChanged();
};
}
}
/// <summary>
/// Implementation of a CVar option that simply corresponds with a floating-point <see cref="OptionSlider"/>.
/// </summary>
/// <seealso cref="OptionsTabControlRow"/>
public sealed class OptionSliderFloatCVar : BaseOptionCVar<float>
{
/// <summary>
/// Scale with which to multiply slider values when mapped to the backing CVar.
/// </summary>
/// <remarks>
/// For example, if a scale of 2 is set, a slider at 75% writes a value of 1.5 to the CVar.
/// </remarks>
public float Scale { get; }
private readonly OptionSlider _slider;
private readonly Func<OptionSliderFloatCVar, float, string> _format;
protected override float Value
{
get => _slider.Slider.Value * Scale;
set
{
_slider.Slider.Value = value / Scale;
UpdateLabelValue();
}
}
/// <summary>
/// Creates a new instance of this type.
/// </summary>
/// <remarks>
/// <para>
/// It is generally more convenient to call overloads on <see cref="OptionsTabControlRow"/>
/// such as <see cref="OptionsTabControlRow.AddOptionPercentSlider"/> instead of instantiating this type directly.
/// </para>
/// </remarks>
/// <param name="controller">The control row that owns this option.</param>
/// <param name="cfg">The configuration manager to get and set values from.</param>
/// <param name="cVar">The CVar that is being controlled by this option.</param>
/// <param name="slider">The UI control for the option.</param>
/// <param name="minValue">The minimum value the slider should allow.</param>
/// <param name="maxValue">The maximum value the slider should allow.</param>
/// <param name="scale">
/// Scale with which to multiply slider values when mapped to the backing CVar. See <see cref="Scale"/>.
/// </param>
/// <param name="format">Function that will be called to format the value display next to the slider.</param>
public OptionSliderFloatCVar(
OptionsTabControlRow controller,
IConfigurationManager cfg,
CVarDef<float> cVar,
OptionSlider slider,
float minValue,
float maxValue,
float scale,
Func<OptionSliderFloatCVar, float, string> format) : base(controller, cfg, cVar)
{
Scale = scale;
_slider = slider;
_format = format;
slider.Slider.MinValue = minValue;
slider.Slider.MaxValue = maxValue;
slider.Slider.OnValueChanged += _ =>
{
ValueChanged();
UpdateLabelValue();
};
}
private void UpdateLabelValue()
{
_slider.ValueLabel.Text = _format(this, _slider.Slider.Value);
}
}
/// <summary>
/// Implementation of a CVar option that simply corresponds with an integer <see cref="OptionSlider"/>.
/// </summary>
/// <seealso cref="OptionsTabControlRow"/>
public sealed class OptionSliderIntCVar : BaseOptionCVar<int>
{
private readonly OptionSlider _slider;
private readonly Func<OptionSliderIntCVar, int, string> _format;
protected override int Value
{
get => (int) _slider.Slider.Value;
set
{
_slider.Slider.Value = value;
UpdateLabelValue();
}
}
/// <summary>
/// Creates a new instance of this type.
/// </summary>
/// <remarks>
/// <para>
/// It is generally more convenient to call overloads on <see cref="OptionsTabControlRow"/>
/// such as <see cref="OptionsTabControlRow.AddOptionPercentSlider"/> instead of instantiating this type directly.
/// </para>
/// </remarks>
/// <param name="controller">The control row that owns this option.</param>
/// <param name="cfg">The configuration manager to get and set values from.</param>
/// <param name="cVar">The CVar that is being controlled by this option.</param>
/// <param name="slider">The UI control for the option.</param>
/// <param name="minValue">The minimum value the slider should allow.</param>
/// <param name="maxValue">The maximum value the slider should allow.</param>
/// <param name="format">Function that will be called to format the value display next to the slider.</param>
public OptionSliderIntCVar(
OptionsTabControlRow controller,
IConfigurationManager cfg,
CVarDef<int> cVar,
OptionSlider slider,
int minValue,
int maxValue,
Func<OptionSliderIntCVar, int, string> format) : base(controller, cfg, cVar)
{
_slider = slider;
_format = format;
slider.Slider.MinValue = minValue;
slider.Slider.MaxValue = maxValue;
slider.Slider.Rounded = true;
slider.Slider.OnValueChanged += _ =>
{
ValueChanged();
UpdateLabelValue();
};
}
private void UpdateLabelValue()
{
_slider.ValueLabel.Text = _format(this, (int) _slider.Slider.Value);
}
}
/// <summary>
/// Implementation of a CVar option via a drop-down.
/// </summary>
/// <seealso cref="OptionsTabControlRow"/>
public sealed class OptionDropDownCVar<T> : BaseOptionCVar<T> where T : notnull
{
private readonly OptionDropDown _dropDown;
private readonly ItemEntry[] _entries;
protected override T Value
{
get => (T) _dropDown.Button.SelectedMetadata!;
set => _dropDown.Button.SelectId(FindValueId(value));
}
/// <summary>
/// Creates a new instance of this type.
/// </summary>
/// <remarks>
/// <para>
/// It is generally more convenient to call overloads on <see cref="OptionsTabControlRow"/>
/// such as <see cref="OptionsTabControlRow.AddOptionDropDown{T}"/> instead of instantiating this type directly.
/// </para>
/// </remarks>
/// <param name="controller">The control row that owns this option.</param>
/// <param name="cfg">The configuration manager to get and set values from.</param>
/// <param name="cVar">The CVar that is being controlled by this option.</param>
/// <param name="dropDown">The UI control for the option.</param>
/// <param name="options">The list of options shown to the user.</param>
public OptionDropDownCVar(
OptionsTabControlRow controller,
IConfigurationManager cfg,
CVarDef<T> cVar,
OptionDropDown dropDown,
IReadOnlyCollection<ValueOption> options) : base(controller, cfg, cVar)
{
if (options.Count == 0)
throw new ArgumentException("Need at least one option!");
_dropDown = dropDown;
_entries = new ItemEntry[options.Count];
var button = dropDown.Button;
var i = 0;
foreach (var option in options)
{
_entries[i] = new ItemEntry
{
Key = option.Key,
};
button.AddItem(option.Label, i);
button.SetItemMetadata(button.GetIdx(i), option.Key);
i += 1;
}
dropDown.Button.OnItemSelected += args =>
{
dropDown.Button.SelectId(args.Id);
ValueChanged();
};
}
private int FindValueId(T value)
{
for (var i = 0; i < _entries.Length; i++)
{
if (IsValueEqual(_entries[i].Key, value))
return i;
}
// This will just default select the first entry or whatever.
return 0;
}
/// <summary>
/// A single option for a drop-down.
/// </summary>
/// <param name="key">The value that this option has. This is what will be written to the CVar if selected.</param>
/// <param name="label">The visual text shown to the user for the option.</param>
/// <seealso cref="OptionDropDownCVar{T}"/>
/// <seealso cref="OptionsTabControlRow.AddOptionDropDown{T}"/>
public sealed class ValueOption(T key, string label)
{
/// <summary>
/// The value that this option has. This is what will be written to the CVar if selected.
/// </summary>
public readonly T Key = key;
/// <summary>
/// The visual text shown to the user for the option.
/// </summary>
public readonly string Label = label;
}
private struct ItemEntry
{
public T Key;
}
}

View File

@@ -0,0 +1,16 @@
<Control xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:Content.Client.Options.UI">
<BoxContainer Orientation="Vertical">
<ScrollContainer VerticalExpand="True" HScrollEnabled="False">
<BoxContainer Orientation="Vertical" Margin="8">
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
<CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" />
<ui:OptionSlider Name="ChatWindowOpacitySlider" Title="{Loc 'ui-options-chat-window-opacity'}" />
<ui:OptionSlider Name="ScreenShakeIntensitySlider" Title="{Loc 'ui-options-screen-shake-intensity'}" />
</BoxContainer>
</ScrollContainer>
<ui:OptionsTabControlRow Name="Control" Access="Public" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,24 @@
using Content.Shared.CCVar;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Options.UI.Tabs;
[GenerateTypedNameReferences]
public sealed partial class AccessibilityTab : Control
{
public AccessibilityTab()
{
RobustXamlLoader.Load(this);
Control.AddOptionCheckBox(CCVars.ChatEnableColorName, EnableColorNameCheckBox);
Control.AddOptionCheckBox(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox);
Control.AddOptionCheckBox(CCVars.ReducedMotion, ReducedMotionCheckBox);
Control.AddOptionPercentSlider(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider);
Control.AddOptionPercentSlider(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider);
Control.Initialize();
}
}

View File

@@ -1,138 +1,37 @@
<Control xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:Content.Client.Stylesheets"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:Content.Client.Options.UI">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
<Label Text="{Loc 'ui-options-volume-label'}" FontColorOverride="{x:Static s:StyleNano.NanoGold}" StyleClasses="LabelKeyText"/>
<Label Text="{Loc 'ui-options-volume-label'}"
StyleClasses="LabelKeyText"/>
<BoxContainer Orientation="Vertical" Margin="0 3 0 0">
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-master-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="MasterVolumeSlider" MinValue="0" MaxValue="100" HorizontalExpand="True" MinSize="80 0" Rounded="True" />
<Control MinSize="8 0" />
<Label Name="MasterVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
<Control MinSize="0 8" />
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-midi-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="MidiVolumeSlider" MinValue="0" MaxValue="100" HorizontalExpand="True" MinSize="80 0" Rounded="True" />
<Control MinSize="8 0" />
<Label Name="MidiVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-ambient-music-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="AmbientMusicVolumeSlider" MinValue="0" MaxValue="100" HorizontalExpand="True" MinSize="80 0" Rounded="True" />
<Control MinSize="8 0" />
<Label Name="AmbientMusicVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
<ui:OptionSlider Name="SliderVolumeMaster" Title="{Loc 'ui-options-master-volume'}"
Margin="0 0 0 8" />
<ui:OptionSlider Name="SliderVolumeMidi" Title="{Loc 'ui-options-midi-volume'}" />
<ui:OptionSlider Name="SliderVolumeAmbientMusic" Title="{Loc 'ui-options-ambient-music-volume'}" />
<ui:OptionSlider Name="SliderVolumeAmbience" Title="{Loc 'ui-options-ambience-volume'}" />
<ui:OptionSlider Name="SliderVolumeLobby" Title="{Loc 'ui-options-lobby-volume'}" />
<ui:OptionSlider Name="SliderVolumeInterface" Title="{Loc 'ui-options-interface-volume'}" />
<ui:OptionSlider Name="SliderVolumeAnnouncer" Title="{Loc 'ui-options-announcer-volume'}" />
<!--WD EDIT START-->
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-tts-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="TtsVolumeSlider"
MinValue="0"
MaxValue="200"
HorizontalExpand="True"
MinSize="80 0"
Rounded="True" />
<Control MinSize="8 0" />
<Label Name="TtsVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-bark-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="BarkVolumeSlider"
MinValue="0"
MaxValue="200"
HorizontalExpand="True"
MinSize="80 0"
Rounded="True" />
<Control MinSize="8 0" />
<Label Name="BarkVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-bark-limit'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="BarkLimitSlider"
MinValue="0"
MaxValue="128"
HorizontalExpand="True"
MinSize="80 0"
Rounded="True" />
<Control MinSize="8 0" />
<Label Name="BarkLimitLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0" />
</BoxContainer>
<ui:OptionSlider Name="SliderVolumeTts" Title="{Loc 'ui-options-tts-volume'}" />
<ui:OptionSlider Name="SliderVolumeBark" Title="{Loc 'ui-options-bark-volume'}" />
<ui:OptionSlider Name="SliderLimitBark" Title="{Loc 'ui-options-bark-limit'}" />
<!--WD EDIT END-->
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-ambience-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="AmbienceVolumeSlider" MinValue="0" MaxValue="100" HorizontalExpand="True" MinSize="80 0" Rounded="True" />
<Control MinSize="8 0" />
<Label Name="AmbienceVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-lobby-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="LobbyVolumeSlider" MinValue="0" MaxValue="100" HorizontalExpand="True" MinSize="80 0" Rounded="True" />
<Control MinSize="8 0" />
<Label Name="LobbyVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-interface-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="InterfaceVolumeSlider" MinValue="0" MaxValue="100" HorizontalExpand="True" MinSize="80 0" Rounded="True" />
<Control MinSize="8 0" />
<Label Name="InterfaceVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-ambience-max-sounds'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="AmbienceSoundsSlider" MinValue="0" MaxValue="1" HorizontalExpand="True" MinSize="80 0" Rounded="True" />
<Control MinSize="8 0" />
<Label Name="AmbienceSoundsLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
<Label Text="{Loc 'ui-options-announcer-volume'}" HorizontalExpand="True" />
<Control MinSize="8 0" />
<Slider Name="AnnouncerVolumeSlider" MinValue="0" MaxValue="100" HorizontalExpand="True" MinSize="80 0" Rounded="True" />
<Control MinSize="8 0" />
<Label Name="AnnouncerVolumeLabel" MinSize="48 0" Align="Right" />
<Control MinSize="4 0"/>
</BoxContainer>
<Control MinSize="0 8" />
<ui:OptionSlider Name="SliderMaxAmbienceSounds" Title="{Loc 'ui-options-ambience-max-sounds'}"
Margin="0 0 0 8" />
<CheckBox Name="LobbyMusicCheckBox" Text="{Loc 'ui-options-lobby-music'}" />
<CheckBox Name="RestartSoundsCheckBox" Text="{Loc 'ui-options-restart-sounds'}" />
<CheckBox Name="EventMusicCheckBox" Text="{Loc 'ui-options-event-music'}" />
<CheckBox Name="AnnouncerDisableMultipleSoundsCheckBox" Text="{Loc 'ui-options-announcer-disable-multiple-sounds'}" ToolTip="{Loc 'ui-options-announcer-disable-multiple-sounds-tooltip'}" />
<CheckBox Name="AdminSoundsCheckBox" Text="{Loc 'ui-options-admin-sounds'}" />
<!--WD EDIT START-->
<CheckBox Name="ToggleCombatModeCheckBox" Text="{Loc 'ui-options-toggle-combat-mode-sounds'}" />
<BoxContainer Orientation="Horizontal" SeparationOverride="5">
<Label Text="{Loc 'ui-voice-option'}"/>
<OptionButton Name="CharVoiceType"/>
</BoxContainer>
<CheckBox Name="CombatModeSoundCheckBox" Text="{Loc 'ui-options-toggle-combat-mode-sounds'}" />
<ui:OptionDropDown Name="DropDownVoiceType" Title="{Loc 'ui-voice-option'}" />
<!--WD EDIT END-->
</BoxContainer>
</BoxContainer>
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
<BoxContainer Orientation="Horizontal" Align="End" HorizontalExpand="True" VerticalExpand="True">
<Button Name="ResetButton" Text="{Loc 'ui-options-reset-all'}" StyleClasses="Danger" HorizontalExpand="True" HorizontalAlignment="Right" />
<Control MinSize="2 0" />
<Button Name="ApplyButton" Text="{Loc 'ui-options-apply'}" TextAlign="Center" HorizontalAlignment="Right" />
</BoxContainer>
</controls:StripeBack>
<ui:OptionsTabControlRow Name="Control" Access="Public" />
</BoxContainer>
</Control>

View File

@@ -1,298 +1,111 @@
using Content.Client.Audio;
using Content.Shared._White.Bark;
using Content.Shared._White.Bark.Systems;
using Content.Shared._White.CCVar;
using Content.Shared.CCVar;
using Robust.Client.Audio;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared;
using Robust.Shared.Configuration;
using Range = Robust.Client.UserInterface.Controls.Range;
namespace Content.Client.Options.UI.Tabs
namespace Content.Client.Options.UI.Tabs;
[GenerateTypedNameReferences]
public sealed partial class AudioTab : Control
{
[GenerateTypedNameReferences]
public sealed partial class AudioTab : Control
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IAudioManager _audio = default!;
public AudioTab()
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
private readonly IAudioManager _audio;
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
public AudioTab()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var masterVolume = Control.AddOptionPercentSlider(
CVars.AudioMasterVolume,
SliderVolumeMaster,
scale: ContentAudioSystem.MasterVolumeMultiplier);
masterVolume.ImmediateValueChanged += OnMasterVolumeSliderChanged;
CharVoiceType.AddItem(Loc.GetString("char-voice-none"), (int) CharacterVoiceType.None); // WD EDIT
CharVoiceType.AddItem(Loc.GetString("char-voice-bark"), (int) CharacterVoiceType.Bark); // WD EDIT
CharVoiceType.AddItem(Loc.GetString("char-voice-tts"), (int) CharacterVoiceType.TTS); // WD EDIT
Control.AddOptionPercentSlider(
CVars.MidiVolume,
SliderVolumeMidi,
scale: ContentAudioSystem.MidiVolumeMultiplier);
_audio = IoCManager.Resolve<IAudioManager>();
LobbyMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.LobbyMusicEnabled);
RestartSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.RestartSoundsEnabled);
EventMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.EventMusicEnabled);
AdminSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.AdminSoundsEnabled);
ToggleCombatModeCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.ToggleCombatModeSound); // WD EDIT
Control.AddOptionPercentSlider(
CCVars.AmbientMusicVolume,
SliderVolumeAmbientMusic,
scale: ContentAudioSystem.AmbientMusicMultiplier);
ApplyButton.OnPressed += OnApplyButtonPressed;
ResetButton.OnPressed += OnResetButtonPressed;
Control.AddOptionPercentSlider(
CCVars.AmbienceVolume,
SliderVolumeAmbience,
scale: ContentAudioSystem.AmbienceMultiplier);
AttachUpdateChangesHandler(
MasterVolumeSlider,
MidiVolumeSlider,
AmbientMusicVolumeSlider,
AmbienceVolumeSlider,
AmbienceSoundsSlider,
LobbyVolumeSlider,
InterfaceVolumeSlider,
AnnouncerVolumeSlider,
// WD EDIT START
TtsVolumeSlider,
BarkVolumeSlider,
BarkLimitSlider,
// WD EDIT END
Control.AddOptionPercentSlider(
CCVars.LobbyMusicVolume,
SliderVolumeLobby,
scale: ContentAudioSystem.LobbyMultiplier);
LobbyMusicCheckBox,
RestartSoundsCheckBox,
EventMusicCheckBox,
AnnouncerDisableMultipleSoundsCheckBox,
AdminSoundsCheckBox,
// WD EDIT START
ToggleCombatModeCheckBox,
Control.AddOptionPercentSlider(
CCVars.InterfaceVolume,
SliderVolumeInterface,
scale: ContentAudioSystem.InterfaceMultiplier);
CharVoiceType
// WD EDIT END
);
AmbienceSoundsSlider.MinValue = _cfg.GetCVar(CCVars.MinMaxAmbientSourcesConfigured);
AmbienceSoundsSlider.MaxValue = _cfg.GetCVar(CCVars.MaxMaxAmbientSourcesConfigured);
Reset();
return;
void AttachUpdateChangesHandler(params Control[] controls)
{
foreach (var control in controls)
{
switch (control)
{
case Slider slider:
slider.OnValueChanged += _ => UpdateChanges();
break;
case CheckBox checkBox:
checkBox.OnToggled += _ => UpdateChanges();
break;
// WWDP EDIT START
case OptionButton optionButton:
optionButton.OnItemSelected += UpdateChangesOptionButton;
break;
// WWDP EDIT END
}
}
}
}
protected override void Dispose(bool disposing)
{
ApplyButton.OnPressed -= OnApplyButtonPressed;
ResetButton.OnPressed -= OnResetButtonPressed;
DetachUpdateChangesHandler(
MasterVolumeSlider,
MidiVolumeSlider,
AmbientMusicVolumeSlider,
AmbienceVolumeSlider,
AmbienceSoundsSlider,
LobbyVolumeSlider,
InterfaceVolumeSlider,
AnnouncerVolumeSlider,
// WD EDIT START
TtsVolumeSlider,
BarkVolumeSlider,
BarkLimitSlider,
// WD EDIT END
LobbyMusicCheckBox,
RestartSoundsCheckBox,
EventMusicCheckBox,
AnnouncerDisableMultipleSoundsCheckBox,
AdminSoundsCheckBox,
// WD EDIT START
ToggleCombatModeCheckBox,
CharVoiceType
// WD EDIT END
);
base.Dispose(disposing);
return;
void DetachUpdateChangesHandler(params Control[] controls)
{
foreach (var control in controls)
{
switch (control)
{
case Slider slider:
slider.OnValueChanged -= _ => UpdateChanges();
break;
case CheckBox checkBox:
checkBox.OnToggled -= _ => UpdateChanges();
break;
// WWDP EDIT START
case OptionButton optionButton:
optionButton.OnItemSelected -= UpdateChangesOptionButton;
break;
// WWDP EDIT END
}
}
}
}
Control.AddOptionPercentSlider(
CCVars.AnnouncerVolume,
SliderVolumeAnnouncer,
scale: ContentAudioSystem.AnnouncerMultiplier);
// WD EDIT START
private void UpdateChangesOptionButton(OptionButton.ItemSelectedEventArgs args)
{
CharVoiceType.SelectId(args.Id);
UpdateChanges();
}
Control.AddOptionPercentSlider(
WhiteCVars.TTSVolume,
SliderVolumeTts,
scale: ContentAudioSystem.TTSMultiplier);
Control.AddOptionPercentSlider(
WhiteCVars.BarkVolume,
SliderVolumeBark);
Control.AddOptionSlider(
WhiteCVars.BarkLimit,
SliderLimitBark,
0,
128);
// WD EDIT END
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
{
_cfg.SetCVar(CVars.AudioMasterVolume, MasterVolumeSlider.Value / 100f * ContentAudioSystem.MasterVolumeMultiplier);
// Want the CVar updated values to have the multiplier applied
// For the UI we just display 0-100 still elsewhere
_cfg.SetCVar(CVars.MidiVolume, MidiVolumeSlider.Value / 100f * ContentAudioSystem.MidiVolumeMultiplier);
_cfg.SetCVar(CCVars.AmbienceVolume, AmbienceVolumeSlider.Value / 100f * ContentAudioSystem.AmbienceMultiplier);
_cfg.SetCVar(CCVars.AmbientMusicVolume, AmbientMusicVolumeSlider.Value / 100f * ContentAudioSystem.AmbientMusicMultiplier);
_cfg.SetCVar(CCVars.LobbyMusicVolume, LobbyVolumeSlider.Value / 100f * ContentAudioSystem.LobbyMultiplier);
_cfg.SetCVar(CCVars.InterfaceVolume, InterfaceVolumeSlider.Value / 100f * ContentAudioSystem.InterfaceMultiplier);
_cfg.SetCVar(CCVars.AnnouncerVolume, AnnouncerVolumeSlider.Value / 100f * ContentAudioSystem.AnnouncerMultiplier);
// WD EDIT START
_cfg.SetCVar(WhiteCVars.TTSVolume, TtsVolumeSlider.Value / 100f * ContentAudioSystem.TTSMultiplier);
_cfg.SetCVar(WhiteCVars.BarkVolume, BarkVolumeSlider.Value / 100f );
_cfg.SetCVar(WhiteCVars.BarkLimit, (int)BarkLimitSlider.Value);
// WD EDIT END
Control.AddOptionSlider(
CCVars.MaxAmbientSources,
SliderMaxAmbienceSounds,
_cfg.GetCVar(CCVars.MinMaxAmbientSourcesConfigured),
_cfg.GetCVar(CCVars.MaxMaxAmbientSourcesConfigured));
_cfg.SetCVar(CCVars.MaxAmbientSources, (int)AmbienceSoundsSlider.Value);
Control.AddOptionCheckBox(CCVars.LobbyMusicEnabled, LobbyMusicCheckBox);
Control.AddOptionCheckBox(CCVars.RestartSoundsEnabled, RestartSoundsCheckBox);
Control.AddOptionCheckBox(CCVars.EventMusicEnabled, EventMusicCheckBox);
Control.AddOptionCheckBox(CCVars.AnnouncerDisableMultipleEnabled, AnnouncerDisableMultipleSoundsCheckBox);
Control.AddOptionCheckBox(CCVars.AdminSoundsEnabled, AdminSoundsCheckBox);
Control.AddOptionCheckBox(WhiteCVars.CombatModeSoundEnabled, CombatModeSoundCheckBox); // WD EDIT
_cfg.SetCVar(CCVars.LobbyMusicEnabled, LobbyMusicCheckBox.Pressed);
_cfg.SetCVar(CCVars.RestartSoundsEnabled, RestartSoundsCheckBox.Pressed);
_cfg.SetCVar(CCVars.EventMusicEnabled, EventMusicCheckBox.Pressed);
_cfg.SetCVar(CCVars.AnnouncerDisableMultipleSounds, AnnouncerDisableMultipleSoundsCheckBox.Pressed);
_cfg.SetCVar(CCVars.AdminSoundsEnabled, AdminSoundsCheckBox.Pressed);
// WD EDIT START
_cfg.SetCVar(WhiteCVars.ToggleCombatModeSound, ToggleCombatModeCheckBox.Pressed);
// WD EDIT START
Control.AddOptionDropDown(
WhiteCVars.VoiceType,
DropDownVoiceType,
[
new (CharacterVoiceType.None, Loc.GetString("char-voice-none")),
new (CharacterVoiceType.Bark, Loc.GetString("char-voice-bark")),
new (CharacterVoiceType.TTS, Loc.GetString("char-voice-tts")),
]);
// WD EDIT END
_cfg.SetCVar(WhiteCVars.VoiceType, (CharacterVoiceType) CharVoiceType.SelectedId);
// WD EDIT END
Control.Initialize();
}
_cfg.SaveToFile();
UpdateChanges();
}
private void OnResetButtonPressed(BaseButton.ButtonEventArgs args)
{
Reset();
}
private void Reset()
{
MasterVolumeSlider.Value = _cfg.GetCVar(CVars.AudioMasterVolume) * 100f / ContentAudioSystem.MasterVolumeMultiplier;
MidiVolumeSlider.Value = _cfg.GetCVar(CVars.MidiVolume) * 100f / ContentAudioSystem.MidiVolumeMultiplier;
AmbienceVolumeSlider.Value = _cfg.GetCVar(CCVars.AmbienceVolume) * 100f / ContentAudioSystem.AmbienceMultiplier;
AmbientMusicVolumeSlider.Value = _cfg.GetCVar(CCVars.AmbientMusicVolume) * 100f / ContentAudioSystem.AmbientMusicMultiplier;
LobbyVolumeSlider.Value = _cfg.GetCVar(CCVars.LobbyMusicVolume) * 100f / ContentAudioSystem.LobbyMultiplier;
InterfaceVolumeSlider.Value = _cfg.GetCVar(CCVars.InterfaceVolume) * 100f / ContentAudioSystem.InterfaceMultiplier;
AnnouncerVolumeSlider.Value = _cfg.GetCVar(CCVars.AnnouncerVolume) * 100f / ContentAudioSystem.AnnouncerMultiplier;
// WD EDIT START
TtsVolumeSlider.Value = _cfg.GetCVar(WhiteCVars.TTSVolume) * 100f / ContentAudioSystem.TTSMultiplier;
BarkVolumeSlider.Value = _cfg.GetCVar(WhiteCVars.BarkVolume) * 100;
BarkLimitSlider.Value = _cfg.GetCVar(WhiteCVars.BarkLimit);
// WD EDIT END
AmbienceSoundsSlider.Value = _cfg.GetCVar(CCVars.MaxAmbientSources);
LobbyMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.LobbyMusicEnabled);
RestartSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.RestartSoundsEnabled);
EventMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.EventMusicEnabled);
AnnouncerDisableMultipleSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.AnnouncerDisableMultipleSounds);
AdminSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.AdminSoundsEnabled);
// WD EDIT START
ToggleCombatModeCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.ToggleCombatModeSound);
CharVoiceType.SelectId((int)_cfg.GetCVar(WhiteCVars.VoiceType));
// WD EDIT END
UpdateChanges();
}
private void UpdateChanges()
{
// y'all need jesus.
var isMasterVolumeSame =
Math.Abs(MasterVolumeSlider.Value - _cfg.GetCVar(CVars.AudioMasterVolume) * 100f / ContentAudioSystem.MasterVolumeMultiplier) < 0.01f;
var isMidiVolumeSame =
Math.Abs(MidiVolumeSlider.Value - _cfg.GetCVar(CVars.MidiVolume) * 100f / ContentAudioSystem.MidiVolumeMultiplier) < 0.01f;
var isAmbientVolumeSame =
Math.Abs(AmbienceVolumeSlider.Value - _cfg.GetCVar(CCVars.AmbienceVolume) * 100f / ContentAudioSystem.AmbienceMultiplier) < 0.01f;
var isAmbientMusicVolumeSame =
Math.Abs(AmbientMusicVolumeSlider.Value - _cfg.GetCVar(CCVars.AmbientMusicVolume) * 100f / ContentAudioSystem.AmbientMusicMultiplier) < 0.01f;
var isLobbyVolumeSame =
Math.Abs(LobbyVolumeSlider.Value - _cfg.GetCVar(CCVars.LobbyMusicVolume) * 100f / ContentAudioSystem.LobbyMultiplier) < 0.01f;
var isInterfaceVolumeSame =
Math.Abs(InterfaceVolumeSlider.Value - _cfg.GetCVar(CCVars.InterfaceVolume) * 100f / ContentAudioSystem.InterfaceMultiplier) < 0.01f;
var isAnnouncerVolumeSame =
Math.Abs(AnnouncerVolumeSlider.Value - _cfg.GetCVar(CCVars.AnnouncerVolume) * 100f / ContentAudioSystem.AnnouncerMultiplier) < 0.01f;
// WD EDIT START
var isTtsVolumeSame =
Math.Abs(TtsVolumeSlider.Value - _cfg.GetCVar(WhiteCVars.TTSVolume) * 100f / ContentAudioSystem.TTSMultiplier) < 0.01f;
var isBarkVolumeSame =
Math.Abs(BarkVolumeSlider.Value - _cfg.GetCVar(WhiteCVars.BarkVolume) * 100f) < 0.01f;
var isBarkLimitSame = (int) BarkLimitSlider.Value == _cfg.GetCVar(WhiteCVars.BarkLimit);
// WD EDIT END
var isAmbientSoundsSame = (int)AmbienceSoundsSlider.Value == _cfg.GetCVar(CCVars.MaxAmbientSources);
var isLobbySame = LobbyMusicCheckBox.Pressed == _cfg.GetCVar(CCVars.LobbyMusicEnabled);
var isRestartSoundsSame = RestartSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.RestartSoundsEnabled);
var isEventSame = EventMusicCheckBox.Pressed == _cfg.GetCVar(CCVars.EventMusicEnabled);
var isAnnouncerDisableMultipleSoundsSame = AnnouncerDisableMultipleSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.AnnouncerDisableMultipleSounds);
var isToggleCombatModeSoundsSame = AdminSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.AdminSoundsEnabled);
// WD EDIT START
var isAdminSoundsSame = ToggleCombatModeCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.ToggleCombatModeSound);
var isVoiceTypeSame = CharVoiceType.SelectedId == (int) _cfg.GetCVar(WhiteCVars.VoiceType);
// WD EDIT END
var isEverythingSame = isMasterVolumeSame && isMidiVolumeSame && isAmbientVolumeSame
&& isAmbientMusicVolumeSame && isAmbientSoundsSame && isLobbySame && isRestartSoundsSame && isEventSame
&& isAnnouncerDisableMultipleSoundsSame && isAdminSoundsSame && isLobbyVolumeSame
&& isInterfaceVolumeSame && isAnnouncerVolumeSame && isTtsVolumeSame && isBarkVolumeSame
&& isVoiceTypeSame && isBarkLimitSame && isToggleCombatModeSoundsSame; // WD EDIT
ApplyButton.Disabled = isEverythingSame;
ResetButton.Disabled = isEverythingSame;
MasterVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", MasterVolumeSlider.Value / 100));
MidiVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", MidiVolumeSlider.Value / 100));
AmbientMusicVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", AmbientMusicVolumeSlider.Value / 100));
AmbienceVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", AmbienceVolumeSlider.Value / 100));
LobbyVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", LobbyVolumeSlider.Value / 100));
InterfaceVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", InterfaceVolumeSlider.Value / 100));
AnnouncerVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", AnnouncerVolumeSlider.Value / 100));
TtsVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", TtsVolumeSlider.Value / 100)); // WD EDIT
BarkVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", BarkVolumeSlider.Value / 100)); // WD EDIT
BarkLimitLabel.Text = ((int) BarkLimitSlider.Value).ToString(); // WD EDIT
AmbienceSoundsLabel.Text = ((int)AmbienceSoundsSlider.Value).ToString();
}
private void OnMasterVolumeSliderChanged(float value)
{
// TODO: I was thinking of giving OptionsTabControlRow a flag to "set CVar immediately", but I'm deferring that
// until there's a proper system for enforcing people don't close the window with pending changes.
_audio.SetMasterGain(value);
}
}

View File

@@ -1,67 +1,44 @@
<tabs:GraphicsTab xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs">
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
xmlns:ui="clr-namespace:Content.Client.Options.UI">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
<CheckBox Name="VSyncCheckBox" Text="{Loc 'ui-options-vsync'}" />
<CheckBox Name="FullscreenCheckBox" Text="{Loc 'ui-options-fullscreen'}" />
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-lighting-label'}" />
<Control MinSize="4 0" />
<OptionButton Name="LightingPresetOption" MinSize="100 0" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-scale-label'}" />
<Control MinSize="4 0" />
<OptionButton Name="UIScaleOption" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<ScrollContainer VerticalExpand="True">
<BoxContainer Orientation="Vertical" Margin="8 8 8 8">
<!-- Display -->
<Label Text="{Loc 'ui-options-display-label'}" StyleClasses="LabelKeyText"/>
<CheckBox Name="VSyncCheckBox" Text="{Loc 'ui-options-vsync'}" />
<CheckBox Name="FullscreenCheckBox" Text="{Loc 'ui-options-fullscreen'}" />
<!-- Quality -->
<Label Text="{Loc 'ui-options-quality-label'}" StyleClasses="LabelKeyText"/>
<ui:OptionDropDown Name="DropDownLightingQuality" Title="{Loc 'ui-options-lighting-label'}" />
<CheckBox Name="ViewportLowResCheckBox" Text="{Loc 'ui-options-vp-low-res'}" />
<CheckBox Name="ParallaxLowQualityCheckBox" Text="{Loc 'ui-options-parallax-low-quality'}" />
<!-- WD EDIT START -->
<CheckBox Name="FilmGrainCheckBox" Text="{Loc 'ui-options-film-grain'}" />
<ui:OptionSlider Name="FilmGrainSlider"/>
<!-- WD EDIT END -->
<!-- Interface -->
<Label Text="{Loc 'ui-options-interface-label'}" StyleClasses="LabelKeyText"/>
<ui:OptionDropDown Name="DropDownUIScale" Title="{Loc 'ui-options-scale-label'}" />
<CheckBox Name="ViewportStretchCheckBox" Text="{Loc 'ui-options-vp-stretch'}" />
<BoxContainer Name="ViewportScaleBox" Orientation="Horizontal">
<Label Name="ViewportScaleText" Margin="8 0" />
<Slider Name="ViewportScaleSlider"
MinValue="1"
MaxValue="5"
Rounded="True"
MinWidth="200" />
</BoxContainer>
<ui:OptionSlider Name="ViewportScaleSlider" Title="{Loc ui-options-vp-scale}" />
<ui:OptionSlider Name="ViewportWidthSlider" Title="{Loc ui-options-vp-width}" />
<CheckBox Name="IntegerScalingCheckBox"
Text="{Loc 'ui-options-vp-integer-scaling'}"
ToolTip="{Loc 'ui-options-vp-integer-scaling-tooltip'}" />
<CheckBox Name="ViewportVerticalFitCheckBox"
Text="{Loc 'ui-options-vp-vertical-fit'}"
ToolTip="{Loc 'ui-options-vp-vertical-fit-tooltip'}" />
<!-- Misc -->
<Label Text="{Loc 'ui-options-misc-label'}" StyleClasses="LabelKeyText"/>
<CheckBox Name="FpsCounterCheckBox" Text="{Loc 'ui-options-fps-counter'}" />
<CheckBox Name="MoodVisualEffectsCheckBox" Text="{Loc 'ui-options-mood-visual-effects'}" />
<CheckBox Name="PixelSnapCameraCheckBox" Text="{Loc 'ui-options-pixel-snap-camera-experimental'}" /> <!-- WD EDIT -->
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Name="ViewportWidthSliderDisplay" />
<Control MinSize="4 0" />
<Slider Name="ViewportWidthSlider"
Rounded="True"
MinWidth="200" />
</BoxContainer>
<CheckBox Name="IntegerScalingCheckBox"
Text="{Loc 'ui-options-vp-integer-scaling'}"
ToolTip="{Loc 'ui-options-vp-integer-scaling-tooltip'}" />
<CheckBox Name="ViewportVerticalFitCheckBox"
Text="{Loc 'ui-options-vp-vertical-fit'}"
ToolTip="{Loc 'ui-options-vp-vertical-fit-tooltip'}" />
<CheckBox Name="ViewportLowResCheckBox" Text="{Loc 'ui-options-vp-low-res'}" />
<CheckBox Name="PixelSnapCameraCheckBox" Text="{Loc 'ui-options-pixel-snap-camera-experimental'}" /> <!-- wwdp edit -->
<CheckBox Name="ParallaxLowQualityCheckBox" Text="{Loc 'ui-options-parallax-low-quality'}" />
<CheckBox Name="FpsCounterCheckBox" Text="{Loc 'ui-options-fps-counter'}" />
<!-- WD EDIT START -->
<CheckBox Name="FilmGrainCheckBox" Text="{Loc 'ui-options-film-grain'}" />
<BoxContainer Name="FilmGrainBox" Orientation="Horizontal">
<Label Name="FilmGrainText"/>
<Control MinSize="4 0" />
<Slider Name="FilmGrainSlider"
MinValue="25"
MaxValue="125"
Rounded="True"
MinWidth="500" />
</BoxContainer>
<!-- WD EDIT END -->
<CheckBox Name="MoodVisualEffectsCheckBox" Text="{Loc 'ui-options-mood-visual-effects'}" />
</BoxContainer>
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
<Button Name="ApplyButton"
Text="{Loc 'ui-options-apply'}"
TextAlign="Center"
HorizontalAlignment="Right" />
</controls:StripeBack>
</ScrollContainer>
<ui:OptionsTabControlRow Name="Control" Access="Public" />
</BoxContainer>
</tabs:GraphicsTab>

View File

@@ -8,258 +8,151 @@ using Robust.Client.UserInterface.XAML;
using Robust.Shared;
using Robust.Shared.Configuration;
namespace Content.Client.Options.UI.Tabs
namespace Content.Client.Options.UI.Tabs;
[GenerateTypedNameReferences]
public sealed partial class GraphicsTab : Control
{
[GenerateTypedNameReferences]
public sealed partial class GraphicsTab : Control
[Dependency] private readonly IConfigurationManager _cfg = default!;
public GraphicsTab()
{
private static readonly float[] UIScaleOptions =
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
Control.AddOptionCheckBox(CVars.DisplayVSync, VSyncCheckBox);
Control.AddOption(new OptionFullscreen(Control, _cfg, FullscreenCheckBox));
Control.AddOption(new OptionLightingQuality(Control, _cfg, DropDownLightingQuality));
Control.AddOptionDropDown(
CVars.DisplayUIScale,
DropDownUIScale,
[
new OptionDropDownCVar<float>.ValueOption(
0f,
Loc.GetString("ui-options-scale-auto", ("scale", UserInterfaceManager.DefaultUIScale))),
new OptionDropDownCVar<float>.ValueOption(0.75f, Loc.GetString("ui-options-scale-75")),
new OptionDropDownCVar<float>.ValueOption(1.00f, Loc.GetString("ui-options-scale-100")),
new OptionDropDownCVar<float>.ValueOption(1.25f, Loc.GetString("ui-options-scale-125")),
new OptionDropDownCVar<float>.ValueOption(1.50f, Loc.GetString("ui-options-scale-150")),
new OptionDropDownCVar<float>.ValueOption(1.75f, Loc.GetString("ui-options-scale-175")),
new OptionDropDownCVar<float>.ValueOption(2.00f, Loc.GetString("ui-options-scale-200")),
]);
var vpStretch = Control.AddOptionCheckBox(CCVars.ViewportStretch, ViewportStretchCheckBox);
var vpVertFit = Control.AddOptionCheckBox(CCVars.ViewportVerticalFit, ViewportVerticalFitCheckBox);
Control.AddOptionSlider(
CCVars.ViewportFixedScaleFactor,
ViewportScaleSlider,
1,
5,
(_, value) => Loc.GetString("ui-options-vp-scale-value", ("scale", value)));
vpStretch.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
vpVertFit.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
Control.AddOptionSlider(
CCVars.ViewportWidth,
ViewportWidthSlider,
(int)ViewportWidthSlider.Slider.MinValue,
(int)ViewportWidthSlider.Slider.MaxValue);
Control.AddOption(new OptionIntegerScaling(Control, _cfg, IntegerScalingCheckBox));
Control.AddOptionCheckBox(CCVars.ViewportScaleRender, ViewportLowResCheckBox, invert: true);
Control.AddOptionCheckBox(CCVars.ParallaxLowQuality, ParallaxLowQualityCheckBox);
// WD EDIT START
Control.AddOptionCheckBox(WhiteCVars.FilmGrain, FilmGrainCheckBox);
Control.AddOptionPercentSlider(
WhiteCVars.FilmGrainStrength,
FilmGrainSlider,
25,
125);
// WD EDIT END
Control.AddOptionCheckBox(CCVars.HudFpsCounterVisible, FpsCounterCheckBox);
Control.AddOptionCheckBox(CCVars.MoodVisualEffects, MoodVisualEffectsCheckBox);
Control.AddOptionCheckBox(WhiteCVars.PixelSnapCamera, PixelSnapCameraCheckBox); // WD EDIT
Control.Initialize();
_cfg.OnValueChanged(CCVars.ViewportMinimumWidth, _ => UpdateViewportWidthRange());
_cfg.OnValueChanged(CCVars.ViewportMaximumWidth, _ => UpdateViewportWidthRange());
UpdateViewportWidthRange();
UpdateViewportSettingsVisibility();
}
private void UpdateViewportSettingsVisibility()
{
ViewportScaleSlider.Visible = !ViewportStretchCheckBox.Pressed;
IntegerScalingCheckBox.Visible = ViewportStretchCheckBox.Pressed;
ViewportVerticalFitCheckBox.Visible = ViewportStretchCheckBox.Pressed;
ViewportWidthSlider.Visible = !ViewportStretchCheckBox.Pressed || !ViewportVerticalFitCheckBox.Pressed;
}
private void UpdateViewportWidthRange()
{
var min = _cfg.GetCVar(CCVars.ViewportMinimumWidth);
var max = _cfg.GetCVar(CCVars.ViewportMaximumWidth);
ViewportWidthSlider.Slider.MinValue = min;
ViewportWidthSlider.Slider.MaxValue = max;
}
private sealed class OptionLightingQuality : BaseOption
{
private readonly IConfigurationManager _cfg;
private readonly OptionDropDown _dropDown;
private const int QualityVeryLow = 0;
private const int QualityLow = 1;
private const int QualityMedium = 2;
private const int QualityHigh = 3;
private const int QualityDefault = QualityMedium;
public OptionLightingQuality(OptionsTabControlRow controller, IConfigurationManager cfg, OptionDropDown dropDown) : base(controller)
{
0f,
0.75f,
1f,
1.25f,
1.50f,
1.75f,
2f
};
[Dependency] private readonly IConfigurationManager _cfg = default!;
public GraphicsTab()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
VSyncCheckBox.OnToggled += OnCheckBoxToggled;
FullscreenCheckBox.OnToggled += OnCheckBoxToggled;
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-very-low"));
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-low"));
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-medium"));
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-high"));
LightingPresetOption.OnItemSelected += OnLightingQualityChanged;
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-auto",
("scale", UserInterfaceManager.DefaultUIScale)));
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-75"));
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-100"));
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-125"));
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-150"));
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-175"));
UIScaleOption.AddItem(Loc.GetString("ui-options-scale-200"));
UIScaleOption.OnItemSelected += OnUIScaleChanged;
ViewportStretchCheckBox.OnToggled += _ =>
{
UpdateViewportScale();
UpdateApplyButton();
};
ViewportScaleSlider.OnValueChanged += _ =>
{
UpdateApplyButton();
UpdateViewportScale();
};
ViewportWidthSlider.OnValueChanged += _ =>
{
UpdateViewportWidthDisplay();
UpdateApplyButton();
};
ViewportVerticalFitCheckBox.OnToggled += _ =>
{
UpdateViewportScale();
UpdateApplyButton();
};
// WD EDIT START
FilmGrainSlider.OnValueChanged += _ =>
{
UpdateFilmGrainDisplay();
UpdateApplyButton();
};
FilmGrainCheckBox.OnToggled += _ =>
{
UpdateFilmGrainScale();
UpdateApplyButton();
};
//WD EDIT END
IntegerScalingCheckBox.OnToggled += OnCheckBoxToggled;
ViewportLowResCheckBox.OnToggled += OnCheckBoxToggled;
PixelSnapCameraCheckBox.OnToggled += OnCheckBoxToggled; // WWDP EDIT
ParallaxLowQualityCheckBox.OnToggled += OnCheckBoxToggled;
FpsCounterCheckBox.OnToggled += OnCheckBoxToggled;
MoodVisualEffectsCheckBox.OnToggled += OnCheckBoxToggled;
FilmGrainCheckBox.OnToggled += OnFilmGrainCheckBoxToggled; // WD EDIT
ApplyButton.OnPressed += OnApplyButtonPressed;
VSyncCheckBox.Pressed = _cfg.GetCVar(CVars.DisplayVSync);
FullscreenCheckBox.Pressed = ConfigIsFullscreen;
LightingPresetOption.SelectId(GetConfigLightingQuality());
UIScaleOption.SelectId(GetConfigUIScalePreset(ConfigUIScale));
ViewportScaleSlider.Value = _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
ViewportStretchCheckBox.Pressed = _cfg.GetCVar(CCVars.ViewportStretch);
IntegerScalingCheckBox.Pressed = _cfg.GetCVar(CCVars.ViewportSnapToleranceMargin) != 0;
ViewportVerticalFitCheckBox.Pressed = _cfg.GetCVar(CCVars.ViewportVerticalFit);
ViewportLowResCheckBox.Pressed = !_cfg.GetCVar(CCVars.ViewportScaleRender);
PixelSnapCameraCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.PixelSnapCamera); // WWDP EDIT
ParallaxLowQualityCheckBox.Pressed = _cfg.GetCVar(CCVars.ParallaxLowQuality);
FpsCounterCheckBox.Pressed = _cfg.GetCVar(CCVars.HudFpsCounterVisible);
MoodVisualEffectsCheckBox.Pressed = _cfg.GetCVar(CCVars.MoodVisualEffects);
ViewportWidthSlider.Value = _cfg.GetCVar(CCVars.ViewportWidth);
FilmGrainCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.FilmGrain); //WD EDIT
FilmGrainSlider.Value = _cfg.GetCVar(WhiteCVars.FilmGrainStrength); // WD EDIT
_cfg.OnValueChanged(CCVars.ViewportMinimumWidth, _ => UpdateViewportWidthRange());
_cfg.OnValueChanged(CCVars.ViewportMaximumWidth, _ => UpdateViewportWidthRange());
UpdateViewportWidthRange();
UpdateViewportWidthDisplay();
UpdateViewportScale();
UpdateApplyButton();
_cfg = cfg;
_dropDown = dropDown;
var button = dropDown.Button;
button.AddItem(Loc.GetString("ui-options-lighting-very-low"), QualityVeryLow);
button.AddItem(Loc.GetString("ui-options-lighting-low"), QualityLow);
button.AddItem(Loc.GetString("ui-options-lighting-medium"), QualityMedium);
button.AddItem(Loc.GetString("ui-options-lighting-high"), QualityHigh);
button.OnItemSelected += OnOptionSelected;
}
private void OnUIScaleChanged(OptionButton.ItemSelectedEventArgs args)
private void OnOptionSelected(OptionButton.ItemSelectedEventArgs obj)
{
UIScaleOption.SelectId(args.Id);
UpdateApplyButton();
_dropDown.Button.SelectId(obj.Id);
ValueChanged();
}
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
public override void LoadValue()
{
_cfg.SetCVar(CVars.DisplayVSync, VSyncCheckBox.Pressed);
SetConfigLightingQuality(LightingPresetOption.SelectedId);
_cfg.SetCVar(CVars.DisplayWindowMode,
(int) (FullscreenCheckBox.Pressed ? WindowMode.Fullscreen : WindowMode.Windowed));
_cfg.SetCVar(CVars.DisplayUIScale, UIScaleOptions[UIScaleOption.SelectedId]);
_cfg.SetCVar(CCVars.ViewportStretch, ViewportStretchCheckBox.Pressed);
_cfg.SetCVar(CCVars.ViewportFixedScaleFactor, (int) ViewportScaleSlider.Value);
_cfg.SetCVar(CCVars.ViewportSnapToleranceMargin,
IntegerScalingCheckBox.Pressed ? CCVars.ViewportSnapToleranceMargin.DefaultValue : 0);
_cfg.SetCVar(CCVars.ViewportVerticalFit, ViewportVerticalFitCheckBox.Pressed);
_cfg.SetCVar(CCVars.ViewportScaleRender, !ViewportLowResCheckBox.Pressed);
_cfg.SetCVar(WhiteCVars.PixelSnapCamera, PixelSnapCameraCheckBox.Pressed); // WWDP EDIT
_cfg.SetCVar(CCVars.ParallaxLowQuality, ParallaxLowQualityCheckBox.Pressed);
_cfg.SetCVar(CCVars.HudFpsCounterVisible, FpsCounterCheckBox.Pressed);
_cfg.SetCVar(CCVars.MoodVisualEffects, MoodVisualEffectsCheckBox.Pressed);
_cfg.SetCVar(CCVars.ViewportWidth, (int) ViewportWidthSlider.Value);
_cfg.SetCVar(WhiteCVars.FilmGrain, FilmGrainCheckBox.Pressed); // WD EDIT
_cfg.SetCVar(WhiteCVars.FilmGrainStrength, (int) FilmGrainSlider.Value); // WD EDIT
_cfg.SaveToFile();
UpdateApplyButton();
_dropDown.Button.SelectId(GetConfigLightingQuality());
}
private void OnCheckBoxToggled(BaseButton.ButtonToggledEventArgs args)
public override void SaveValue()
{
UpdateApplyButton();
}
private void OnFilmGrainCheckBoxToggled(BaseButton.ButtonToggledEventArgs obj)
{
UpdateApplyButton(); // WD EDIT
}
private void OnLightingQualityChanged(OptionButton.ItemSelectedEventArgs args)
{
LightingPresetOption.SelectId(args.Id);
UpdateApplyButton();
}
private void UpdateApplyButton()
{
var isVSyncSame = VSyncCheckBox.Pressed == _cfg.GetCVar(CVars.DisplayVSync);
var isFullscreenSame = FullscreenCheckBox.Pressed == ConfigIsFullscreen;
var isLightingQualitySame = LightingPresetOption.SelectedId == GetConfigLightingQuality();
var isUIScaleSame = MathHelper.CloseToPercent(UIScaleOptions[UIScaleOption.SelectedId], ConfigUIScale);
var isVPStretchSame = ViewportStretchCheckBox.Pressed == _cfg.GetCVar(CCVars.ViewportStretch);
var isVPScaleSame = (int) ViewportScaleSlider.Value == _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
var isIntegerScalingSame = IntegerScalingCheckBox.Pressed == (_cfg.GetCVar(CCVars.ViewportSnapToleranceMargin) != 0);
var isVPVerticalFitSame = ViewportVerticalFitCheckBox.Pressed == _cfg.GetCVar(CCVars.ViewportVerticalFit);
var isPixelSnapCameraSame = PixelSnapCameraCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.PixelSnapCamera); // WWDP EDIT
var isVPResSame = ViewportLowResCheckBox.Pressed == !_cfg.GetCVar(CCVars.ViewportScaleRender);
var isPLQSame = ParallaxLowQualityCheckBox.Pressed == _cfg.GetCVar(CCVars.ParallaxLowQuality);
var isFpsCounterVisibleSame = FpsCounterCheckBox.Pressed == _cfg.GetCVar(CCVars.HudFpsCounterVisible);
var isMoodVisualEffectsSame = MoodVisualEffectsCheckBox.Pressed == _cfg.GetCVar(CCVars.MoodVisualEffects); // WWDP EDIT
var isWidthSame = (int) ViewportWidthSlider.Value == _cfg.GetCVar(CCVars.ViewportWidth);
var isFilmGrainSame = FilmGrainCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.FilmGrain); // WD EDIT
var isFilmGrainStrengthSame = (float) FilmGrainSlider.Value == _cfg.GetCVar(WhiteCVars.FilmGrainStrength); // WD EDIT
ApplyButton.Disabled = isVSyncSame &&
isFullscreenSame &&
isLightingQualitySame &&
isUIScaleSame &&
isVPStretchSame &&
isVPScaleSame &&
isIntegerScalingSame &&
isVPVerticalFitSame &&
isPixelSnapCameraSame && // WWDP EDIT
isVPResSame &&
isPLQSame &&
isFpsCounterVisibleSame &&
isMoodVisualEffectsSame && // WWDP EDIT
isWidthSame &&
isFilmGrainSame && // WD EDIT
isFilmGrainStrengthSame; // WD EDIT
}
private bool ConfigIsFullscreen =>
_cfg.GetCVar(CVars.DisplayWindowMode) == (int) WindowMode.Fullscreen;
public void UpdateProperties()
{
FullscreenCheckBox.Pressed = ConfigIsFullscreen;
}
private float ConfigUIScale => _cfg.GetCVar(CVars.DisplayUIScale);
private int GetConfigLightingQuality()
{
var val = _cfg.GetCVar(CVars.LightResolutionScale);
var soft = _cfg.GetCVar(CVars.LightSoftShadows);
if (val <= 0.125)
switch (_dropDown.Button.SelectedId)
{
return 0;
}
else if ((val <= 0.5) && !soft)
{
return 1;
}
else if (val <= 0.5)
{
return 2;
}
else
{
return 3;
}
}
private void SetConfigLightingQuality(int value)
{
switch (value)
{
case 0:
case QualityVeryLow:
_cfg.SetCVar(CVars.LightResolutionScale, 0.125f);
_cfg.SetCVar(CVars.LightSoftShadows, false);
_cfg.SetCVar(CVars.LightBlur, false);
break;
case 1:
case QualityLow:
_cfg.SetCVar(CVars.LightResolutionScale, 0.5f);
_cfg.SetCVar(CVars.LightSoftShadows, false);
_cfg.SetCVar(CVars.LightBlur, true);
break;
case 2:
default: // = QualityMedium
_cfg.SetCVar(CVars.LightResolutionScale, 0.5f);
_cfg.SetCVar(CVars.LightSoftShadows, true);
_cfg.SetCVar(CVars.LightBlur, true);
break;
case 3:
case QualityHigh:
_cfg.SetCVar(CVars.LightResolutionScale, 1);
_cfg.SetCVar(CVars.LightSoftShadows, true);
_cfg.SetCVar(CVars.LightBlur, true);
@@ -267,55 +160,83 @@ namespace Content.Client.Options.UI.Tabs
}
}
private static int GetConfigUIScalePreset(float value)
public override void ResetToDefault()
{
for (var i = 0; i < UIScaleOptions.Length; i++)
_dropDown.Button.SelectId(QualityDefault);
}
public override bool IsModified()
{
return _dropDown.Button.SelectedId != GetConfigLightingQuality();
}
public override bool IsModifiedFromDefault()
{
return _dropDown.Button.SelectedId != QualityDefault;
}
private int GetConfigLightingQuality()
{
var val = _cfg.GetCVar(CVars.LightResolutionScale);
var soft = _cfg.GetCVar(CVars.LightSoftShadows);
if (val <= 0.125)
return QualityVeryLow;
if ((val <= 0.5) && !soft)
return QualityLow;
if (val <= 0.5)
return QualityMedium;
return QualityHigh;
}
}
private sealed class OptionFullscreen : BaseOptionCVar<int>
{
private readonly CheckBox _checkBox;
protected override int Value
{
get => _checkBox.Pressed ? (int) WindowMode.Fullscreen : (int) WindowMode.Windowed;
set => _checkBox.Pressed = (value == (int) WindowMode.Fullscreen);
}
public OptionFullscreen(
OptionsTabControlRow controller,
IConfigurationManager cfg,
CheckBox checkBox)
: base(controller, cfg, CVars.DisplayWindowMode)
{
_checkBox = checkBox;
_checkBox.OnToggled += _ =>
{
if (MathHelper.CloseToPercent(UIScaleOptions[i], value))
{
return i;
}
}
return 0;
ValueChanged();
};
}
}
private void UpdateViewportScale()
private sealed class OptionIntegerScaling : BaseOptionCVar<int>
{
private readonly CheckBox _checkBox;
protected override int Value
{
ViewportScaleBox.Visible = !ViewportStretchCheckBox.Pressed;
IntegerScalingCheckBox.Visible = ViewportStretchCheckBox.Pressed;
ViewportVerticalFitCheckBox.Visible = ViewportStretchCheckBox.Pressed;
ViewportWidthSlider.Visible = ViewportWidthSliderDisplay.Visible = !ViewportStretchCheckBox.Pressed || ViewportStretchCheckBox.Pressed && !ViewportVerticalFitCheckBox.Pressed;
ViewportScaleText.Text = Loc.GetString("ui-options-vp-scale", ("scale", ViewportScaleSlider.Value));
get => _checkBox.Pressed ? CCVars.ViewportSnapToleranceMargin.DefaultValue : 0;
set => _checkBox.Pressed = (value != 0);
}
private void UpdateViewportWidthRange()
public OptionIntegerScaling(
OptionsTabControlRow controller,
IConfigurationManager cfg,
CheckBox checkBox)
: base(controller, cfg, CCVars.ViewportSnapToleranceMargin)
{
var min = _cfg.GetCVar(CCVars.ViewportMinimumWidth);
var max = _cfg.GetCVar(CCVars.ViewportMaximumWidth);
ViewportWidthSlider.MinValue = min;
ViewportWidthSlider.MaxValue = max;
_checkBox = checkBox;
_checkBox.OnToggled += _ =>
{
ValueChanged();
};
}
private void UpdateViewportWidthDisplay()
{
ViewportWidthSliderDisplay.Text = Loc.GetString("ui-options-vp-width", ("width", (int) ViewportWidthSlider.Value));
}
// WD EDIT START
private void UpdateFilmGrainScale()
{
FilmGrainBox.Visible = FilmGrainCheckBox.Pressed;
FilmGrainText.Text = Loc.GetString("ui-options-film-grain-strength", ("strength", FilmGrainSlider.Value));
}
private void UpdateFilmGrainDisplay()
{
FilmGrainText.Text = Loc.GetString("ui-options-film-grain-strength", ("strength", FilmGrainSlider.Value));
}
// WD EDIT END
}
}

View File

@@ -1,97 +1,45 @@
<tabs:MiscTab xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
xmlns:xNamespace="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:Content.Client.Stylesheets">
xmlns:tabs="clr-namespace:Content.Client.Options.UI.Tabs"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:Content.Client.Options.UI"
xmlns:s="clr-namespace:Content.Client.Stylesheets">
<BoxContainer Orientation="Vertical">
<ScrollContainer VerticalExpand="True" HorizontalExpand="True">
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
<Label Text="{Loc 'ui-options-general-ui-style'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-hud-theme'}" />
<Control MinSize="4 0" />
<OptionButton Name="HudThemeOption" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-hud-layout'}" />
<Control MinSize="4 0" />
<OptionButton Name="HudLayoutOption" />
</BoxContainer>
<!--WD EDIT START-->
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-emotes-menu'}" />
<Control MinSize="4 0" />
<OptionButton Name="EmotesMenuType" />
</BoxContainer>
<!--WD EDIT END-->
<Label Text="{Loc 'ui-options-general-accessibility'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
<CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" />
<CheckBox Name="DisableFiltersCheckBox" Text="{Loc 'ui-options-no-filters'}" />
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-chatstack'}" />
<Control MinSize="4 0" />
<OptionButton Name="ChatStackOption" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-chat-window-opacity'}" Margin="8 0" />
<Slider Name="ChatWindowOpacitySlider"
MinValue="0"
MaxValue="1"
MinWidth="200" />
<Label Name="ChatWindowOpacityLabel" Margin="8 0" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-screen-shake-intensity'}" Margin="8 0" />
<Slider Name="ScreenShakeIntensitySlider"
MinValue="0"
MaxValue="100"
Rounded="True"
MinWidth="200" />
<Label Name="ScreenShakeIntensityLabel" Margin="8 0" />
</BoxContainer>
<ui:OptionDropDown Name="DropDownHudTheme" Title="{Loc 'ui-options-hud-theme'}" />
<ui:OptionDropDown Name="DropDownHudLayout" Title="{Loc 'ui-options-hud-layout'}" />
<ui:OptionDropDown Name="DropDownEmotesMenuType" Title="{Loc 'ui-options-emotes-menu'}" /> <!-- WD EDIT -->
<Label Text="{Loc 'ui-options-general-discord'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="DiscordRich" Text="{Loc 'ui-options-discordrich'}" />
<Label Text="{Loc 'ui-options-general-speech'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ShowOocPatronColor" Text="{Loc 'ui-options-show-ooc-patron-color'}" />
<CheckBox Name="ShowLoocAboveHeadCheckBox" Text="{Loc 'ui-options-show-looc-on-head'}" />
<CheckBox Name="FancySpeechBubblesCheckBox" Text="{Loc 'ui-options-fancy-speech'}" />
<CheckBox Name="FancyNameBackgroundsCheckBox" Text="{Loc 'ui-options-fancy-name-background'}" />
<CheckBox Name="EnableColorBubbleChatCheckBox" Text="{Loc 'ui-options-enable-color-in-bubble-chat'}" /> <!-- WD EDIT -->
<CheckBox Name="EnableChatFancyFontCheckBox" Text="{Loc 'ui-options-enable-chat-fancy-font'}" /> <!-- WD EDIT -->
<CheckBox Name="FancyNameBackgroundsCheckBox" Text="{Loc 'ui-options-fancy-name-background'}" />
<ui:OptionDropDown Name="ChatStackOption" Title="{Loc 'ui-options-chatstack'}" />
<CheckBox Name="LogInChatCheckBox" Text="{Loc 'ui-options-log-in-chat'}" /> <!-- WD EDIT -->
<Label Text="{Loc 'ui-options-general-cursor'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ShowHeldItemCheckBox" Text="{Loc 'ui-options-show-held-item'}" />
<CheckBox Name="ShowCombatModeIndicatorsCheckBox" Text="{Loc 'ui-options-show-combat-mode-indicators'}" />
<CheckBox Name="ShowOfferModeIndicatorsCheckBox" Text="{Loc 'ui-options-show-offer-mode-indicators'}" />
<Label Text="{Loc 'ui-options-general-storage'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="OpaqueStorageWindowCheckBox" Text="{Loc 'ui-options-opaque-storage-window'}" />
<CheckBox Name="StaticStorageUI" Text="{Loc 'ui-options-static-storage-ui'}" />
<Label Text="{Loc 'ui-options-general-other'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
FontColorOverride="{x:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="DisableFiltersCheckBox" Text="{Loc 'ui-options-no-filters'}" />
<CheckBox Name="ModernProgressBar" Text="{Loc 'ui-options-modern-progress-bar'}" />
<!-- <CheckBox Name="ToggleWalk" Text="{Loc 'ui-options-hotkey-toggle-walk'}" /> -->
</BoxContainer>
</ScrollContainer>
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
<Button Name="ApplyButton"
Text="{Loc 'ui-options-apply'}"
TextAlign="Center"
HorizontalAlignment="Right" />
</controls:StripeBack>
<ui:OptionsTabControlRow Name="Control" Access="Public" />
</BoxContainer>
</tabs:MiscTab>

View File

@@ -1,283 +1,83 @@
using System.Linq;
using Content.Client.UserInterface.Screens;
using Content.Shared._White.CCVar;
using Content.Shared._White.UserInterface.Emotes;
using Content.Shared._White.UserInterface;
using Content.Shared.CCVar;
using Content.Shared.HUD;
using Robust.Client.AutoGenerated;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Range = Robust.Client.UserInterface.Controls.Range;
namespace Content.Client.Options.UI.Tabs
namespace Content.Client.Options.UI.Tabs;
[GenerateTypedNameReferences]
public sealed partial class MiscTab : Control
{
[GenerateTypedNameReferences]
public sealed partial class MiscTab : Control
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public MiscTab()
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
private readonly Dictionary<string, int> _hudThemeIdToIndex = new();
public MiscTab()
var themes = _prototypeManager.EnumeratePrototypes<HudThemePrototype>().ToList();
themes.Sort();
var themeEntries = new List<OptionDropDownCVar<string>.ValueOption>();
foreach (var gear in themes)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var themes = _prototypeManager.EnumeratePrototypes<HudThemePrototype>().ToList();
themes.Sort();
foreach (var gear in themes)
{
HudThemeOption.AddItem(Loc.GetString(gear.Name));
_hudThemeIdToIndex.Add(gear.ID, HudThemeOption.GetItemId(HudThemeOption.ItemCount - 1));
}
var hudLayout = _cfg.GetCVar(CCVars.UILayout);
var id = 0;
foreach (var layout in Enum.GetValues(typeof(ScreenType)))
{
var name = layout.ToString()!;
HudLayoutOption.AddItem(name, id);
if (name == hudLayout)
{
HudLayoutOption.SelectId(id);
}
HudLayoutOption.SetItemMetadata(id, name);
id++;
}
HudLayoutOption.OnItemSelected += args =>
{
HudLayoutOption.SelectId(args.Id);
UpdateApplyButton();
};
// WD EDIT START
id = 0;
var emotesMenuStyle = _cfg.GetCVar(WhiteCVars.EmotesMenuStyle);
foreach (var type in Enum.GetValues(typeof(EmotesMenuType)))
{
var name = type.ToString()!;
EmotesMenuType.AddItem(name, id);
if (name == emotesMenuStyle)
EmotesMenuType.SelectId(id);
EmotesMenuType.SetItemMetadata(id, name);
id++;
}
EmotesMenuType.OnItemSelected += args =>
{
EmotesMenuType.SelectId(args.Id);
UpdateApplyButton();
};
// WD EDIT END
ChatStackOption.AddItem(Loc.GetString("ui-options-chatstack-off"), 0);
ChatStackOption.AddItem(Loc.GetString("ui-options-chatstack-single"), 1);
ChatStackOption.AddItem(Loc.GetString("ui-options-chatstack-double"), 2);
ChatStackOption.AddItem(Loc.GetString("ui-options-chatstack-triple"), 3);
ChatStackOption.TrySelectId(_cfg.GetCVar(CCVars.ChatStackLastLines));
ChatStackOption.OnItemSelected += args =>
{
ChatStackOption.SelectId(args.Id);
UpdateApplyButton();
};
// Channel can be null in replays so.
// ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
ShowOocPatronColor.Visible = _playerManager.LocalSession?.Channel?.UserData.PatronTier is { };
HudThemeOption.OnItemSelected += OnHudThemeChanged;
DiscordRich.OnToggled += OnCheckBoxToggled;
ShowOocPatronColor.OnToggled += OnCheckBoxToggled;
ShowLoocAboveHeadCheckBox.OnToggled += OnCheckBoxToggled;
ShowHeldItemCheckBox.OnToggled += OnCheckBoxToggled;
ShowCombatModeIndicatorsCheckBox.OnToggled += OnCheckBoxToggled;
ShowOfferModeIndicatorsCheckBox.OnToggled += OnCheckBoxToggled;
OpaqueStorageWindowCheckBox.OnToggled += OnCheckBoxToggled;
FancySpeechBubblesCheckBox.OnToggled += OnCheckBoxToggled;
FancyNameBackgroundsCheckBox.OnToggled += OnCheckBoxToggled;
EnableColorNameCheckBox.OnToggled += OnCheckBoxToggled;
EnableColorBubbleChatCheckBox.OnToggled += OnCheckBoxToggled; // WWDP EDIT
EnableChatFancyFontCheckBox.OnToggled += OnCheckBoxToggled; // WWDP EDIT
ColorblindFriendlyCheckBox.OnToggled += OnCheckBoxToggled;
ReducedMotionCheckBox.OnToggled += OnCheckBoxToggled;
ChatWindowOpacitySlider.OnValueChanged += OnChatWindowOpacitySliderChanged;
ScreenShakeIntensitySlider.OnValueChanged += OnScreenShakeIntensitySliderChanged;
// ToggleWalk.OnToggled += OnCheckBoxToggled;
StaticStorageUI.OnToggled += OnCheckBoxToggled;
ModernProgressBar.OnToggled += OnCheckBoxToggled;
DisableFiltersCheckBox.OnToggled += OnCheckBoxToggled;
LogInChatCheckBox.OnToggled += OnCheckBoxToggled; // WD EDIT
HudThemeOption.SelectId(_hudThemeIdToIndex.GetValueOrDefault(_cfg.GetCVar(CVars.InterfaceTheme), 0));
DiscordRich.Pressed = _cfg.GetCVar(CVars.DiscordEnabled);
ShowOocPatronColor.Pressed = _cfg.GetCVar(CCVars.ShowOocPatronColor);
ShowLoocAboveHeadCheckBox.Pressed = _cfg.GetCVar(CCVars.LoocAboveHeadShow);
ShowHeldItemCheckBox.Pressed = _cfg.GetCVar(CCVars.HudHeldItemShow);
ShowCombatModeIndicatorsCheckBox.Pressed = _cfg.GetCVar(CCVars.CombatModeIndicatorsPointShow);
ShowOfferModeIndicatorsCheckBox.Pressed = _cfg.GetCVar(CCVars.OfferModeIndicatorsPointShow);
OpaqueStorageWindowCheckBox.Pressed = _cfg.GetCVar(CCVars.OpaqueStorageWindow);
FancySpeechBubblesCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
FancyNameBackgroundsCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatFancyNameBackground);
EnableColorNameCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatEnableColorName);
EnableColorBubbleChatCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.ColoredBubbleChat); // WWDP EDIT
EnableChatFancyFontCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.ChatFancyFont); // WWDP EDIT
ColorblindFriendlyCheckBox.Pressed = _cfg.GetCVar(CCVars.AccessibilityColorblindFriendly);
ReducedMotionCheckBox.Pressed = _cfg.GetCVar(CCVars.ReducedMotion);
ChatWindowOpacitySlider.Value = _cfg.GetCVar(CCVars.ChatWindowOpacity);
ScreenShakeIntensitySlider.Value = _cfg.GetCVar(CCVars.ScreenShakeIntensity) * 100f;
// ToggleWalk.Pressed = _cfg.GetCVar(CCVars.ToggleWalk);
StaticStorageUI.Pressed = _cfg.GetCVar(CCVars.StaticStorageUI);
ModernProgressBar.Pressed = _cfg.GetCVar(CCVars.ModernProgressBar);
DisableFiltersCheckBox.Pressed = _cfg.GetCVar(CCVars.NoVisionFilters);
LogInChatCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.LogInChat); // WD EDIT
ApplyButton.OnPressed += OnApplyButtonPressed;
UpdateApplyButton();
themeEntries.Add(new OptionDropDownCVar<string>.ValueOption(gear.ID, Loc.GetString(gear.Name)));
}
private void OnCheckBoxToggled(BaseButton.ButtonToggledEventArgs args)
var layoutEntries = new List<OptionDropDownCVar<string>.ValueOption>();
foreach (var layout in Enum.GetValues(typeof(ScreenType)))
{
UpdateApplyButton();
layoutEntries.Add(new OptionDropDownCVar<string>.ValueOption(layout.ToString()!, layout.ToString()!));
}
private void OnHudThemeChanged(OptionButton.ItemSelectedEventArgs args)
var chatStackEntries = new List<OptionDropDownCVar<int>.ValueOption>();
for (var chatStack = 0; chatStack < 4; chatStack++)
{
HudThemeOption.SelectId(args.Id);
UpdateApplyButton();
chatStackEntries.Add(new OptionDropDownCVar<int>.ValueOption(chatStack, Loc.GetString($"ui-options-chatstack-{chatStack}")));
}
private void OnChatWindowOpacitySliderChanged(Range range)
{
ChatWindowOpacityLabel.Text = Loc.GetString("ui-options-chat-window-opacity-percent",
("opacity", range.Value));
UpdateApplyButton();
}
// Channel can be null in replays so.
// ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
ShowOocPatronColor.Visible = _playerManager.LocalSession?.Channel?.UserData.PatronTier is { };
private void OnScreenShakeIntensitySliderChanged(Range obj)
{
ScreenShakeIntensityLabel.Text = Loc.GetString("ui-options-screen-shake-percent", ("intensity", ScreenShakeIntensitySlider.Value / 100f));
UpdateApplyButton();
}
Control.AddOptionDropDown(CVars.InterfaceTheme, DropDownHudTheme, themeEntries);
Control.AddOptionDropDown(CCVars.UILayout, DropDownHudLayout, layoutEntries);
// WD EDIT START
Control.AddOptionDropDown(
WhiteCVars.EmotesMenuStyle,
DropDownEmotesMenuType,
[
new (EmotesMenuType.Window, nameof(EmotesMenuType.Window)),
new (EmotesMenuType.Radial, nameof(EmotesMenuType.Window))
]);
// WD EDIT END
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
{
foreach (var theme in _prototypeManager.EnumeratePrototypes<HudThemePrototype>())
{
if (_hudThemeIdToIndex[theme.ID] != HudThemeOption.SelectedId)
continue;
_cfg.SetCVar(CVars.InterfaceTheme, theme.ID);
break;
}
_cfg.SetCVar(CVars.DiscordEnabled, DiscordRich.Pressed);
_cfg.SetCVar(CCVars.HudHeldItemShow, ShowHeldItemCheckBox.Pressed);
_cfg.SetCVar(CCVars.CombatModeIndicatorsPointShow, ShowCombatModeIndicatorsCheckBox.Pressed);
_cfg.SetCVar(CCVars.OfferModeIndicatorsPointShow, ShowOfferModeIndicatorsCheckBox.Pressed);
_cfg.SetCVar(CCVars.OpaqueStorageWindow, OpaqueStorageWindowCheckBox.Pressed);
_cfg.SetCVar(CCVars.ShowOocPatronColor, ShowOocPatronColor.Pressed);
_cfg.SetCVar(CCVars.LoocAboveHeadShow, ShowLoocAboveHeadCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatEnableFancyBubbles, FancySpeechBubblesCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatFancyNameBackground, FancyNameBackgroundsCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatEnableColorName, EnableColorNameCheckBox.Pressed);
_cfg.SetCVar(WhiteCVars.ColoredBubbleChat, EnableColorBubbleChatCheckBox.Pressed); // WWDP EDIT
_cfg.SetCVar(WhiteCVars.ChatFancyFont, EnableChatFancyFontCheckBox.Pressed); // WWDP EDIT
_cfg.SetCVar(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox.Pressed);
_cfg.SetCVar(CCVars.ReducedMotion, ReducedMotionCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider.Value);
_cfg.SetCVar(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider.Value / 100f);
// _cfg.SetCVar(CCVars.ToggleWalk, ToggleWalk.Pressed);
_cfg.SetCVar(CCVars.StaticStorageUI, StaticStorageUI.Pressed);
_cfg.SetCVar(CCVars.ModernProgressBar, ModernProgressBar.Pressed);
_cfg.SetCVar(CCVars.NoVisionFilters, DisableFiltersCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatStackLastLines, ChatStackOption.SelectedId);
_cfg.SetCVar(WhiteCVars.LogInChat, LogInChatCheckBox.Pressed); // WD EDIT
if (HudLayoutOption.SelectedMetadata is string opt)
{
_cfg.SetCVar(CCVars.UILayout, opt);
}
// WD EDIT START
if (EmotesMenuType.SelectedMetadata is string emotesMenuType)
_cfg.SetCVar(WhiteCVars.EmotesMenuStyle, emotesMenuType);
// WD EDIT END
_cfg.SaveToFile();
UpdateApplyButton();
}
private void UpdateApplyButton()
{
var isHudThemeSame = HudThemeOption.SelectedId == _hudThemeIdToIndex.GetValueOrDefault(_cfg.GetCVar(CVars.InterfaceTheme), 0);
var isLayoutSame = HudLayoutOption.SelectedMetadata is string opt && opt == _cfg.GetCVar(CCVars.UILayout);
var isEmotesMenuTypeSame = EmotesMenuType.SelectedMetadata is string emotesMenuType && emotesMenuType == _cfg.GetCVar(WhiteCVars.EmotesMenuStyle); // WD EDIT
var isDiscordSame = DiscordRich.Pressed == _cfg.GetCVar(CVars.DiscordEnabled);
var isShowHeldItemSame = ShowHeldItemCheckBox.Pressed == _cfg.GetCVar(CCVars.HudHeldItemShow);
var isCombatModeIndicatorsSame = ShowCombatModeIndicatorsCheckBox.Pressed == _cfg.GetCVar(CCVars.CombatModeIndicatorsPointShow);
var isOfferModeIndicatorsSame = ShowOfferModeIndicatorsCheckBox.Pressed == _cfg.GetCVar(CCVars.OfferModeIndicatorsPointShow);
var isOpaqueStorageWindow = OpaqueStorageWindowCheckBox.Pressed == _cfg.GetCVar(CCVars.OpaqueStorageWindow);
var isOocPatronColorShowSame = ShowOocPatronColor.Pressed == _cfg.GetCVar(CCVars.ShowOocPatronColor);
var isLoocShowSame = ShowLoocAboveHeadCheckBox.Pressed == _cfg.GetCVar(CCVars.LoocAboveHeadShow);
var isFancyChatSame = FancySpeechBubblesCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
var isFancyBackgroundSame = FancyNameBackgroundsCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatFancyNameBackground);
var isEnableColorNameSame = EnableColorNameCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableColorName);
var isEnableColorBubbleChatSame = EnableColorBubbleChatCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.ColoredBubbleChat); // WWDP EDIT
var isEnableFancyChatFontSame = EnableChatFancyFontCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.ChatFancyFont); // WWDP EDIT
var isColorblindFriendly = ColorblindFriendlyCheckBox.Pressed == _cfg.GetCVar(CCVars.AccessibilityColorblindFriendly);
var isReducedMotionSame = ReducedMotionCheckBox.Pressed == _cfg.GetCVar(CCVars.ReducedMotion);
var isChatWindowOpacitySame = Math.Abs(ChatWindowOpacitySlider.Value - _cfg.GetCVar(CCVars.ChatWindowOpacity)) < 0.01f;
var isScreenShakeIntensitySame = Math.Abs(ScreenShakeIntensitySlider.Value / 100f - _cfg.GetCVar(CCVars.ScreenShakeIntensity)) < 0.01f;
// var isToggleWalkSame = ToggleWalk.Pressed == _cfg.GetCVar(CCVars.ToggleWalk);
var isStaticStorageUISame = StaticStorageUI.Pressed == _cfg.GetCVar(CCVars.StaticStorageUI);
var isModernProgressBarSame = ModernProgressBar.Pressed == _cfg.GetCVar(CCVars.ModernProgressBar);
var isNoVisionFiltersSame = DisableFiltersCheckBox.Pressed == _cfg.GetCVar(CCVars.NoVisionFilters);
var isChatStackTheSame = ChatStackOption.SelectedId == _cfg.GetCVar(CCVars.ChatStackLastLines);
var isLogInChatCheckBoxSame = LogInChatCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.LogInChat); // WD EDIT
ApplyButton.Disabled = isHudThemeSame &&
isLayoutSame &&
isEmotesMenuTypeSame && // WD EDIT
isDiscordSame &&
isShowHeldItemSame &&
isCombatModeIndicatorsSame &&
isOfferModeIndicatorsSame &&
isOpaqueStorageWindow &&
isOocPatronColorShowSame &&
isLoocShowSame &&
isFancyChatSame &&
isFancyBackgroundSame &&
isEnableColorNameSame &&
isEnableColorBubbleChatSame && // WWDP EDIT
isEnableFancyChatFontSame && // WWDP EDIT
isColorblindFriendly &&
isReducedMotionSame &&
isChatWindowOpacitySame &&
isScreenShakeIntensitySame &&
// isToggleWalkSame &&
isStaticStorageUISame &&
isModernProgressBarSame &&
isNoVisionFiltersSame &&
isChatStackTheSame &&
isLogInChatCheckBoxSame; // WD EDIT
}
Control.AddOptionCheckBox(CVars.DiscordEnabled, DiscordRich);
Control.AddOptionCheckBox(CCVars.ShowOocPatronColor, ShowOocPatronColor);
Control.AddOptionCheckBox(CCVars.LoocAboveHeadShow, ShowLoocAboveHeadCheckBox);
Control.AddOptionCheckBox(CCVars.HudHeldItemShow, ShowHeldItemCheckBox);
Control.AddOptionCheckBox(CCVars.CombatModeIndicatorsPointShow, ShowCombatModeIndicatorsCheckBox);
Control.AddOptionCheckBox(CCVars.OpaqueStorageWindow, OpaqueStorageWindowCheckBox);
Control.AddOptionCheckBox(CCVars.ChatEnableFancyBubbles, FancySpeechBubblesCheckBox);
Control.AddOptionCheckBox(CCVars.ChatFancyNameBackground, FancyNameBackgroundsCheckBox);
// WD EDIT START
Control.AddOptionCheckBox(WhiteCVars.ColoredBubbleChat, EnableColorBubbleChatCheckBox);
Control.AddOptionCheckBox(WhiteCVars.ChatFancyFont, EnableChatFancyFontCheckBox);
// WD EDIT END
Control.AddOptionDropDown(CCVars.ChatStackLastLines, ChatStackOption, chatStackEntries);
Control.AddOptionCheckBox(WhiteCVars.LogInChat, LogInChatCheckBox); // WD EDIT
Control.AddOptionCheckBox(CCVars.StaticStorageUI, StaticStorageUI);
Control.AddOptionCheckBox(CCVars.NoVisionFilters, DisableFiltersCheckBox);
Control.AddOptionCheckBox(CCVars.ModernProgressBar, ModernProgressBar);
Control.Initialize();
}
}

View File

@@ -4,7 +4,7 @@ using Content.Client.Gameplay;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.MenuBar.Widgets;
using Content.Shared._White.CCVar;
using Content.Shared._White.UserInterface.Emotes;
using Content.Shared._White.UserInterface;
using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Input;
@@ -87,11 +87,8 @@ public sealed class WhiteEmotesUIController : UIController, IOnStateChanged<Game
{
if (_window == null)
{
if (!Enum.TryParse(_configurationManager.GetCVar(WhiteCVars.EmotesMenuStyle), out EmotesMenuType emotesMenuStyle))
emotesMenuStyle = EmotesMenuType.Window;
// setup window
switch (emotesMenuStyle)
switch (_configurationManager.GetCVar(WhiteCVars.EmotesMenuStyle))
{
case EmotesMenuType.Window:
_window = UIManager.CreateWindow<WhiteEmotesMenu>();

View File

@@ -32,6 +32,6 @@ public sealed partial class CCVars
/// <summary>
/// Disables multiple announcement sounds from playing at once
/// </summary>
public static readonly CVarDef<bool> AnnouncerDisableMultipleSounds =
public static readonly CVarDef<bool> AnnouncerDisableMultipleEnabled =
CVarDef.Create("announcer.disable_multiple_sounds", false, CVar.ARCHIVE | CVar.CLIENTONLY);
}

View File

@@ -4,6 +4,6 @@ namespace Content.Shared._White.CCVar;
public sealed partial class WhiteCVars
{
public static readonly CVarDef<bool> ToggleCombatModeSound =
public static readonly CVarDef<bool> CombatModeSoundEnabled =
CVarDef.Create("combatMode.toggle_sound", false, CVar.CLIENTONLY | CVar.ARCHIVE);
}

View File

@@ -1,9 +1,10 @@
using Content.Shared._White.UserInterface;
using Robust.Shared.Configuration;
namespace Content.Shared._White.CCVar;
public sealed partial class WhiteCVars
{
public static readonly CVarDef<string> EmotesMenuStyle =
CVarDef.Create("interface.emotes_menu_style", "Window", CVar.CLIENT | CVar.ARCHIVE);
public static readonly CVarDef<EmotesMenuType> EmotesMenuStyle =
CVarDef.Create("interface.emotes_menu_style", EmotesMenuType.Window, CVar.CLIENT | CVar.ARCHIVE);
}

View File

@@ -1,6 +1,8 @@
namespace Content.Shared._White.UserInterface.Emotes;
using Robust.Shared.Serialization;
namespace Content.Shared._White.UserInterface;
[Serializable, NetSerializable]
public enum EmotesMenuType
{
/// <summary>

View File

@@ -1,15 +1,18 @@
## General stuff
ui-options-title = Game Options
ui-options-tab-accessibility = Accessibility
ui-options-tab-graphics = Graphics
ui-options-tab-controls = Controls
ui-options-tab-audio = Audio
ui-options-tab-network = Network
ui-options-tab-misc = General
ui-options-apply = Apply
ui-options-reset-all = Reset All
ui-options-default = Default
ui-options-apply = Save & apply
ui-options-reset-all = Reset changed
ui-options-default = Reset to defaults
ui-options-value-percent = { TOSTRING($value, "P0") }
# Misc/General menu
@@ -22,10 +25,10 @@ ui-options-general-storage = Storage
ui-options-general-other = Other
ui-options-general-accessibility = Accessibility
ui-options-chatstack = Automatically merge identical chat messages
ui-options-chatstack-off = Off
ui-options-chatstack-single = Only last message
ui-options-chatstack-double = Last two messages
ui-options-chatstack-triple = Last three messages
ui-options-chatstack-0 = Off
ui-options-chatstack-1 = Only last message
ui-options-chatstack-2 = Last two messages
ui-options-chatstack-3 = Last three messages
## Audio menu
@@ -44,10 +47,15 @@ ui-options-announcer-disable-multiple-sounds = Disable Overlapping Announcer Sou
ui-options-announcer-disable-multiple-sounds-tooltip = Some announcements will not sound right, this setting isn't recommended
ui-options-admin-sounds = Play Admin Sounds
ui-options-volume-label = Volume
ui-options-volume-percent = { TOSTRING($volume, "P0") }
## Graphics menu
ui-options-display-label = Display
ui-options-quality-label = Quality
ui-options-misc-label = Misc
ui-options-interface-label = Interface
ui-options-show-held-item = Show held item next to cursor
ui-options-show-combat-mode-indicators = Show combat mode indicators with cursor
ui-options-show-offer-mode-indicators = Show offer mode indicators with cursor
@@ -56,14 +64,7 @@ ui-options-show-ooc-patron-color = Show OOC Patreon color
ui-options-show-looc-on-head = Show LOOC chat above characters head
ui-options-fancy-speech = Show names in speech bubbles
ui-options-fancy-name-background = Add background to speech bubble names
ui-options-enable-color-name = Add colors to character names
ui-options-colorblind-friendly = Colorblind friendly mode
ui-options-no-filters = Disable species vision filters
ui-options-reduced-motion = Reduce motion of visual effects
ui-options-chat-window-opacity = Chat window opacity
ui-options-chat-window-opacity-percent = { TOSTRING($opacity, "P0") }
ui-options-screen-shake-intensity = Screen shake intensity
ui-options-screen-shake-percent = { TOSTRING($intensity, "P0") }
ui-options-vsync = VSync
ui-options-fullscreen = Fullscreen
ui-options-lighting-label = Lighting Quality:
@@ -88,7 +89,8 @@ ui-options-hud-theme-retro = Retro
ui-options-hud-theme-minimalist = Minimalist
ui-options-hud-theme-ashen = Ashen
ui-options-vp-stretch = Stretch viewport to fit game window
ui-options-vp-scale = Fixed viewport scale: x{ $scale }
ui-options-vp-scale = Fixed viewport scale:
ui-options-vp-scale-value = x{ $scale }
ui-options-vp-integer-scaling = Prefer integer scaling (might cause black bars/clipping)
ui-options-vp-integer-scaling-tooltip = If this option is enabled, the viewport will be scaled using an integer value
at specific resolutions. While this results in crisp textures, it also often
@@ -199,6 +201,7 @@ ui-options-function-open-crafting-menu = Open crafting menu
ui-options-function-open-inventory-menu = Open inventory
ui-options-function-open-a-help = Open admin help
ui-options-function-open-abilities-menu = Open action menu
ui-options-function-open-emotes-menu = Open emotes menu
ui-options-function-toggle-round-end-summary-window = Toggle round end summary window
ui-options-function-open-entity-spawn-window = Open entity spawn menu
ui-options-function-open-sandbox-window = Open sandbox menu
@@ -296,5 +299,15 @@ ui-options-net-pvs-leave-tooltip = This limits the rate at which the client will
cmd-options-desc = Opens options menu, optionally with a specific tab selected.
cmd-options-help = Usage: options [tab]
## Accessibility menu
ui-options-enable-color-name = Add colors to character names
ui-options-colorblind-friendly = Colorblind friendly mode
ui-options-reduced-motion = Reduce motion of visual effects
ui-options-chat-window-opacity = Chat window opacity
ui-options-chat-window-opacity-percent = { TOSTRING($opacity, "P0") }
ui-options-screen-shake-intensity = Screen shake intensity
ui-options-screen-shake-percent = { TOSTRING($intensity, "P0") }
## Combat Options
ui-options-function-auto-get-up = Automatically get up after falling