Skip to content

Commit 98d0e70

Browse files
committed
Cap window scale to available screen
1 parent 61a62aa commit 98d0e70

7 files changed

Lines changed: 81 additions & 6 deletions

File tree

WheelWizard.Test/Features/Settings/SettingsTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,32 @@ public void Set_ReturnsFalse_WhenValidationFails()
4343
Assert.Equal(0, manager.Get<int>(manager.FOCUSED_USER));
4444
}
4545

46+
[Theory]
47+
[InlineData(0.49)]
48+
[InlineData(2.01)]
49+
public void SavedWindowScale_RejectsValuesOutsideBounds(double scale)
50+
{
51+
var manager = CreateManager(new MockFileSystem(), out _, out _, out _);
52+
53+
var result = manager.Set(manager.SAVED_WINDOW_SCALE, scale, skipSave: true);
54+
55+
Assert.False(result);
56+
Assert.Equal(1.0, manager.Get<double>(manager.SAVED_WINDOW_SCALE));
57+
}
58+
59+
[Theory]
60+
[InlineData(0.49)]
61+
[InlineData(2.01)]
62+
public void WindowScalePreview_RejectsValuesOutsideBounds(double scale)
63+
{
64+
var manager = CreateManager(new MockFileSystem(), out _, out _, out _);
65+
66+
var result = manager.Set(manager.WINDOW_SCALE, scale, skipSave: true);
67+
68+
Assert.False(result);
69+
Assert.Equal(1.0, manager.Get<double>(manager.WINDOW_SCALE));
70+
}
71+
4672
[Fact]
4773
public void ValidateCorePathSettings_ReturnsAllExpectedIssues_WhenDefaultsAreInvalid()
4874
{

WheelWizard/Features/Settings/SettingsManager.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ IFileSystem fileSystem
116116

117117
ENABLE_ANIMATIONS = RegisterWhWz("EnableAnimations", true);
118118
TESTING_MODE_ENABLED = RegisterWhWz("TestingModeEnabled", false);
119-
SAVED_WINDOW_SCALE = RegisterWhWz("WindowScale", 1.0, value => (double)(value ?? -1) >= 0.5 && (double)(value ?? -1) <= 2.0);
119+
SAVED_WINDOW_SCALE = RegisterWhWz("WindowScale", 1.0, SettingValues.IsValidWindowScale);
120120
REMOVE_BLUR = RegisterWhWz("REMOVE_BLUR", true);
121121
RR_REGION = RegisterWhWz("RR_Region", MarioKartWiiEnums.Regions.None);
122122
WW_LANGUAGE = RegisterWhWz("WW_Language", "en", value => SettingValues.WhWzLanguages.ContainsKey((string)value!));
@@ -155,11 +155,13 @@ IFileSystem fileSystem
155155
#endregion
156156

157157
#region Virtual settings
158-
WINDOW_SCALE = new VirtualSetting(
158+
var windowScale = new VirtualSetting(
159159
typeof(double),
160160
value => _internalScale = (double)value!,
161161
() => _internalScale == -1.0 ? SAVED_WINDOW_SCALE.Get() : _internalScale
162-
).SetDependencies(SAVED_WINDOW_SCALE);
162+
);
163+
windowScale.SetValidation(SettingValues.IsValidWindowScale);
164+
WINDOW_SCALE = windowScale.SetDependencies(SAVED_WINDOW_SCALE);
163165

164166
RECOMMENDED_SETTINGS = new VirtualSetting(
165167
typeof(bool),

WheelWizard/Features/Settings/Types/SettingConstants.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,16 @@ public static class SettingValues
1414
// you check for this value and replace it with its corresponding value in the language file
1515
public const string NoName = "no name";
1616
public const string NoLicense = "no license";
17+
public const double MinWindowScale = 0.5;
18+
public const double MaxWindowScale = 2.0;
1719

1820
public static readonly double[] WindowScales = [0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2];
1921

22+
public static bool IsValidWindowScale(object? value)
23+
{
24+
return value is double scale && scale >= MinWindowScale && scale <= MaxWindowScale;
25+
}
26+
2027
public static readonly Dictionary<string, string> GFXRenderers = new() //Display name, value
2128
{
2229
#if WINDOWS

WheelWizard/Views/Layout.axaml.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public Layout()
7777
InitializeComponent();
7878
AddLayer();
7979

80+
ClampSavedWindowScaleToCurrentScreen();
8081
OnSettingChanged(SettingsService.SAVED_WINDOW_SCALE);
8182
_settingsSignalSubscription = SettingsSignalBus.Subscribe(OnSettingSignal);
8283
UpdateTestingButtonVisibility();
@@ -148,7 +149,7 @@ private void OnSettingChanged(Setting setting)
148149
// Note that this method will also be called whenever the setting changes
149150
if (setting == SettingsService.WINDOW_SCALE || setting == SettingsService.SAVED_WINDOW_SCALE)
150151
{
151-
var scaleFactor = (double)setting.Get();
152+
var scaleFactor = GetUsableWindowScale((double)setting.Get());
152153
Height = WindowHeight * scaleFactor;
153154
Width = WindowWidth * scaleFactor;
154155
CompleteGrid.RenderTransform = new ScaleTransform(scaleFactor, scaleFactor);
@@ -163,6 +164,17 @@ private void OnSettingChanged(Setting setting)
163164
UpdateTestingButtonVisibility();
164165
}
165166

167+
private void ClampSavedWindowScaleToCurrentScreen()
168+
{
169+
var savedScale = SettingsService.Get<double>(SettingsService.SAVED_WINDOW_SCALE);
170+
var usableScale = GetUsableWindowScale(savedScale);
171+
if (!savedScale.Equals(usableScale))
172+
SettingsService.Set(SettingsService.SAVED_WINDOW_SCALE, usableScale);
173+
}
174+
175+
private double GetUsableWindowScale(double requestedScale) =>
176+
ViewUtils.GetUsableWindowScale(requestedScale, new Size(WindowWidth, WindowHeight), this);
177+
166178
private void UpdateModsButtonText()
167179
{
168180
ModsButton.Text = Common.PageTitle_Patches;

WheelWizard/Views/Pages/Settings/WhWzSettings.axaml.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,18 @@ private async void WindowScaleDropdown_OnSelectionChanged(object sender, Selecti
647647
_editingScale = true;
648648
var selectedScale = WindowScaleDropdown.SelectedItem?.ToString() ?? "1";
649649
var scale = double.Parse(selectedScale.Split(" ").Last().Replace("%", "")) / 100;
650+
scale = ViewUtils.GetUsableWindowScale(scale, new Avalonia.Size(Layout.WindowWidth, Layout.WindowHeight), ViewUtils.GetLayout());
651+
var selectedItemText = ScaleToString(scale);
652+
if (!WindowScaleDropdown.Items.Contains(selectedItemText))
653+
WindowScaleDropdown.Items.Add(selectedItemText);
654+
WindowScaleDropdown.SelectedItem = selectedItemText;
650655

651-
SettingsService.WINDOW_SCALE.Set(scale);
656+
if (!SettingsService.WINDOW_SCALE.Set(scale))
657+
{
658+
WindowScaleDropdown.SelectedItem = ScaleToString((double)SettingsService.WINDOW_SCALE.Get());
659+
_editingScale = false;
660+
return;
661+
}
652662
var seconds = 10;
653663

654664
string ExtraScaleText() =>

WheelWizard/Views/Popups/Base/PopupWindow.axaml.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Avalonia.Media;
88
using WheelWizard.Settings;
99
using WheelWizard.Shared.DependencyInjection;
10+
using WheelWizard.Views;
1011

1112
namespace WheelWizard.Views.Popups.Base;
1213

@@ -147,7 +148,7 @@ protected override void OnResized(WindowResizedEventArgs e)
147148

148149
public void SetWindowSize(Size size)
149150
{
150-
var scaleFactor = SettingsService.Get<double>(SettingsService.WINDOW_SCALE);
151+
var scaleFactor = ViewUtils.GetUsableWindowScale(SettingsService.Get<double>(SettingsService.WINDOW_SCALE), size, this);
151152
Width = size.Width * scaleFactor;
152153
Height = size.Height * scaleFactor;
153154
CompleteGrid.RenderTransform = new ScaleTransform(scaleFactor, scaleFactor);

WheelWizard/Views/ViewUtils.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Avalonia.Controls;
44
using Avalonia.Media;
55
using WheelWizard.Services.LiveData;
6+
using WheelWizard.Settings.Types;
67
using WheelWizard.Utilities.RepeatedTasks;
78

89
namespace WheelWizard.Views;
@@ -26,6 +27,22 @@ public static void OpenLink(string link)
2627

2728
public static Layout GetLayout() => Layout.Instance;
2829

30+
public static double GetUsableWindowScale(double requestedScale, Size unscaledSize, Window window)
31+
{
32+
var maxScale = SettingValues.MaxWindowScale;
33+
var screen = window.Screens.ScreenFromWindow(window) ?? window.Screens.Primary;
34+
if (screen != null)
35+
{
36+
var screenScale = screen.Scaling <= 0 ? 1 : screen.Scaling;
37+
var availableWidth = screen.WorkingArea.Width / screenScale;
38+
var availableHeight = screen.WorkingArea.Height / screenScale;
39+
maxScale = Math.Min(maxScale, Math.Min(availableWidth / unscaledSize.Width, availableHeight / unscaledSize.Height));
40+
}
41+
42+
maxScale = Math.Max(SettingValues.MinWindowScale, maxScale);
43+
return Math.Clamp(requestedScale, SettingValues.MinWindowScale, maxScale);
44+
}
45+
2946
public static void RefreshWindow()
3047
{
3148
// Refresh window opens in the start page again, that is nessesairy

0 commit comments

Comments
 (0)