From ce8b2c1e379de69697ca880a24be662ae726a120 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Mon, 17 May 2021 01:08:02 +0700 Subject: [PATCH 01/93] add WikiMarkdownContainer --- .../Wiki/Markdown/WikiMarkdownContainer.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs new file mode 100644 index 0000000000..ac128d79dc --- /dev/null +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Graphics.Containers.Markdown; + +namespace osu.Game.Overlays.Wiki.Markdown +{ + public class WikiMarkdownContainer : OsuMarkdownContainer + { + public string CurrentPath + { + set => Schedule(() => DocumentUrl += $"wiki/{value}"); + } + } +} From a38c33841a8b4cb46f07acc16ad5bdc79b635a58 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 16:30:41 +0700 Subject: [PATCH 02/93] add test scene wiki container --- .../Online/TestSceneWikiMarkdownContainer.cs | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs new file mode 100644 index 0000000000..fd4c2e2372 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Overlays; +using osu.Game.Overlays.Wiki.Markdown; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneWikiMarkdownContainer : OsuTestScene + { + private WikiMarkdownContainer markdownContainer; + + [Cached] + private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); + + [SetUp] + public void Setup() => Schedule(() => + { + Children = new Drawable[] + { + new Box + { + Colour = overlayColour.Background5, + RelativeSizeAxes = Axes.Both, + }, + new BasicScrollContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(20), + Child = markdownContainer = new WikiMarkdownContainer() + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + } + }; + }); + + [Test] + public void TestLink() + { + AddStep("set current path", () => markdownContainer.CurrentPath = "Article_styling_criteria/"); + + AddStep("set '/wiki/Main_Page''", () => markdownContainer.Text = "[wiki main page](/wiki/Main_Page)"); + + AddStep("set '../FAQ''", () => markdownContainer.Text = "[FAQ](../FAQ)"); + + AddStep("set './Writing''", () => markdownContainer.Text = "[wiki writing guidline](./Writing)"); + + AddStep("set 'Formatting''", () => markdownContainer.Text = "[wiki formatting guidline](Formatting)"); + } + } +} From 98af998978c7f128733cda2dc97db0694a64fd10 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 25 May 2021 09:56:26 +0700 Subject: [PATCH 03/93] add test markdown class --- .../Online/TestSceneWikiMarkdownContainer.cs | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index fd4c2e2372..993525e7db 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -1,11 +1,15 @@ // 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 Markdig.Syntax.Inlines; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Containers.Markdown; using osu.Game.Overlays; using osu.Game.Overlays.Wiki.Markdown; @@ -13,7 +17,7 @@ namespace osu.Game.Tests.Visual.Online { public class TestSceneWikiMarkdownContainer : OsuTestScene { - private WikiMarkdownContainer markdownContainer; + private TestMarkdownContainer markdownContainer; [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); @@ -32,7 +36,7 @@ public void Setup() => Schedule(() => { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(20), - Child = markdownContainer = new WikiMarkdownContainer() + Child = markdownContainer = new TestMarkdownContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -54,5 +58,27 @@ public void TestLink() AddStep("set 'Formatting''", () => markdownContainer.Text = "[wiki formatting guidline](Formatting)"); } + + private class TestMarkdownContainer : WikiMarkdownContainer + { + public LinkInline Link; + + public override MarkdownTextFlowContainer CreateTextFlow() => new TestMarkdownTextFlowContainer + { + UrlAdded = link => Link = link, + }; + + private class TestMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer + { + public Action UrlAdded; + + protected override void AddLinkText(string text, LinkInline linkInline) + { + base.AddLinkText(text, linkInline); + + UrlAdded?.Invoke(linkInline); + } + } + } } } From 5c1c43dea395211307b848bfa3dbdd218289814b Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 25 May 2021 10:44:22 +0700 Subject: [PATCH 04/93] add link assert --- .../Visual/Online/TestSceneWikiMarkdownContainer.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 993525e7db..cadf876094 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers.Markdown; +using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Overlays.Wiki.Markdown; @@ -22,6 +23,9 @@ public class TestSceneWikiMarkdownContainer : OsuTestScene [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); + [Cached] + private readonly IAPIProvider api = new DummyAPIAccess(); + [SetUp] public void Setup() => Schedule(() => { @@ -51,12 +55,16 @@ public void TestLink() AddStep("set current path", () => markdownContainer.CurrentPath = "Article_styling_criteria/"); AddStep("set '/wiki/Main_Page''", () => markdownContainer.Text = "[wiki main page](/wiki/Main_Page)"); + AddAssert("check url", () => markdownContainer.Link.Url == $"{api.WebsiteRootUrl}/wiki/Main_Page"); AddStep("set '../FAQ''", () => markdownContainer.Text = "[FAQ](../FAQ)"); + AddAssert("check url", () => markdownContainer.Link.Url == $"{api.WebsiteRootUrl}/wiki/FAQ"); AddStep("set './Writing''", () => markdownContainer.Text = "[wiki writing guidline](./Writing)"); + AddAssert("check url", () => markdownContainer.Link.Url == $"{api.WebsiteRootUrl}/wiki/Article_styling_criteria/Writing"); AddStep("set 'Formatting''", () => markdownContainer.Text = "[wiki formatting guidline](Formatting)"); + AddAssert("check url", () => markdownContainer.Link.Url == $"{api.WebsiteRootUrl}/wiki/Article_styling_criteria/Formatting"); } private class TestMarkdownContainer : WikiMarkdownContainer From 292f314feeba625149aa30b639503ca794b2a67f Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 16:04:08 +0700 Subject: [PATCH 05/93] initial wiki notice container --- .../Wiki/Markdown/WikiMarkdownContainer.cs | 19 +++++++++++++++++++ .../Wiki/Markdown/WikiNoticeContainer.cs | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index ac128d79dc..3dfb9828cf 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -1,6 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using Markdig.Extensions.Yaml; +using Markdig.Syntax; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers.Markdown; namespace osu.Game.Overlays.Wiki.Markdown @@ -11,5 +14,21 @@ public string CurrentPath { set => Schedule(() => DocumentUrl += $"wiki/{value}"); } + + protected override void AddMarkdownComponent(IMarkdownObject markdownObject, FillFlowContainer container, int level) + { + switch (markdownObject) + { + case YamlFrontMatterBlock yamlFrontMatterBlock: + container.Add(CreateNotice(yamlFrontMatterBlock)); + break; + + default: + base.AddMarkdownComponent(markdownObject, container, level); + break; + } + } + + protected virtual FillFlowContainer CreateNotice(YamlFrontMatterBlock yamlFrontMatterBlock) => new WikiNoticeContainer(yamlFrontMatterBlock); } } diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs new file mode 100644 index 0000000000..e42834cea7 --- /dev/null +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig.Extensions.Yaml; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Overlays.Wiki.Markdown +{ + public class WikiNoticeContainer : FillFlowContainer + { + public WikiNoticeContainer(YamlFrontMatterBlock yamlFrontMatterBlock) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + } + } +} From 8f1b48d766ad31253a3a105c832120516d488b58 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 17:29:48 +0700 Subject: [PATCH 06/93] add test for notice box --- .../Online/TestSceneWikiMarkdownContainer.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index cadf876094..018e1bf9f1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -67,6 +67,40 @@ public void TestLink() AddAssert("check url", () => markdownContainer.Link.Url == $"{api.WebsiteRootUrl}/wiki/Article_styling_criteria/Formatting"); } + [Test] + public void TestOutdatedNoticeBox() + { + AddStep("Add outdated yaml header", () => + { + markdownContainer.Text = @"--- +outdated: true +---"; + }); + } + + [Test] + public void TestNeedsCleanupNoticeBox() + { + AddStep("Add needs cleanup yaml header", () => + { + markdownContainer.Text = @"--- +needs_cleanup: true +---"; + }); + } + + [Test] + public void TestOnlyShowOutdatedNoticeBox() + { + AddStep("Add outdated and needs cleanup yaml", () => + { + markdownContainer.Text = @"--- +outdated: true +needs_cleanup: true +---"; + }); + } + private class TestMarkdownContainer : WikiMarkdownContainer { public LinkInline Link; From b3eff65a0cf70742e9dca2dae768015b988b06e5 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 16:05:37 +0700 Subject: [PATCH 07/93] parse isOutdated and needsCleanup --- .../Wiki/Markdown/WikiNoticeContainer.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs index e42834cea7..3070d20798 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -9,11 +9,28 @@ namespace osu.Game.Overlays.Wiki.Markdown { public class WikiNoticeContainer : FillFlowContainer { + private readonly bool isOutdated; + private readonly bool needsCleanup; + public WikiNoticeContainer(YamlFrontMatterBlock yamlFrontMatterBlock) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Direction = FillDirection.Vertical; + + foreach (var line in yamlFrontMatterBlock.Lines) + { + switch (line.ToString()) + { + case "outdated: true": + isOutdated = true; + break; + + case "needs_cleanup: true": + needsCleanup = true; + break; + } + } } } } From e23ea00197ff7eb0c6d2e719aa7f54b3c5625025 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 16:06:43 +0700 Subject: [PATCH 08/93] add notice box --- .../Wiki/Markdown/WikiNoticeContainer.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs index 3070d20798..f2821d14eb 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -2,8 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using Markdig.Extensions.Yaml; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; namespace osu.Game.Overlays.Wiki.Markdown { @@ -32,5 +36,41 @@ public WikiNoticeContainer(YamlFrontMatterBlock yamlFrontMatterBlock) } } } + + private class NoticeBox : Container + { + [Resolved] + private IMarkdownTextFlowComponent parentFlowComponent { get; set; } + + public string Text { get; set; } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider, OsuColour colour) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + MarkdownTextFlowContainer textFlow; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4, + }, + textFlow = parentFlowComponent.CreateTextFlow().With(t => + { + t.Colour = colour.Orange1; + t.Padding = new MarginPadding + { + Vertical = 10, + Horizontal = 15, + }; + }) + }; + + textFlow.AddText(Text); + } + } } } From 7a8a37f4a0e6536fdd659e447e820a37e746937a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 21 May 2021 16:08:30 +0700 Subject: [PATCH 09/93] load notice box --- .../Wiki/Markdown/WikiNoticeContainer.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs index f2821d14eb..421806eea8 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -37,6 +37,27 @@ public WikiNoticeContainer(YamlFrontMatterBlock yamlFrontMatterBlock) } } + [BackgroundDependencyLoader] + private void load() + { + // Reference : https://github.com/ppy/osu-web/blob/master/resources/views/wiki/_notice.blade.php and https://github.com/ppy/osu-web/blob/master/resources/lang/en/wiki.php + // TODO : add notice box for fallback translation, legal translation and outdated translation after implement wiki locale in the future. + if (isOutdated) + { + Add(new NoticeBox + { + Text = "The content on this page is incomplete or outdated. If you are able to help out, please consider updating the article!", + }); + } + else if (needsCleanup) + { + Add(new NoticeBox + { + Text = "This page does not meet the standards of the osu! wiki and needs to be cleaned up or rewritten. If you are able to help out, please consider updating the article!", + }); + } + } + private class NoticeBox : Container { [Resolved] From 6585dd3a3e7eea2d7db371111b92a63434cab84a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 16:30:41 +0700 Subject: [PATCH 10/93] add image test --- .../Online/TestSceneWikiMarkdownContainer.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 018e1bf9f1..3731e7a782 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -101,6 +101,25 @@ public void TestOnlyShowOutdatedNoticeBox() }); } + [Test] + public void TestAbsoluteImage() + { + AddStep("Add absolute image", () => + { + markdownContainer.Text = "![intro](/wiki/Interface/img/intro-screen.jpg)"; + }); + } + + [Test] + public void TestRelativeImage() + { + AddStep("Add relative image", () => + { + markdownContainer.CurrentPath = "Interface/"; + markdownContainer.Text = "![intro](img/intro-screen.jpg)"; + }); + } + private class TestMarkdownContainer : WikiMarkdownContainer { public LinkInline Link; From ef707bd09951b88a39f75ce889cd0524f78c3e5a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 2 May 2021 22:02:06 +0700 Subject: [PATCH 11/93] add WikiMarkdownImage --- .../Wiki/Markdown/WikiMarkdownContainer.cs | 3 ++ .../Wiki/Markdown/WikiMarkdownImage.cs | 38 +++++++++++++++++++ .../Markdown/WikiMarkdownTextFlowContainer.cs | 13 +++++++ 3 files changed, 54 insertions(+) create mode 100644 osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs create mode 100644 osu.Game/Overlays/Wiki/Markdown/WikiMarkdownTextFlowContainer.cs diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index 3dfb9828cf..994bab7d04 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -4,6 +4,7 @@ using Markdig.Extensions.Yaml; using Markdig.Syntax; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics.Containers.Markdown; namespace osu.Game.Overlays.Wiki.Markdown @@ -29,6 +30,8 @@ protected override void AddMarkdownComponent(IMarkdownObject markdownObject, Fil } } + public override MarkdownTextFlowContainer CreateTextFlow() => new WikiMarkdownTextFlowContainer(); + protected virtual FillFlowContainer CreateNotice(YamlFrontMatterBlock yamlFrontMatterBlock) => new WikiNoticeContainer(yamlFrontMatterBlock); } } diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs new file mode 100644 index 0000000000..361aa2e95f --- /dev/null +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig.Syntax.Inlines; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Framework.Graphics.Cursor; +using osu.Game.Online.API; + +namespace osu.Game.Overlays.Wiki.Markdown +{ + public class WikiMarkdownImage : MarkdownImage, IHasTooltip + { + private readonly string url; + + public string TooltipText { get; } + + public WikiMarkdownImage(LinkInline linkInline) + : base(linkInline.Url) + { + url = linkInline.Url; + TooltipText = linkInline.Title; + } + + [BackgroundDependencyLoader] + private void load(IAPIProvider api) + { + // The idea is replace "{api.WebsiteRootUrl}/wiki/{path-to-image}" to "{api.WebsiteRootUrl}/wiki/images/{path-to-image}" + // "/wiki/images/*" is route to fetch wiki image from osu!web server (see: https://github.com/ppy/osu-web/blob/4205eb66a4da86bdee7835045e4bf28c35456e04/routes/web.php#L289) + // Currently all image in dev server (https://dev.ppy.sh/wiki/image/*) is 404 + // So for now just replace "{api.WebsiteRootUrl}/wiki/*" to "https://osu.ppy.sh/wiki/images/*" for simplicity + var imageUrl = url.Replace($"{api.WebsiteRootUrl}/wiki", "https://osu.ppy.sh/wiki/images"); + + InternalChild = new DelayedLoadWrapper(CreateImageContainer(imageUrl)); + } + } +} diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownTextFlowContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownTextFlowContainer.cs new file mode 100644 index 0000000000..1c2b37a219 --- /dev/null +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownTextFlowContainer.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig.Syntax.Inlines; +using osu.Game.Graphics.Containers.Markdown; + +namespace osu.Game.Overlays.Wiki.Markdown +{ + public class WikiMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer + { + protected override void AddImage(LinkInline linkInline) => AddDrawable(new WikiMarkdownImage(linkInline)); + } +} From b78ec8307df7880f518626bf24160ece2d6dbd12 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 2 May 2021 22:22:22 +0700 Subject: [PATCH 12/93] add markdown paragraph with image block --- .../Wiki/Markdown/WikiMarkdownContainer.cs | 2 + .../Wiki/Markdown/WikiMarkdownParagraph.cs | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 osu.Game/Overlays/Wiki/Markdown/WikiMarkdownParagraph.cs diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index 994bab7d04..81115293d4 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -32,6 +32,8 @@ protected override void AddMarkdownComponent(IMarkdownObject markdownObject, Fil public override MarkdownTextFlowContainer CreateTextFlow() => new WikiMarkdownTextFlowContainer(); + protected override MarkdownParagraph CreateParagraph(ParagraphBlock paragraphBlock, int level) => new WikiMarkdownParagraph(paragraphBlock); + protected virtual FillFlowContainer CreateNotice(YamlFrontMatterBlock yamlFrontMatterBlock) => new WikiNoticeContainer(yamlFrontMatterBlock); } } diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownParagraph.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownParagraph.cs new file mode 100644 index 0000000000..4a7ce24aba --- /dev/null +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownParagraph.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers.Markdown; +using osuTK; + +namespace osu.Game.Overlays.Wiki.Markdown +{ + public class WikiMarkdownParagraph : MarkdownParagraph + { + private readonly ParagraphBlock paragraphBlock; + + public WikiMarkdownParagraph(ParagraphBlock paragraphBlock) + : base(paragraphBlock) + { + this.paragraphBlock = paragraphBlock; + } + + [BackgroundDependencyLoader] + private void load() + { + MarkdownTextFlowContainer textFlow; + InternalChild = textFlow = CreateTextFlow(); + textFlow.AddInlineText(paragraphBlock.Inline); + + // Check if paragraph only contains an image. + if (paragraphBlock.Inline.Count() == 1 && paragraphBlock.Inline.FirstChild is LinkInline { IsImage: true } linkInline) + { + textFlow.TextAnchor = Anchor.TopCentre; + textFlow.Spacing = new Vector2(0, 5); + textFlow.AddText($"\n{linkInline.Title}"); + } + } + } +} From 075350e12572188f25d5a8b02fedf1a9edf73f83 Mon Sep 17 00:00:00 2001 From: Ibby Date: Sun, 9 May 2021 15:51:17 +1000 Subject: [PATCH 13/93] Adding a reset button to individual keybinds --- .../Settings/TestSceneKeyBindingPanel.cs | 40 +++++++++++++++++++ osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 28 +++++++++++++ 2 files changed, 68 insertions(+) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index f495e0fb23..75bbd8f86c 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -104,6 +104,46 @@ void clickClearButton() } } + [Test] + public void TestSingleBindResetButton() + { + KeyBindingRow multiBindingRow = null; + + AddStep("click first row with two bindings", () => + { + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + InputManager.MoveMouseTo(multiBindingRow); + InputManager.Click(MouseButton.Left); + }); + + clickSingleBindResetButton(); + + AddAssert("first binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); + + AddStep("click second binding", () => + { + var target = multiBindingRow.ChildrenOfType().ElementAt(1); + + InputManager.MoveMouseTo(target); + InputManager.Click(MouseButton.Left); + }); + + clickSingleBindResetButton(); + + AddAssert("second binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); + + void clickSingleBindResetButton() + { + AddStep("click reset button for single binding", () => + { + var clearButton = multiBindingRow.ChildrenOfType().Single(); + + InputManager.MoveMouseTo(clearButton); + InputManager.Click(MouseButton.Left); + }); + } + } + [Test] public void TestClickRowSelectsFirstBinding() { diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 300fce962a..1fbaa374d4 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -109,6 +109,7 @@ private void load(OsuColour colours) Children = new Drawable[] { new CancelButton { Action = finalise }, + new SingleBindResetButton { Action = singleBindReset }, new ClearButton { Action = clear }, }, } @@ -281,6 +282,15 @@ private void clear() finalise(); } + private void singleBindReset() + { + if (bindTarget == null) + return; + + bindTarget.UpdateKeyCombination(Defaults.ElementAt(buttons.IndexOf(bindTarget))); + finalise(); + } + private void finalise() { if (bindTarget != null) @@ -339,6 +349,24 @@ public CancelButton() } } + public class SingleBindResetButton : TriangleButton + { + public SingleBindResetButton() + { + Text = "Reset"; + Size = new Vector2(80, 20); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Green; + + Triangles.ColourDark = colours.GreenDark; + Triangles.ColourLight = colours.GreenLight; + } + } + public class ClearButton : TriangleButton { public ClearButton() From 1a465c60ca54ea5f386bab902b62df12f512ac34 Mon Sep 17 00:00:00 2001 From: Swords Date: Sun, 9 May 2021 16:07:18 +1000 Subject: [PATCH 14/93] Rename Tests --- osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 75bbd8f86c..41b65e84b6 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -105,7 +105,7 @@ void clickClearButton() } [Test] - public void TestSingleBindResetButton() + public void TestResetButtonOnBindings() { KeyBindingRow multiBindingRow = null; From 0725088fdef8cd2aef018e78c8f29f74153a860f Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 01:01:17 +1000 Subject: [PATCH 15/93] Well it works, just pretty ugly looking. --- .../Settings/TestSceneKeyBindingPanel.cs | 69 +++++++--- .../Visual/Settings/TestSceneSettingsItem.cs | 5 +- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 76 ++++++----- .../KeyBinding/KeyBindingsSubsection.cs | 13 +- .../KeyBinding/SettingsKeyBindingRow.cs | 70 +++++++++++ .../Overlays/RestoreDefaultValueButton.cs | 119 ++++++++++++++++++ osu.Game/Overlays/Settings/SettingsItem.cs | 103 +-------------- 7 files changed, 299 insertions(+), 156 deletions(-) create mode 100644 osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs create mode 100644 osu.Game/Overlays/RestoreDefaultValueButton.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 41b65e84b6..09c8696ee0 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Linq; using NUnit.Framework; +using osu.Framework.Input.Bindings; using osu.Framework.Testing; using osu.Framework.Threading; using osu.Game.Overlays; @@ -31,13 +32,16 @@ protected override void LoadComplete() [Test] public void TestClickTwiceOnClearButton() { + SettingsKeyBindingRow firstSettingRow = null; KeyBindingRow firstRow = null; AddStep("click first row", () => { - firstRow = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(firstRow); + firstSettingRow = panel.ChildrenOfType().First(); + InputManager.MoveMouseTo(firstSettingRow); InputManager.Click(MouseButton.Left); + + firstRow = firstSettingRow.KeyBindingRow; }); AddStep("schedule button clicks", () => @@ -71,7 +75,7 @@ public void TestClearButtonOnBindings() AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).KeyBindingRow; InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); @@ -105,38 +109,67 @@ void clickClearButton() } [Test] - public void TestResetButtonOnBindings() + public void TestSingleBindResetButton() { + SettingsKeyBindingRow multiSettingsBindingRow = null; KeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { + multiSettingsBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); + InputManager.PressKey(Key.P); + InputManager.ReleaseKey(Key.P); }); + AddUntilStep("restore button shown", () => multiSettingsBindingRow.ChildrenOfType>().First().Alpha > 0); + clickSingleBindResetButton(); AddAssert("first binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); - - AddStep("click second binding", () => - { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); - - InputManager.MoveMouseTo(target); - InputManager.Click(MouseButton.Left); - }); - - clickSingleBindResetButton(); - AddAssert("second binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); + AddUntilStep("restore button hidden", () => multiSettingsBindingRow.ChildrenOfType>().First().Alpha == 0); + void clickSingleBindResetButton() { - AddStep("click reset button for single binding", () => + AddStep("click reset button for bindings", () => { - var clearButton = multiBindingRow.ChildrenOfType().Single(); + var clearButton = multiSettingsBindingRow.ChildrenOfType>().Single(); + + InputManager.MoveMouseTo(clearButton); + InputManager.Click(MouseButton.Left); + }); + } + } + + [Test] + public void TestResetAllBindingsButton() + { + SettingsKeyBindingRow multiSettingsBindingRow = null; + KeyBindingRow multiBindingRow = null; + + AddStep("click first row and press p", () => + { + multiSettingsBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(); + InputManager.MoveMouseTo(multiBindingRow); + InputManager.Click(MouseButton.Left); + InputManager.PressKey(Key.P); + InputManager.ReleaseKey(Key.P); + }); + + clickResetAllBindingsButton(); + + AddAssert("bindings cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); + + void clickResetAllBindingsButton() + { + AddStep("click reset button for all bindings", () => + { + var clearButton = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(clearButton); InputManager.Click(MouseButton.Left); @@ -176,4 +209,4 @@ public void TestClickRowSelectsFirstBinding() AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); } } -} +} \ No newline at end of file diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs index 8f1c17ed29..f63145f534 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Overlays.Settings; +using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Settings { @@ -37,7 +38,7 @@ public void TestRestoreDefaultValueButtonVisibility() private class TestSettingsTextBox : SettingsTextBox { - public new Drawable RestoreDefaultValueButton => this.ChildrenOfType().Single(); + public Drawable RestoreDefaultValueButton => this.ChildrenOfType>().Single(); } } -} +} \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 1fbaa374d4..4d2738f244 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -4,12 +4,14 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; @@ -22,7 +24,7 @@ namespace osu.Game.Overlays.KeyBinding { - public class KeyBindingRow : Container, IFilterable + public class KeyBindingRow : Container, IFilterable, IHasCurrentValue { private readonly object action; private readonly IEnumerable bindings; @@ -51,6 +53,13 @@ public bool MatchingFilter private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; + private BindableWithCurrent isKeysDefaultValue; + public Bindable Current + { + get => isKeysDefaultValue.Current; + set => isKeysDefaultValue.Current = value; + } + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); public KeyBindingRow(object action, IEnumerable bindings) @@ -58,6 +67,11 @@ public KeyBindingRow(object action, IEnumerable() + { + Default = true + }; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -71,6 +85,17 @@ public KeyBindingRow(object action, IEnumerable b.KeyCombination).SequenceEqual(Defaults); + isKeysDefaultValue.BindValueChanged(resetButtons => + { + if (resetButtons.NewValue != resetButtons.OldValue && resetButtons.NewValue && !bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults)) + { + RestoreDefaults(); + finalise(); + } + }); + EdgeEffect = new EdgeEffectParameters { Radius = 2, @@ -109,7 +134,6 @@ private void load(OsuColour colours) Children = new Drawable[] { new CancelButton { Action = finalise }, - new SingleBindResetButton { Action = singleBindReset }, new ClearButton { Action = clear }, }, } @@ -129,6 +153,8 @@ public void RestoreDefaults() button.UpdateKeyCombination(d); store.Update(button.KeyBinding); } + + isKeysDefaultValue.Value = true; } protected override bool OnHover(HoverEvent e) @@ -282,21 +308,29 @@ private void clear() finalise(); } - private void singleBindReset() - { - if (bindTarget == null) - return; - - bindTarget.UpdateKeyCombination(Defaults.ElementAt(buttons.IndexOf(bindTarget))); - finalise(); - } - private void finalise() { if (bindTarget != null) { store.Update(bindTarget.KeyBinding); + KeyCombination keyDefault = Defaults.ElementAt(buttons.IndexOf(bindTarget)); + if (isKeysDefaultValue.Value) + { + if (!keyDefault.Equals(bindTarget.KeyBinding.KeyCombination)) + { + isKeysDefaultValue.Value = false; + } + } + else + { + if (keyDefault.Equals(bindTarget.KeyBinding.KeyCombination) && + buttons.Select(b => b.KeyBinding.KeyCombination).SequenceEqual(Defaults)) + { + isKeysDefaultValue.Value = true; + } + } + bindTarget.IsBinding = false; Schedule(() => { @@ -349,24 +383,6 @@ public CancelButton() } } - public class SingleBindResetButton : TriangleButton - { - public SingleBindResetButton() - { - Text = "Reset"; - Size = new Vector2(80, 20); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - BackgroundColour = colours.Green; - - Triangles.ColourDark = colours.GreenDark; - Triangles.ColourLight = colours.GreenLight; - } - } - public class ClearButton : TriangleButton { public ClearButton() @@ -487,4 +503,4 @@ public void UpdateKeyCombination(KeyCombination newCombination) } } } -} +} \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index d784b7aec9..d130a3f536 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -1,17 +1,20 @@ // 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 osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Overlays.Settings; using osu.Game.Rulesets; using osuTK; using osu.Game.Graphics; +using osu.Framework.Input.Bindings; namespace osu.Game.Overlays.KeyBinding { @@ -41,16 +44,12 @@ private void load(KeyBindingStore store) int intKey = (int)defaultGroup.Key; // one row per valid action. - Add(new KeyBindingRow(defaultGroup.Key, bindings.Where(b => ((int)b.Action).Equals(intKey))) - { - AllowMainMouseButtons = Ruleset != null, - Defaults = defaultGroup.Select(d => d.KeyCombination) - }); + Add(new SettingsKeyBindingRow(defaultGroup, bindings, Ruleset)); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) }); } } @@ -72,4 +71,4 @@ private void load(OsuColour colours) Triangles.ColourLight = colours.Pink; } } -} +} \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs new file mode 100644 index 0000000000..da8a628b51 --- /dev/null +++ b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs @@ -0,0 +1,70 @@ +// 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.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets; + +namespace osu.Game.Overlays.KeyBinding +{ + public class SettingsKeyBindingRow : Container, IFilterable + { + private readonly IGrouping defaultGroup; + private readonly IEnumerable bindings; + public readonly KeyBindingRow KeyBindingRow; + + private bool matchingFilter; + + public bool MatchingFilter + { + get => matchingFilter; + set + { + matchingFilter = value; + this.FadeTo(!matchingFilter ? 0 : 1); + } + } + + public bool FilteringActive { get; set; } + + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(defaultGroup.Key.ToString()); + + public SettingsKeyBindingRow( + IGrouping defaultGroup, + IEnumerable bindings, + RulesetInfo ruleset) + { + this.defaultGroup = defaultGroup; + this.bindings = bindings; + + KeyBindingRow = new KeyBindingRow(defaultGroup.Key, bindings.Where(b => ((int)b.Action).Equals((int)defaultGroup.Key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaultGroup.Select(d => d.KeyCombination) + }; + + + RestoreDefaultValueButton restoreDefaultButton; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; + + InternalChildren = new Drawable[] + { + restoreDefaultButton = new RestoreDefaultValueButton(), + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, + Child = KeyBindingRow + }, + }; + + restoreDefaultButton.Bindable = KeyBindingRow.Current; + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs new file mode 100644 index 0000000000..6d6616a893 --- /dev/null +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -0,0 +1,119 @@ +// 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.Bindables; +using osuTK.Graphics; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osuTK; + +namespace osu.Game.Overlays +{ + public class RestoreDefaultValueButton : Container, IHasTooltip + { + public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; + + private Bindable bindable; + + public Bindable Bindable + { + get => bindable; + set + { + bindable = value; + bindable.ValueChanged += _ => UpdateState(); + bindable.DisabledChanged += _ => UpdateState(); + bindable.DefaultChanged += _ => UpdateState(); + UpdateState(); + } + } + + private Color4 buttonColour; + + private bool hovering; + + public RestoreDefaultValueButton() + { + RelativeSizeAxes = Axes.Y; + Width = SettingsPanel.CONTENT_MARGINS; + Alpha = 0f; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + buttonColour = colour.Yellow; + + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + CornerRadius = 3, + Masking = true, + Colour = buttonColour, + EdgeEffect = new EdgeEffectParameters + { + Colour = buttonColour.Opacity(0.1f), + Type = EdgeEffectType.Glow, + Radius = 2, + }, + Size = new Vector2(0.33f, 0.8f), + Child = new Box { RelativeSizeAxes = Axes.Both }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + UpdateState(); + } + + public string TooltipText => "revert to default"; + + protected override bool OnClick(ClickEvent e) + { + if (bindable != null && !bindable.Disabled) + bindable.SetDefault(); + return true; + } + + protected override bool OnHover(HoverEvent e) + { + hovering = true; + UpdateState(); + return false; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + hovering = false; + UpdateState(); + } + + public void SetButtonColour(Color4 buttonColour) + { + this.buttonColour = buttonColour; + UpdateState(); + } + + public void UpdateState() => Scheduler.AddOnce(updateState); + + private void updateState() + { + if (bindable == null) + return; + + this.FadeTo(bindable.IsDefault ? 0f : + hovering && !bindable.Disabled ? 1f : 0.65f, 200, Easing.OutQuint); + this.FadeColour(bindable.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 86a836d29b..7677931fde 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -108,7 +108,8 @@ public bool MatchingFilter protected SettingsItem() { - RestoreDefaultValueButton restoreDefaultButton; + + RestoreDefaultValueButton restoreDefaultButton; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -116,7 +117,7 @@ protected SettingsItem() InternalChildren = new Drawable[] { - restoreDefaultButton = new RestoreDefaultValueButton(), + restoreDefaultButton = new RestoreDefaultValueButton(), FlowContent = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -146,101 +147,5 @@ private void updateDisabled() if (labelText != null) labelText.Alpha = controlWithCurrent.Current.Disabled ? 0.3f : 1; } - - protected internal class RestoreDefaultValueButton : Container, IHasTooltip - { - public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; - - private Bindable bindable; - - public Bindable Bindable - { - get => bindable; - set - { - bindable = value; - bindable.ValueChanged += _ => UpdateState(); - bindable.DisabledChanged += _ => UpdateState(); - bindable.DefaultChanged += _ => UpdateState(); - UpdateState(); - } - } - - private Color4 buttonColour; - - private bool hovering; - - public RestoreDefaultValueButton() - { - RelativeSizeAxes = Axes.Y; - Width = SettingsPanel.CONTENT_MARGINS; - Padding = new MarginPadding { Vertical = 1.5f }; - Alpha = 0f; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colour) - { - buttonColour = colour.Yellow; - - Child = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - CornerRadius = 3, - Masking = true, - Colour = buttonColour, - EdgeEffect = new EdgeEffectParameters - { - Colour = buttonColour.Opacity(0.1f), - Type = EdgeEffectType.Glow, - Radius = 2, - }, - Width = 0.33f, - Child = new Box { RelativeSizeAxes = Axes.Both }, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - UpdateState(); - } - - public string TooltipText => "revert to default"; - - protected override bool OnClick(ClickEvent e) - { - if (bindable != null && !bindable.Disabled) - bindable.SetDefault(); - return true; - } - - protected override bool OnHover(HoverEvent e) - { - hovering = true; - UpdateState(); - return false; - } - - protected override void OnHoverLost(HoverLostEvent e) - { - hovering = false; - UpdateState(); - } - - public void UpdateState() => Scheduler.AddOnce(updateState); - - private void updateState() - { - if (bindable == null) - return; - - this.FadeTo(bindable.IsDefault ? 0f : - hovering && !bindable.Disabled ? 1f : 0.65f, 200, Easing.OutQuint); - this.FadeColour(bindable.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); - } - } } -} +} \ No newline at end of file From 753bdf208385285eb8ce24213365ddb74299a290 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 01:04:15 +1000 Subject: [PATCH 16/93] Fixed formatting --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 1 - osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs | 1 - osu.Game/Overlays/Settings/SettingsItem.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 4d2738f244..eeb9a5f7ec 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -85,7 +85,6 @@ public KeyBindingRow(object action, IEnumerable b.KeyCombination).SequenceEqual(Defaults); isKeysDefaultValue.BindValueChanged(resetButtons => { diff --git a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs index da8a628b51..15392efc9a 100644 --- a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs @@ -45,7 +45,6 @@ public SettingsKeyBindingRow( Defaults = defaultGroup.Select(d => d.KeyCombination) }; - RestoreDefaultValueButton restoreDefaultButton; RelativeSizeAxes = Axes.X; diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 7677931fde..57d1549910 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -108,7 +108,6 @@ public bool MatchingFilter protected SettingsItem() { - RestoreDefaultValueButton restoreDefaultButton; RelativeSizeAxes = Axes.X; From 1603b92211a478846e8db583747fb66826034ceb Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 01:30:54 +1000 Subject: [PATCH 17/93] Reformatting --- .../Settings/TestSceneKeyBindingPanel.cs | 19 +++++++------------ osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 6 ++++-- .../KeyBinding/KeyBindingsSubsection.cs | 5 ----- osu.Game/Overlays/Settings/SettingsItem.cs | 5 ----- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 09c8696ee0..9126808c88 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Linq; using NUnit.Framework; -using osu.Framework.Input.Bindings; using osu.Framework.Testing; using osu.Framework.Threading; using osu.Game.Overlays; @@ -32,16 +31,14 @@ protected override void LoadComplete() [Test] public void TestClickTwiceOnClearButton() { - SettingsKeyBindingRow firstSettingRow = null; KeyBindingRow firstRow = null; AddStep("click first row", () => { - firstSettingRow = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(firstSettingRow); + InputManager.MoveMouseTo(panel.ChildrenOfType().First()); InputManager.Click(MouseButton.Left); - firstRow = firstSettingRow.KeyBindingRow; + firstRow = panel.ChildrenOfType().First().KeyBindingRow; }); AddStep("schedule button clicks", () => @@ -111,12 +108,10 @@ void clickClearButton() [Test] public void TestSingleBindResetButton() { - SettingsKeyBindingRow multiSettingsBindingRow = null; KeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiSettingsBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); @@ -124,20 +119,20 @@ public void TestSingleBindResetButton() InputManager.ReleaseKey(Key.P); }); - AddUntilStep("restore button shown", () => multiSettingsBindingRow.ChildrenOfType>().First().Alpha > 0); + AddUntilStep("restore button shown", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().First().Alpha > 0); clickSingleBindResetButton(); - AddAssert("first binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); - AddAssert("second binding cleared", () => multiBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); + AddAssert("first binding cleared", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); + AddAssert("second binding cleared", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); - AddUntilStep("restore button hidden", () => multiSettingsBindingRow.ChildrenOfType>().First().Alpha == 0); + AddUntilStep("restore button hidden", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().First().Alpha == 0); void clickSingleBindResetButton() { AddStep("click reset button for bindings", () => { - var clearButton = multiSettingsBindingRow.ChildrenOfType>().Single(); + var clearButton = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().Single(); InputManager.MoveMouseTo(clearButton); InputManager.Click(MouseButton.Left); diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index eeb9a5f7ec..3d89028f96 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -53,7 +53,8 @@ public bool MatchingFilter private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - private BindableWithCurrent isKeysDefaultValue; + private readonly BindableWithCurrent isKeysDefaultValue; + public Bindable Current { get => isKeysDefaultValue.Current; @@ -67,7 +68,7 @@ public KeyBindingRow(object action, IEnumerable() + isKeysDefaultValue = new BindableWithCurrent { Default = true }; @@ -314,6 +315,7 @@ private void finalise() store.Update(bindTarget.KeyBinding); KeyCombination keyDefault = Defaults.ElementAt(buttons.IndexOf(bindTarget)); + if (isKeysDefaultValue.Value) { if (!keyDefault.Equals(bindTarget.KeyBinding.KeyCombination)) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index d130a3f536..84630703bd 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -1,20 +1,17 @@ // 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 osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Overlays.Settings; using osu.Game.Rulesets; using osuTK; using osu.Game.Graphics; -using osu.Framework.Input.Bindings; namespace osu.Game.Overlays.KeyBinding { @@ -41,8 +38,6 @@ private void load(KeyBindingStore store) foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { - int intKey = (int)defaultGroup.Key; - // one row per valid action. Add(new SettingsKeyBindingRow(defaultGroup, bindings, Ruleset)); } diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 57d1549910..aa5cbf3d4e 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -5,16 +5,11 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osuTK.Graphics; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; From 843da30f9d0f3ae60687eef1ddb1180178585f08 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 01:52:16 +1000 Subject: [PATCH 18/93] Reformatting --- osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs | 4 +--- osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 9126808c88..cfef0ecf5a 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -143,13 +143,11 @@ void clickSingleBindResetButton() [Test] public void TestResetAllBindingsButton() { - SettingsKeyBindingRow multiSettingsBindingRow = null; KeyBindingRow multiBindingRow = null; AddStep("click first row and press p", () => { - multiSettingsBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); - multiBindingRow = panel.ChildrenOfType().First(); + multiBindingRow = panel.ChildrenOfType().First().KeyBindingRow; InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 73f4e6c371..e07e5a52c6 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -11,7 +11,6 @@ using osu.Game.Overlays.Settings; using osu.Game.Rulesets; using osuTK; -using osu.Game.Graphics; namespace osu.Game.Overlays.KeyBinding { From 304caf8bdf79aabbd588d07b907e85e32915ba8e Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 11:24:08 +1000 Subject: [PATCH 19/93] Adding Requested changed --- .../Settings/TestSceneKeyBindingPanel.cs | 67 ++++++++----------- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 32 ++------- .../KeyBinding/SettingsKeyBindingRow.cs | 6 +- .../Overlays/RestoreDefaultValueButton.cs | 33 ++++----- osu.Game/Overlays/Settings/SettingsItem.cs | 2 +- 5 files changed, 56 insertions(+), 84 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index cfef0ecf5a..669338d714 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -35,10 +35,10 @@ public void TestClickTwiceOnClearButton() AddStep("click first row", () => { - InputManager.MoveMouseTo(panel.ChildrenOfType().First()); - InputManager.Click(MouseButton.Left); + firstRow = panel.ChildrenOfType().First(); - firstRow = panel.ChildrenOfType().First().KeyBindingRow; + InputManager.MoveMouseTo(firstRow); + InputManager.Click(MouseButton.Left); }); AddStep("schedule button clicks", () => @@ -72,7 +72,7 @@ public void TestClearButtonOnBindings() AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).KeyBindingRow; + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); @@ -108,66 +108,55 @@ void clickClearButton() [Test] public void TestSingleBindResetButton() { - KeyBindingRow multiBindingRow = null; + SettingsKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); - InputManager.MoveMouseTo(multiBindingRow); + settingsKeyBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); + InputManager.MoveMouseTo(settingsKeyBindingRow.KeyBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); InputManager.ReleaseKey(Key.P); }); - AddUntilStep("restore button shown", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().First().Alpha > 0); + AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha > 0); - clickSingleBindResetButton(); - - AddAssert("first binding cleared", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); - AddAssert("second binding cleared", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(1))); - - AddUntilStep("restore button hidden", () => panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().First().Alpha == 0); - - void clickSingleBindResetButton() + AddStep("click reset button for bindings", () => { - AddStep("click reset button for bindings", () => - { - var clearButton = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1).ChildrenOfType>().Single(); + var clearButton = settingsKeyBindingRow.ChildrenOfType>().Single(); - InputManager.MoveMouseTo(clearButton); - InputManager.Click(MouseButton.Left); - }); - } + InputManager.MoveMouseTo(clearButton); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); + + AddAssert("first binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("second binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(1))); } [Test] public void TestResetAllBindingsButton() { - KeyBindingRow multiBindingRow = null; + KeyBindingRow keyBindingRow = null; AddStep("click first row and press p", () => { - multiBindingRow = panel.ChildrenOfType().First().KeyBindingRow; - InputManager.MoveMouseTo(multiBindingRow); + keyBindingRow = panel.ChildrenOfType().First(); + InputManager.MoveMouseTo(keyBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); InputManager.ReleaseKey(Key.P); }); - - clickResetAllBindingsButton(); - - AddAssert("bindings cleared", () => multiBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(multiBindingRow.Defaults.ElementAt(0))); - - void clickResetAllBindingsButton() + AddStep("click reset button for all bindings", () => { - AddStep("click reset button for all bindings", () => - { - var clearButton = panel.ChildrenOfType().First(); + var clearButton = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(clearButton); - InputManager.Click(MouseButton.Left); - }); - } + InputManager.MoveMouseTo(clearButton); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("bindings cleared", () => keyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(keyBindingRow.Defaults.ElementAt(0))); } [Test] diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 8336dae9ac..6f4c5f1179 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -53,7 +53,11 @@ public bool MatchingFilter private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - private readonly BindableWithCurrent isKeysDefaultValue; + private readonly BindableWithCurrent isKeysDefaultValue = new BindableWithCurrent + { + Default = true + }; + public Bindable Current { @@ -67,12 +71,6 @@ public KeyBindingRow(object action, IEnumerable - { - Default = true - }; - RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -89,7 +87,7 @@ private void load(OsuColour colours) isKeysDefaultValue.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); isKeysDefaultValue.BindValueChanged(resetButtons => { - if (resetButtons.NewValue != resetButtons.OldValue && resetButtons.NewValue && !bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults)) + if (resetButtons.NewValue && !bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults)) { RestoreDefaults(); finalise(); @@ -314,23 +312,7 @@ private void finalise() { store.Update(bindTarget.KeyBinding); - KeyCombination keyDefault = Defaults.ElementAt(buttons.IndexOf(bindTarget)); - - if (isKeysDefaultValue.Value) - { - if (!keyDefault.Equals(bindTarget.KeyBinding.KeyCombination)) - { - isKeysDefaultValue.Value = false; - } - } - else - { - if (keyDefault.Equals(bindTarget.KeyBinding.KeyCombination) && - buttons.Select(b => b.KeyBinding.KeyCombination).SequenceEqual(Defaults)) - { - isKeysDefaultValue.Value = true; - } - } + isKeysDefaultValue.Value = buttons.Select(b => b.KeyBinding.KeyCombination).SequenceEqual(Defaults); bindTarget.IsBinding = false; Schedule(() => diff --git a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs index 15392efc9a..31374a8120 100644 --- a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.KeyBinding public class SettingsKeyBindingRow : Container, IFilterable { private readonly IGrouping defaultGroup; - private readonly IEnumerable bindings; + private readonly ICollection bindings; public readonly KeyBindingRow KeyBindingRow; private bool matchingFilter; @@ -33,7 +33,7 @@ public bool MatchingFilter public SettingsKeyBindingRow( IGrouping defaultGroup, - IEnumerable bindings, + ICollection bindings, RulesetInfo ruleset) { this.defaultGroup = defaultGroup; @@ -63,7 +63,7 @@ public SettingsKeyBindingRow( }, }; - restoreDefaultButton.Bindable = KeyBindingRow.Current; + restoreDefaultButton.Current = KeyBindingRow.Current; } } } \ No newline at end of file diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 6d6616a893..5d61b76915 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -10,27 +10,27 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; using osuTK; namespace osu.Game.Overlays { - public class RestoreDefaultValueButton : Container, IHasTooltip + public class RestoreDefaultValueButton : Container, IHasTooltip, IHasCurrentValue { public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; - private Bindable bindable; + private BindableWithCurrent current = new BindableWithCurrent(); - public Bindable Bindable + public Bindable Current { - get => bindable; - set - { - bindable = value; - bindable.ValueChanged += _ => UpdateState(); - bindable.DisabledChanged += _ => UpdateState(); - bindable.DefaultChanged += _ => UpdateState(); + get => current.Current; + set { + current.Current = value; + current.ValueChanged += _ => UpdateState(); + current.DisabledChanged += _ => UpdateState(); + current.DefaultChanged += _ => UpdateState(); UpdateState(); } } @@ -43,6 +43,7 @@ public RestoreDefaultValueButton() { RelativeSizeAxes = Axes.Y; Width = SettingsPanel.CONTENT_MARGINS; + Padding = new MarginPadding { Vertical = 1.5f }; Alpha = 0f; } @@ -80,8 +81,8 @@ protected override void LoadComplete() protected override bool OnClick(ClickEvent e) { - if (bindable != null && !bindable.Disabled) - bindable.SetDefault(); + if (current != null && !current.Disabled) + current.SetDefault(); return true; } @@ -108,12 +109,12 @@ public void SetButtonColour(Color4 buttonColour) private void updateState() { - if (bindable == null) + if (current == null) return; - this.FadeTo(bindable.IsDefault ? 0f : - hovering && !bindable.Disabled ? 1f : 0.65f, 200, Easing.OutQuint); - this.FadeColour(bindable.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); + this.FadeTo(current.IsDefault ? 0f : + hovering && !current.Disabled ? 1f : 0.65f, 200, Easing.OutQuint); + this.FadeColour(current.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); } } } \ No newline at end of file diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index aa5cbf3d4e..807916e7f6 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -132,7 +132,7 @@ protected SettingsItem() controlWithCurrent.Current.DisabledChanged += _ => updateDisabled(); if (ShowsDefaultIndicator) - restoreDefaultButton.Bindable = controlWithCurrent.Current; + restoreDefaultButton.Current = controlWithCurrent.Current; } } From d85f17159f0e3f5e3cf4b61165ec1f9de5339837 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 11:25:56 +1000 Subject: [PATCH 20/93] Formatting --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 6f4c5f1179..7e81f64458 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -58,7 +58,6 @@ public bool MatchingFilter Default = true }; - public Bindable Current { get => isKeysDefaultValue.Current; From d988194dd3638749bcf3e53ef6f08ca63928ca52 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 11:40:42 +1000 Subject: [PATCH 21/93] Formatting --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 5d61b76915..e709e874ce 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -21,12 +21,13 @@ public class RestoreDefaultValueButton : Container, IHasTooltip, IHasCurrentV { public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; - private BindableWithCurrent current = new BindableWithCurrent(); + private readonly BindableWithCurrent current = new BindableWithCurrent(); public Bindable Current { get => current.Current; - set { + set + { current.Current = value; current.ValueChanged += _ => UpdateState(); current.DisabledChanged += _ => UpdateState(); From 50d5af9662475aba7dadbe7302750ca57f3d9899 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 12:05:22 +1000 Subject: [PATCH 22/93] Removed unused method --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index e709e874ce..5c07eac838 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -100,12 +100,6 @@ protected override void OnHoverLost(HoverLostEvent e) UpdateState(); } - public void SetButtonColour(Color4 buttonColour) - { - this.buttonColour = buttonColour; - UpdateState(); - } - public void UpdateState() => Scheduler.AddOnce(updateState); private void updateState() From c282f0e6035a2388d0360086bceed1d96d04d931 Mon Sep 17 00:00:00 2001 From: Swords Date: Sat, 15 May 2021 19:42:33 +1000 Subject: [PATCH 23/93] Fixing tests For some reason moving the mouse and clicking doesn't work with "dotnet test", but works when you run the osu.Game.Tests project. --- .../Settings/TestSceneKeyBindingPanel.cs | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 669338d714..8053a41de2 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -106,14 +106,15 @@ void clickClearButton() } [Test] - public void TestSingleBindResetButton() + public void TestSingleBindingResetButton() { SettingsKeyBindingRow settingsKeyBindingRow = null; - AddStep("click first row with two bindings", () => + AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(row => row.KeyBindingRow.Defaults.Count() > 1); - InputManager.MoveMouseTo(settingsKeyBindingRow.KeyBindingRow); + settingsKeyBindingRow = panel.ChildrenOfType().First(); + + InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); InputManager.ReleaseKey(Key.P); @@ -123,40 +124,43 @@ public void TestSingleBindResetButton() AddStep("click reset button for bindings", () => { - var clearButton = settingsKeyBindingRow.ChildrenOfType>().Single(); + var resetButton = settingsKeyBindingRow.ChildrenOfType>().First(); - InputManager.MoveMouseTo(clearButton); - InputManager.Click(MouseButton.Left); + resetButton.Click(); }); AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("first binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); - AddAssert("second binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(1).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(1))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestResetAllBindingsButton() { - KeyBindingRow keyBindingRow = null; + SettingsKeyBindingRow settingsKeyBindingRow = null; - AddStep("click first row and press p", () => + AddStep("click first row", () => { - keyBindingRow = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(keyBindingRow); + settingsKeyBindingRow = panel.ChildrenOfType().First(); + + InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); InputManager.PressKey(Key.P); InputManager.ReleaseKey(Key.P); }); - AddStep("click reset button for all bindings", () => - { - var clearButton = panel.ChildrenOfType().First(); - InputManager.MoveMouseTo(clearButton); - InputManager.Click(MouseButton.Left); + AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha > 0); + + AddStep("click reset button for bindings", () => + { + var resetButton = panel.ChildrenOfType().First(); + + resetButton.Click(); }); - AddUntilStep("bindings cleared", () => keyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(keyBindingRow.Defaults.ElementAt(0))); + AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); + + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); } [Test] From 264d8b9b86c17f09448c78df43aa6d904c492201 Mon Sep 17 00:00:00 2001 From: Swords Date: Sun, 16 May 2021 14:48:00 +1000 Subject: [PATCH 24/93] Finishing requested changes, and tidy up --- .../Settings/TestSceneKeyBindingPanel.cs | 8 +++--- .../KeyBinding/KeyBindingsSubsection.cs | 4 +-- ...ndingRow.cs => RestorableKeyBindingRow.cs} | 28 ++++++++++--------- 3 files changed, 21 insertions(+), 19 deletions(-) rename osu.Game/Overlays/KeyBinding/{SettingsKeyBindingRow.cs => RestorableKeyBindingRow.cs} (74%) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 8053a41de2..3edba2ddd7 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -108,11 +108,11 @@ void clickClearButton() [Test] public void TestSingleBindingResetButton() { - SettingsKeyBindingRow settingsKeyBindingRow = null; + RestorableKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -137,11 +137,11 @@ public void TestSingleBindingResetButton() [Test] public void TestResetAllBindingsButton() { - SettingsKeyBindingRow settingsKeyBindingRow = null; + RestorableKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index e07e5a52c6..dc29f0b4e5 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -38,12 +38,12 @@ private void load(KeyBindingStore store) foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { // one row per valid action. - Add(new SettingsKeyBindingRow(defaultGroup, bindings, Ruleset)); + Add(new RestorableKeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs similarity index 74% rename from osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs rename to osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 31374a8120..0461ae4f35 100644 --- a/osu.Game/Overlays/KeyBinding/SettingsKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -5,13 +5,14 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; using osu.Game.Rulesets; namespace osu.Game.Overlays.KeyBinding { - public class SettingsKeyBindingRow : Container, IFilterable + public class RestorableKeyBindingRow : Container, IFilterable { - private readonly IGrouping defaultGroup; + private readonly object key; private readonly ICollection bindings; public readonly KeyBindingRow KeyBindingRow; @@ -29,28 +30,29 @@ public bool MatchingFilter public bool FilteringActive { get; set; } - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(defaultGroup.Key.ToString()); + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public SettingsKeyBindingRow( - IGrouping defaultGroup, + public RestorableKeyBindingRow( + object key, ICollection bindings, - RulesetInfo ruleset) + RulesetInfo ruleset, + IEnumerable defaults) { - this.defaultGroup = defaultGroup; + this.key = key; this.bindings = bindings; - KeyBindingRow = new KeyBindingRow(defaultGroup.Key, bindings.Where(b => ((int)b.Action).Equals((int)defaultGroup.Key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaultGroup.Select(d => d.KeyCombination) - }; - RestoreDefaultValueButton restoreDefaultButton; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; + KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + }; + InternalChildren = new Drawable[] { restoreDefaultButton = new RestoreDefaultValueButton(), From 90f00a76633eb622b72073e32214ff4fc62710e3 Mon Sep 17 00:00:00 2001 From: Swords Date: Sun, 16 May 2021 15:01:19 +1000 Subject: [PATCH 25/93] Fixes ResotreDefaultValue to use the BindableWithCurrent correctly --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 5c07eac838..f390fb1e46 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -29,9 +29,6 @@ public Bindable Current set { current.Current = value; - current.ValueChanged += _ => UpdateState(); - current.DisabledChanged += _ => UpdateState(); - current.DefaultChanged += _ => UpdateState(); UpdateState(); } } @@ -46,6 +43,10 @@ public RestoreDefaultValueButton() Width = SettingsPanel.CONTENT_MARGINS; Padding = new MarginPadding { Vertical = 1.5f }; Alpha = 0f; + + Current.ValueChanged += _ => UpdateState(); + Current.DisabledChanged += _ => UpdateState(); + Current.DefaultChanged += _ => UpdateState(); } [BackgroundDependencyLoader] From 33fe843ba9eba9fcdedd8a59969b016a2abde848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 May 2021 20:44:47 +0200 Subject: [PATCH 26/93] Move value change bindings to `LoadComplete()` Also removes a redundant one from the setter of `Current`. If the set to current comes with an associated value change, the bind-unbind flow that `BindableWithCurrent` implements will handle that change anyway. --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index f390fb1e46..34ebe270ef 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -26,11 +26,7 @@ public class RestoreDefaultValueButton : Container, IHasTooltip, IHasCurrentV public Bindable Current { get => current.Current; - set - { - current.Current = value; - UpdateState(); - } + set => current.Current = value; } private Color4 buttonColour; @@ -43,10 +39,6 @@ public RestoreDefaultValueButton() Width = SettingsPanel.CONTENT_MARGINS; Padding = new MarginPadding { Vertical = 1.5f }; Alpha = 0f; - - Current.ValueChanged += _ => UpdateState(); - Current.DisabledChanged += _ => UpdateState(); - Current.DefaultChanged += _ => UpdateState(); } [BackgroundDependencyLoader] @@ -76,6 +68,11 @@ private void load(OsuColour colour) protected override void LoadComplete() { base.LoadComplete(); + + Current.ValueChanged += _ => UpdateState(); + Current.DisabledChanged += _ => UpdateState(); + Current.DefaultChanged += _ => UpdateState(); + UpdateState(); } @@ -113,4 +110,4 @@ private void updateState() this.FadeColour(current.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); } } -} \ No newline at end of file +} From 30d7768971208bf50324aeb32bf103e1851cba30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 May 2021 20:47:56 +0200 Subject: [PATCH 27/93] Remove now-redundant null check --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 34ebe270ef..3f4a9785a6 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -80,7 +80,7 @@ protected override void LoadComplete() protected override bool OnClick(ClickEvent e) { - if (current != null && !current.Disabled) + if (!current.Disabled) current.SetDefault(); return true; } From ef114f240799be93ef7448e7bf33da9693390dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 May 2021 20:57:48 +0200 Subject: [PATCH 28/93] Simplify bindable flow in `KeyBindingRow` --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 45 ++++++++++--------- .../KeyBinding/RestorableKeyBindingRow.cs | 4 +- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 7e81f64458..33f32493ad 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; @@ -24,7 +23,7 @@ namespace osu.Game.Overlays.KeyBinding { - public class KeyBindingRow : Container, IFilterable, IHasCurrentValue + public class KeyBindingRow : Container, IFilterable { private readonly object action; private readonly IEnumerable bindings; @@ -53,17 +52,11 @@ public bool MatchingFilter private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - private readonly BindableWithCurrent isKeysDefaultValue = new BindableWithCurrent + public Bindable IsDefault { get; } = new BindableBool(true) { Default = true }; - public Bindable Current - { - get => isKeysDefaultValue.Current; - set => isKeysDefaultValue.Current = value; - } - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); public KeyBindingRow(object action, IEnumerable bindings) @@ -83,15 +76,7 @@ public KeyBindingRow(object action, IEnumerable b.KeyCombination).SequenceEqual(Defaults); - isKeysDefaultValue.BindValueChanged(resetButtons => - { - if (resetButtons.NewValue && !bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults)) - { - RestoreDefaults(); - finalise(); - } - }); + updateIsDefaultValue(); EdgeEffect = new EdgeEffectParameters { @@ -140,6 +125,24 @@ private void load(OsuColour colours) buttons.Add(new KeyButton(b)); } + protected override void LoadComplete() + { + base.LoadComplete(); + + IsDefault.BindValueChanged(resetButtons => + { + if (resetButtons.NewValue && !computeIsDefaultValue()) + { + RestoreDefaults(); + finalise(); + } + }); + } + + private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); + + private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + public void RestoreDefaults() { int i = 0; @@ -151,7 +154,7 @@ public void RestoreDefaults() store.Update(button.KeyBinding); } - isKeysDefaultValue.Value = true; + updateIsDefaultValue(); } protected override bool OnHover(HoverEvent e) @@ -311,7 +314,7 @@ private void finalise() { store.Update(bindTarget.KeyBinding); - isKeysDefaultValue.Value = buttons.Select(b => b.KeyBinding.KeyCombination).SequenceEqual(Defaults); + updateIsDefaultValue(); bindTarget.IsBinding = false; Schedule(() => @@ -476,4 +479,4 @@ public void UpdateKeyCombination(KeyCombination newCombination) } } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 0461ae4f35..b09c21378e 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -65,7 +65,7 @@ public RestorableKeyBindingRow( }, }; - restoreDefaultButton.Current = KeyBindingRow.Current; + restoreDefaultButton.Current = KeyBindingRow.IsDefault; } } -} \ No newline at end of file +} From 0e91a00a7e3b4084ee3395c1d88d1437740a87f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 May 2021 21:18:45 +0200 Subject: [PATCH 29/93] Revert to previous width spec instead of size --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 3f4a9785a6..51fb87da1d 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; -using osuTK; namespace osu.Game.Overlays { @@ -60,7 +59,7 @@ private void load(OsuColour colour) Type = EdgeEffectType.Glow, Radius = 2, }, - Size = new Vector2(0.33f, 0.8f), + Width = 0.33f, Child = new Box { RelativeSizeAxes = Axes.Both }, }; } From 3a5b21c0f5caafc98e93783f5d014dbc34841f8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 May 2021 13:47:39 +0900 Subject: [PATCH 30/93] Update "reset all bindings" button to better match new key binding row widths --- osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index dc29f0b4e5..737c640b5a 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -55,10 +55,13 @@ private void load() { Text = "Reset all bindings in section"; RelativeSizeAxes = Axes.X; - Margin = new MarginPadding { Top = 5 }; - Height = 20; + Width = 0.5f; + Anchor = Anchor.TopCentre; + Origin = Anchor.TopCentre; + Margin = new MarginPadding { Top = 15 }; + Height = 30; Content.CornerRadius = 5; } } -} \ No newline at end of file +} From 0100b88a8601a693de45531576d4b2ad32900ae0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 May 2021 14:11:26 +0900 Subject: [PATCH 31/93] Move private methods down --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 33f32493ad..959ba36c6a 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -129,9 +129,9 @@ protected override void LoadComplete() { base.LoadComplete(); - IsDefault.BindValueChanged(resetButtons => + IsDefault.BindValueChanged(isDefault => { - if (resetButtons.NewValue && !computeIsDefaultValue()) + if (isDefault.NewValue && !computeIsDefaultValue()) { RestoreDefaults(); finalise(); @@ -139,10 +139,6 @@ protected override void LoadComplete() }); } - private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); - - private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); - public void RestoreDefaults() { int i = 0; @@ -331,6 +327,10 @@ private void finalise() cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; } + private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); + + private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + protected override void OnFocus(FocusEvent e) { AutoSizeDuration = 500; From b8a5b5aaf8b7097f0b1a0be57156a5fd15aefa0a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 23 May 2021 17:22:31 +0700 Subject: [PATCH 32/93] add test for image block and inline image --- .../Online/TestSceneWikiMarkdownContainer.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 3731e7a782..67030631b0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -120,6 +120,29 @@ public void TestRelativeImage() }); } + [Test] + public void TestBlockImage() + { + AddStep("Add paragraph with block image", () => + { + markdownContainer.CurrentPath = "Interface/"; + markdownContainer.Text = @"Line before image + +![play menu](img/play-menu.jpg ""Main Menu in osu!"") + +Line after image"; + }); + } + + [Test] + public void TestInlineImage() + { + AddStep("Add inline image", () => + { + markdownContainer.Text = "![osu! mode icon](/wiki/shared/mode/osu.png) osu!"; + }); + } + private class TestMarkdownContainer : WikiMarkdownContainer { public LinkInline Link; From dc322d1c63f33712d0d4a1488bda78b0d4222448 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 23 May 2021 20:22:48 +0900 Subject: [PATCH 33/93] Run all type and sample mutations through standardising methods --- osu.Game.Rulesets.Taiko/Objects/Hit.cs | 21 +++++---------- .../Objects/TaikoHitObject.cs | 26 +++++++++++++++++++ .../Objects/TaikoStrongableHitObject.cs | 22 +++++++++++----- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index f4a66c39a8..8ede21fdad 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -2,30 +2,23 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Framework.Bindables; using osu.Game.Audio; namespace osu.Game.Rulesets.Taiko.Objects { public class Hit : TaikoStrongableHitObject { - public readonly Bindable TypeBindable = new Bindable(); - - /// - /// The that actuates this . - /// - public HitType Type + protected override void UpdateTypeFromSamples() { - get => TypeBindable.Value; - set - { - TypeBindable.Value = value; - updateSamplesFromType(); - } + base.UpdateTypeFromSamples(); + + Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; } - private void updateSamplesFromType() + protected override void UpdateSamplesFromType() { + base.UpdateSamplesFromType(); + var rimSamples = getRimSamples(); bool isRimType = Type == HitType.Rim; diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs index f047c03f4b..46b864e7de 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.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 osu.Framework.Bindables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; @@ -11,6 +12,17 @@ namespace osu.Game.Rulesets.Taiko.Objects { public abstract class TaikoHitObject : HitObject { + public readonly Bindable TypeBindable = new Bindable(); + + /// + /// The that actuates this . + /// + public HitType Type + { + get => TypeBindable.Value; + set => TypeBindable.Value = value; + } + /// /// Default size of a drawable taiko hit object. /// @@ -19,5 +31,19 @@ public abstract class TaikoHitObject : HitObject public override Judgement CreateJudgement() => new TaikoJudgement(); protected override HitWindows CreateHitWindows() => new TaikoHitWindows(); + + protected TaikoHitObject() + { + SamplesBindable.BindCollectionChanged((_, __) => UpdateTypeFromSamples()); + TypeBindable.BindValueChanged(_ => UpdateSamplesFromType()); + } + + protected virtual void UpdateSamplesFromType() + { + } + + protected virtual void UpdateTypeFromSamples() + { + } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs index cac56d1269..237000474d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs @@ -33,15 +33,25 @@ public abstract class TaikoStrongableHitObject : TaikoHitObject public bool IsStrong { get => IsStrongBindable.Value; - set - { - IsStrongBindable.Value = value; - updateSamplesFromStrong(); - } + set => IsStrongBindable.Value = value; } - private void updateSamplesFromStrong() + protected TaikoStrongableHitObject() { + IsStrongBindable.BindValueChanged(_ => UpdateSamplesFromType()); + } + + protected override void UpdateTypeFromSamples() + { + base.UpdateTypeFromSamples(); + + IsStrong = getStrongSamples().Any(); + } + + protected override void UpdateSamplesFromType() + { + base.UpdateSamplesFromType(); + var strongSamples = getStrongSamples(); if (IsStrongBindable.Value != strongSamples.Any()) From 4c9d72e62ae4d82404aa69a0b0d34b81db4b93a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 23 May 2021 21:19:38 +0900 Subject: [PATCH 34/93] Ensure `EditorBeatmap.Update` is called inside `PerformOnSelection` calls --- osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs | 6 +++++- .../Edit/Compose/Components/EditorBlueprintContainer.cs | 8 +++++++- .../Edit/Compose/Components/EditorSelectionHandler.cs | 7 ++++++- .../Components/Timeline/TimelineBlueprintContainer.cs | 6 +++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs index a24130d6ac..ab3b729307 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs @@ -69,7 +69,11 @@ public void SetRimState(bool state) { EditorBeatmap.PerformOnSelection(h => { - if (h is Hit taikoHit) taikoHit.Type = state ? HitType.Rim : HitType.Centre; + if (h is Hit taikoHit) + { + taikoHit.Type = state ? HitType.Rim : HitType.Centre; + EditorBeatmap.Update(h); + } }); } diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs index 5a6f98f504..22b211f257 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs @@ -77,7 +77,13 @@ protected override bool ApplySnapResult(SelectionBlueprint[] blueprin double offset = result.Time.Value - blueprints.First().Item.StartTime; if (offset != 0) - Beatmap.PerformOnSelection(obj => obj.StartTime += offset); + { + Beatmap.PerformOnSelection(obj => + { + obj.StartTime += offset; + Beatmap.Update(obj); + }); + } } return true; diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index 2141c490df..246d4aa8d7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -125,6 +125,7 @@ public void AddHitSample(string sampleName) return; h.Samples.Add(new HitSampleInfo(sampleName)); + EditorBeatmap.Update(h); }); } @@ -134,7 +135,11 @@ public void AddHitSample(string sampleName) /// The name of the hit sample. public void RemoveHitSample(string sampleName) { - EditorBeatmap.PerformOnSelection(h => h.SamplesBindable.RemoveAll(s => s.Name == sampleName)); + EditorBeatmap.PerformOnSelection(h => + { + h.SamplesBindable.RemoveAll(s => s.Name == sampleName); + EditorBeatmap.Update(h); + }); } /// diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 7c1bbd65f9..6f04f36b83 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -276,7 +276,11 @@ private void nudgeSelection(int amount) var timingPoint = EditorBeatmap.ControlPointInfo.TimingPointAt(selected.First().StartTime); double adjustment = timingPoint.BeatLength / EditorBeatmap.BeatDivisor * amount; - EditorBeatmap.PerformOnSelection(h => h.StartTime += adjustment); + EditorBeatmap.PerformOnSelection(h => + { + h.StartTime += adjustment; + EditorBeatmap.Update(h); + }); } } From a69a1b521105654d716a7876b279a0d0a1322bd4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 May 2021 13:53:51 +0900 Subject: [PATCH 35/93] Fix `Player` potentially running `MakeCurrent` when already removed from the screen stack Closes #12919. --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 39f9e2d388..ee940fae40 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -519,7 +519,7 @@ protected void PerformExit(bool showDialogFirst) // there is a chance that the exit was performed after the transition to results has started. // we want to give the user what they want, so forcefully return to this screen (to proceed with the upwards exit process). - if (!this.IsCurrentScreen()) + if (!this.IsCurrentScreen() && this.GetChildScreen() != null) { ValidForResume = false; this.MakeCurrent(); From 06fe0563d30d515a40729c7946ed326c41292ac7 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 24 May 2021 08:26:44 +0300 Subject: [PATCH 36/93] Move GetNewsRequest from ArticleListing to NewsOverlay --- .../Overlays/News/Displays/ArticleListing.cs | 46 ++++------------ osu.Game/Overlays/NewsOverlay.cs | 54 ++++++++++++++++--- 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/osu.Game/Overlays/News/Displays/ArticleListing.cs b/osu.Game/Overlays/News/Displays/ArticleListing.cs index b49326a1f1..b554b462a9 100644 --- a/osu.Game/Overlays/News/Displays/ArticleListing.cs +++ b/osu.Game/Overlays/News/Displays/ArticleListing.cs @@ -8,9 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; using osu.Game.Online.API.Requests; -using osu.Game.Online.API.Requests.Responses; using osuTK; namespace osu.Game.Overlays.News.Displays @@ -20,26 +18,20 @@ namespace osu.Game.Overlays.News.Displays /// public class ArticleListing : CompositeDrawable { - public Action SidebarMetadataUpdated; - - [Resolved] - private IAPIProvider api { get; set; } + public Action RequestMorePosts; private FillFlowContainer content; private ShowMoreButton showMore; - private GetNewsRequest request; - private Cursor lastCursor; - - private readonly int? year; + private readonly GetNewsResponse initialResponse; /// /// Instantiate a listing for the specified year. /// - /// The year to load articles from. If null, will show the most recent articles. - public ArticleListing(int? year = null) + /// Initial response to create articles from. + public ArticleListing(GetNewsResponse initialResponse) { - this.year = year; + this.initialResponse = initialResponse; } [BackgroundDependencyLoader] @@ -69,7 +61,8 @@ private void load() RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 10) + Spacing = new Vector2(0, 10), + Children = initialResponse.NewsPosts.Select(p => new NewsCard(p)).ToList() }, showMore = new ShowMoreButton { @@ -79,37 +72,19 @@ private void load() { Top = 15 }, - Action = performFetch, - Alpha = 0 + Action = RequestMorePosts, + Alpha = initialResponse.Cursor != null ? 1 : 0 } } }; - - performFetch(); - } - - private void performFetch() - { - request?.Cancel(); - - request = new GetNewsRequest(year, lastCursor); - request.Success += response => Schedule(() => onSuccess(response)); - api.PerformAsync(request); } private CancellationTokenSource cancellationToken; - private void onSuccess(GetNewsResponse response) + public void AddPosts(GetNewsResponse response) { cancellationToken?.Cancel(); - // only needs to be updated on the initial load, as the content won't change during pagination. - if (lastCursor == null) - SidebarMetadataUpdated?.Invoke(response.SidebarMetadata); - - // store cursor for next pagination request. - lastCursor = response.Cursor; - LoadComponentsAsync(response.NewsPosts.Select(p => new NewsCard(p)).ToList(), loaded => { content.AddRange(loaded); @@ -121,7 +96,6 @@ private void onSuccess(GetNewsResponse response) protected override void Dispose(bool isDisposing) { - request?.Cancel(); cancellationToken?.Cancel(); base.Dispose(isDisposing); } diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index dd6de40ecb..751ac1d10a 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -6,6 +6,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osu.Game.Overlays.News; using osu.Game.Overlays.News.Displays; using osu.Game.Overlays.News.Sidebar; @@ -18,9 +20,12 @@ public class NewsOverlay : OnlineOverlay private readonly Container sidebarContainer; private readonly NewsSidebar sidebar; - private readonly Container content; + private APIRequest lastRequest; + private Cursor lastCursor; + private int? year; + private CancellationTokenSource cancellationToken; private bool displayUpdateRequired = true; @@ -108,7 +113,11 @@ public void ShowArticle(string slug) protected void LoadDisplay(Drawable display) { ScrollFlow.ScrollToStart(); - LoadComponentAsync(display, loaded => content.Child = loaded, (cancellationToken = new CancellationTokenSource()).Token); + LoadComponentAsync(display, loaded => + { + content.Child = loaded; + Loading.Hide(); + }, (cancellationToken = new CancellationTokenSource()).Token); } protected override void UpdateAfterChildren() @@ -132,13 +141,41 @@ private void loadFrontPage(int? year = null) Header.SetFrontPage(); - var page = new ArticleListing(year); - page.SidebarMetadataUpdated += metadata => Schedule(() => + this.year = year; + lastCursor = null; + + performListingRequest(response => { - sidebar.Metadata.Value = metadata; - Loading.Hide(); + sidebar.Metadata.Value = response.SidebarMetadata; + + var listing = new ArticleListing(response); + listing.RequestMorePosts += getMorePosts; + + LoadDisplay(listing); }); - LoadDisplay(page); + } + + private void getMorePosts() + { + lastRequest?.Cancel(); + performListingRequest(response => + { + if (content.Child is ArticleListing listing) + listing.AddPosts(response); + }); + } + + private void performListingRequest(Action onSuccess) + { + lastRequest = new GetNewsRequest(year, lastCursor); + + ((GetNewsRequest)lastRequest).Success += response => Schedule(() => + { + lastCursor = response.Cursor; + onSuccess?.Invoke(response); + }); + + API.PerformAsync(lastRequest); } private void loadArticle(string article) @@ -149,17 +186,18 @@ private void loadArticle(string article) // Temporary, should be handled by ArticleDisplay later LoadDisplay(Empty()); - Loading.Hide(); } private void beginLoading() { + lastRequest?.Cancel(); cancellationToken?.Cancel(); Loading.Show(); } protected override void Dispose(bool isDisposing) { + lastRequest?.Cancel(); cancellationToken?.Cancel(); base.Dispose(isDisposing); } From 100e2d14a5084c6373da786d8370767ec686ce8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 May 2021 15:14:55 +0900 Subject: [PATCH 37/93] Move call inside conditional --- osu.Game/Screens/Play/Player.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index ee940fae40..a9f3edf049 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -519,10 +519,13 @@ protected void PerformExit(bool showDialogFirst) // there is a chance that the exit was performed after the transition to results has started. // we want to give the user what they want, so forcefully return to this screen (to proceed with the upwards exit process). - if (!this.IsCurrentScreen() && this.GetChildScreen() != null) + if (!this.IsCurrentScreen()) { ValidForResume = false; - this.MakeCurrent(); + + // in the potential case that this instance has already been exited, this is required to avoid a crash. + if (this.GetChildScreen() != null) + this.MakeCurrent(); return; } From ca1d1c58aba7888cf89bd42f8ced6539a1833d6a Mon Sep 17 00:00:00 2001 From: Swords Date: Mon, 24 May 2021 21:34:47 +1000 Subject: [PATCH 38/93] RestoreDefaultValueButton implements OsuButton --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 3 +- .../KeyBinding/RestorableKeyBindingRow.cs | 1 + .../Overlays/RestoreDefaultValueButton.cs | 44 +++++++------------ 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 959ba36c6a..8cc03160a2 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -131,9 +131,8 @@ protected override void LoadComplete() IsDefault.BindValueChanged(isDefault => { - if (isDefault.NewValue && !computeIsDefaultValue()) + if (isDefault.NewValue) { - RestoreDefaults(); finalise(); } }); diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index b09c21378e..d07fffe6bc 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -65,6 +65,7 @@ public RestorableKeyBindingRow( }, }; + restoreDefaultButton.Action = () => { KeyBindingRow.RestoreDefaults(); }; restoreDefaultButton.Current = KeyBindingRow.IsDefault; } } diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 51fb87da1d..d75657ea7a 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -6,17 +6,16 @@ using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays { - public class RestoreDefaultValueButton : Container, IHasTooltip, IHasCurrentValue + public class RestoreDefaultValueButton : OsuButton, IHasTooltip, IHasCurrentValue { public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; @@ -34,34 +33,30 @@ public Bindable Current public RestoreDefaultValueButton() { + Height = 1; + RelativeSizeAxes = Axes.Y; Width = SettingsPanel.CONTENT_MARGINS; - Padding = new MarginPadding { Vertical = 1.5f }; - Alpha = 0f; } [BackgroundDependencyLoader] private void load(OsuColour colour) { + BackgroundColour = colour.Yellow; buttonColour = colour.Yellow; - - Child = new Container + Content.Width = 0.33f; + Content.CornerRadius = 3; + Content.EdgeEffect = new EdgeEffectParameters { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - CornerRadius = 3, - Masking = true, - Colour = buttonColour, - EdgeEffect = new EdgeEffectParameters - { - Colour = buttonColour.Opacity(0.1f), - Type = EdgeEffectType.Glow, - Radius = 2, - }, - Width = 0.33f, - Child = new Box { RelativeSizeAxes = Axes.Both }, + Colour = buttonColour.Opacity(0.1f), + Type = EdgeEffectType.Glow, + Radius = 2, }; + + Padding = new MarginPadding { Vertical = 1.5f }; + Alpha = 0f; + + Action += () => { if (!current.Disabled) current.SetDefault(); }; } protected override void LoadComplete() @@ -77,13 +72,6 @@ protected override void LoadComplete() public string TooltipText => "revert to default"; - protected override bool OnClick(ClickEvent e) - { - if (!current.Disabled) - current.SetDefault(); - return true; - } - protected override bool OnHover(HoverEvent e) { hovering = true; From 441e4e7d56fe35088bb2faef2ed741bb3ad82814 Mon Sep 17 00:00:00 2001 From: Swords Date: Mon, 24 May 2021 22:08:34 +1000 Subject: [PATCH 39/93] Formatting --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index d75657ea7a..0fe7b7322f 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -56,7 +56,10 @@ private void load(OsuColour colour) Padding = new MarginPadding { Vertical = 1.5f }; Alpha = 0f; - Action += () => { if (!current.Disabled) current.SetDefault(); }; + Action += () => + { + if (!current.Disabled) current.SetDefault(); + }; } protected override void LoadComplete() From 518999ffab72b414a5d82bb0ba908d505d7f5187 Mon Sep 17 00:00:00 2001 From: Swords Date: Mon, 24 May 2021 22:49:40 +1000 Subject: [PATCH 40/93] Renaming files --- .../Settings/TestSceneKeyBindingPanel.cs | 42 +- .../Overlays/KeyBinding/BasicKeyBindingRow.cs | 463 +++++++++++++++++ osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 465 ++---------------- .../KeyBinding/KeyBindingsSubsection.cs | 4 +- .../KeyBinding/RestorableKeyBindingRow.cs | 72 --- 5 files changed, 514 insertions(+), 532 deletions(-) create mode 100644 osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs delete mode 100644 osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 3edba2ddd7..face2a498d 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -31,11 +31,11 @@ protected override void LoadComplete() [Test] public void TestClickTwiceOnClearButton() { - KeyBindingRow firstRow = null; + BasicKeyBindingRow firstRow = null; AddStep("click first row", () => { - firstRow = panel.ChildrenOfType().First(); + firstRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(firstRow); InputManager.Click(MouseButton.Left); @@ -43,7 +43,7 @@ public void TestClickTwiceOnClearButton() AddStep("schedule button clicks", () => { - var clearButton = firstRow.ChildrenOfType().Single(); + var clearButton = firstRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); @@ -68,22 +68,22 @@ public void TestClickTwiceOnClearButton() [Test] public void TestClearButtonOnBindings() { - KeyBindingRow multiBindingRow = null; + BasicKeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); clickClearButton(); - AddAssert("first binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().First().Text.Text.ToString())); + AddAssert("first binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().First().Text.Text.ToString())); AddStep("click second binding", () => { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); + var target = multiBindingRow.ChildrenOfType().ElementAt(1); InputManager.MoveMouseTo(target); InputManager.Click(MouseButton.Left); @@ -91,13 +91,13 @@ public void TestClearButtonOnBindings() clickClearButton(); - AddAssert("second binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().ElementAt(1).Text.Text.ToString())); + AddAssert("second binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().ElementAt(1).Text.Text.ToString())); void clickClearButton() { AddStep("click clear button", () => { - var clearButton = multiBindingRow.ChildrenOfType().Single(); + var clearButton = multiBindingRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); InputManager.Click(MouseButton.Left); @@ -108,11 +108,11 @@ void clickClearButton() [Test] public void TestSingleBindingResetButton() { - RestorableKeyBindingRow settingsKeyBindingRow = null; + KeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -131,17 +131,17 @@ public void TestSingleBindingResetButton() AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestResetAllBindingsButton() { - RestorableKeyBindingRow settingsKeyBindingRow = null; + KeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -160,26 +160,26 @@ public void TestResetAllBindingsButton() AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestClickRowSelectsFirstBinding() { - KeyBindingRow multiBindingRow = null; + BasicKeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); - AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); + AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); AddStep("click second binding", () => { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); + var target = multiBindingRow.ChildrenOfType().ElementAt(1); InputManager.MoveMouseTo(target); InputManager.Click(MouseButton.Left); @@ -187,12 +187,12 @@ public void TestClickRowSelectsFirstBinding() AddStep("click back binding row", () => { - multiBindingRow = panel.ChildrenOfType().ElementAt(10); + multiBindingRow = panel.ChildrenOfType().ElementAt(10); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); - AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); + AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); } } } \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs new file mode 100644 index 0000000000..acdf273622 --- /dev/null +++ b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs @@ -0,0 +1,463 @@ +// 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.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Input; +using osuTK; +using osuTK.Graphics; +using osuTK.Input; + +namespace osu.Game.Overlays.KeyBinding +{ + public class BasicKeyBindingRow : Container + { + private readonly object action; + private readonly IEnumerable bindings; + + private const float transition_time = 150; + + private const float height = 20; + + private const float padding = 5; + + private FillFlowContainer cancelAndClearButtons; + private FillFlowContainer buttons; + + public Bindable IsDefault { get; } = new BindableBool(true) + { + Default = true + }; + + public BasicKeyBindingRow(object action, IEnumerable bindings) + { + this.action = action; + this.bindings = bindings; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + Masking = true; + CornerRadius = padding; + } + + [Resolved] + private KeyBindingStore store { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + updateIsDefaultValue(); + + EdgeEffect = new EdgeEffectParameters + { + Radius = 2, + Colour = colours.YellowDark.Opacity(0), + Type = EdgeEffectType.Shadow, + Hollow = true, + }; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + new OsuSpriteText + { + Text = action.GetDescription(), + Margin = new MarginPadding(padding), + }, + buttons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight + }, + cancelAndClearButtons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding(padding) { Top = height + padding * 2 }, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Alpha = 0, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new CancelButton { Action = finalise }, + new ClearButton { Action = clear }, + }, + } + }; + foreach (var b in bindings) + buttons.Add(new KeyButton(b)); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + IsDefault.BindValueChanged(isDefault => + { + if (isDefault.NewValue) + { + finalise(); + } + }); + } + + public void RestoreDefaults() + { + int i = 0; + + foreach (var d in Defaults) + { + var button = buttons[i++]; + button.UpdateKeyCombination(d); + store.Update(button.KeyBinding); + } + + updateIsDefaultValue(); + } + + protected override bool OnHover(HoverEvent e) + { + FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); + + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); + + base.OnHoverLost(e); + } + + public override bool AcceptsFocus => bindTarget == null; + + private KeyButton bindTarget; + + public bool AllowMainMouseButtons; + + public IEnumerable Defaults; + + private bool isModifier(Key k) => k < Key.F1; + + protected override bool OnClick(ClickEvent e) => true; + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (!HasFocus || !bindTarget.IsHovered) + return base.OnMouseDown(e); + + if (!AllowMainMouseButtons) + { + switch (e.Button) + { + case MouseButton.Left: + case MouseButton.Right: + return true; + } + } + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + return true; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + // don't do anything until the last button is released. + if (!HasFocus || e.HasAnyButtonPressed) + { + base.OnMouseUp(e); + return; + } + + if (bindTarget.IsHovered) + finalise(); + // prevent updating bind target before clear button's action + else if (!cancelAndClearButtons.Any(b => b.IsHovered)) + updateBindTarget(); + } + + protected override bool OnScroll(ScrollEvent e) + { + if (HasFocus) + { + if (bindTarget.IsHovered) + { + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta)); + finalise(); + return true; + } + } + + return base.OnScroll(e); + } + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + if (!isModifier(e.Key)) finalise(); + + return true; + } + + protected override void OnKeyUp(KeyUpEvent e) + { + if (!HasFocus) + { + base.OnKeyUp(e); + return; + } + + finalise(); + } + + protected override bool OnJoystickPress(JoystickPressEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnJoystickRelease(JoystickReleaseEvent e) + { + if (!HasFocus) + { + base.OnJoystickRelease(e); + return; + } + + finalise(); + } + + protected override bool OnMidiDown(MidiDownEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnMidiUp(MidiUpEvent e) + { + if (!HasFocus) + { + base.OnMidiUp(e); + return; + } + + finalise(); + } + + private void clear() + { + if (bindTarget == null) + return; + + bindTarget.UpdateKeyCombination(InputKey.None); + finalise(); + } + + private void finalise() + { + if (bindTarget != null) + { + store.Update(bindTarget.KeyBinding); + + updateIsDefaultValue(); + + bindTarget.IsBinding = false; + Schedule(() => + { + // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) + bindTarget = null; + }); + } + + if (HasFocus) + GetContainingInputManager().ChangeFocus(null); + + cancelAndClearButtons.FadeOut(300, Easing.OutQuint); + cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; + } + + private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); + + private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + + protected override void OnFocus(FocusEvent e) + { + AutoSizeDuration = 500; + AutoSizeEasing = Easing.OutQuint; + + cancelAndClearButtons.FadeIn(300, Easing.OutQuint); + cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; + + updateBindTarget(); + base.OnFocus(e); + } + + protected override void OnFocusLost(FocusLostEvent e) + { + finalise(); + base.OnFocusLost(e); + } + + /// + /// Updates the bind target to the currently hovered key button or the first if clicked anywhere else. + /// + private void updateBindTarget() + { + if (bindTarget != null) bindTarget.IsBinding = false; + bindTarget = buttons.FirstOrDefault(b => b.IsHovered) ?? buttons.FirstOrDefault(); + if (bindTarget != null) bindTarget.IsBinding = true; + } + + private class CancelButton : TriangleButton + { + public CancelButton() + { + Text = "Cancel"; + Size = new Vector2(80, 20); + } + } + + public class ClearButton : DangerousTriangleButton + { + public ClearButton() + { + Text = "Clear"; + Size = new Vector2(80, 20); + } + } + + public class KeyButton : Container + { + public readonly Framework.Input.Bindings.KeyBinding KeyBinding; + + private readonly Box box; + public readonly OsuSpriteText Text; + + private Color4 hoverColour; + + private bool isBinding; + + public bool IsBinding + { + get => isBinding; + set + { + if (value == isBinding) return; + + isBinding = value; + + updateHoverState(); + } + } + + public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding) + { + KeyBinding = keyBinding; + + Margin = new MarginPadding(padding); + + // todo: use this in a meaningful way + // var isDefault = keyBinding.Action is Enum; + + Masking = true; + CornerRadius = padding; + + Height = height; + AutoSizeAxes = Axes.X; + + Children = new Drawable[] + { + new Container + { + AlwaysPresent = true, + Width = 80, + Height = height, + }, + box = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + Text = new OsuSpriteText + { + Font = OsuFont.Numeric.With(size: 10), + Margin = new MarginPadding(5), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = keyBinding.KeyCombination.ReadableString(), + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverColour = colours.YellowDark; + } + + protected override bool OnHover(HoverEvent e) + { + updateHoverState(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateHoverState(); + base.OnHoverLost(e); + } + + private void updateHoverState() + { + if (isBinding) + { + box.FadeColour(Color4.White, transition_time, Easing.OutQuint); + Text.FadeColour(Color4.Black, transition_time, Easing.OutQuint); + } + else + { + box.FadeColour(IsHovered ? hoverColour : Color4.Black, transition_time, Easing.OutQuint); + Text.FadeColour(IsHovered ? Color4.Black : Color4.White, transition_time, Easing.OutQuint); + } + } + + public void UpdateKeyCombination(KeyCombination newCombination) + { + KeyBinding.KeyCombination = newCombination; + Text.Text = KeyBinding.KeyCombination.ReadableString(); + } + } + } +} diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 8cc03160a2..3221b66bce 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -1,38 +1,20 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// 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.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Input; -using osuTK; -using osuTK.Graphics; -using osuTK.Input; +using osu.Game.Rulesets; namespace osu.Game.Overlays.KeyBinding { public class KeyBindingRow : Container, IFilterable { - private readonly object action; - private readonly IEnumerable bindings; - - private const float transition_time = 150; - - private const float height = 20; - - private const float padding = 5; + private readonly object key; + private readonly ICollection bindings; + public readonly BasicKeyBindingRow BasicKeyBindingRow; private bool matchingFilter; @@ -48,434 +30,43 @@ public bool MatchingFilter public bool FilteringActive { get; set; } - private OsuSpriteText text; - private FillFlowContainer cancelAndClearButtons; - private FillFlowContainer buttons; + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public Bindable IsDefault { get; } = new BindableBool(true) + public KeyBindingRow( + object key, + ICollection bindings, + RulesetInfo ruleset, + IEnumerable defaults) { - Default = true - }; - - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); - - public KeyBindingRow(object action, IEnumerable bindings) - { - this.action = action; + this.key = key; this.bindings = bindings; + + RestoreDefaultValueButton restoreDefaultButton; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - Masking = true; - CornerRadius = padding; - } - - [Resolved] - private KeyBindingStore store { get; set; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - updateIsDefaultValue(); - - EdgeEffect = new EdgeEffectParameters + BasicKeyBindingRow = new BasicKeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) { - Radius = 2, - Colour = colours.YellowDark.Opacity(0), - Type = EdgeEffectType.Shadow, - Hollow = true, + AllowMainMouseButtons = ruleset != null, + Defaults = defaults }; - Children = new Drawable[] + InternalChildren = new Drawable[] { - new Box + restoreDefaultButton = new RestoreDefaultValueButton(), + new FillFlowContainer { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.6f, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, + Child = BasicKeyBindingRow }, - text = new OsuSpriteText - { - Text = action.GetDescription(), - Margin = new MarginPadding(padding), - }, - buttons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight - }, - cancelAndClearButtons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding(padding) { Top = height + padding * 2 }, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Alpha = 0, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new CancelButton { Action = finalise }, - new ClearButton { Action = clear }, - }, - } }; - foreach (var b in bindings) - buttons.Add(new KeyButton(b)); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - IsDefault.BindValueChanged(isDefault => - { - if (isDefault.NewValue) - { - finalise(); - } - }); - } - - public void RestoreDefaults() - { - int i = 0; - - foreach (var d in Defaults) - { - var button = buttons[i++]; - button.UpdateKeyCombination(d); - store.Update(button.KeyBinding); - } - - updateIsDefaultValue(); - } - - protected override bool OnHover(HoverEvent e) - { - FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); - - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); - - base.OnHoverLost(e); - } - - public override bool AcceptsFocus => bindTarget == null; - - private KeyButton bindTarget; - - public bool AllowMainMouseButtons; - - public IEnumerable Defaults; - - private bool isModifier(Key k) => k < Key.F1; - - protected override bool OnClick(ClickEvent e) => true; - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (!HasFocus || !bindTarget.IsHovered) - return base.OnMouseDown(e); - - if (!AllowMainMouseButtons) - { - switch (e.Button) - { - case MouseButton.Left: - case MouseButton.Right: - return true; - } - } - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - return true; - } - - protected override void OnMouseUp(MouseUpEvent e) - { - // don't do anything until the last button is released. - if (!HasFocus || e.HasAnyButtonPressed) - { - base.OnMouseUp(e); - return; - } - - if (bindTarget.IsHovered) - finalise(); - // prevent updating bind target before clear button's action - else if (!cancelAndClearButtons.Any(b => b.IsHovered)) - updateBindTarget(); - } - - protected override bool OnScroll(ScrollEvent e) - { - if (HasFocus) - { - if (bindTarget.IsHovered) - { - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta)); - finalise(); - return true; - } - } - - return base.OnScroll(e); - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - if (!isModifier(e.Key)) finalise(); - - return true; - } - - protected override void OnKeyUp(KeyUpEvent e) - { - if (!HasFocus) - { - base.OnKeyUp(e); - return; - } - - finalise(); - } - - protected override bool OnJoystickPress(JoystickPressEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - finalise(); - - return true; - } - - protected override void OnJoystickRelease(JoystickReleaseEvent e) - { - if (!HasFocus) - { - base.OnJoystickRelease(e); - return; - } - - finalise(); - } - - protected override bool OnMidiDown(MidiDownEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - finalise(); - - return true; - } - - protected override void OnMidiUp(MidiUpEvent e) - { - if (!HasFocus) - { - base.OnMidiUp(e); - return; - } - - finalise(); - } - - private void clear() - { - if (bindTarget == null) - return; - - bindTarget.UpdateKeyCombination(InputKey.None); - finalise(); - } - - private void finalise() - { - if (bindTarget != null) - { - store.Update(bindTarget.KeyBinding); - - updateIsDefaultValue(); - - bindTarget.IsBinding = false; - Schedule(() => - { - // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) - bindTarget = null; - }); - } - - if (HasFocus) - GetContainingInputManager().ChangeFocus(null); - - cancelAndClearButtons.FadeOut(300, Easing.OutQuint); - cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; - } - - private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); - - private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); - - protected override void OnFocus(FocusEvent e) - { - AutoSizeDuration = 500; - AutoSizeEasing = Easing.OutQuint; - - cancelAndClearButtons.FadeIn(300, Easing.OutQuint); - cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; - - updateBindTarget(); - base.OnFocus(e); - } - - protected override void OnFocusLost(FocusLostEvent e) - { - finalise(); - base.OnFocusLost(e); - } - - /// - /// Updates the bind target to the currently hovered key button or the first if clicked anywhere else. - /// - private void updateBindTarget() - { - if (bindTarget != null) bindTarget.IsBinding = false; - bindTarget = buttons.FirstOrDefault(b => b.IsHovered) ?? buttons.FirstOrDefault(); - if (bindTarget != null) bindTarget.IsBinding = true; - } - - private class CancelButton : TriangleButton - { - public CancelButton() - { - Text = "Cancel"; - Size = new Vector2(80, 20); - } - } - - public class ClearButton : DangerousTriangleButton - { - public ClearButton() - { - Text = "Clear"; - Size = new Vector2(80, 20); - } - } - - public class KeyButton : Container - { - public readonly Framework.Input.Bindings.KeyBinding KeyBinding; - - private readonly Box box; - public readonly OsuSpriteText Text; - - private Color4 hoverColour; - - private bool isBinding; - - public bool IsBinding - { - get => isBinding; - set - { - if (value == isBinding) return; - - isBinding = value; - - updateHoverState(); - } - } - - public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding) - { - KeyBinding = keyBinding; - - Margin = new MarginPadding(padding); - - // todo: use this in a meaningful way - // var isDefault = keyBinding.Action is Enum; - - Masking = true; - CornerRadius = padding; - - Height = height; - AutoSizeAxes = Axes.X; - - Children = new Drawable[] - { - new Container - { - AlwaysPresent = true, - Width = 80, - Height = height, - }, - box = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black - }, - Text = new OsuSpriteText - { - Font = OsuFont.Numeric.With(size: 10), - Margin = new MarginPadding(5), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = keyBinding.KeyCombination.ReadableString(), - }, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - hoverColour = colours.YellowDark; - } - - protected override bool OnHover(HoverEvent e) - { - updateHoverState(); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - updateHoverState(); - base.OnHoverLost(e); - } - - private void updateHoverState() - { - if (isBinding) - { - box.FadeColour(Color4.White, transition_time, Easing.OutQuint); - Text.FadeColour(Color4.Black, transition_time, Easing.OutQuint); - } - else - { - box.FadeColour(IsHovered ? hoverColour : Color4.Black, transition_time, Easing.OutQuint); - Text.FadeColour(IsHovered ? Color4.Black : Color4.White, transition_time, Easing.OutQuint); - } - } - - public void UpdateKeyCombination(KeyCombination newCombination) - { - KeyBinding.KeyCombination = newCombination; - Text.Text = KeyBinding.KeyCombination.ReadableString(); - } + restoreDefaultButton.Action = () => { BasicKeyBindingRow.RestoreDefaults(); }; + restoreDefaultButton.Current = BasicKeyBindingRow.IsDefault; } } } diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 737c640b5a..b1a5895449 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -38,12 +38,12 @@ private void load(KeyBindingStore store) foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { // one row per valid action. - Add(new RestorableKeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); + Add(new KeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.BasicKeyBindingRow.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs deleted file mode 100644 index d07fffe6bc..0000000000 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ /dev/null @@ -1,72 +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 System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Bindings; -using osu.Game.Rulesets; - -namespace osu.Game.Overlays.KeyBinding -{ - public class RestorableKeyBindingRow : Container, IFilterable - { - private readonly object key; - private readonly ICollection bindings; - public readonly KeyBindingRow KeyBindingRow; - - private bool matchingFilter; - - public bool MatchingFilter - { - get => matchingFilter; - set - { - matchingFilter = value; - this.FadeTo(!matchingFilter ? 0 : 1); - } - } - - public bool FilteringActive { get; set; } - - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - - public RestorableKeyBindingRow( - object key, - ICollection bindings, - RulesetInfo ruleset, - IEnumerable defaults) - { - this.key = key; - this.bindings = bindings; - - RestoreDefaultValueButton restoreDefaultButton; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - - KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - }; - - InternalChildren = new Drawable[] - { - restoreDefaultButton = new RestoreDefaultValueButton(), - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = KeyBindingRow - }, - }; - - restoreDefaultButton.Action = () => { KeyBindingRow.RestoreDefaults(); }; - restoreDefaultButton.Current = KeyBindingRow.IsDefault; - } - } -} From 9de07de46784c479fd32f6867eee3692f911693d Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 25 May 2021 12:14:07 +0700 Subject: [PATCH 41/93] move text flow container inside markdown container --- .../Overlays/Wiki/Markdown/WikiMarkdownContainer.cs | 6 ++++++ .../Wiki/Markdown/WikiMarkdownTextFlowContainer.cs | 13 ------------- 2 files changed, 6 insertions(+), 13 deletions(-) delete mode 100644 osu.Game/Overlays/Wiki/Markdown/WikiMarkdownTextFlowContainer.cs diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index 81115293d4..d4ad0bee4d 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -3,6 +3,7 @@ using Markdig.Extensions.Yaml; using Markdig.Syntax; +using Markdig.Syntax.Inlines; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics.Containers.Markdown; @@ -35,5 +36,10 @@ protected override void AddMarkdownComponent(IMarkdownObject markdownObject, Fil protected override MarkdownParagraph CreateParagraph(ParagraphBlock paragraphBlock, int level) => new WikiMarkdownParagraph(paragraphBlock); protected virtual FillFlowContainer CreateNotice(YamlFrontMatterBlock yamlFrontMatterBlock) => new WikiNoticeContainer(yamlFrontMatterBlock); + + private class WikiMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer + { + protected override void AddImage(LinkInline linkInline) => AddDrawable(new WikiMarkdownImage(linkInline)); + } } } diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownTextFlowContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownTextFlowContainer.cs deleted file mode 100644 index 1c2b37a219..0000000000 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownTextFlowContainer.cs +++ /dev/null @@ -1,13 +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 Markdig.Syntax.Inlines; -using osu.Game.Graphics.Containers.Markdown; - -namespace osu.Game.Overlays.Wiki.Markdown -{ - public class WikiMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer - { - protected override void AddImage(LinkInline linkInline) => AddDrawable(new WikiMarkdownImage(linkInline)); - } -} From e3507d545391b6cbf665de5e58fdd485e7e48ab5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 16:06:39 +0900 Subject: [PATCH 42/93] Move `DrawableStoryboard`'s aspect application to inside its own class --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 3 +++ osu.Game/Storyboards/Storyboard.cs | 8 ++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index 4c42823779..1cd9b40089 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -58,6 +58,9 @@ public DrawableStoryboard(Storyboard storyboard) { Storyboard = storyboard; Size = new Vector2(640, 480); + + Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f); + Anchor = Anchor.Centre; Origin = Anchor.Centre; diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index bc61f704dd..08e80bc48c 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -85,12 +85,8 @@ public bool ReplacesBackground } } - public DrawableStoryboard CreateDrawable(WorkingBeatmap working = null) - { - var drawable = new DrawableStoryboard(this); - drawable.Width = drawable.Height * (BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f); - return drawable; - } + public DrawableStoryboard CreateDrawable(WorkingBeatmap working = null) => + new DrawableStoryboard(this); public Drawable CreateSpriteFromResourcePath(string path, TextureStore textureStore) { From 0c55bba220ec1f95bdfaf27cd105c0a72eafb6a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 16:07:17 +0900 Subject: [PATCH 43/93] Allow storyboards to be widescreen if only a video element exists This matches stable behaviour, which will allow videos to display filling the screen if they are the only thing contained within the "storyboard". --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index 1cd9b40089..bf67194e84 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -57,9 +57,12 @@ protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnl public DrawableStoryboard(Storyboard storyboard) { Storyboard = storyboard; + Size = new Vector2(640, 480); - Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f); + bool onlyHasVideoElements = !Storyboard.Layers.Any(l => l.Elements.Any(e => !(e is StoryboardVideo))); + + Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard || onlyHasVideoElements ? 16 / 9f : 4 / 3f); Anchor = Anchor.Centre; Origin = Anchor.Centre; From 5ea948aabe67b7ec36eddb884c158d4540141051 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 16:17:28 +0900 Subject: [PATCH 44/93] Bypass 640x480 coordinate space for video storyboard elements This allows the `FillMode.Fill` to take up the full space of the storyboard container. --- .../Drawables/DrawableStoryboardLayer.cs | 11 ++++--- osu.Game/Storyboards/Storyboard.cs | 2 +- osu.Game/Storyboards/StoryboardLayer.cs | 2 +- osu.Game/Storyboards/StoryboardLayerVideo.cs | 32 +++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Storyboards/StoryboardLayerVideo.cs diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs index 2ada83c3b4..1085b52d65 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osuTK; namespace osu.Game.Storyboards.Drawables { @@ -15,6 +16,8 @@ public class DrawableStoryboardLayer : CompositeDrawable public override bool IsPresent => Enabled && base.IsPresent; + protected LayerElementContainer ElementContainer { get; } + public DrawableStoryboardLayer(StoryboardLayer layer) { Layer = layer; @@ -24,10 +27,10 @@ public DrawableStoryboardLayer(StoryboardLayer layer) Enabled = layer.VisibleWhenPassing; Masking = layer.Masking; - InternalChild = new LayerElementContainer(layer); + InternalChild = ElementContainer = new LayerElementContainer(layer); } - private class LayerElementContainer : LifetimeManagementContainer + protected class LayerElementContainer : LifetimeManagementContainer { private readonly StoryboardLayer storyboardLayer; @@ -35,8 +38,8 @@ public LayerElementContainer(StoryboardLayer layer) { storyboardLayer = layer; - Width = 640; - Height = 480; + Size = new Vector2(640, 480); + Anchor = Anchor.Centre; Origin = Anchor.Centre; } diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 08e80bc48c..06be6c2d20 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -53,7 +53,7 @@ public class Storyboard public Storyboard() { - layers.Add("Video", new StoryboardLayer("Video", 4, false)); + layers.Add("Video", new StoryboardLayerVideo("Video", 4, false)); layers.Add("Background", new StoryboardLayer("Background", 3)); layers.Add("Fail", new StoryboardLayer("Fail", 2) { VisibleWhenPassing = false, }); layers.Add("Pass", new StoryboardLayer("Pass", 1) { VisibleWhenFailing = false, }); diff --git a/osu.Game/Storyboards/StoryboardLayer.cs b/osu.Game/Storyboards/StoryboardLayer.cs index 1cde7cf67a..fa9d4ebfea 100644 --- a/osu.Game/Storyboards/StoryboardLayer.cs +++ b/osu.Game/Storyboards/StoryboardLayer.cs @@ -32,7 +32,7 @@ public void Add(IStoryboardElement element) Elements.Add(element); } - public DrawableStoryboardLayer CreateDrawable() + public virtual DrawableStoryboardLayer CreateDrawable() => new DrawableStoryboardLayer(this) { Depth = Depth, Name = Name }; } } diff --git a/osu.Game/Storyboards/StoryboardLayerVideo.cs b/osu.Game/Storyboards/StoryboardLayerVideo.cs new file mode 100644 index 0000000000..7235df7a41 --- /dev/null +++ b/osu.Game/Storyboards/StoryboardLayerVideo.cs @@ -0,0 +1,32 @@ +// 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.Storyboards.Drawables; +using osuTK; + +namespace osu.Game.Storyboards +{ + public class StoryboardLayerVideo : StoryboardLayer + { + public StoryboardLayerVideo(string name, int depth, bool masking) + : base(name, depth, masking) + { + } + + public override DrawableStoryboardLayer CreateDrawable() + => new DrawableStoryboardLayerVideo(this) { Depth = Depth, Name = Name }; + + public class DrawableStoryboardLayerVideo : DrawableStoryboardLayer + { + public DrawableStoryboardLayerVideo(StoryboardLayerVideo layer) + : base(layer) + { + // for videos we want to take on the full size of the storyboard container hierarchy + // to allow the video to fill the full available region. + ElementContainer.RelativeSizeAxes = Axes.Both; + ElementContainer.Size = Vector2.One; + } + } + } +} From 871ca8054f4cfe36567fe653f45f9a333c5018bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 18:50:33 +0900 Subject: [PATCH 45/93] Rename classes as per review feedback --- osu.Game/Storyboards/Storyboard.cs | 2 +- ...StoryboardLayerVideo.cs => StoryboardVideoLayer.cs} | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) rename osu.Game/Storyboards/{StoryboardLayerVideo.cs => StoryboardVideoLayer.cs} (71%) diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 06be6c2d20..3486c1d66a 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -53,7 +53,7 @@ public class Storyboard public Storyboard() { - layers.Add("Video", new StoryboardLayerVideo("Video", 4, false)); + layers.Add("Video", new StoryboardVideoLayer("Video", 4, false)); layers.Add("Background", new StoryboardLayer("Background", 3)); layers.Add("Fail", new StoryboardLayer("Fail", 2) { VisibleWhenPassing = false, }); layers.Add("Pass", new StoryboardLayer("Pass", 1) { VisibleWhenFailing = false, }); diff --git a/osu.Game/Storyboards/StoryboardLayerVideo.cs b/osu.Game/Storyboards/StoryboardVideoLayer.cs similarity index 71% rename from osu.Game/Storyboards/StoryboardLayerVideo.cs rename to osu.Game/Storyboards/StoryboardVideoLayer.cs index 7235df7a41..2a01c2274a 100644 --- a/osu.Game/Storyboards/StoryboardLayerVideo.cs +++ b/osu.Game/Storyboards/StoryboardVideoLayer.cs @@ -7,19 +7,19 @@ namespace osu.Game.Storyboards { - public class StoryboardLayerVideo : StoryboardLayer + public class StoryboardVideoLayer : StoryboardLayer { - public StoryboardLayerVideo(string name, int depth, bool masking) + public StoryboardVideoLayer(string name, int depth, bool masking) : base(name, depth, masking) { } public override DrawableStoryboardLayer CreateDrawable() - => new DrawableStoryboardLayerVideo(this) { Depth = Depth, Name = Name }; + => new DrawableStoryboardVideoLayer(this) { Depth = Depth, Name = Name }; - public class DrawableStoryboardLayerVideo : DrawableStoryboardLayer + public class DrawableStoryboardVideoLayer : DrawableStoryboardLayer { - public DrawableStoryboardLayerVideo(StoryboardLayerVideo layer) + public DrawableStoryboardVideoLayer(StoryboardVideoLayer layer) : base(layer) { // for videos we want to take on the full size of the storyboard container hierarchy From 342acadae2381c0822c596f5f3c71efcdc9afef5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 May 2021 18:51:49 +0900 Subject: [PATCH 46/93] Change LINQ query for better readability --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index bf67194e84..ca041da801 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -60,7 +60,7 @@ public DrawableStoryboard(Storyboard storyboard) Size = new Vector2(640, 480); - bool onlyHasVideoElements = !Storyboard.Layers.Any(l => l.Elements.Any(e => !(e is StoryboardVideo))); + bool onlyHasVideoElements = Storyboard.Layers.SelectMany(l => l.Elements).Any(e => !(e is StoryboardVideo)); Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard || onlyHasVideoElements ? 16 / 9f : 4 / 3f); From ce845a9f8d5748c0ef1ca35edcde6e5469abb076 Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 21:00:38 +1000 Subject: [PATCH 47/93] Apply the rest of requested changes --- .../Overlays/KeyBinding/BasicKeyBindingRow.cs | 5 +--- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 30 +++++++------------ 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs index acdf273622..91d9aa70bd 100644 --- a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs @@ -37,10 +37,7 @@ public class BasicKeyBindingRow : Container private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - public Bindable IsDefault { get; } = new BindableBool(true) - { - Default = true - }; + public Bindable IsDefault { get; } = new BindableBool(true); public BasicKeyBindingRow(object action, IEnumerable bindings) { diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 3221b66bce..f799b4810f 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -32,41 +32,33 @@ public bool MatchingFilter public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public KeyBindingRow( - object key, - ICollection bindings, - RulesetInfo ruleset, - IEnumerable defaults) - { + public KeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { this.key = key; this.bindings = bindings; - RestoreDefaultValueButton restoreDefaultButton; - RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - BasicKeyBindingRow = new BasicKeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - }; - InternalChildren = new Drawable[] { - restoreDefaultButton = new RestoreDefaultValueButton(), + new RestoreDefaultValueButton() + { + Current = BasicKeyBindingRow.IsDefault, + Action = () => { BasicKeyBindingRow.RestoreDefaults(); } + }, new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = BasicKeyBindingRow + Child = BasicKeyBindingRow = new BasicKeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + } }, }; - - restoreDefaultButton.Action = () => { BasicKeyBindingRow.RestoreDefaults(); }; - restoreDefaultButton.Current = BasicKeyBindingRow.IsDefault; } } } From d9f5b578bf6f81fad7037480cf8ce95ac47eadad Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 21:08:40 +1000 Subject: [PATCH 48/93] Restore class names --- .../Settings/TestSceneKeyBindingPanel.cs | 42 +- .../Overlays/KeyBinding/BasicKeyBindingRow.cs | 460 ----------------- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 474 ++++++++++++++++-- .../KeyBinding/KeyBindingsSubsection.cs | 4 +- .../KeyBinding/RestorableKeyBindingRow.cs | 64 +++ 5 files changed, 522 insertions(+), 522 deletions(-) delete mode 100644 osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs create mode 100644 osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index face2a498d..bd3e94dffa 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -31,11 +31,11 @@ protected override void LoadComplete() [Test] public void TestClickTwiceOnClearButton() { - BasicKeyBindingRow firstRow = null; + KeyBindingRow firstRow = null; AddStep("click first row", () => { - firstRow = panel.ChildrenOfType().First(); + firstRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(firstRow); InputManager.Click(MouseButton.Left); @@ -43,7 +43,7 @@ public void TestClickTwiceOnClearButton() AddStep("schedule button clicks", () => { - var clearButton = firstRow.ChildrenOfType().Single(); + var clearButton = firstRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); @@ -68,22 +68,22 @@ public void TestClickTwiceOnClearButton() [Test] public void TestClearButtonOnBindings() { - BasicKeyBindingRow multiBindingRow = null; + KeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); clickClearButton(); - AddAssert("first binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().First().Text.Text.ToString())); + AddAssert("first binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().First().Text.Text.ToString())); AddStep("click second binding", () => { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); + var target = multiBindingRow.ChildrenOfType().ElementAt(1); InputManager.MoveMouseTo(target); InputManager.Click(MouseButton.Left); @@ -91,13 +91,13 @@ public void TestClearButtonOnBindings() clickClearButton(); - AddAssert("second binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().ElementAt(1).Text.Text.ToString())); + AddAssert("second binding cleared", () => string.IsNullOrEmpty(multiBindingRow.ChildrenOfType().ElementAt(1).Text.Text.ToString())); void clickClearButton() { AddStep("click clear button", () => { - var clearButton = multiBindingRow.ChildrenOfType().Single(); + var clearButton = multiBindingRow.ChildrenOfType().Single(); InputManager.MoveMouseTo(clearButton); InputManager.Click(MouseButton.Left); @@ -108,11 +108,11 @@ void clickClearButton() [Test] public void TestSingleBindingResetButton() { - KeyBindingRow settingsKeyBindingRow = null; + RestorableKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -131,17 +131,17 @@ public void TestSingleBindingResetButton() AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestResetAllBindingsButton() { - KeyBindingRow settingsKeyBindingRow = null; + RestorableKeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -160,26 +160,26 @@ public void TestResetAllBindingsButton() AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestClickRowSelectsFirstBinding() { - BasicKeyBindingRow multiBindingRow = null; + KeyBindingRow multiBindingRow = null; AddStep("click first row with two bindings", () => { - multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); + multiBindingRow = panel.ChildrenOfType().First(row => row.Defaults.Count() > 1); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); - AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); + AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); AddStep("click second binding", () => { - var target = multiBindingRow.ChildrenOfType().ElementAt(1); + var target = multiBindingRow.ChildrenOfType().ElementAt(1); InputManager.MoveMouseTo(target); InputManager.Click(MouseButton.Left); @@ -187,12 +187,12 @@ public void TestClickRowSelectsFirstBinding() AddStep("click back binding row", () => { - multiBindingRow = panel.ChildrenOfType().ElementAt(10); + multiBindingRow = panel.ChildrenOfType().ElementAt(10); InputManager.MoveMouseTo(multiBindingRow); InputManager.Click(MouseButton.Left); }); - AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); + AddAssert("first binding selected", () => multiBindingRow.ChildrenOfType().First().IsBinding); } } } \ No newline at end of file diff --git a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs deleted file mode 100644 index 91d9aa70bd..0000000000 --- a/osu.Game/Overlays/KeyBinding/BasicKeyBindingRow.cs +++ /dev/null @@ -1,460 +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 System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Input; -using osuTK; -using osuTK.Graphics; -using osuTK.Input; - -namespace osu.Game.Overlays.KeyBinding -{ - public class BasicKeyBindingRow : Container - { - private readonly object action; - private readonly IEnumerable bindings; - - private const float transition_time = 150; - - private const float height = 20; - - private const float padding = 5; - - private FillFlowContainer cancelAndClearButtons; - private FillFlowContainer buttons; - - public Bindable IsDefault { get; } = new BindableBool(true); - - public BasicKeyBindingRow(object action, IEnumerable bindings) - { - this.action = action; - this.bindings = bindings; - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - Masking = true; - CornerRadius = padding; - } - - [Resolved] - private KeyBindingStore store { get; set; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - updateIsDefaultValue(); - - EdgeEffect = new EdgeEffectParameters - { - Radius = 2, - Colour = colours.YellowDark.Opacity(0), - Type = EdgeEffectType.Shadow, - Hollow = true, - }; - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.6f, - }, - new OsuSpriteText - { - Text = action.GetDescription(), - Margin = new MarginPadding(padding), - }, - buttons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight - }, - cancelAndClearButtons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding(padding) { Top = height + padding * 2 }, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Alpha = 0, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new CancelButton { Action = finalise }, - new ClearButton { Action = clear }, - }, - } - }; - foreach (var b in bindings) - buttons.Add(new KeyButton(b)); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - IsDefault.BindValueChanged(isDefault => - { - if (isDefault.NewValue) - { - finalise(); - } - }); - } - - public void RestoreDefaults() - { - int i = 0; - - foreach (var d in Defaults) - { - var button = buttons[i++]; - button.UpdateKeyCombination(d); - store.Update(button.KeyBinding); - } - - updateIsDefaultValue(); - } - - protected override bool OnHover(HoverEvent e) - { - FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); - - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); - - base.OnHoverLost(e); - } - - public override bool AcceptsFocus => bindTarget == null; - - private KeyButton bindTarget; - - public bool AllowMainMouseButtons; - - public IEnumerable Defaults; - - private bool isModifier(Key k) => k < Key.F1; - - protected override bool OnClick(ClickEvent e) => true; - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (!HasFocus || !bindTarget.IsHovered) - return base.OnMouseDown(e); - - if (!AllowMainMouseButtons) - { - switch (e.Button) - { - case MouseButton.Left: - case MouseButton.Right: - return true; - } - } - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - return true; - } - - protected override void OnMouseUp(MouseUpEvent e) - { - // don't do anything until the last button is released. - if (!HasFocus || e.HasAnyButtonPressed) - { - base.OnMouseUp(e); - return; - } - - if (bindTarget.IsHovered) - finalise(); - // prevent updating bind target before clear button's action - else if (!cancelAndClearButtons.Any(b => b.IsHovered)) - updateBindTarget(); - } - - protected override bool OnScroll(ScrollEvent e) - { - if (HasFocus) - { - if (bindTarget.IsHovered) - { - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta)); - finalise(); - return true; - } - } - - return base.OnScroll(e); - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - if (!isModifier(e.Key)) finalise(); - - return true; - } - - protected override void OnKeyUp(KeyUpEvent e) - { - if (!HasFocus) - { - base.OnKeyUp(e); - return; - } - - finalise(); - } - - protected override bool OnJoystickPress(JoystickPressEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - finalise(); - - return true; - } - - protected override void OnJoystickRelease(JoystickReleaseEvent e) - { - if (!HasFocus) - { - base.OnJoystickRelease(e); - return; - } - - finalise(); - } - - protected override bool OnMidiDown(MidiDownEvent e) - { - if (!HasFocus) - return false; - - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); - finalise(); - - return true; - } - - protected override void OnMidiUp(MidiUpEvent e) - { - if (!HasFocus) - { - base.OnMidiUp(e); - return; - } - - finalise(); - } - - private void clear() - { - if (bindTarget == null) - return; - - bindTarget.UpdateKeyCombination(InputKey.None); - finalise(); - } - - private void finalise() - { - if (bindTarget != null) - { - store.Update(bindTarget.KeyBinding); - - updateIsDefaultValue(); - - bindTarget.IsBinding = false; - Schedule(() => - { - // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) - bindTarget = null; - }); - } - - if (HasFocus) - GetContainingInputManager().ChangeFocus(null); - - cancelAndClearButtons.FadeOut(300, Easing.OutQuint); - cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; - } - - private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); - - private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); - - protected override void OnFocus(FocusEvent e) - { - AutoSizeDuration = 500; - AutoSizeEasing = Easing.OutQuint; - - cancelAndClearButtons.FadeIn(300, Easing.OutQuint); - cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; - - updateBindTarget(); - base.OnFocus(e); - } - - protected override void OnFocusLost(FocusLostEvent e) - { - finalise(); - base.OnFocusLost(e); - } - - /// - /// Updates the bind target to the currently hovered key button or the first if clicked anywhere else. - /// - private void updateBindTarget() - { - if (bindTarget != null) bindTarget.IsBinding = false; - bindTarget = buttons.FirstOrDefault(b => b.IsHovered) ?? buttons.FirstOrDefault(); - if (bindTarget != null) bindTarget.IsBinding = true; - } - - private class CancelButton : TriangleButton - { - public CancelButton() - { - Text = "Cancel"; - Size = new Vector2(80, 20); - } - } - - public class ClearButton : DangerousTriangleButton - { - public ClearButton() - { - Text = "Clear"; - Size = new Vector2(80, 20); - } - } - - public class KeyButton : Container - { - public readonly Framework.Input.Bindings.KeyBinding KeyBinding; - - private readonly Box box; - public readonly OsuSpriteText Text; - - private Color4 hoverColour; - - private bool isBinding; - - public bool IsBinding - { - get => isBinding; - set - { - if (value == isBinding) return; - - isBinding = value; - - updateHoverState(); - } - } - - public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding) - { - KeyBinding = keyBinding; - - Margin = new MarginPadding(padding); - - // todo: use this in a meaningful way - // var isDefault = keyBinding.Action is Enum; - - Masking = true; - CornerRadius = padding; - - Height = height; - AutoSizeAxes = Axes.X; - - Children = new Drawable[] - { - new Container - { - AlwaysPresent = true, - Width = 80, - Height = height, - }, - box = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black - }, - Text = new OsuSpriteText - { - Font = OsuFont.Numeric.With(size: 10), - Margin = new MarginPadding(5), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = keyBinding.KeyCombination.ReadableString(), - }, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - hoverColour = colours.YellowDark; - } - - protected override bool OnHover(HoverEvent e) - { - updateHoverState(); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - updateHoverState(); - base.OnHoverLost(e); - } - - private void updateHoverState() - { - if (isBinding) - { - box.FadeColour(Color4.White, transition_time, Easing.OutQuint); - Text.FadeColour(Color4.Black, transition_time, Easing.OutQuint); - } - else - { - box.FadeColour(IsHovered ? hoverColour : Color4.Black, transition_time, Easing.OutQuint); - Text.FadeColour(IsHovered ? Color4.Black : Color4.White, transition_time, Easing.OutQuint); - } - } - - public void UpdateKeyCombination(KeyCombination newCombination) - { - KeyBinding.KeyCombination = newCombination; - Text.Text = KeyBinding.KeyCombination.ReadableString(); - } - } - } -} diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index f799b4810f..216eabcf67 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -1,64 +1,460 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// 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.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Input; +using osuTK; +using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Overlays.KeyBinding { - public class KeyBindingRow : Container, IFilterable + public class KeyBindingRow : Container { - private readonly object key; - private readonly ICollection bindings; - public readonly BasicKeyBindingRow BasicKeyBindingRow; + private readonly object action; + private readonly IEnumerable bindings; - private bool matchingFilter; + private const float transition_time = 150; - public bool MatchingFilter + private const float height = 20; + + private const float padding = 5; + + private FillFlowContainer cancelAndClearButtons; + private FillFlowContainer buttons; + + public Bindable IsDefault { get; } = new BindableBool(true); + + public KeyBindingRow(object action, IEnumerable bindings) { - get => matchingFilter; - set + this.action = action; + this.bindings = bindings; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + Masking = true; + CornerRadius = padding; + } + + [Resolved] + private KeyBindingStore store { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + updateIsDefaultValue(); + + EdgeEffect = new EdgeEffectParameters { - matchingFilter = value; - this.FadeTo(!matchingFilter ? 0 : 1); + Radius = 2, + Colour = colours.YellowDark.Opacity(0), + Type = EdgeEffectType.Shadow, + Hollow = true, + }; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + new OsuSpriteText + { + Text = action.GetDescription(), + Margin = new MarginPadding(padding), + }, + buttons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight + }, + cancelAndClearButtons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding(padding) { Top = height + padding * 2 }, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Alpha = 0, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new CancelButton { Action = finalise }, + new ClearButton { Action = clear }, + }, + } + }; + foreach (var b in bindings) + buttons.Add(new KeyButton(b)); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + IsDefault.BindValueChanged(isDefault => + { + if (isDefault.NewValue) + { + finalise(); + } + }); + } + + public void RestoreDefaults() + { + int i = 0; + + foreach (var d in Defaults) + { + var button = buttons[i++]; + button.UpdateKeyCombination(d); + store.Update(button.KeyBinding); + } + + updateIsDefaultValue(); + } + + protected override bool OnHover(HoverEvent e) + { + FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); + + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); + + base.OnHoverLost(e); + } + + public override bool AcceptsFocus => bindTarget == null; + + private KeyButton bindTarget; + + public bool AllowMainMouseButtons; + + public IEnumerable Defaults; + + private bool isModifier(Key k) => k < Key.F1; + + protected override bool OnClick(ClickEvent e) => true; + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (!HasFocus || !bindTarget.IsHovered) + return base.OnMouseDown(e); + + if (!AllowMainMouseButtons) + { + switch (e.Button) + { + case MouseButton.Left: + case MouseButton.Right: + return true; + } + } + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + return true; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + // don't do anything until the last button is released. + if (!HasFocus || e.HasAnyButtonPressed) + { + base.OnMouseUp(e); + return; + } + + if (bindTarget.IsHovered) + finalise(); + // prevent updating bind target before clear button's action + else if (!cancelAndClearButtons.Any(b => b.IsHovered)) + updateBindTarget(); + } + + protected override bool OnScroll(ScrollEvent e) + { + if (HasFocus) + { + if (bindTarget.IsHovered) + { + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta)); + finalise(); + return true; + } + } + + return base.OnScroll(e); + } + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + if (!isModifier(e.Key)) finalise(); + + return true; + } + + protected override void OnKeyUp(KeyUpEvent e) + { + if (!HasFocus) + { + base.OnKeyUp(e); + return; + } + + finalise(); + } + + protected override bool OnJoystickPress(JoystickPressEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnJoystickRelease(JoystickReleaseEvent e) + { + if (!HasFocus) + { + base.OnJoystickRelease(e); + return; + } + + finalise(); + } + + protected override bool OnMidiDown(MidiDownEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnMidiUp(MidiUpEvent e) + { + if (!HasFocus) + { + base.OnMidiUp(e); + return; + } + + finalise(); + } + + private void clear() + { + if (bindTarget == null) + return; + + bindTarget.UpdateKeyCombination(InputKey.None); + finalise(); + } + + private void finalise() + { + if (bindTarget != null) + { + store.Update(bindTarget.KeyBinding); + + updateIsDefaultValue(); + + bindTarget.IsBinding = false; + Schedule(() => + { + // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) + bindTarget = null; + }); + } + + if (HasFocus) + GetContainingInputManager().ChangeFocus(null); + + cancelAndClearButtons.FadeOut(300, Easing.OutQuint); + cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; + } + + private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); + + private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + + protected override void OnFocus(FocusEvent e) + { + AutoSizeDuration = 500; + AutoSizeEasing = Easing.OutQuint; + + cancelAndClearButtons.FadeIn(300, Easing.OutQuint); + cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; + + updateBindTarget(); + base.OnFocus(e); + } + + protected override void OnFocusLost(FocusLostEvent e) + { + finalise(); + base.OnFocusLost(e); + } + + /// + /// Updates the bind target to the currently hovered key button or the first if clicked anywhere else. + /// + private void updateBindTarget() + { + if (bindTarget != null) bindTarget.IsBinding = false; + bindTarget = buttons.FirstOrDefault(b => b.IsHovered) ?? buttons.FirstOrDefault(); + if (bindTarget != null) bindTarget.IsBinding = true; + } + + private class CancelButton : TriangleButton + { + public CancelButton() + { + Text = "Cancel"; + Size = new Vector2(80, 20); } } - public bool FilteringActive { get; set; } - - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - - public KeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { - this.key = key; - this.bindings = bindings; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - - InternalChildren = new Drawable[] + public class ClearButton : DangerousTriangleButton + { + public ClearButton() { - new RestoreDefaultValueButton() + Text = "Clear"; + Size = new Vector2(80, 20); + } + } + + public class KeyButton : Container + { + public readonly Framework.Input.Bindings.KeyBinding KeyBinding; + + private readonly Box box; + public readonly OsuSpriteText Text; + + private Color4 hoverColour; + + private bool isBinding; + + public bool IsBinding + { + get => isBinding; + set { - Current = BasicKeyBindingRow.IsDefault, - Action = () => { BasicKeyBindingRow.RestoreDefaults(); } - }, - new FillFlowContainer + if (value == isBinding) return; + + isBinding = value; + + updateHoverState(); + } + } + + public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding) + { + KeyBinding = keyBinding; + + Margin = new MarginPadding(padding); + + // todo: use this in a meaningful way + // var isDefault = keyBinding.Action is Enum; + + Masking = true; + CornerRadius = padding; + + Height = height; + AutoSizeAxes = Axes.X; + + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = BasicKeyBindingRow = new BasicKeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + new Container { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - } - }, - }; + AlwaysPresent = true, + Width = 80, + Height = height, + }, + box = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + Text = new OsuSpriteText + { + Font = OsuFont.Numeric.With(size: 10), + Margin = new MarginPadding(5), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = keyBinding.KeyCombination.ReadableString(), + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverColour = colours.YellowDark; + } + + protected override bool OnHover(HoverEvent e) + { + updateHoverState(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateHoverState(); + base.OnHoverLost(e); + } + + private void updateHoverState() + { + if (isBinding) + { + box.FadeColour(Color4.White, transition_time, Easing.OutQuint); + Text.FadeColour(Color4.Black, transition_time, Easing.OutQuint); + } + else + { + box.FadeColour(IsHovered ? hoverColour : Color4.Black, transition_time, Easing.OutQuint); + Text.FadeColour(IsHovered ? Color4.Black : Color4.White, transition_time, Easing.OutQuint); + } + } + + public void UpdateKeyCombination(KeyCombination newCombination) + { + KeyBinding.KeyCombination = newCombination; + Text.Text = KeyBinding.KeyCombination.ReadableString(); + } } } } diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index b1a5895449..fc370bd87e 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -38,12 +38,12 @@ private void load(KeyBindingStore store) foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { // one row per valid action. - Add(new KeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); + Add(new RestorableKeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.BasicKeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.BasicKeyBindingRow.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs new file mode 100644 index 0000000000..9bfdda727c --- /dev/null +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -0,0 +1,64 @@ +// 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.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; +using osu.Game.Rulesets; + +namespace osu.Game.Overlays.KeyBinding +{ + public class RestorableKeyBindingRow : Container, IFilterable + { + private readonly object key; + private readonly ICollection bindings; + public readonly KeyBindingRow BasicKeyBindingRow; + + private bool matchingFilter; + + public bool MatchingFilter + { + get => matchingFilter; + set + { + matchingFilter = value; + this.FadeTo(!matchingFilter ? 0 : 1); + } + } + + public bool FilteringActive { get; set; } + + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); + + public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { + this.key = key; + this.bindings = bindings; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; + + InternalChildren = new Drawable[] + { + new RestoreDefaultValueButton() + { + Current = BasicKeyBindingRow.IsDefault, + Action = () => { BasicKeyBindingRow.RestoreDefaults(); } + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, + Child = BasicKeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + } + }, + }; + } + } +} From d5feb8353d874c00f73b2d79623e47e3457871a4 Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 21:37:08 +1000 Subject: [PATCH 49/93] Formatting, renaming --- .../Visual/Settings/TestSceneKeyBindingPanel.cs | 4 ++-- osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs | 2 +- .../Overlays/KeyBinding/RestorableKeyBindingRow.cs | 11 ++++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index bd3e94dffa..3edba2ddd7 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -131,7 +131,7 @@ public void TestSingleBindingResetButton() AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); } [Test] @@ -160,7 +160,7 @@ public void TestResetAllBindingsButton() AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.BasicKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); } [Test] diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index fc370bd87e..737c640b5a 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -43,7 +43,7 @@ private void load(KeyBindingStore store) Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.BasicKeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 9bfdda727c..2981c77e15 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -14,7 +14,7 @@ public class RestorableKeyBindingRow : Container, IFilterable { private readonly object key; private readonly ICollection bindings; - public readonly KeyBindingRow BasicKeyBindingRow; + public readonly KeyBindingRow KeyBindingRow; private bool matchingFilter; @@ -32,7 +32,8 @@ public bool MatchingFilter public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { + public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) + { this.key = key; this.bindings = bindings; @@ -44,15 +45,15 @@ public RestorableKeyBindingRow(object key, ICollection() { - Current = BasicKeyBindingRow.IsDefault, - Action = () => { BasicKeyBindingRow.RestoreDefaults(); } + Current = KeyBindingRow.IsDefault, + Action = () => { KeyBindingRow.RestoreDefaults(); } }, new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = BasicKeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + Child = KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) { AllowMainMouseButtons = ruleset != null, Defaults = defaults From 9c2dca8229b5b956f1715bc67acc5cf42b7460c5 Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 21:53:00 +1000 Subject: [PATCH 50/93] Removing redundant argument list --- osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 2981c77e15..62a56ab055 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -43,7 +43,7 @@ public RestorableKeyBindingRow(object key, ICollection() + new RestoreDefaultValueButton { Current = KeyBindingRow.IsDefault, Action = () => { KeyBindingRow.RestoreDefaults(); } From 07a24d2747acc4e38d5a88ca67b290617b76de19 Mon Sep 17 00:00:00 2001 From: Swords Date: Tue, 25 May 2021 23:54:13 +1000 Subject: [PATCH 51/93] Fixing errors --- .../Overlays/KeyBinding/RestorableKeyBindingRow.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 62a56ab055..09b2efd7fa 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -41,6 +41,12 @@ public RestorableKeyBindingRow(object key, ICollection ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + }; + InternalChildren = new Drawable[] { new RestoreDefaultValueButton @@ -53,11 +59,7 @@ public RestorableKeyBindingRow(object key, ICollection ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - } + Child = KeyBindingRow }, }; } From 9223d85f37d33481fd0704349adaf19880728102 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 13:22:58 +0900 Subject: [PATCH 52/93] Remove all local type update logic from `TaikoBeatmapConverter` I believe the original goal was to keep this in the converter with the idea that samples may not always be hard coupled to the strong/rim states. But for now I think we can assume this coupling is going to continue into the near future, so let's keep all the logic in `TaikoHitObject`. --- .../Beatmaps/TaikoBeatmapConverter.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index b51f096d7d..90c99316b1 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -79,8 +79,6 @@ protected override IEnumerable ConvertHitObject(HitObject obj, I // Old osu! used hit sounding to determine various hit type information IList samples = obj.Samples; - bool strong = samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH); - switch (obj) { case IHasDistance distanceData: @@ -94,15 +92,11 @@ protected override IEnumerable ConvertHitObject(HitObject obj, I for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing) { IList currentSamples = allSamples[i]; - bool isRim = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE); - strong = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_FINISH); yield return new Hit { StartTime = j, - Type = isRim ? HitType.Rim : HitType.Centre, Samples = currentSamples, - IsStrong = strong }; i = (i + 1) % allSamples.Count; @@ -117,7 +111,6 @@ protected override IEnumerable ConvertHitObject(HitObject obj, I { StartTime = obj.StartTime, Samples = obj.Samples, - IsStrong = strong, Duration = taikoDuration, TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4 }; @@ -143,16 +136,10 @@ protected override IEnumerable ConvertHitObject(HitObject obj, I default: { - bool isRimDefinition(HitSampleInfo s) => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE; - - bool isRim = samples.Any(isRimDefinition); - yield return new Hit { StartTime = obj.StartTime, - Type = isRim ? HitType.Rim : HitType.Centre, Samples = samples, - IsStrong = strong }; break; From 912748b4280b152f3dda8bb9d49b074d5f6e80e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 13:24:22 +0900 Subject: [PATCH 53/93] Avoid bindable feedback causing overwrites --- osu.Game.Rulesets.Taiko/Objects/Hit.cs | 35 ------------------- .../Objects/TaikoHitObject.cs | 26 ++++++++++++-- .../Objects/TaikoStrongableHitObject.cs | 6 ++-- 3 files changed, 26 insertions(+), 41 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index 8ede21fdad..6b6c04e92e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -1,45 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; -using osu.Game.Audio; - namespace osu.Game.Rulesets.Taiko.Objects { public class Hit : TaikoStrongableHitObject { - protected override void UpdateTypeFromSamples() - { - base.UpdateTypeFromSamples(); - - Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; - } - - protected override void UpdateSamplesFromType() - { - base.UpdateSamplesFromType(); - - var rimSamples = getRimSamples(); - - bool isRimType = Type == HitType.Rim; - - if (isRimType != rimSamples.Any()) - { - if (isRimType) - Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_CLAP)); - else - { - foreach (var sample in rimSamples) - Samples.Remove(sample); - } - } - } - - /// - /// Returns an array of any samples which would cause this object to be a "rim" type hit. - /// - private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray(); - protected override StrongNestedHitObject CreateStrongNestedHit(double startTime) => new StrongNestedHit { StartTime = startTime }; public class StrongNestedHit : StrongNestedHitObject diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs index 46b864e7de..71214a4017 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Bindables; +using osu.Game.Audio; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; @@ -35,15 +37,35 @@ public HitType Type protected TaikoHitObject() { SamplesBindable.BindCollectionChanged((_, __) => UpdateTypeFromSamples()); - TypeBindable.BindValueChanged(_ => UpdateSamplesFromType()); + TypeBindable.BindValueChanged(_ => updateSamplesFromType()); } - protected virtual void UpdateSamplesFromType() + private void updateSamplesFromType() { + var rimSamples = getRimSamples(); + + bool isRimType = Type == HitType.Rim; + + if (isRimType != rimSamples.Any()) + { + if (isRimType) + Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_CLAP)); + else + { + foreach (var sample in rimSamples) + Samples.Remove(sample); + } + } } protected virtual void UpdateTypeFromSamples() { + Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; } + + /// + /// Returns an array of any samples which would cause this object to be a "rim" type hit. + /// + private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs index 237000474d..5cddc00a1e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs @@ -38,7 +38,7 @@ public bool IsStrong protected TaikoStrongableHitObject() { - IsStrongBindable.BindValueChanged(_ => UpdateSamplesFromType()); + IsStrongBindable.BindValueChanged(_ => updateSamplesFromType()); } protected override void UpdateTypeFromSamples() @@ -48,10 +48,8 @@ protected override void UpdateTypeFromSamples() IsStrong = getStrongSamples().Any(); } - protected override void UpdateSamplesFromType() + private void updateSamplesFromType() { - base.UpdateSamplesFromType(); - var strongSamples = getStrongSamples(); if (IsStrongBindable.Value != strongSamples.Any()) From cbad7bb7f0d4f58707c737809e9384936a8e476c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 13:40:36 +0900 Subject: [PATCH 54/93] Move taiko `Type` to `Hit` and localise all bind handling --- osu.Game.Rulesets.Taiko/Objects/Hit.cs | 49 +++++++++++++++++++ .../Objects/TaikoHitObject.cs | 48 ------------------ .../Objects/TaikoStrongableHitObject.cs | 5 +- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index 6b6c04e92e..b4ed242893 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -1,10 +1,59 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; +using osu.Framework.Bindables; +using osu.Game.Audio; + namespace osu.Game.Rulesets.Taiko.Objects { public class Hit : TaikoStrongableHitObject { + public readonly Bindable TypeBindable = new Bindable(); + + /// + /// The that actuates this . + /// + public HitType Type + { + get => TypeBindable.Value; + set => TypeBindable.Value = value; + } + + public Hit() + { + TypeBindable.BindValueChanged(_ => updateSamplesFromType()); + SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples()); + } + + private void updateTypeFromSamples() + { + Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; + } + + /// + /// Returns an array of any samples which would cause this object to be a "rim" type hit. + /// + private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray(); + + private void updateSamplesFromType() + { + var rimSamples = getRimSamples(); + + bool isRimType = Type == HitType.Rim; + + if (isRimType != rimSamples.Any()) + { + if (isRimType) + Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_CLAP)); + else + { + foreach (var sample in rimSamples) + Samples.Remove(sample); + } + } + } + protected override StrongNestedHitObject CreateStrongNestedHit(double startTime) => new StrongNestedHit { StartTime = startTime }; public class StrongNestedHit : StrongNestedHitObject diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs index 71214a4017..f047c03f4b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; -using osu.Framework.Bindables; -using osu.Game.Audio; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; @@ -14,17 +11,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public abstract class TaikoHitObject : HitObject { - public readonly Bindable TypeBindable = new Bindable(); - - /// - /// The that actuates this . - /// - public HitType Type - { - get => TypeBindable.Value; - set => TypeBindable.Value = value; - } - /// /// Default size of a drawable taiko hit object. /// @@ -33,39 +19,5 @@ public HitType Type public override Judgement CreateJudgement() => new TaikoJudgement(); protected override HitWindows CreateHitWindows() => new TaikoHitWindows(); - - protected TaikoHitObject() - { - SamplesBindable.BindCollectionChanged((_, __) => UpdateTypeFromSamples()); - TypeBindable.BindValueChanged(_ => updateSamplesFromType()); - } - - private void updateSamplesFromType() - { - var rimSamples = getRimSamples(); - - bool isRimType = Type == HitType.Rim; - - if (isRimType != rimSamples.Any()) - { - if (isRimType) - Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_CLAP)); - else - { - foreach (var sample in rimSamples) - Samples.Remove(sample); - } - } - } - - protected virtual void UpdateTypeFromSamples() - { - Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre; - } - - /// - /// Returns an array of any samples which would cause this object to be a "rim" type hit. - /// - private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs index 5cddc00a1e..6c17573b50 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs @@ -39,12 +39,11 @@ public bool IsStrong protected TaikoStrongableHitObject() { IsStrongBindable.BindValueChanged(_ => updateSamplesFromType()); + SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples()); } - protected override void UpdateTypeFromSamples() + private void updateTypeFromSamples() { - base.UpdateTypeFromSamples(); - IsStrong = getStrongSamples().Any(); } From 7b09955d59c7538b8ff6d526c71193e9943ead34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 14:17:40 +0900 Subject: [PATCH 55/93] Remove redundant default bindable value --- osu.Game/Overlays/NewsOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index 751ac1d10a..d4ccf4970b 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays { public class NewsOverlay : OnlineOverlay { - private readonly Bindable article = new Bindable(null); + private readonly Bindable article = new Bindable(); private readonly Container sidebarContainer; private readonly NewsSidebar sidebar; From 8ffa7f4a5ae5087e7c6f3e3e3f44f012fa95e1e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 14:28:20 +0900 Subject: [PATCH 56/93] Tidy up code --- osu.Game/Overlays/NewsOverlay.cs | 43 +++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index d4ccf4970b..400505ba52 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -6,7 +6,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.News; using osu.Game.Overlays.News.Displays; @@ -22,9 +21,14 @@ public class NewsOverlay : OnlineOverlay private readonly NewsSidebar sidebar; private readonly Container content; - private APIRequest lastRequest; + private GetNewsRequest lastRequest; + private Cursor lastCursor; - private int? year; + + /// + /// The year currently being displayed. If null, the main listing is being displayed. + /// + private int? displayedYear; private CancellationTokenSource cancellationToken; @@ -100,7 +104,7 @@ public void ShowFrontPage() public void ShowYear(int year) { - loadFrontPage(year); + loadListing(year); Show(); } @@ -130,18 +134,18 @@ protected override void UpdateAfterChildren() private void onArticleChanged(ValueChangedEvent article) { if (article.NewValue == null) - loadFrontPage(); + loadListing(); else loadArticle(article.NewValue); } - private void loadFrontPage(int? year = null) + private void loadListing(int? year = null) { beginLoading(); Header.SetFrontPage(); - this.year = year; + displayedYear = year; lastCursor = null; performListingRequest(response => @@ -165,19 +169,6 @@ private void getMorePosts() }); } - private void performListingRequest(Action onSuccess) - { - lastRequest = new GetNewsRequest(year, lastCursor); - - ((GetNewsRequest)lastRequest).Success += response => Schedule(() => - { - lastCursor = response.Cursor; - onSuccess?.Invoke(response); - }); - - API.PerformAsync(lastRequest); - } - private void loadArticle(string article) { beginLoading(); @@ -188,6 +179,18 @@ private void loadArticle(string article) LoadDisplay(Empty()); } + private void performListingRequest(Action onSuccess) + { + lastRequest = new GetNewsRequest(displayedYear, lastCursor); + lastRequest.Success += response => Schedule(() => + { + lastCursor = response.Cursor; + onSuccess?.Invoke(response); + }); + + API.PerformAsync(lastRequest); + } + private void beginLoading() { lastRequest?.Cancel(); From 0f21510b8bc3a57347027c19ab9ecca306e32637 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 14:29:46 +0900 Subject: [PATCH 57/93] Move code around --- osu.Game/Overlays/NewsOverlay.cs | 36 +++++++++++++++----------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index 400505ba52..ede9432a17 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -74,7 +74,13 @@ protected override void LoadComplete() base.LoadComplete(); // should not be run until first pop-in to avoid requesting data before user views. - article.BindValueChanged(onArticleChanged); + article.BindValueChanged(a => + { + if (a.NewValue == null) + loadListing(); + else + loadArticle(a.NewValue); + }); } protected override NewsHeader CreateHeader() => new NewsHeader { ShowFrontPage = ShowFrontPage }; @@ -131,14 +137,6 @@ protected override void UpdateAfterChildren() sidebarContainer.Y = Math.Clamp(ScrollFlow.Current - Header.DrawHeight, 0, Math.Max(ScrollFlow.ScrollContent.DrawHeight - DrawHeight - Header.DrawHeight, 0)); } - private void onArticleChanged(ValueChangedEvent article) - { - if (article.NewValue == null) - loadListing(); - else - loadArticle(article.NewValue); - } - private void loadListing(int? year = null) { beginLoading(); @@ -159,16 +157,6 @@ private void loadListing(int? year = null) }); } - private void getMorePosts() - { - lastRequest?.Cancel(); - performListingRequest(response => - { - if (content.Child is ArticleListing listing) - listing.AddPosts(response); - }); - } - private void loadArticle(string article) { beginLoading(); @@ -179,6 +167,16 @@ private void loadArticle(string article) LoadDisplay(Empty()); } + private void getMorePosts() + { + lastRequest?.Cancel(); + performListingRequest(response => + { + if (content.Child is ArticleListing listing) + listing.AddPosts(response); + }); + } + private void performListingRequest(Action onSuccess) { lastRequest = new GetNewsRequest(displayedYear, lastCursor); From d165a758233d355f9fc9e70ad94740da2d955ce1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 14:37:52 +0900 Subject: [PATCH 58/93] Inline request flow to make it easier to understand --- osu.Game/Overlays/NewsOverlay.cs | 60 +++++++++++++++----------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index ede9432a17..8d0d242e39 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -21,7 +21,7 @@ public class NewsOverlay : OnlineOverlay private readonly NewsSidebar sidebar; private readonly Container content; - private GetNewsRequest lastRequest; + private GetNewsRequest request; private Cursor lastCursor; @@ -139,66 +139,64 @@ protected override void UpdateAfterChildren() private void loadListing(int? year = null) { - beginLoading(); - Header.SetFrontPage(); displayedYear = year; lastCursor = null; - performListingRequest(response => + beginLoading(true); + + request = new GetNewsRequest(displayedYear); + request.Success += response => Schedule(() => { + lastCursor = response.Cursor; sidebar.Metadata.Value = response.SidebarMetadata; - var listing = new ArticleListing(response); - listing.RequestMorePosts += getMorePosts; - - LoadDisplay(listing); + LoadDisplay(new ArticleListing(response) + { + RequestMorePosts = getMorePosts + }); }); - } - private void loadArticle(string article) - { - beginLoading(); - - Header.SetArticle(article); - - // Temporary, should be handled by ArticleDisplay later - LoadDisplay(Empty()); + API.PerformAsync(request); } private void getMorePosts() { - lastRequest?.Cancel(); - performListingRequest(response => + beginLoading(false); + + request = new GetNewsRequest(displayedYear, lastCursor); + request.Success += response => Schedule(() => { + lastCursor = response.Cursor; if (content.Child is ArticleListing listing) listing.AddPosts(response); }); + + API.PerformAsync(request); } - private void performListingRequest(Action onSuccess) + private void loadArticle(string article) { - lastRequest = new GetNewsRequest(displayedYear, lastCursor); - lastRequest.Success += response => Schedule(() => - { - lastCursor = response.Cursor; - onSuccess?.Invoke(response); - }); + // This is not yet implemented nor called from anywhere. + beginLoading(true); - API.PerformAsync(lastRequest); + Header.SetArticle(article); + LoadDisplay(Empty()); } - private void beginLoading() + private void beginLoading(bool showLoadingOverlay) { - lastRequest?.Cancel(); + request?.Cancel(); cancellationToken?.Cancel(); - Loading.Show(); + + if (showLoadingOverlay) + Loading.Show(); } protected override void Dispose(bool isDisposing) { - lastRequest?.Cancel(); + request?.Cancel(); cancellationToken?.Cancel(); base.Dispose(isDisposing); } From e4780abdfddf1642ff454e2fcad4e882adbe58e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 14:43:59 +0900 Subject: [PATCH 59/93] Split out `base` call from `switch` statement --- osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index d4ad0bee4d..b9037a5c77 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -23,12 +23,10 @@ protected override void AddMarkdownComponent(IMarkdownObject markdownObject, Fil { case YamlFrontMatterBlock yamlFrontMatterBlock: container.Add(CreateNotice(yamlFrontMatterBlock)); - break; - - default: - base.AddMarkdownComponent(markdownObject, container, level); - break; + return; } + + base.AddMarkdownComponent(markdownObject, container, level); } public override MarkdownTextFlowContainer CreateTextFlow() => new WikiMarkdownTextFlowContainer(); From b3b39c4c137d0068c188fb3c8b52d0e8739930b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 15:42:26 +0900 Subject: [PATCH 60/93] Fix `BeatmapCarousel` accessing `ScreenSpaceDrawQuad` of non-loaded children Fixes failure seen at https://ci.appveyor.com/project/peppy/osu/builds/39302762/tests. --- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index a3fca3d4e1..5875685965 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -36,7 +36,7 @@ public class DrawableCarouselBeatmapSet : DrawableCarouselItem, IHasContextMenu [Resolved(CanBeNull = true)] private ManageCollectionsDialog manageCollectionsDialog { get; set; } - public IEnumerable DrawableBeatmaps => beatmapContainer?.Children ?? Enumerable.Empty(); + public IEnumerable DrawableBeatmaps => beatmapContainer?.AliveChildren ?? Enumerable.Empty(); [CanBeNull] private Container beatmapContainer; From eeb6647bc50986ff123e483888df59f1af4b721b Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 14:59:36 +0700 Subject: [PATCH 61/93] remove schedule in set current path --- osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index b9037a5c77..dfec437fe4 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -14,7 +14,7 @@ public class WikiMarkdownContainer : OsuMarkdownContainer { public string CurrentPath { - set => Schedule(() => DocumentUrl += $"wiki/{value}"); + set => DocumentUrl = $"{DocumentUrl}wiki/{value}"; } protected override void AddMarkdownComponent(IMarkdownObject markdownObject, FillFlowContainer container, int level) From 47cbbee4d12760107bfe8c1294c7035224759b01 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 15:01:16 +0700 Subject: [PATCH 62/93] remove CreateNotice method and move implementation to local --- osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index dfec437fe4..fbfdc5feaf 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -22,7 +22,7 @@ protected override void AddMarkdownComponent(IMarkdownObject markdownObject, Fil switch (markdownObject) { case YamlFrontMatterBlock yamlFrontMatterBlock: - container.Add(CreateNotice(yamlFrontMatterBlock)); + container.Add(new WikiNoticeContainer(yamlFrontMatterBlock)); return; } @@ -33,8 +33,6 @@ protected override void AddMarkdownComponent(IMarkdownObject markdownObject, Fil protected override MarkdownParagraph CreateParagraph(ParagraphBlock paragraphBlock, int level) => new WikiMarkdownParagraph(paragraphBlock); - protected virtual FillFlowContainer CreateNotice(YamlFrontMatterBlock yamlFrontMatterBlock) => new WikiNoticeContainer(yamlFrontMatterBlock); - private class WikiMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer { protected override void AddImage(LinkInline linkInline) => AddDrawable(new WikiMarkdownImage(linkInline)); From f8a3a3779721ec862d6e920aa5ede5f57ff90f11 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 May 2021 17:34:17 +0900 Subject: [PATCH 63/93] Remove outdated comment --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 546049ea9b..5a2a9baf44 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -386,9 +386,6 @@ public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding) Margin = new MarginPadding(padding); - // todo: use this in a meaningful way - // var isDefault = keyBinding.Action is Enum; - Masking = true; CornerRadius = padding; From 71f77eb902c8e680b31f1ae39e2d68e28de9f3b4 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 15:04:04 +0700 Subject: [PATCH 64/93] fix image test --- .../Visual/Online/TestSceneWikiMarkdownContainer.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 67030631b0..ebabfc9479 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -106,6 +106,7 @@ public void TestAbsoluteImage() { AddStep("Add absolute image", () => { + markdownContainer.DocumentUrl = "https://osu.ppy.sh"; markdownContainer.Text = "![intro](/wiki/Interface/img/intro-screen.jpg)"; }); } @@ -115,6 +116,7 @@ public void TestRelativeImage() { AddStep("Add relative image", () => { + markdownContainer.DocumentUrl = "https://osu.ppy.sh"; markdownContainer.CurrentPath = "Interface/"; markdownContainer.Text = "![intro](img/intro-screen.jpg)"; }); @@ -125,6 +127,7 @@ public void TestBlockImage() { AddStep("Add paragraph with block image", () => { + markdownContainer.DocumentUrl = "https://osu.ppy.sh"; markdownContainer.CurrentPath = "Interface/"; markdownContainer.Text = @"Line before image @@ -139,6 +142,7 @@ public void TestInlineImage() { AddStep("Add inline image", () => { + markdownContainer.DocumentUrl = "https://osu.ppy.sh"; markdownContainer.Text = "![osu! mode icon](/wiki/shared/mode/osu.png) osu!"; }); } @@ -147,6 +151,11 @@ private class TestMarkdownContainer : WikiMarkdownContainer { public LinkInline Link; + public new string DocumentUrl + { + set => base.DocumentUrl = value; + } + public override MarkdownTextFlowContainer CreateTextFlow() => new TestMarkdownTextFlowContainer { UrlAdded = link => Link = link, @@ -162,6 +171,8 @@ protected override void AddLinkText(string text, LinkInline linkInline) UrlAdded?.Invoke(linkInline); } + + protected override void AddImage(LinkInline linkInline) => AddDrawable(new WikiMarkdownImage(linkInline)); } } } From 49b4a6ea67babd011e9f815b04d2ac60884c5c3d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 17:07:24 +0900 Subject: [PATCH 65/93] Replace local namespace qualifiers with `using` --- osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 09b2efd7fa..70b4fabd6d 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Game.Input.Bindings; using osu.Game.Rulesets; namespace osu.Game.Overlays.KeyBinding @@ -13,7 +14,7 @@ namespace osu.Game.Overlays.KeyBinding public class RestorableKeyBindingRow : Container, IFilterable { private readonly object key; - private readonly ICollection bindings; + private readonly ICollection bindings; public readonly KeyBindingRow KeyBindingRow; private bool matchingFilter; @@ -32,7 +33,7 @@ public bool MatchingFilter public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) + public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) { this.key = key; this.bindings = bindings; From 9c31b8856d8d4dc2d91a344249f02590c7809e61 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 15:10:09 +0700 Subject: [PATCH 66/93] change image url replace implementation --- .../Overlays/Wiki/Markdown/WikiMarkdownImage.cs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs index 361aa2e95f..c2115efeb5 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs @@ -2,37 +2,28 @@ // See the LICENCE file in the repository root for full licence text. using Markdig.Syntax.Inlines; -using osu.Framework.Allocation; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Cursor; -using osu.Game.Online.API; namespace osu.Game.Overlays.Wiki.Markdown { public class WikiMarkdownImage : MarkdownImage, IHasTooltip { - private readonly string url; - public string TooltipText { get; } public WikiMarkdownImage(LinkInline linkInline) : base(linkInline.Url) { - url = linkInline.Url; TooltipText = linkInline.Title; } - [BackgroundDependencyLoader] - private void load(IAPIProvider api) + protected override ImageContainer CreateImageContainer(string url) { - // The idea is replace "{api.WebsiteRootUrl}/wiki/{path-to-image}" to "{api.WebsiteRootUrl}/wiki/images/{path-to-image}" + // The idea is replace "https://website.url/wiki/{path-to-image}" to "https://website.url/wiki/images/{path-to-image}" // "/wiki/images/*" is route to fetch wiki image from osu!web server (see: https://github.com/ppy/osu-web/blob/4205eb66a4da86bdee7835045e4bf28c35456e04/routes/web.php#L289) - // Currently all image in dev server (https://dev.ppy.sh/wiki/image/*) is 404 - // So for now just replace "{api.WebsiteRootUrl}/wiki/*" to "https://osu.ppy.sh/wiki/images/*" for simplicity - var imageUrl = url.Replace($"{api.WebsiteRootUrl}/wiki", "https://osu.ppy.sh/wiki/images"); + url = url.Replace("/wiki/", "/wiki/images/"); - InternalChild = new DelayedLoadWrapper(CreateImageContainer(imageUrl)); + return base.CreateImageContainer(url); } } } From 17334fd2e6b3ee4280ca5ebcbe0b70a7bb04fd22 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 17:12:12 +0900 Subject: [PATCH 67/93] Inline `KeyBindingRow` construction --- .../Overlays/KeyBinding/RestorableKeyBindingRow.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs index 70b4fabd6d..5d1dc6a4d1 100644 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs @@ -42,12 +42,6 @@ public RestorableKeyBindingRow(object key, ICollection bind AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - }; - InternalChildren = new Drawable[] { new RestoreDefaultValueButton @@ -60,7 +54,11 @@ public RestorableKeyBindingRow(object key, ICollection bind RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = KeyBindingRow + Child = KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) + { + AllowMainMouseButtons = ruleset != null, + Defaults = defaults + } }, }; } From 02806fedb06b7c90ac6e32217fe7d41e783ad59f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 17:17:02 +0900 Subject: [PATCH 68/93] Add missing newline --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 5a2a9baf44..e8f6a4d065 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -101,6 +101,7 @@ private void load(OsuColour colours) }, } }; + foreach (var b in bindings) buttons.Add(new KeyButton(b)); } From 7c9383b586ad2ab0cf73e22c3b3505957f26f0cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 18:03:15 +0900 Subject: [PATCH 69/93] Combine `RestorableKeyBindingRow` back into `KeyBindingRow` --- .../Settings/TestSceneKeyBindingPanel.cs | 14 +- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 132 ++++++++++++------ .../KeyBinding/KeyBindingsSubsection.cs | 10 +- .../KeyBinding/RestorableKeyBindingRow.cs | 66 --------- .../Overlays/RestoreDefaultValueButton.cs | 3 + 5 files changed, 104 insertions(+), 121 deletions(-) delete mode 100644 osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 4d0321b29d..acf9deb3cb 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -142,11 +142,11 @@ void clickClearButton() [Test] public void TestSingleBindingResetButton() { - RestorableKeyBindingRow settingsKeyBindingRow = null; + KeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -165,17 +165,17 @@ public void TestSingleBindingResetButton() AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); } [Test] public void TestResetAllBindingsButton() { - RestorableKeyBindingRow settingsKeyBindingRow = null; + KeyBindingRow settingsKeyBindingRow = null; AddStep("click first row", () => { - settingsKeyBindingRow = panel.ChildrenOfType().First(); + settingsKeyBindingRow = panel.ChildrenOfType().First(); InputManager.MoveMouseTo(settingsKeyBindingRow); InputManager.Click(MouseButton.Left); @@ -194,7 +194,7 @@ public void TestResetAllBindingsButton() AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.KeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); } [Test] @@ -261,4 +261,4 @@ private void scrollToAndStartBinding(string name) }); } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index e8f6a4d065..c9ed64cc3f 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.KeyBinding { - public class KeyBindingRow : Container + public class KeyBindingRow : Container, IFilterable { private readonly object action; private readonly IEnumerable bindings; @@ -35,20 +35,40 @@ public class KeyBindingRow : Container private const float padding = 5; + private bool matchingFilter; + + public bool MatchingFilter + { + get => matchingFilter; + set + { + matchingFilter = value; + this.FadeTo(!matchingFilter ? 0 : 1); + } + } + + private Container content; + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + content.ReceivePositionalInputAt(screenSpacePos); + + public bool FilteringActive { get; set; } + + private OsuSpriteText text; private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; public Bindable IsDefault { get; } = new BindableBool(true); + public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); + public KeyBindingRow(object action, IEnumerable bindings) { this.action = action; this.bindings = bindings; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - - Masking = true; - CornerRadius = padding; } [Resolved] @@ -59,46 +79,65 @@ private void load(OsuColour colours) { updateIsDefaultValue(); - EdgeEffect = new EdgeEffectParameters - { - Radius = 2, - Colour = colours.YellowDark.Opacity(0), - Type = EdgeEffectType.Shadow, - Hollow = true, - }; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS }; - Children = new Drawable[] + InternalChildren = new Drawable[] { - new Box + new RestoreDefaultValueButton { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.6f, - }, - new OsuSpriteText - { - Text = action.GetDescription(), - Margin = new MarginPadding(padding), - }, - buttons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight - }, - cancelAndClearButtons = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding(padding) { Top = height + padding * 2 }, - Anchor = Anchor.TopRight, + Current = IsDefault, + Action = RestoreDefaults, Origin = Anchor.TopRight, - Alpha = 0, - Spacing = new Vector2(5), + }, + content = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Masking = true, + CornerRadius = padding, + EdgeEffect = new EdgeEffectParameters + { + Radius = 2, + Colour = colours.YellowDark.Opacity(0), + Type = EdgeEffectType.Shadow, + Hollow = true, + }, Children = new Drawable[] { - new CancelButton { Action = finalise }, - new ClearButton { Action = clear }, - }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + text = new OsuSpriteText + { + Text = action.GetDescription(), + Margin = new MarginPadding(padding), + }, + buttons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight + }, + cancelAndClearButtons = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding(padding) { Top = height + padding * 2 }, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Alpha = 0, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new CancelButton { Action = finalise }, + new ClearButton { Action = clear }, + }, + } + } } }; @@ -135,14 +174,14 @@ public void RestoreDefaults() protected override bool OnHover(HoverEvent e) { - FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); + content.FadeEdgeEffectTo(1, transition_time, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); + content.FadeEdgeEffectTo(0, transition_time, Easing.OutQuint); base.OnHoverLost(e); } @@ -307,14 +346,10 @@ private void finalise() cancelAndClearButtons.BypassAutoSizeAxes |= Axes.Y; } - private void updateIsDefaultValue() => IsDefault.Value = computeIsDefaultValue(); - - private bool computeIsDefaultValue() => bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); - protected override void OnFocus(FocusEvent e) { - AutoSizeDuration = 500; - AutoSizeEasing = Easing.OutQuint; + content.AutoSizeDuration = 500; + content.AutoSizeEasing = Easing.OutQuint; cancelAndClearButtons.FadeIn(300, Easing.OutQuint); cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y; @@ -339,6 +374,11 @@ private void updateBindTarget() if (bindTarget != null) bindTarget.IsBinding = true; } + private void updateIsDefaultValue() + { + IsDefault.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + } + private class CancelButton : TriangleButton { public CancelButton() diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 737c640b5a..5e1f9d8f75 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -37,13 +37,19 @@ private void load(KeyBindingStore store) foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { + int intKey = (int)defaultGroup.Key; + // one row per valid action. - Add(new RestorableKeyBindingRow(defaultGroup.Key, bindings, Ruleset, defaultGroup.Select(d => d.KeyCombination))); + Add(new KeyBindingRow(defaultGroup.Key, bindings.Where(b => ((int)b.Action).Equals(intKey))) + { + AllowMainMouseButtons = Ruleset != null, + Defaults = defaultGroup.Select(d => d.KeyCombination) + }); } Add(new ResetButton { - Action = () => Children.OfType().ForEach(k => k.KeyBindingRow.RestoreDefaults()) + Action = () => Children.OfType().ForEach(k => k.RestoreDefaults()) }); } } diff --git a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs deleted file mode 100644 index 5d1dc6a4d1..0000000000 --- a/osu.Game/Overlays/KeyBinding/RestorableKeyBindingRow.cs +++ /dev/null @@ -1,66 +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 System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Bindings; -using osu.Game.Input.Bindings; -using osu.Game.Rulesets; - -namespace osu.Game.Overlays.KeyBinding -{ - public class RestorableKeyBindingRow : Container, IFilterable - { - private readonly object key; - private readonly ICollection bindings; - public readonly KeyBindingRow KeyBindingRow; - - private bool matchingFilter; - - public bool MatchingFilter - { - get => matchingFilter; - set - { - matchingFilter = value; - this.FadeTo(!matchingFilter ? 0 : 1); - } - } - - public bool FilteringActive { get; set; } - - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(key.ToString()); - - public RestorableKeyBindingRow(object key, ICollection bindings, RulesetInfo ruleset, IEnumerable defaults) - { - this.key = key; - this.bindings = bindings; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; - - InternalChildren = new Drawable[] - { - new RestoreDefaultValueButton - { - Current = KeyBindingRow.IsDefault, - Action = () => { KeyBindingRow.RestoreDefaults(); } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS }, - Child = KeyBindingRow = new KeyBindingRow(key, bindings.Where(b => ((int)b.Action).Equals((int)key))) - { - AllowMainMouseButtons = ruleset != null, - Defaults = defaults - } - }, - }; - } - } -} diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 0fe7b7322f..213ad2ba68 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -21,6 +21,9 @@ public class RestoreDefaultValueButton : OsuButton, IHasTooltip, IHasCurrentV private readonly BindableWithCurrent current = new BindableWithCurrent(); + // this is done to ensure a click on this button doesn't trigger focus on a parent element which contains the button. + public override bool AcceptsFocus => true; + public Bindable Current { get => current.Current; From c05dfee22042f0ccdf305e9474b7b3d0b18de9ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 18:28:00 +0900 Subject: [PATCH 70/93] Simplify default handling flow --- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index c9ed64cc3f..0df3359c28 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -58,7 +58,7 @@ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; - public Bindable IsDefault { get; } = new BindableBool(true); + private Bindable isDefault { get; } = new BindableBool(true); public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); @@ -77,8 +77,6 @@ public KeyBindingRow(object action, IEnumerable { - Current = IsDefault, + Current = isDefault, Action = RestoreDefaults, Origin = Anchor.TopRight, }, @@ -143,19 +141,8 @@ private void load(OsuColour colours) foreach (var b in bindings) buttons.Add(new KeyButton(b)); - } - protected override void LoadComplete() - { - base.LoadComplete(); - - IsDefault.BindValueChanged(isDefault => - { - if (isDefault.NewValue) - { - finalise(); - } - }); + updateIsDefaultValue(); } public void RestoreDefaults() @@ -169,7 +156,7 @@ public void RestoreDefaults() store.Update(button.KeyBinding); } - updateIsDefaultValue(); + isDefault.Value = true; } protected override bool OnHover(HoverEvent e) @@ -376,7 +363,7 @@ private void updateBindTarget() private void updateIsDefaultValue() { - IsDefault.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); + isDefault.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); } private class CancelButton : TriangleButton From a77de24746a1aa085e7b707f811c53e3a6b41e78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 18:58:18 +0900 Subject: [PATCH 71/93] Fix `SlowLoadPlayer` potentially not being instantiated in time for test --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index cfdea31a75..1e0aee2149 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -176,11 +176,9 @@ public void TestLoadContinuation() { SlowLoadPlayer slowPlayer = null; - AddStep("load slow dummy beatmap", () => - { - LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); - Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000); - }); + AddStep("load slow dummy beatmap", () => LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)))); + AddUntilStep("wait for slow player to be instantiated", () => slowPlayer != null); + AddStep("schedule slow load", () => Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000)); AddUntilStep("wait for player to be current", () => slowPlayer.IsCurrentScreen()); } From 878079d3d7d32e04bcac1b05b9fc26f91bae9586 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 19:08:00 +0900 Subject: [PATCH 72/93] Fix correct beatmap not being set if running test alone --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 1e0aee2149..8a7e4da693 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -88,13 +88,18 @@ private void resetPlayer(bool interactive, Action beforeLoadAction = null) { beforeLoadAction?.Invoke(); + prepareBeatmap(); + + LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive))); + } + + private void prepareBeatmap() + { Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning; foreach (var mod in SelectedMods.Value.OfType()) mod.ApplyToTrack(Beatmap.Value.Track); - - LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive))); } [Test] @@ -176,7 +181,12 @@ public void TestLoadContinuation() { SlowLoadPlayer slowPlayer = null; - AddStep("load slow dummy beatmap", () => LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)))); + AddStep("load slow dummy beatmap", () => + { + prepareBeatmap(); + LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); + }); + AddUntilStep("wait for slow player to be instantiated", () => slowPlayer != null); AddStep("schedule slow load", () => Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000)); From 7ed4cbf7bff7a6800ae7c12d92dddbb2ddf9e1d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 19:25:05 +0900 Subject: [PATCH 73/93] Fix settings panel hide animation looking wrong when a sub-panel is visible when hidden --- osu.Game/Overlays/SettingsPanel.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index f0a11d67b7..eae828c142 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -10,6 +10,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Graphics; @@ -49,8 +50,6 @@ public abstract class SettingsPanel : OsuFocusedOverlayContainer private readonly bool showSidebar; - protected Box Background; - protected SettingsPanel(bool showSidebar) { this.showSidebar = showSidebar; @@ -63,13 +62,13 @@ protected SettingsPanel(bool showSidebar) [BackgroundDependencyLoader] private void load() { - InternalChild = ContentContainer = new Container + InternalChild = ContentContainer = new NonMaskedContent { Width = WIDTH, RelativeSizeAxes = Axes.Y, Children = new Drawable[] { - Background = new Box + new Box { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -165,7 +164,7 @@ protected override void PopOut() { base.PopOut(); - ContentContainer.MoveToX(-WIDTH, TRANSITION_LENGTH, Easing.OutQuint); + ContentContainer.MoveToX(-WIDTH + ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint); Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint); this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); @@ -191,6 +190,12 @@ protected override void UpdateAfterChildren() Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; } + private class NonMaskedContent : Container + { + // masking breaks the pan-out transform with nested sub-settings panels. + protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; + } + public class SettingsSectionsContainer : SectionsContainer { public SearchContainer SearchContainer; From fbfbd992235b2a4ac2b7467521ae715f61795f4c Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 19:20:39 +0700 Subject: [PATCH 74/93] change document url test to dev server --- .../Visual/Online/TestSceneWikiMarkdownContainer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index ebabfc9479..57bd8cd077 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -106,7 +106,7 @@ public void TestAbsoluteImage() { AddStep("Add absolute image", () => { - markdownContainer.DocumentUrl = "https://osu.ppy.sh"; + markdownContainer.DocumentUrl = "https://dev.ppy.sh"; markdownContainer.Text = "![intro](/wiki/Interface/img/intro-screen.jpg)"; }); } @@ -116,7 +116,7 @@ public void TestRelativeImage() { AddStep("Add relative image", () => { - markdownContainer.DocumentUrl = "https://osu.ppy.sh"; + markdownContainer.DocumentUrl = "https://dev.ppy.sh"; markdownContainer.CurrentPath = "Interface/"; markdownContainer.Text = "![intro](img/intro-screen.jpg)"; }); @@ -127,7 +127,7 @@ public void TestBlockImage() { AddStep("Add paragraph with block image", () => { - markdownContainer.DocumentUrl = "https://osu.ppy.sh"; + markdownContainer.DocumentUrl = "https://dev.ppy.sh"; markdownContainer.CurrentPath = "Interface/"; markdownContainer.Text = @"Line before image @@ -142,7 +142,7 @@ public void TestInlineImage() { AddStep("Add inline image", () => { - markdownContainer.DocumentUrl = "https://osu.ppy.sh"; + markdownContainer.DocumentUrl = "https://dev.ppy.sh"; markdownContainer.Text = "![osu! mode icon](/wiki/shared/mode/osu.png) osu!"; }); } From 62fb09774a7588e9bb9babd29ded257c0325901d Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 19:22:21 +0700 Subject: [PATCH 75/93] create WikiMarkdownImageBlock --- .../Wiki/Markdown/WikiMarkdownImageBlock.cs | 49 +++++++++++++++++++ .../Wiki/Markdown/WikiMarkdownParagraph.cs | 40 --------------- 2 files changed, 49 insertions(+), 40 deletions(-) create mode 100644 osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImageBlock.cs delete mode 100644 osu.Game/Overlays/Wiki/Markdown/WikiMarkdownParagraph.cs diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImageBlock.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImageBlock.cs new file mode 100644 index 0000000000..179762103a --- /dev/null +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImageBlock.cs @@ -0,0 +1,49 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig.Syntax.Inlines; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; +using osuTK; + +namespace osu.Game.Overlays.Wiki.Markdown +{ + public class WikiMarkdownImageBlock : FillFlowContainer + { + [Resolved] + private IMarkdownTextComponent parentTextComponent { get; set; } + + private readonly LinkInline linkInline; + + public WikiMarkdownImageBlock(LinkInline linkInline) + { + this.linkInline = linkInline; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + Spacing = new Vector2(0, 3); + } + + [BackgroundDependencyLoader] + private void load() + { + Children = new Drawable[] + { + new WikiMarkdownImage(linkInline) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + parentTextComponent.CreateSpriteText().With(t => + { + t.Text = linkInline.Title; + t.Anchor = Anchor.TopCentre; + t.Origin = Anchor.TopCentre; + }), + }; + } + } +} diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownParagraph.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownParagraph.cs deleted file mode 100644 index 4a7ce24aba..0000000000 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownParagraph.cs +++ /dev/null @@ -1,40 +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 System.Linq; -using Markdig.Syntax; -using Markdig.Syntax.Inlines; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers.Markdown; -using osuTK; - -namespace osu.Game.Overlays.Wiki.Markdown -{ - public class WikiMarkdownParagraph : MarkdownParagraph - { - private readonly ParagraphBlock paragraphBlock; - - public WikiMarkdownParagraph(ParagraphBlock paragraphBlock) - : base(paragraphBlock) - { - this.paragraphBlock = paragraphBlock; - } - - [BackgroundDependencyLoader] - private void load() - { - MarkdownTextFlowContainer textFlow; - InternalChild = textFlow = CreateTextFlow(); - textFlow.AddInlineText(paragraphBlock.Inline); - - // Check if paragraph only contains an image. - if (paragraphBlock.Inline.Count() == 1 && paragraphBlock.Inline.FirstChild is LinkInline { IsImage: true } linkInline) - { - textFlow.TextAnchor = Anchor.TopCentre; - textFlow.Spacing = new Vector2(0, 5); - textFlow.AddText($"\n{linkInline.Title}"); - } - } - } -} From 2344a1a411cf1778ffd21635e2167f13e0039f89 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 26 May 2021 19:22:33 +0700 Subject: [PATCH 76/93] use image block in markdown container --- .../Wiki/Markdown/WikiMarkdownContainer.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index fbfdc5feaf..4e671cca6d 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.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.Linq; using Markdig.Extensions.Yaml; using Markdig.Syntax; using Markdig.Syntax.Inlines; @@ -23,7 +24,17 @@ protected override void AddMarkdownComponent(IMarkdownObject markdownObject, Fil { case YamlFrontMatterBlock yamlFrontMatterBlock: container.Add(new WikiNoticeContainer(yamlFrontMatterBlock)); - return; + break; + + case ParagraphBlock paragraphBlock: + // Check if paragraph only contains an image + if (paragraphBlock.Inline.Count() == 1 && paragraphBlock.Inline.FirstChild is LinkInline { IsImage: true } linkInline) + { + container.Add(new WikiMarkdownImageBlock(linkInline)); + return; + } + + break; } base.AddMarkdownComponent(markdownObject, container, level); @@ -31,8 +42,6 @@ protected override void AddMarkdownComponent(IMarkdownObject markdownObject, Fil public override MarkdownTextFlowContainer CreateTextFlow() => new WikiMarkdownTextFlowContainer(); - protected override MarkdownParagraph CreateParagraph(ParagraphBlock paragraphBlock, int level) => new WikiMarkdownParagraph(paragraphBlock); - private class WikiMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer { protected override void AddImage(LinkInline linkInline) => AddDrawable(new WikiMarkdownImage(linkInline)); From 1bde11a07e202e9c643d3602d66cd2948b83b807 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 26 May 2021 15:35:38 +0300 Subject: [PATCH 77/93] Refactor ArticleListing --- .../Overlays/News/Displays/ArticleListing.cs | 58 ++++++++++++------- osu.Game/Overlays/NewsOverlay.cs | 9 ++- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/osu.Game/Overlays/News/Displays/ArticleListing.cs b/osu.Game/Overlays/News/Displays/ArticleListing.cs index b554b462a9..4bbc80c5f3 100644 --- a/osu.Game/Overlays/News/Displays/ArticleListing.cs +++ b/osu.Game/Overlays/News/Displays/ArticleListing.cs @@ -2,13 +2,16 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Collections.Specialized; using System.Linq; using System.Threading; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osuTK; namespace osu.Game.Overlays.News.Displays @@ -20,20 +23,12 @@ public class ArticleListing : CompositeDrawable { public Action RequestMorePosts; + private readonly BindableList posts = new BindableList(); + private bool showMoreButtonIsVisible; + private FillFlowContainer content; private ShowMoreButton showMore; - private readonly GetNewsResponse initialResponse; - - /// - /// Instantiate a listing for the specified year. - /// - /// Initial response to create articles from. - public ArticleListing(GetNewsResponse initialResponse) - { - this.initialResponse = initialResponse; - } - [BackgroundDependencyLoader] private void load() { @@ -45,7 +40,6 @@ private void load() Left = 30, Right = 50 }; - InternalChild = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -61,8 +55,7 @@ private void load() RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 10), - Children = initialResponse.NewsPosts.Select(p => new NewsCard(p)).ToList() + Spacing = new Vector2(0, 10) }, showMore = new ShowMoreButton { @@ -73,24 +66,45 @@ private void load() Top = 15 }, Action = RequestMorePosts, - Alpha = initialResponse.Cursor != null ? 1 : 0 + Alpha = 0 } } }; } + protected override void LoadComplete() + { + base.LoadComplete(); + + posts.BindCollectionChanged((sender, args) => + { + switch (args.Action) + { + case NotifyCollectionChangedAction.Add: + addPosts(args.NewItems.Cast()); + break; + + default: + throw new NotSupportedException(@"You can only add items to this list. Other actions are not supported."); + } + }, true); + } + + public void AddPosts(IEnumerable posts, bool showMoreButtonIsVisible) + { + this.showMoreButtonIsVisible = showMoreButtonIsVisible; + this.posts.AddRange(posts); + } + private CancellationTokenSource cancellationToken; - public void AddPosts(GetNewsResponse response) + private void addPosts(IEnumerable posts) { - cancellationToken?.Cancel(); - - LoadComponentsAsync(response.NewsPosts.Select(p => new NewsCard(p)).ToList(), loaded => + LoadComponentsAsync(posts.Select(p => new NewsCard(p)).ToList(), loaded => { content.AddRange(loaded); - showMore.IsLoading = false; - showMore.Alpha = response.Cursor != null ? 1 : 0; + showMore.Alpha = showMoreButtonIsVisible ? 1 : 0; }, (cancellationToken = new CancellationTokenSource()).Token); } diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index 8d0d242e39..34bacd5540 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -152,10 +152,9 @@ private void loadListing(int? year = null) lastCursor = response.Cursor; sidebar.Metadata.Value = response.SidebarMetadata; - LoadDisplay(new ArticleListing(response) - { - RequestMorePosts = getMorePosts - }); + var listing = new ArticleListing { RequestMorePosts = getMorePosts }; + listing.AddPosts(response.NewsPosts, response.Cursor != null); + LoadDisplay(listing); }); API.PerformAsync(request); @@ -170,7 +169,7 @@ private void getMorePosts() { lastCursor = response.Cursor; if (content.Child is ArticleListing listing) - listing.AddPosts(response); + listing.AddPosts(response.NewsPosts, response.Cursor != null); }); API.PerformAsync(request); From 8e923a5d8ff233db20652edbc33d7d217830580a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 22:24:51 +0900 Subject: [PATCH 78/93] Instantiate immediately, rather than waiting for instantiation --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 8a7e4da693..8160a62991 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -184,10 +184,10 @@ public void TestLoadContinuation() AddStep("load slow dummy beatmap", () => { prepareBeatmap(); - LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false))); + slowPlayer = new SlowLoadPlayer(false, false); + LoadScreen(loader = new TestPlayerLoader(() => slowPlayer)); }); - AddUntilStep("wait for slow player to be instantiated", () => slowPlayer != null); AddStep("schedule slow load", () => Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000)); AddUntilStep("wait for player to be current", () => slowPlayer.IsCurrentScreen()); From 71de541245060ea4b48d38820c233e30d5ee29bb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 22:35:11 +0900 Subject: [PATCH 79/93] Minor spacing / reformatting --- osu.Game/Overlays/News/Displays/ArticleListing.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/News/Displays/ArticleListing.cs b/osu.Game/Overlays/News/Displays/ArticleListing.cs index 4bbc80c5f3..3524b8652c 100644 --- a/osu.Game/Overlays/News/Displays/ArticleListing.cs +++ b/osu.Game/Overlays/News/Displays/ArticleListing.cs @@ -34,12 +34,14 @@ private void load() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Vertical = 20, Left = 30, Right = 50 }; + InternalChild = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -61,10 +63,7 @@ private void load() { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Margin = new MarginPadding - { - Top = 15 - }, + Margin = new MarginPadding { Top = 15 }, Action = RequestMorePosts, Alpha = 0 } From 9947867e8408e8f2d0d4296061c9f67ea3bf1ffe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 22:46:43 +0900 Subject: [PATCH 80/93] Remove unnecessary bindable flow --- .../Overlays/News/Displays/ArticleListing.cs | 42 +++---------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/osu.Game/Overlays/News/Displays/ArticleListing.cs b/osu.Game/Overlays/News/Displays/ArticleListing.cs index 3524b8652c..48a3f5498a 100644 --- a/osu.Game/Overlays/News/Displays/ArticleListing.cs +++ b/osu.Game/Overlays/News/Displays/ArticleListing.cs @@ -3,11 +3,9 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.Linq; using System.Threading; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -23,9 +21,6 @@ public class ArticleListing : CompositeDrawable { public Action RequestMorePosts; - private readonly BindableList posts = new BindableList(); - private bool showMoreButtonIsVisible; - private FillFlowContainer content; private ShowMoreButton showMore; @@ -71,41 +66,16 @@ private void load() }; } - protected override void LoadComplete() - { - base.LoadComplete(); - - posts.BindCollectionChanged((sender, args) => - { - switch (args.Action) - { - case NotifyCollectionChangedAction.Add: - addPosts(args.NewItems.Cast()); - break; - - default: - throw new NotSupportedException(@"You can only add items to this list. Other actions are not supported."); - } - }, true); - } - - public void AddPosts(IEnumerable posts, bool showMoreButtonIsVisible) - { - this.showMoreButtonIsVisible = showMoreButtonIsVisible; - this.posts.AddRange(posts); - } - - private CancellationTokenSource cancellationToken; - - private void addPosts(IEnumerable posts) - { + public void AddPosts(IEnumerable posts, bool morePostsAvailable) => Schedule(() => LoadComponentsAsync(posts.Select(p => new NewsCard(p)).ToList(), loaded => { content.AddRange(loaded); showMore.IsLoading = false; - showMore.Alpha = showMoreButtonIsVisible ? 1 : 0; - }, (cancellationToken = new CancellationTokenSource()).Token); - } + showMore.Alpha = morePostsAvailable ? 1 : 0; + }, (cancellationToken = new CancellationTokenSource()).Token) + ); + + private CancellationTokenSource cancellationToken; protected override void Dispose(bool isDisposing) { From 735e7b9c741e2bc0d4d29df6e880daf5ff44a665 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 22:49:39 +0900 Subject: [PATCH 81/93] Pass fetch more action in via ctor to avoid potential nullref --- osu.Game/Overlays/News/Displays/ArticleListing.cs | 13 +++++++++---- osu.Game/Overlays/NewsOverlay.cs | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/News/Displays/ArticleListing.cs b/osu.Game/Overlays/News/Displays/ArticleListing.cs index 48a3f5498a..dc3b17b323 100644 --- a/osu.Game/Overlays/News/Displays/ArticleListing.cs +++ b/osu.Game/Overlays/News/Displays/ArticleListing.cs @@ -19,11 +19,18 @@ namespace osu.Game.Overlays.News.Displays /// public class ArticleListing : CompositeDrawable { - public Action RequestMorePosts; + private readonly Action fetchMorePosts; private FillFlowContainer content; private ShowMoreButton showMore; + private CancellationTokenSource cancellationToken; + + public ArticleListing(Action fetchMorePosts) + { + this.fetchMorePosts = fetchMorePosts; + } + [BackgroundDependencyLoader] private void load() { @@ -59,7 +66,7 @@ private void load() Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Margin = new MarginPadding { Top = 15 }, - Action = RequestMorePosts, + Action = fetchMorePosts, Alpha = 0 } } @@ -75,8 +82,6 @@ public void AddPosts(IEnumerable posts, bool morePostsAvailable) => }, (cancellationToken = new CancellationTokenSource()).Token) ); - private CancellationTokenSource cancellationToken; - protected override void Dispose(bool isDisposing) { cancellationToken?.Cancel(); diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index 34bacd5540..12e3f81ca1 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -152,7 +152,7 @@ private void loadListing(int? year = null) lastCursor = response.Cursor; sidebar.Metadata.Value = response.SidebarMetadata; - var listing = new ArticleListing { RequestMorePosts = getMorePosts }; + var listing = new ArticleListing(getMorePosts); listing.AddPosts(response.NewsPosts, response.Cursor != null); LoadDisplay(listing); }); From c0a8382175a55e0323ab11ed456f3584489ea356 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 00:12:22 +0900 Subject: [PATCH 82/93] Remove local API construction --- .../Visual/Online/TestSceneWikiMarkdownContainer.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 57bd8cd077..c423d46aa3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -23,9 +23,6 @@ public class TestSceneWikiMarkdownContainer : OsuTestScene [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); - [Cached] - private readonly IAPIProvider api = new DummyAPIAccess(); - [SetUp] public void Setup() => Schedule(() => { @@ -55,16 +52,16 @@ public void TestLink() AddStep("set current path", () => markdownContainer.CurrentPath = "Article_styling_criteria/"); AddStep("set '/wiki/Main_Page''", () => markdownContainer.Text = "[wiki main page](/wiki/Main_Page)"); - AddAssert("check url", () => markdownContainer.Link.Url == $"{api.WebsiteRootUrl}/wiki/Main_Page"); + AddAssert("check url", () => markdownContainer.Link.Url == $"{API.WebsiteRootUrl}/wiki/Main_Page"); AddStep("set '../FAQ''", () => markdownContainer.Text = "[FAQ](../FAQ)"); - AddAssert("check url", () => markdownContainer.Link.Url == $"{api.WebsiteRootUrl}/wiki/FAQ"); + AddAssert("check url", () => markdownContainer.Link.Url == $"{API.WebsiteRootUrl}/wiki/FAQ"); AddStep("set './Writing''", () => markdownContainer.Text = "[wiki writing guidline](./Writing)"); - AddAssert("check url", () => markdownContainer.Link.Url == $"{api.WebsiteRootUrl}/wiki/Article_styling_criteria/Writing"); + AddAssert("check url", () => markdownContainer.Link.Url == $"{API.WebsiteRootUrl}/wiki/Article_styling_criteria/Writing"); AddStep("set 'Formatting''", () => markdownContainer.Text = "[wiki formatting guidline](Formatting)"); - AddAssert("check url", () => markdownContainer.Link.Url == $"{api.WebsiteRootUrl}/wiki/Article_styling_criteria/Formatting"); + AddAssert("check url", () => markdownContainer.Link.Url == $"{API.WebsiteRootUrl}/wiki/Article_styling_criteria/Formatting"); } [Test] From 74fc0a17d5f668c3e178c428c2e6abb30e6871db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 00:55:05 +0900 Subject: [PATCH 83/93] Remove unused using statement --- osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index c423d46aa3..1e19af933a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers.Markdown; -using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Overlays.Wiki.Markdown; From 9ac4ef273e72435d21f09e70c7297b53bcb32049 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Wed, 26 May 2021 23:21:05 +0300 Subject: [PATCH 84/93] Make DrawableSliderTail not require ITrackSnaking --- .../Objects/Drawables/DrawableSliderTail.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index d81af053d1..cd6bf1d8d2 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -7,13 +7,14 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, ITrackSnaking, IHasMainCirclePiece + public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, IHasMainCirclePiece { public new SliderTailCircle HitObject => (SliderTailCircle)base.HitObject; @@ -111,7 +112,12 @@ protected override void CheckForResult(bool userTriggered, double timeOffset) ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult); } - public void UpdateSnakingPosition(Vector2 start, Vector2 end) => - Position = HitObject.RepeatIndex % 2 == 0 ? end : start; + protected override void OnApply() + { + base.OnApply(); + + if (Slider != null) + Position = Slider.CurvePositionAt(HitObject.RepeatIndex % 2 == 0 ? 1 : 0); + } } } From 122bb05aa81d78af1671cf8e00f21e06134a5798 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 15:20:35 +0900 Subject: [PATCH 85/93] Add a mention that `OnApply/OnFree` is performed after `ApplyDefaults` --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index cc663c37af..cca55819c5 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -311,6 +311,7 @@ protected sealed override void OnFree(HitObjectLifetimeEntry entry) /// /// Invoked for this to take on any values from a newly-applied . + /// This is also fired after any changes which occurred via an call. /// protected virtual void OnApply() { @@ -318,6 +319,7 @@ protected virtual void OnApply() /// /// Invoked for this to revert any values previously taken on from the currently-applied . + /// This is also fired after any changes which occurred via an call. /// protected virtual void OnFree() { From 5c44083856ca22055275fa4271933e2f024dbd3d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 16:12:49 +0900 Subject: [PATCH 86/93] Fix test potentially not waiting for drawable beatmaps to be loaded --- .../Visual/SongSelect/TestSceneBeatmapCarousel.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 44c9361ff8..78ddfa9ed2 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -786,9 +786,12 @@ private void advanceSelection(bool diff, int direction = 1, int count = 1) } } - private void checkVisibleItemCount(bool diff, int count) => - AddAssert($"{count} {(diff ? "diffs" : "sets")} visible", () => + private void checkVisibleItemCount(bool diff, int count) + { + // until step required as we are querying against alive items, which are loaded asynchronously inside DrawableCarouselBeatmapSet. + AddUntilStep($"{count} {(diff ? "diffs" : "sets")} visible", () => carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count); + } private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null); From 046087a367b6a608620b05f014a985e60232fdea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 16:58:01 +0900 Subject: [PATCH 87/93] Fix access to `AliveChildren` before `IsLoaded` --- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 5875685965..9773bd5ce9 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -36,7 +36,7 @@ public class DrawableCarouselBeatmapSet : DrawableCarouselItem, IHasContextMenu [Resolved(CanBeNull = true)] private ManageCollectionsDialog manageCollectionsDialog { get; set; } - public IEnumerable DrawableBeatmaps => beatmapContainer?.AliveChildren ?? Enumerable.Empty(); + public IEnumerable DrawableBeatmaps => beatmapContainer?.IsLoaded != true ? Enumerable.Empty() : beatmapContainer.AliveChildren; [CanBeNull] private Container beatmapContainer; From 37ef368738139e0214dc046693d67e928c939813 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:03:59 +0900 Subject: [PATCH 88/93] Move async call out of `using` to better define the flow of data --- osu.Game/Collections/CollectionManager.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Collections/CollectionManager.cs b/osu.Game/Collections/CollectionManager.cs index 3a63587b30..086cc573d5 100644 --- a/osu.Game/Collections/CollectionManager.cs +++ b/osu.Game/Collections/CollectionManager.cs @@ -58,8 +58,13 @@ private void load() if (storage.Exists(database_name)) { + List beatmapCollections; + using (var stream = storage.GetStream(database_name)) - importCollections(readCollections(stream)); + beatmapCollections = readCollections(stream); + + // intentionally fire-and-forget async. + importCollections(beatmapCollections); } } From 0c4d4ee0d2f4792964a5b2630ec90c780853d208 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:16:22 +0900 Subject: [PATCH 89/93] Fix collection import tests deadlocking due to `TaskCompletionSource` continuation triggering host disposal --- .../Collections/IO/ImportCollectionsTest.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs index a8ee1bcc2e..040c0d7165 100644 --- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs +++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs @@ -23,7 +23,7 @@ public async Task TestImportEmptyDatabase() { var osu = LoadOsuIntoHost(host); - await osu.CollectionManager.Import(new MemoryStream()); + await importCollectionsFromStream(osu, new MemoryStream()); Assert.That(osu.CollectionManager.Collections.Count, Is.Zero); } @@ -36,14 +36,14 @@ public async Task TestImportEmptyDatabase() [Test] public async Task TestImportWithNoBeatmaps() - { +{ using (HeadlessGameHost host = new CleanRunHeadlessGameHost()) { try { var osu = LoadOsuIntoHost(host); - await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db")); + await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db")); Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2)); @@ -69,7 +69,7 @@ public async Task TestImportWithBeatmaps() { var osu = LoadOsuIntoHost(host, true); - await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db")); + await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db")); Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2)); @@ -110,7 +110,7 @@ public async Task TestImportMalformedDatabase() ms.Seek(0, SeekOrigin.Begin); - await osu.CollectionManager.Import(ms); + await importCollectionsFromStream(osu, ms); } Assert.That(host.UpdateThread.Running, Is.True); @@ -134,7 +134,7 @@ public async Task TestSaveAndReload() { var osu = LoadOsuIntoHost(host, true); - await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db")); + await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db")); // Move first beatmap from second collection into the first. osu.CollectionManager.Collections[0].Beatmaps.Add(osu.CollectionManager.Collections[1].Beatmaps[0]); @@ -169,5 +169,12 @@ public async Task TestSaveAndReload() } } } + + private static async Task importCollectionsFromStream(TestOsuGameBase osu, Stream stream) + { + // intentionally spin this up on a separate task to avoid disposal deadlocks. + // see https://github.com/EventStore/EventStore/issues/1179 + await Task.Run(() => osu.CollectionManager.Import(stream).Wait()); + } } } From a2ed85bf460c128425a264a9409d6544b50cc4d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:34:39 +0900 Subject: [PATCH 90/93] Fix broken formatting --- osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs index 040c0d7165..a47631a83b 100644 --- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs +++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs @@ -36,7 +36,7 @@ public async Task TestImportEmptyDatabase() [Test] public async Task TestImportWithNoBeatmaps() -{ + { using (HeadlessGameHost host = new CleanRunHeadlessGameHost()) { try From bcf1e3db1ed995edc4236f18f90e18150db5a4b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:45:53 +0900 Subject: [PATCH 91/93] Fix test failures in `TestSceneStoryboardWithOutro` Test was not accounting for the fact that the results may not have loaded in time. --- osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs index 0ac8e01482..5ef3eff856 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs @@ -53,7 +53,8 @@ public void TestStoryboardSkipOutro() CreateTest(null); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space)); - AddAssert("score shown", () => Player.IsScoreShown); + AddUntilStep("wait for score shown", () => Player.IsScoreShown); + AddUntilStep("time less than storyboard duration", () => Player.GameplayClockContainer.GameplayClock.CurrentTime < currentStoryboardDuration); } [Test] From 121dd175e67be92c3796462b5fa6e7f04124c5d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 19:57:19 +0900 Subject: [PATCH 92/93] Fix test failure in `TestSceneMultiplayerGameplayLeaderboard` The transfer of users was not accounting for the fact that the `StartPlay` calls are now scheduled and not necessarily run in time. --- .../TestSceneMultiplayerGameplayLeaderboard.cs | 8 ++++++-- osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 80b9aa8228..af2f6fa5fe 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -73,8 +73,11 @@ public override void SetUpSteps() for (int i = 0; i < users; i++) spectatorClient.StartPlay(i, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); - Client.CurrentMatchPlayingUserIds.Clear(); - Client.CurrentMatchPlayingUserIds.AddRange(spectatorClient.PlayingUsers); + spectatorClient.Schedule(() => + { + Client.CurrentMatchPlayingUserIds.Clear(); + Client.CurrentMatchPlayingUserIds.AddRange(spectatorClient.PlayingUsers); + }); Children = new Drawable[] { @@ -91,6 +94,7 @@ public override void SetUpSteps() }); AddUntilStep("wait for load", () => leaderboard.IsLoaded); + AddUntilStep("wait for user population", () => Client.CurrentMatchPlayingUserIds.Count > 0); } [Test] diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index 3a5ffa8770..c7aa43b377 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -3,6 +3,7 @@ #nullable enable +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -53,6 +54,8 @@ public void EndPlay(int userId) }); } + public new void Schedule(Action action) => base.Schedule(action); + /// /// Sends frames for an arbitrary user. /// From ff1fa71e6f7b03eafd91739f20d0b7ded6cdbe60 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 May 2021 20:06:37 +0900 Subject: [PATCH 93/93] Remove feature request issue template and link to discussions --- .github/ISSUE_TEMPLATE/02-feature-request-issues.md | 7 ------- .github/ISSUE_TEMPLATE/config.yml | 9 ++++++++- 2 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/02-feature-request-issues.md diff --git a/.github/ISSUE_TEMPLATE/02-feature-request-issues.md b/.github/ISSUE_TEMPLATE/02-feature-request-issues.md deleted file mode 100644 index c3357dd780..0000000000 --- a/.github/ISSUE_TEMPLATE/02-feature-request-issues.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: Feature Request -about: Propose a feature you would like to see in the game! ---- -**Describe the new feature:** - -**Proposal designs of the feature:** diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 69baeee60c..c62231e8e0 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,12 @@ blank_issues_enabled: false contact_links: + - name: Suggestions or feature request + url: https://github.com/ppy/osu/discussions/categories/ideas + about: Got something you think should change or be added? Search for or start a new discussion! + - name: Help + url: https://github.com/ppy/osu/discussions/categories/q-a + about: osu! not working as you'd expect? Not sure it's a bug? Check the Q&A section! - name: osu!stable issues url: https://github.com/ppy/osu-stable-issues - about: For issues regarding osu!stable (not osu!lazer), open them here. + about: For osu!stable bugs (not osu!lazer), check out the dedicated repository. Note that we only accept serious bug reports. +