diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs new file mode 100644 index 0000000000..b4d219456c --- /dev/null +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs @@ -0,0 +1,56 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.IO; +using NUnit.Framework; +using osu.Game.Beatmaps.Formats; +using osu.Game.Tests.Resources; + +namespace osu.Game.Tests.Beatmaps.Formats +{ + [TestFixture] + public class LegacyDecoderTest + { + [Test] + public void TestDecodeComments() + { + var decoder = new LineLoggingDecoder(14); + + using (var resStream = TestResources.OpenResource("comments.osu")) + using (var stream = new StreamReader(resStream)) + { + decoder.Decode(stream); + + Assert.That(decoder.ParsedLines, Has.None.EqualTo("// Combo1: 0, 0, 0")); + Assert.That(decoder.ParsedLines, Has.None.EqualTo("//Combo2: 0, 0, 0")); + Assert.That(decoder.ParsedLines, Has.None.EqualTo(" // Combo3: 0, 0, 0")); + Assert.That(decoder.ParsedLines, Has.One.EqualTo("Combo1: 100, 100, 100 // Comment at end of line")); + } + } + + private class LineLoggingDecoder : LegacyDecoder + { + public readonly List ParsedLines = new List(); + + public LineLoggingDecoder(int version) + : base(version) + { + } + + protected override bool ShouldSkipLine(string line) + { + var result = base.ShouldSkipLine(line); + + if (!result) + ParsedLines.Add(line); + + return result; + } + } + + private class TestModel + { + } + } +} diff --git a/osu.Game.Tests/Resources/comments.osu b/osu.Game.Tests/Resources/comments.osu new file mode 100644 index 0000000000..78b48dd804 --- /dev/null +++ b/osu.Game.Tests/Resources/comments.osu @@ -0,0 +1,9 @@ +osu file format v14 + +[Colours] + +// Combo1: 0, 0, 0 +//Combo2: 0, 0, 0 + // Combo3: 0, 0, 0 + +Combo1: 100, 100, 100 // Comment at end of line \ No newline at end of file diff --git a/osu.Game.Tests/Visual/Settings/TestCaseKeyConfiguration.cs b/osu.Game.Tests/Visual/Settings/TestCaseKeyConfiguration.cs index ce179c21ba..fccd48b85c 100644 --- a/osu.Game.Tests/Visual/Settings/TestCaseKeyConfiguration.cs +++ b/osu.Game.Tests/Visual/Settings/TestCaseKeyConfiguration.cs @@ -9,17 +9,17 @@ namespace osu.Game.Tests.Visual.Settings [TestFixture] public class TestCaseKeyConfiguration : OsuTestCase { - private readonly KeyBindingOverlay overlay; + private readonly KeyBindingPanel panel; public TestCaseKeyConfiguration() { - Child = overlay = new KeyBindingOverlay(); + Child = panel = new KeyBindingPanel(); } protected override void LoadComplete() { base.LoadComplete(); - overlay.Show(); + panel.Show(); } } } diff --git a/osu.Game.Tests/Visual/Settings/TestCaseSettings.cs b/osu.Game.Tests/Visual/Settings/TestCaseSettings.cs index e846d5c020..5b6c033c1d 100644 --- a/osu.Game.Tests/Visual/Settings/TestCaseSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestCaseSettings.cs @@ -11,12 +11,12 @@ namespace osu.Game.Tests.Visual.Settings [TestFixture] public class TestCaseSettings : OsuTestCase { - private readonly SettingsOverlay settings; + private readonly SettingsPanel settings; private readonly DialogOverlay dialogOverlay; public TestCaseSettings() { - settings = new MainSettings + settings = new SettingsOverlay { State = Visibility.Visible }; diff --git a/osu.Game.Tests/Visual/TestCaseOsuGame.cs b/osu.Game.Tests/Visual/TestCaseOsuGame.cs index 9e649b92e4..dd98ff088c 100644 --- a/osu.Game.Tests/Visual/TestCaseOsuGame.cs +++ b/osu.Game.Tests/Visual/TestCaseOsuGame.cs @@ -3,12 +3,30 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Textures; using osu.Framework.Platform; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Database; +using osu.Game.Graphics; +using osu.Game.Input; +using osu.Game.Input.Bindings; +using osu.Game.IO; +using osu.Game.Online.API; +using osu.Game.Online.Chat; +using osu.Game.Overlays; +using osu.Game.Rulesets; +using osu.Game.Scoring; using osu.Game.Screens.Menu; +using osu.Game.Skinning; +using osu.Game.Utils; using osuTK.Graphics; namespace osu.Game.Tests.Visual @@ -21,6 +39,52 @@ namespace osu.Game.Tests.Visual typeof(OsuLogo), }; + private IReadOnlyList requiredGameDependencies => new[] + { + typeof(OsuGame), + typeof(RavenLogger), + typeof(Bindable), + typeof(IBindable), + typeof(OsuLogo), + typeof(IdleTracker), + typeof(OnScreenDisplay), + typeof(NotificationOverlay), + typeof(DirectOverlay), + typeof(SocialOverlay), + typeof(ChannelManager), + typeof(ChatOverlay), + typeof(SettingsOverlay), + typeof(UserProfileOverlay), + typeof(BeatmapSetOverlay), + typeof(LoginOverlay), + typeof(MusicController), + typeof(AccountCreationOverlay), + typeof(DialogOverlay), + }; + + private IReadOnlyList requiredGameBaseDependencies => new[] + { + typeof(OsuGameBase), + typeof(DatabaseContextFactory), + typeof(LargeTextureStore), + typeof(OsuConfigManager), + typeof(SkinManager), + typeof(ISkinSource), + typeof(IAPIProvider), + typeof(RulesetStore), + typeof(FileStore), + typeof(ScoreManager), + typeof(BeatmapManager), + typeof(KeyBindingStore), + typeof(SettingsStore), + typeof(RulesetConfigCache), + typeof(OsuColour), + typeof(IBindable), + typeof(Bindable), + typeof(GlobalActionContainer), + typeof(PreviewTrackManager), + }; + [BackgroundDependencyLoader] private void load(GameHost host) { @@ -36,6 +100,11 @@ namespace osu.Game.Tests.Visual }, game }; + + AddUntilStep("wait for load", () => game.IsLoaded); + + AddAssert("check OsuGame DI members", () => requiredGameDependencies.All(d => game.Dependencies.Get(d) != null)); + AddAssert("check OsuGameBase DI members", () => requiredGameBaseDependencies.All(d => Dependencies.Get(d) != null)); } } } diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index ad5089958c..eb5bcfe824 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -54,7 +54,7 @@ namespace osu.Game.Beatmaps.Formats } } - protected virtual bool ShouldSkipLine(string line) => string.IsNullOrWhiteSpace(line) || line.StartsWith("//", StringComparison.Ordinal); + protected virtual bool ShouldSkipLine(string line) => string.IsNullOrWhiteSpace(line) || line.AsSpan().TrimStart().StartsWith("//".AsSpan(), StringComparison.Ordinal); protected virtual void ParseLine(T output, Section section, string line) { diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 7b2a8184d1..6fe91181fb 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -58,16 +58,8 @@ namespace osu.Game private ChannelManager channelManager; - private MusicController musicController; - private NotificationOverlay notifications; - private LoginOverlay loginOverlay; - - private DialogOverlay dialogOverlay; - - private AccountCreationOverlay accountCreation; - private DirectOverlay direct; private SocialOverlay social; @@ -91,7 +83,6 @@ namespace osu.Game private OsuScreenStack screenStack; private VolumeOverlay volume; - private OnScreenDisplay onscreenDisplay; private OsuLogo osuLogo; private MainMenu menuScreen; @@ -104,7 +95,7 @@ namespace osu.Game private readonly string[] args; - private SettingsOverlay settings; + private SettingsPanel settings; private readonly List overlays = new List(); @@ -124,10 +115,6 @@ namespace osu.Game RavenLogger = new RavenLogger(this); } - public void ToggleSettings() => settings.ToggleVisibility(); - - public void ToggleDirect() => direct.ToggleVisibility(); - private void updateBlockingOverlayFade() => screenContainer.FadeColour(visibleBlockingOverlays.Any() ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint); @@ -381,6 +368,8 @@ namespace osu.Game Container logoContainer; + dependencies.CacheAs(idleTracker = new GameIdleTracker(6000)); + AddRange(new Drawable[] { new VolumeControlReceptor @@ -402,7 +391,7 @@ namespace osu.Game rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, - idleTracker = new GameIdleTracker(6000) + idleTracker }); screenStack.ScreenPushed += screenPushed; @@ -429,59 +418,44 @@ namespace osu.Game }, topMostOverlayContent.Add); loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add); - loadComponentSingleFile(onscreenDisplay = new OnScreenDisplay(), Add); + loadComponentSingleFile(new OnScreenDisplay(), Add, true); loadComponentSingleFile(notifications = new NotificationOverlay { GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - }, rightFloatingOverlayContent.Add); + }, rightFloatingOverlayContent.Add, true); loadComponentSingleFile(screenshotManager, Add); //overlay elements - loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add); - loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add); - loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal); - loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add); - loadComponentSingleFile(settings = new MainSettings { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add); - loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add); - loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add); + loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add, true); + loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add, true); + loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true); + loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); + loadComponentSingleFile(settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); + loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true); + loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true); - loadComponentSingleFile(loginOverlay = new LoginOverlay + loadComponentSingleFile(new LoginOverlay { GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - }, rightFloatingOverlayContent.Add); + }, rightFloatingOverlayContent.Add, true); - loadComponentSingleFile(musicController = new MusicController + loadComponentSingleFile(new MusicController { GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - }, rightFloatingOverlayContent.Add); + }, rightFloatingOverlayContent.Add, true); - loadComponentSingleFile(accountCreation = new AccountCreationOverlay(), topMostOverlayContent.Add); - loadComponentSingleFile(dialogOverlay = new DialogOverlay(), topMostOverlayContent.Add); + loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true); + loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true); loadComponentSingleFile(externalLinkOpener = new ExternalLinkOpener(), topMostOverlayContent.Add); - dependencies.CacheAs(idleTracker); - dependencies.Cache(settings); - dependencies.Cache(onscreenDisplay); - dependencies.Cache(social); - dependencies.Cache(direct); - dependencies.Cache(chatOverlay); - dependencies.Cache(channelManager); - dependencies.Cache(userProfile); - dependencies.Cache(musicController); - dependencies.Cache(beatmapSetOverlay); - dependencies.Cache(notifications); - dependencies.Cache(loginOverlay); - dependencies.Cache(dialogOverlay); - dependencies.Cache(accountCreation); - chatOverlay.StateChanged += state => channelManager.HighPollRate.Value = state == Visibility.Visible; Add(externalLinkOpener = new ExternalLinkOpener()); @@ -544,7 +518,7 @@ namespace osu.Game if (notifications.State == Visibility.Visible) offset -= ToolbarButton.WIDTH / 2; - screenContainer.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); + screenContainer.MoveToX(offset, SettingsPanel.TRANSITION_LENGTH, Easing.OutQuint); } settings.StateChanged += _ => updateScreenOffset(); @@ -610,9 +584,12 @@ namespace osu.Game private Task asyncLoadStream; - private void loadComponentSingleFile(T d, Action add) + private void loadComponentSingleFile(T d, Action add, bool cache = false) where T : Drawable { + if (cache) + dependencies.Cache(d); + // schedule is here to ensure that all component loads are done after LoadComplete is run (and thus all dependencies are cached). // with some better organisation of LoadComplete to do construction and dependency caching in one step, followed by calls to loadComponentSingleFile, // we could avoid the need for scheduling altogether. diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 53cb3edeca..08288516e3 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.KeyBinding this.variant = variant; FlowContent.Spacing = new Vector2(0, 1); - FlowContent.Padding = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS }; + FlowContent.Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS }; } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/KeyBindingOverlay.cs b/osu.Game/Overlays/KeyBindingPanel.cs similarity index 97% rename from osu.Game/Overlays/KeyBindingOverlay.cs rename to osu.Game/Overlays/KeyBindingPanel.cs index b223d4701d..301c8faca2 100644 --- a/osu.Game/Overlays/KeyBindingOverlay.cs +++ b/osu.Game/Overlays/KeyBindingPanel.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Overlays { - public class KeyBindingOverlay : SettingsOverlay + public class KeyBindingPanel : SettingsPanel { protected override Drawable CreateHeader() => new SettingsHeader("key configuration", "Customise your keys!"); @@ -38,7 +38,7 @@ namespace osu.Game.Overlays }); } - public KeyBindingOverlay() + public KeyBindingPanel() : base(true) { } diff --git a/osu.Game/Overlays/MainSettings.cs b/osu.Game/Overlays/MainSettings.cs deleted file mode 100644 index 39bfdfd4d6..0000000000 --- a/osu.Game/Overlays/MainSettings.cs +++ /dev/null @@ -1,77 +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.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Overlays.Settings; -using osu.Game.Overlays.Settings.Sections; -using osuTK.Graphics; -using System.Collections.Generic; - -namespace osu.Game.Overlays -{ - public class MainSettings : SettingsOverlay - { - private readonly KeyBindingOverlay keyBindingOverlay; - - protected override IEnumerable CreateSections() => new SettingsSection[] - { - new GeneralSection(), - new GraphicsSection(), - new GameplaySection(), - new AudioSection(), - new SkinSection(), - new InputSection(keyBindingOverlay), - new OnlineSection(), - new MaintenanceSection(), - new DebugSection(), - }; - - protected override Drawable CreateHeader() => new SettingsHeader("settings", "Change the way osu! behaves"); - protected override Drawable CreateFooter() => new SettingsFooter(); - - public MainSettings() - : base(true) - { - keyBindingOverlay = new KeyBindingOverlay - { - Depth = 1, - Anchor = Anchor.TopRight, - }; - keyBindingOverlay.StateChanged += keyBindingOverlay_StateChanged; - } - - public override bool AcceptsFocus => keyBindingOverlay.State != Visibility.Visible; - - private void keyBindingOverlay_StateChanged(Visibility visibility) - { - switch (visibility) - { - case Visibility.Visible: - Background.FadeTo(0.9f, 300, Easing.OutQuint); - Sidebar?.FadeColour(Color4.DarkGray, 300, Easing.OutQuint); - - SectionsContainer.FadeOut(300, Easing.OutQuint); - ContentContainer.MoveToX(-WIDTH, 500, Easing.OutQuint); - break; - - case Visibility.Hidden: - Background.FadeTo(0.6f, 500, Easing.OutQuint); - Sidebar?.FadeColour(Color4.White, 300, Easing.OutQuint); - - SectionsContainer.FadeIn(500, Easing.OutQuint); - ContentContainer.MoveToX(0, 500, Easing.OutQuint); - break; - } - } - - protected override float ExpandedPosition => keyBindingOverlay.State == Visibility.Visible ? -WIDTH : base.ExpandedPosition; - - [BackgroundDependencyLoader] - private void load() - { - ContentContainer.Add(keyBindingOverlay); - } - } -} diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs index 3f1e77d482..55c7210d6c 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs @@ -9,7 +9,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { protected override string Header => "Keyboard"; - public KeyboardSettings(KeyBindingOverlay keyConfig) + public KeyboardSettings(KeyBindingPanel keyConfig) { Children = new Drawable[] { diff --git a/osu.Game/Overlays/Settings/Sections/InputSection.cs b/osu.Game/Overlays/Settings/Sections/InputSection.cs index 6a3f8783b0..2a348b4e03 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSection.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections public override string Header => "Input"; public override IconUsage Icon => FontAwesome.Regular.Keyboard; - public InputSection(KeyBindingOverlay keyConfig) + public InputSection(KeyBindingPanel keyConfig) { Children = new Drawable[] { diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index ef98c28285..088d69c031 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Settings public SettingsButton() { RelativeSizeAxes = Axes.X; - Padding = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS }; + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS }; } public string TooltipText { get; set; } diff --git a/osu.Game/Overlays/Settings/SettingsHeader.cs b/osu.Game/Overlays/Settings/SettingsHeader.cs index fbf29f7ff5..d8ec00bd99 100644 --- a/osu.Game/Overlays/Settings/SettingsHeader.cs +++ b/osu.Game/Overlays/Settings/SettingsHeader.cs @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings Font = OsuFont.GetFont(size: 40), Margin = new MarginPadding { - Left = SettingsOverlay.CONTENT_MARGINS, + Left = SettingsPanel.CONTENT_MARGINS, Top = Toolbar.Toolbar.TOOLTIP_HEIGHT }, }, @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Settings Font = OsuFont.GetFont(size: 18), Margin = new MarginPadding { - Left = SettingsOverlay.CONTENT_MARGINS, + Left = SettingsPanel.CONTENT_MARGINS, Bottom = 30 }, }, diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 4b64f942bf..4776cd6442 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -87,7 +87,7 @@ namespace osu.Game.Overlays.Settings { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = SettingsOverlay.CONTENT_MARGINS }; + Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; InternalChildren = new Drawable[] { @@ -96,7 +96,7 @@ namespace osu.Game.Overlays.Settings { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS }, + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, Child = Control = CreateControl() }, }; @@ -131,7 +131,7 @@ namespace osu.Game.Overlays.Settings public RestoreDefaultValueButton() { RelativeSizeAxes = Axes.Y; - Width = SettingsOverlay.CONTENT_MARGINS; + Width = SettingsPanel.CONTENT_MARGINS; Alpha = 0f; } diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index e92f28d5d2..c878a9fc65 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -83,7 +83,7 @@ namespace osu.Game.Overlays.Settings Font = OsuFont.GetFont(size: header_size), Text = Header, Colour = colours.Yellow, - Margin = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS } + Margin = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS } }, FlowContent } diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index a1b4d8b131..c9c763e8d4 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.Settings new OsuSpriteText { Text = Header.ToUpperInvariant(), - Margin = new MarginPadding { Bottom = 10, Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS }, + Margin = new MarginPadding { Bottom = 10, Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS }, Font = OsuFont.GetFont(weight: FontWeight.Black), }, FlowContent diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 174d3a3de1..4f3a71a1b3 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -1,224 +1,77 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; -using System.Linq; -using osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; +using osu.Game.Overlays.Settings.Sections; +using osuTK.Graphics; +using System.Collections.Generic; namespace osu.Game.Overlays { - public abstract class SettingsOverlay : OsuFocusedOverlayContainer + public class SettingsOverlay : SettingsPanel { - public const float CONTENT_MARGINS = 15; + private readonly KeyBindingPanel keyBindingPanel; - public const float TRANSITION_LENGTH = 600; - - private const float sidebar_width = Sidebar.DEFAULT_WIDTH; - - protected const float WIDTH = 400; - - private const float sidebar_padding = 10; - - protected Container ContentContainer; - - protected override Container Content => ContentContainer; - - protected Sidebar Sidebar; - private SidebarButton selectedSidebarButton; - - protected SettingsSectionsContainer SectionsContainer; - - private SearchTextBox searchTextBox; - - /// - /// Provide a source for the toolbar height. - /// - public Func GetToolbarHeight; - - private readonly bool showSidebar; - - protected Box Background; - - protected SettingsOverlay(bool showSidebar) + protected override IEnumerable CreateSections() => new SettingsSection[] { - this.showSidebar = showSidebar; - RelativeSizeAxes = Axes.Y; - AutoSizeAxes = Axes.X; + new GeneralSection(), + new GraphicsSection(), + new GameplaySection(), + new AudioSection(), + new SkinSection(), + new InputSection(keyBindingPanel), + new OnlineSection(), + new MaintenanceSection(), + new DebugSection(), + }; + + protected override Drawable CreateHeader() => new SettingsHeader("settings", "Change the way osu! behaves"); + protected override Drawable CreateFooter() => new SettingsFooter(); + + public SettingsOverlay() + : base(true) + { + keyBindingPanel = new KeyBindingPanel + { + Depth = 1, + Anchor = Anchor.TopRight, + }; + keyBindingPanel.StateChanged += keyBindingPanelStateChanged; } - protected virtual IEnumerable CreateSections() => null; + public override bool AcceptsFocus => keyBindingPanel.State != Visibility.Visible; + + private void keyBindingPanelStateChanged(Visibility visibility) + { + switch (visibility) + { + case Visibility.Visible: + Background.FadeTo(0.9f, 300, Easing.OutQuint); + Sidebar?.FadeColour(Color4.DarkGray, 300, Easing.OutQuint); + + SectionsContainer.FadeOut(300, Easing.OutQuint); + ContentContainer.MoveToX(-WIDTH, 500, Easing.OutQuint); + break; + + case Visibility.Hidden: + Background.FadeTo(0.6f, 500, Easing.OutQuint); + Sidebar?.FadeColour(Color4.White, 300, Easing.OutQuint); + + SectionsContainer.FadeIn(500, Easing.OutQuint); + ContentContainer.MoveToX(0, 500, Easing.OutQuint); + break; + } + } + + protected override float ExpandedPosition => keyBindingPanel.State == Visibility.Visible ? -WIDTH : base.ExpandedPosition; [BackgroundDependencyLoader] private void load() { - InternalChild = ContentContainer = new Container - { - Width = WIDTH, - RelativeSizeAxes = Axes.Y, - Children = new Drawable[] - { - Background = new Box - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Scale = new Vector2(2, 1), // over-extend to the left for transitions - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.6f, - }, - SectionsContainer = new SettingsSectionsContainer - { - Masking = true, - RelativeSizeAxes = Axes.Both, - ExpandableHeader = CreateHeader(), - FixedHeader = searchTextBox = new SearchTextBox - { - RelativeSizeAxes = Axes.X, - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Width = 0.95f, - Margin = new MarginPadding - { - Top = 20, - Bottom = 20 - }, - Exit = Hide, - }, - Footer = CreateFooter() - }, - } - }; - - if (showSidebar) - { - AddInternal(Sidebar = new Sidebar { Width = sidebar_width }); - - SectionsContainer.SelectedSection.ValueChanged += section => - { - selectedSidebarButton.Selected = false; - selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); - selectedSidebarButton.Selected = true; - }; - } - - searchTextBox.Current.ValueChanged += term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue; - - CreateSections()?.ForEach(AddSection); - } - - protected void AddSection(SettingsSection section) - { - SectionsContainer.Add(section); - - if (Sidebar != null) - { - var button = new SidebarButton - { - Section = section, - Action = s => - { - SectionsContainer.ScrollTo(s); - Sidebar.State = ExpandedState.Contracted; - }, - }; - - Sidebar.Add(button); - - if (selectedSidebarButton == null) - { - selectedSidebarButton = Sidebar.Children.First(); - selectedSidebarButton.Selected = true; - } - } - } - - protected virtual Drawable CreateHeader() => new Container(); - - protected virtual Drawable CreateFooter() => new Container(); - - protected override void PopIn() - { - base.PopIn(); - - ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint); - - Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint); - this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint); - - searchTextBox.HoldFocus = true; - } - - protected virtual float ExpandedPosition => 0; - - protected override void PopOut() - { - base.PopOut(); - - ContentContainer.MoveToX(-WIDTH, TRANSITION_LENGTH, Easing.OutQuint); - - Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint); - this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); - - searchTextBox.HoldFocus = false; - if (searchTextBox.HasFocus) - GetContainingInputManager().ChangeFocus(null); - } - - public override bool AcceptsFocus => true; - - protected override void OnFocus(FocusEvent e) - { - searchTextBox.TakeFocus(); - base.OnFocus(e); - } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - ContentContainer.Margin = new MarginPadding { Left = Sidebar?.DrawWidth ?? 0 }; - ContentContainer.Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; - } - - protected class SettingsSectionsContainer : SectionsContainer - { - public SearchContainer SearchContainer; - - protected override FlowContainer CreateScrollContentContainer() - => SearchContainer = new SearchContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - }; - - public SettingsSectionsContainer() - { - HeaderBackground = new Box - { - Colour = Color4.Black, - RelativeSizeAxes = Axes.Both - }; - } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - // no null check because the usage of this class is strict - HeaderBackground.Alpha = -ExpandableHeader.Y / ExpandableHeader.LayoutSize.Y * 0.5f; - } + ContentContainer.Add(keyBindingPanel); } } } diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs new file mode 100644 index 0000000000..85b74c0fad --- /dev/null +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -0,0 +1,224 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osuTK; +using osuTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Settings; + +namespace osu.Game.Overlays +{ + public abstract class SettingsPanel : OsuFocusedOverlayContainer + { + public const float CONTENT_MARGINS = 15; + + public const float TRANSITION_LENGTH = 600; + + private const float sidebar_width = Sidebar.DEFAULT_WIDTH; + + protected const float WIDTH = 400; + + private const float sidebar_padding = 10; + + protected Container ContentContainer; + + protected override Container Content => ContentContainer; + + protected Sidebar Sidebar; + private SidebarButton selectedSidebarButton; + + protected SettingsSectionsContainer SectionsContainer; + + private SearchTextBox searchTextBox; + + /// + /// Provide a source for the toolbar height. + /// + public Func GetToolbarHeight; + + private readonly bool showSidebar; + + protected Box Background; + + protected SettingsPanel(bool showSidebar) + { + this.showSidebar = showSidebar; + RelativeSizeAxes = Axes.Y; + AutoSizeAxes = Axes.X; + } + + protected virtual IEnumerable CreateSections() => null; + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = ContentContainer = new Container + { + Width = WIDTH, + RelativeSizeAxes = Axes.Y, + Children = new Drawable[] + { + Background = new Box + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Scale = new Vector2(2, 1), // over-extend to the left for transitions + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + SectionsContainer = new SettingsSectionsContainer + { + Masking = true, + RelativeSizeAxes = Axes.Both, + ExpandableHeader = CreateHeader(), + FixedHeader = searchTextBox = new SearchTextBox + { + RelativeSizeAxes = Axes.X, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 0.95f, + Margin = new MarginPadding + { + Top = 20, + Bottom = 20 + }, + Exit = Hide, + }, + Footer = CreateFooter() + }, + } + }; + + if (showSidebar) + { + AddInternal(Sidebar = new Sidebar { Width = sidebar_width }); + + SectionsContainer.SelectedSection.ValueChanged += section => + { + selectedSidebarButton.Selected = false; + selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); + selectedSidebarButton.Selected = true; + }; + } + + searchTextBox.Current.ValueChanged += term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue; + + CreateSections()?.ForEach(AddSection); + } + + protected void AddSection(SettingsSection section) + { + SectionsContainer.Add(section); + + if (Sidebar != null) + { + var button = new SidebarButton + { + Section = section, + Action = s => + { + SectionsContainer.ScrollTo(s); + Sidebar.State = ExpandedState.Contracted; + }, + }; + + Sidebar.Add(button); + + if (selectedSidebarButton == null) + { + selectedSidebarButton = Sidebar.Children.First(); + selectedSidebarButton.Selected = true; + } + } + } + + protected virtual Drawable CreateHeader() => new Container(); + + protected virtual Drawable CreateFooter() => new Container(); + + protected override void PopIn() + { + base.PopIn(); + + ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint); + + Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint); + this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint); + + searchTextBox.HoldFocus = true; + } + + protected virtual float ExpandedPosition => 0; + + protected override void PopOut() + { + base.PopOut(); + + ContentContainer.MoveToX(-WIDTH, TRANSITION_LENGTH, Easing.OutQuint); + + Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint); + this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); + + searchTextBox.HoldFocus = false; + if (searchTextBox.HasFocus) + GetContainingInputManager().ChangeFocus(null); + } + + public override bool AcceptsFocus => true; + + protected override void OnFocus(FocusEvent e) + { + searchTextBox.TakeFocus(); + base.OnFocus(e); + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + ContentContainer.Margin = new MarginPadding { Left = Sidebar?.DrawWidth ?? 0 }; + ContentContainer.Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; + } + + protected class SettingsSectionsContainer : SectionsContainer + { + public SearchContainer SearchContainer; + + protected override FlowContainer CreateScrollContentContainer() + => SearchContainer = new SearchContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + }; + + public SettingsSectionsContainer() + { + HeaderBackground = new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both + }; + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + // no null check because the usage of this class is strict + HeaderBackground.Alpha = -ExpandableHeader.Y / ExpandableHeader.LayoutSize.Y * 0.5f; + } + } + } +} diff --git a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs index 08f8f867fd..79942012f9 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Toolbar } [BackgroundDependencyLoader(true)] - private void load(MainSettings settings) + private void load(SettingsOverlay settings) { StateContainer = settings; } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 21fc53be6e..788cad3bad 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -20,6 +20,7 @@ using osu.Game.Screens.Multi; using osu.Game.Screens.Select; using osu.Game.Screens.Tournament; using osu.Framework.Platform; +using osu.Game.Overlays; namespace osu.Game.Screens.Menu { @@ -45,7 +46,7 @@ namespace osu.Game.Screens.Menu protected override BackgroundScreen CreateBackground() => background; [BackgroundDependencyLoader(true)] - private void load(OsuGame game = null) + private void load(DirectOverlay direct, SettingsOverlay settings) { if (host.CanExit) AddInternal(new ExitConfirmOverlay { Action = this.Exit }); @@ -86,11 +87,8 @@ namespace osu.Game.Screens.Menu } }; - if (game != null) - { - buttons.OnSettings = game.ToggleSettings; - buttons.OnDirect = game.ToggleDirect; - } + buttons.OnSettings = () => settings?.ToggleVisibility(); + buttons.OnDirect = () => direct?.ToggleVisibility(); LoadComponentAsync(background = new BackgroundScreenDefault()); preloadSongSelect(); diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index d01fba7d39..de3077c025 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osuTK; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -66,13 +67,11 @@ namespace osu.Game.Storyboards.Drawables [BackgroundDependencyLoader] private void load(IBindable beatmap, TextureStore textureStore) { - var basePath = Animation.Path.ToLowerInvariant(); - for (var frame = 0; frame < Animation.FrameCount; frame++) { - var framePath = basePath.Replace(".", frame + "."); + var framePath = Animation.Path.Replace(".", frame + "."); - var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.ToLowerInvariant() == framePath)?.FileInfo.StoragePath; + var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(framePath, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath; if (path == null) continue; diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index 604260a38c..5f1f5ddacb 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osuTK; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -65,8 +66,7 @@ namespace osu.Game.Storyboards.Drawables [BackgroundDependencyLoader] private void load(IBindable beatmap, TextureStore textureStore) { - var spritePath = Sprite.Path.ToLowerInvariant(); - var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.ToLowerInvariant() == spritePath)?.FileInfo.StoragePath; + var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.Equals(Sprite.Path, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath; if (path == null) return;