using System; using Robust.Client.Graphics; using Robust.Client.UserInterface.Controls; using Robust.Shared; using Robust.Shared.Configuration; using Robust.Shared.Maths; using Robust.Shared.ViewVariables; namespace Robust.Client.UserInterface; internal partial class UserInterfaceManager { [ViewVariables] public float DefaultUIScale => _clyde.DefaultWindowScale.X; [ViewVariables] private Vector2i _resolutionAutoScaleUpper; [ViewVariables] private Vector2i _resolutionAutoScaleLower; [ViewVariables] private bool _autoScaleEnabled; [ViewVariables] private float _resolutionAutoScaleMinValue; private void _initScaling() { _clyde.OnWindowResized += WindowSizeChanged; _clyde.OnWindowScaleChanged += WindowContentScaleChanged; RegisterAutoscaleCVarListeners(); _uiScaleChanged(_configurationManager.GetCVar(CVars.DisplayUIScale)); } private void _uiScaleChanged(float newValue) { foreach (var root in _roots) { UpdateUIScale(root); } } private void WindowContentScaleChanged(WindowContentScaleEventArgs args) { if (_windowsToRoot.TryGetValue(args.Window.Id, out var root)) { UpdateUIScale(root); _fontManager.ClearFontCache(); } } private void RegisterAutoscaleCVarListeners() { _configurationManager.OnValueChanged(CVars.ResAutoScaleEnabled, i => { _autoScaleEnabled = i; foreach (var root in _roots) { root.UIScaleSet = 1; _propagateUIScaleChanged(root); root.InvalidateMeasure(); } }, true); _configurationManager.OnValueChanged(CVars.ResAutoScaleLowX, i => { _resolutionAutoScaleLower.X = i; foreach (var root in _roots) { UpdateUIScale(root); } }, true); _configurationManager.OnValueChanged(CVars.ResAutoScaleLowY, i => { _resolutionAutoScaleLower.Y = i; foreach (var root in _roots) { UpdateUIScale(root); } }, true); _configurationManager.OnValueChanged(CVars.ResAutoScaleUpperX, i => { _resolutionAutoScaleUpper.X = i; foreach (var root in _roots) { UpdateUIScale(root); } }, true); _configurationManager.OnValueChanged(CVars.ResAutoScaleUpperY, i => { _resolutionAutoScaleUpper.Y = i; foreach (var root in _roots) { UpdateUIScale(root); } }, true); _configurationManager.OnValueChanged(CVars.ResAutoScaleMin, i => { _resolutionAutoScaleMinValue = i; foreach (var root in _roots) { UpdateUIScale(root); } }, true); } internal static float CalculateUIScale(float osScale, IConfigurationManager cfg) { var cfgScale = cfg.GetCVar(CVars.DisplayUIScale); return cfgScale == 0 ? osScale : cfgScale; } private float CalculateAutoScale(WindowRoot root) { //Grab the OS UIScale or the value set through CVAR debug var osScale = CalculateUIScale(root.Window.ContentScale.X, _configurationManager); var windowSize = root.Window.RenderTarget.Size; //Only run autoscale if it is enabled, otherwise default to just use OS UIScale if (!_autoScaleEnabled || root.DisableAutoScaling || windowSize.X <= 0 || windowSize.Y <= 0) return osScale; var maxScaleRes = _resolutionAutoScaleUpper; var minScaleRes = _resolutionAutoScaleLower; var autoScaleMin = _resolutionAutoScaleMinValue; float scaleRatioX; float scaleRatioY; //Calculate the scale ratios and clamp it between the maximums and minimums scaleRatioX = Math.Clamp(((float) windowSize.X - minScaleRes.X) / (maxScaleRes.X - minScaleRes.X) * osScale, autoScaleMin, osScale); scaleRatioY = Math.Clamp(((float) windowSize.Y - minScaleRes.Y) / (maxScaleRes.Y - minScaleRes.Y) * osScale, autoScaleMin, osScale); //Take the smallest UIScale value and use it for UI scaling return Math.Min(scaleRatioX, scaleRatioY); } private void UpdateUIScale(WindowRoot root) { var newScale = CalculateAutoScale(root); // ReSharper disable once CompareOfFloatsByEqualityOperator if (newScale == root.UIScaleSet) return; root.UIScaleSet = newScale; _propagateUIScaleChanged(root); root.InvalidateMeasure(); } private static void _propagateUIScaleChanged(Control control) { control.UIScaleChanged(); foreach (var child in control.Children) { _propagateUIScaleChanged(child); } } private void WindowSizeChanged(WindowResizedEventArgs windowResizedEventArgs) { if (!_windowsToRoot.TryGetValue(windowResizedEventArgs.Window.Id, out var root)) return; root.UIScaleUpdateNeeded = true; root.InvalidateMeasure(); } private void CheckRootUIScaleUpdate(WindowRoot root) { if (!root.UIScaleUpdateNeeded) return; using (_prof.Group("UIScaleUpdate")) { UpdateUIScale(root); } root.UIScaleUpdateNeeded = false; } }