diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs index 83265e13ad..3e679a7905 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; @@ -83,7 +84,7 @@ namespace osu.Game.Tests.Visual.Settings AddStep("clear label", () => textBox.LabelText = default); AddAssert("default value button centre aligned to control size", () => Precision.AlmostEquals(restoreDefaultValueButton.Parent.DrawHeight, control.DrawHeight, 1)); - AddStep("set warning text", () => textBox.WarningText = "This is some very important warning text! Hopefully it doesn't break the alignment of the default value indicator..."); + AddStep("set warning text", () => textBox.SetNoticeText("This is some very important warning text! Hopefully it doesn't break the alignment of the default value indicator...", true)); AddAssert("default value button centre aligned to control size", () => Precision.AlmostEquals(restoreDefaultValueButton.Parent.DrawHeight, control.DrawHeight, 1)); } @@ -129,16 +130,18 @@ namespace osu.Game.Tests.Visual.Settings SettingsNumberBox numberBox = null; AddStep("create settings item", () => Child = numberBox = new SettingsNumberBox()); - AddAssert("warning text not created", () => !numberBox.ChildrenOfType().Any()); + AddAssert("warning text not created", () => !numberBox.ChildrenOfType().Any()); - AddStep("set warning text", () => numberBox.WarningText = "this is a warning!"); - AddAssert("warning text created", () => numberBox.ChildrenOfType().Single().Alpha == 1); + AddStep("set warning text", () => numberBox.SetNoticeText("this is a warning!", true)); + AddAssert("warning text created", () => numberBox.ChildrenOfType().Single().Alpha == 1); - AddStep("unset warning text", () => numberBox.WarningText = default); - AddAssert("warning text hidden", () => numberBox.ChildrenOfType().Single().Alpha == 0); + AddStep("unset warning text", () => numberBox.ClearNoticeText()); + AddAssert("warning text hidden", () => !numberBox.ChildrenOfType().Any()); - AddStep("set warning text again", () => numberBox.WarningText = "another warning!"); - AddAssert("warning text shown again", () => numberBox.ChildrenOfType().Single().Alpha == 1); + AddStep("set warning text again", () => numberBox.SetNoticeText("another warning!", true)); + AddAssert("warning text shown again", () => numberBox.ChildrenOfType().Single().Alpha == 1); + + AddStep("set non warning text", () => numberBox.SetNoticeText("you did good!")); } } } diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs new file mode 100644 index 0000000000..5ac28f19b3 --- /dev/null +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class LayoutSettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.LayoutSettings"; + + /// + /// "Checking for fullscreen capabilities..." + /// + public static LocalisableString CheckingForFullscreenCapabilities => new TranslatableString(getKey(@"checking_for_fullscreen_capabilities"), @"Checking for fullscreen capabilities..."); + + /// + /// "osu! is running exclusive fullscreen, guaranteeing low latency!" + /// + public static LocalisableString OsuIsRunningExclusiveFullscreen => new TranslatableString(getKey(@"osu_is_running_exclusive_fullscreen"), @"osu! is running exclusive fullscreen, guaranteeing low latency!"); + + /// + /// "Unable to run exclusive fullscreen. You'll still experience some input latency." + /// + public static LocalisableString UnableToRunExclusiveFullscreen => new TranslatableString(getKey(@"unable_to_run_exclusive_fullscreen"), @"Unable to run exclusive fullscreen. You'll still experience some input latency."); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 602ace6dea..d79ba593f7 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Framework.Platform; +using osu.Framework.Platform.Windows; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -34,10 +35,14 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private Bindable sizeFullscreen; private readonly BindableList resolutions = new BindableList(new[] { new Size(9999, 9999) }); + private readonly IBindable fullscreenCapability = new Bindable(FullscreenCapability.Capable); [Resolved] private OsuGameBase game { get; set; } + [Resolved] + private GameHost host { get; set; } + private SettingsDropdown resolutionDropdown; private SettingsDropdown displayDropdown; private SettingsDropdown windowModeDropdown; @@ -65,6 +70,9 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics windowModes.BindTo(host.Window.SupportedWindowModes); } + if (host.Window is WindowsWindow windowsWindow) + fullscreenCapability.BindTo(windowsWindow.FullscreenCapability); + Children = new Drawable[] { windowModeDropdown = new SettingsDropdown @@ -139,6 +147,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } }, }; + + fullscreenCapability.BindValueChanged(_ => Schedule(updateScreenModeWarning), true); } protected override void LoadComplete() @@ -150,8 +160,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics windowModeDropdown.Current.BindValueChanged(mode => { updateDisplayModeDropdowns(); - - windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? GraphicsSettingsStrings.NotFullscreenNote : default; + updateScreenModeWarning(); }, true); windowModes.BindCollectionChanged((sender, args) => @@ -213,6 +222,38 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } } + private void updateScreenModeWarning() + { + if (windowModeDropdown.Current.Value != WindowMode.Fullscreen) + { + windowModeDropdown.SetNoticeText(GraphicsSettingsStrings.NotFullscreenNote, true); + return; + } + + if (host.Window is WindowsWindow) + { + switch (fullscreenCapability.Value) + { + case FullscreenCapability.Unknown: + windowModeDropdown.SetNoticeText(LayoutSettingsStrings.CheckingForFullscreenCapabilities, true); + break; + + case FullscreenCapability.Capable: + windowModeDropdown.SetNoticeText(LayoutSettingsStrings.OsuIsRunningExclusiveFullscreen); + break; + + case FullscreenCapability.Incapable: + windowModeDropdown.SetNoticeText(LayoutSettingsStrings.UnableToRunExclusiveFullscreen, true); + break; + } + } + else + { + // We can only detect exclusive fullscreen status on windows currently. + windowModeDropdown.ClearNoticeText(); + } + } + private void bindPreviewEvent(Bindable bindable) { bindable.ValueChanged += _ => diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs index 653f30a018..8c3e45cd62 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs @@ -48,7 +48,16 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics frameLimiterDropdown.Current.BindValueChanged(limit => { - frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? GraphicsSettingsStrings.UnlimitedFramesNote : default; + switch (limit.NewValue) + { + case FrameSync.Unlimited: + frameLimiterDropdown.SetNoticeText(GraphicsSettingsStrings.UnlimitedFramesNote, true); + break; + + default: + frameLimiterDropdown.ClearNoticeText(); + break; + } }, true); } } diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index 4235dc0a05..1511d53b6b 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -117,9 +117,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) { if (highPrecision.NewValue) - highPrecisionMouse.WarningText = MouseSettingsStrings.HighPrecisionPlatformWarning; + highPrecisionMouse.SetNoticeText(MouseSettingsStrings.HighPrecisionPlatformWarning, true); else - highPrecisionMouse.WarningText = null; + highPrecisionMouse.ClearNoticeText(); } }, true); } diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 802d442ced..5d31c38ae7 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -11,6 +11,7 @@ using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; using osu.Game.Localisation; @@ -95,11 +96,13 @@ namespace osu.Game.Overlays.Settings.Sections.Input Origin = Anchor.TopCentre, Text = TabletSettingsStrings.NoTabletDetected, }, - new SettingsNoticeText(colours) + new LinkFlowContainer(cp => cp.Colour = colours.Yellow) { TextAnchor = Anchor.TopCentre, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, }.With(t => { if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux) diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs index 284e9cb2de..fceffa09c5 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs @@ -61,7 +61,10 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface user.BindValueChanged(u => { - backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? UserInterfaceStrings.NotSupporterNote : default; + if (u.NewValue?.IsSupporter != true) + backgroundSourceDropdown.SetNoticeText(UserInterfaceStrings.NotSupporterNote, true); + else + backgroundSourceDropdown.ClearNoticeText(); }, true); } } diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index ee9daa1c0d..ea076b77ac 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings private SpriteText labelText; - private OsuTextFlowContainer warningText; + private OsuTextFlowContainer noticeText; public bool ShowsDefaultIndicator = true; private readonly Container defaultValueIndicatorContainer; @@ -70,27 +70,32 @@ namespace osu.Game.Overlays.Settings } /// - /// Text to be displayed at the bottom of this . - /// Generally used to recommend the user change their setting as the current one is considered sub-optimal. + /// Clear any warning text. /// - public LocalisableString? WarningText + public void ClearNoticeText() { - set + noticeText?.Expire(); + noticeText = null; + } + + /// + /// Set the text to be displayed at the bottom of this . + /// Generally used to provide feedback to a user about a sub-optimal setting. + /// + /// The text to display. + /// Whether the text is in a warning state. Will decide how this is visually represented. + public void SetNoticeText(LocalisableString text, bool isWarning = false) + { + ClearNoticeText(); + + // construct lazily for cases where the label is not needed (may be provided by the Control). + FlowContent.Add(noticeText = new LinkFlowContainer(cp => cp.Colour = isWarning ? colours.Yellow : colours.Green) { - bool hasValue = value != default; - - if (warningText == null) - { - if (!hasValue) - return; - - // construct lazily for cases where the label is not needed (may be provided by the Control). - FlowContent.Add(warningText = new SettingsNoticeText(colours) { Margin = new MarginPadding { Bottom = 5 } }); - } - - warningText.Alpha = hasValue ? 1 : 0; - warningText.Text = value ?? default; - } + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Bottom = 5 }, + Text = text, + }); } public virtual Bindable Current diff --git a/osu.Game/Overlays/Settings/SettingsNoticeText.cs b/osu.Game/Overlays/Settings/SettingsNoticeText.cs deleted file mode 100644 index 76ecf7edd4..0000000000 --- a/osu.Game/Overlays/Settings/SettingsNoticeText.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; - -namespace osu.Game.Overlays.Settings -{ - public class SettingsNoticeText : LinkFlowContainer - { - public SettingsNoticeText(OsuColour colours) - : base(s => s.Colour = colours.Yellow) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - } - } -}