From fe23b9a262d90ad9926d754e9d6bc4df5dd3ca42 Mon Sep 17 00:00:00 2001 From: Joehu Date: Sun, 3 Nov 2019 07:32:47 -0800 Subject: [PATCH 01/73] Fix mod section overflowing mod select overlay at higher ui scale --- osu.Game/Overlays/Mods/ModSection.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index dedd397fa5..35a94eb43f 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -158,7 +158,8 @@ namespace osu.Game.Overlays.Mods }, ButtonsContainer = new FillFlowContainer { - AutoSizeAxes = Axes.Both, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, Spacing = new Vector2(50f, 0f), From 20d6eceecff465a37d8c6f9a602ec3fe48ad40bb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Nov 2019 16:03:35 +0900 Subject: [PATCH 02/73] Move DrawableOsuMenuItem out of OsuMenu --- .../UserInterface/DrawableOsuMenuItem.cs | 133 ++++++++++++++++++ osu.Game/Graphics/UserInterface/OsuMenu.cs | 123 ---------------- 2 files changed, 133 insertions(+), 123 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs diff --git a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs new file mode 100644 index 0000000000..efa0b3d69c --- /dev/null +++ b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs @@ -0,0 +1,133 @@ +// 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.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Game.Graphics.Sprites; +using osuTK.Graphics; + +namespace osu.Game.Graphics.UserInterface +{ + public class DrawableOsuMenuItem : Menu.DrawableMenuItem + { + private const int margin_horizontal = 17; + private const int text_size = 17; + private const int transition_length = 80; + public const int MARGIN_VERTICAL = 4; + + private SampleChannel sampleClick; + private SampleChannel sampleHover; + + private TextContainer text; + + public DrawableOsuMenuItem(MenuItem item) + : base(item) + { + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleHover = audio.Samples.Get(@"UI/generic-hover"); + sampleClick = audio.Samples.Get(@"UI/generic-select"); + + BackgroundColour = Color4.Transparent; + BackgroundColourHover = OsuColour.FromHex(@"172023"); + + updateTextColour(); + } + + private void updateTextColour() + { + switch ((Item as OsuMenuItem)?.Type) + { + default: + case MenuItemType.Standard: + text.Colour = Color4.White; + break; + + case MenuItemType.Destructive: + text.Colour = Color4.Red; + break; + + case MenuItemType.Highlighted: + text.Colour = OsuColour.FromHex(@"ffcc22"); + break; + } + } + + protected override bool OnHover(HoverEvent e) + { + sampleHover.Play(); + text.BoldText.FadeIn(transition_length, Easing.OutQuint); + text.NormalText.FadeOut(transition_length, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + text.BoldText.FadeOut(transition_length, Easing.OutQuint); + text.NormalText.FadeIn(transition_length, Easing.OutQuint); + base.OnHoverLost(e); + } + + protected override bool OnClick(ClickEvent e) + { + sampleClick.Play(); + return base.OnClick(e); + } + + protected sealed override Drawable CreateContent() => text = CreateTextContainer(); + protected virtual TextContainer CreateTextContainer() => new TextContainer(); + + protected class TextContainer : Container, IHasText + { + public string Text + { + get => NormalText.Text; + set + { + NormalText.Text = value; + BoldText.Text = value; + } + } + + public readonly SpriteText NormalText; + public readonly SpriteText BoldText; + + public TextContainer() + { + Anchor = Anchor.CentreLeft; + Origin = Anchor.CentreLeft; + + AutoSizeAxes = Axes.Both; + + Children = new Drawable[] + { + NormalText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: text_size), + Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, + }, + BoldText = new OsuSpriteText + { + AlwaysPresent = true, + Alpha = 0, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold), + Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, + } + }; + } + } + } +} diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index c4c6950eb1..be642e6afb 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -1,18 +1,12 @@ // 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.Audio; -using osu.Framework.Audio.Sample; using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; using osuTK; namespace osu.Game.Graphics.UserInterface @@ -53,122 +47,5 @@ namespace osu.Game.Graphics.UserInterface { Anchor = Direction == Direction.Horizontal ? Anchor.BottomLeft : Anchor.TopRight }; - - protected class DrawableOsuMenuItem : DrawableMenuItem - { - private const int margin_horizontal = 17; - private const int text_size = 17; - private const int transition_length = 80; - public const int MARGIN_VERTICAL = 4; - - private SampleChannel sampleClick; - private SampleChannel sampleHover; - - private TextContainer text; - - public DrawableOsuMenuItem(MenuItem item) - : base(item) - { - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - sampleHover = audio.Samples.Get(@"UI/generic-hover"); - sampleClick = audio.Samples.Get(@"UI/generic-select"); - - BackgroundColour = Color4.Transparent; - BackgroundColourHover = OsuColour.FromHex(@"172023"); - - updateTextColour(); - } - - private void updateTextColour() - { - switch ((Item as OsuMenuItem)?.Type) - { - default: - case MenuItemType.Standard: - text.Colour = Color4.White; - break; - - case MenuItemType.Destructive: - text.Colour = Color4.Red; - break; - - case MenuItemType.Highlighted: - text.Colour = OsuColour.FromHex(@"ffcc22"); - break; - } - } - - protected override bool OnHover(HoverEvent e) - { - sampleHover.Play(); - text.BoldText.FadeIn(transition_length, Easing.OutQuint); - text.NormalText.FadeOut(transition_length, Easing.OutQuint); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - text.BoldText.FadeOut(transition_length, Easing.OutQuint); - text.NormalText.FadeIn(transition_length, Easing.OutQuint); - base.OnHoverLost(e); - } - - protected override bool OnClick(ClickEvent e) - { - sampleClick.Play(); - return base.OnClick(e); - } - - protected sealed override Drawable CreateContent() => text = CreateTextContainer(); - protected virtual TextContainer CreateTextContainer() => new TextContainer(); - - protected class TextContainer : Container, IHasText - { - public string Text - { - get => NormalText.Text; - set - { - NormalText.Text = value; - BoldText.Text = value; - } - } - - public readonly SpriteText NormalText; - public readonly SpriteText BoldText; - - public TextContainer() - { - Anchor = Anchor.CentreLeft; - Origin = Anchor.CentreLeft; - - AutoSizeAxes = Axes.Both; - - Children = new Drawable[] - { - NormalText = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: text_size), - Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, - }, - BoldText = new OsuSpriteText - { - AlwaysPresent = true, - Alpha = 0, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold), - Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, - } - }; - } - } - } } } From 29672c48e126bb39829426f4174be8207e0f0bc6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Nov 2019 16:04:13 +0900 Subject: [PATCH 03/73] Make simple OsuMenuItem ctor invoke the complex one --- osu.Game/Graphics/UserInterface/OsuMenuItem.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs index b7aa666302..0fe41937ce 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs @@ -11,9 +11,8 @@ namespace osu.Game.Graphics.UserInterface public readonly MenuItemType Type; public OsuMenuItem(string text, MenuItemType type = MenuItemType.Standard) - : base(text) + : this(text, type, null) { - Type = type; } public OsuMenuItem(string text, MenuItemType type, Action action) From c3a3b4091bfd92841521822191b1caea5f6730fb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Nov 2019 22:26:35 +0900 Subject: [PATCH 04/73] Add basic implementation of a toggleable menu item --- .../UserInterface/TestSceneToggleMenuItem.cs | 33 ++++++++++ .../UserInterface/DrawableOsuMenuItem.cs | 8 +-- .../UserInterface/DrawableToggleMenuItem.cs | 60 +++++++++++++++++++ osu.Game/Graphics/UserInterface/OsuMenu.cs | 11 +++- .../Graphics/UserInterface/ToggleMenuItem.cs | 25 ++++++++ 5 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs create mode 100644 osu.Game/Graphics/UserInterface/DrawableToggleMenuItem.cs create mode 100644 osu.Game/Graphics/UserInterface/ToggleMenuItem.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs new file mode 100644 index 0000000000..97257b5226 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs @@ -0,0 +1,33 @@ +// 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 osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneToggleMenuItem : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(OsuMenu), + typeof(ToggleMenuItem), + typeof(DrawableToggleMenuItem) + }; + + public TestSceneToggleMenuItem() + { + Add(new OsuMenu(Direction.Vertical, true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Items = new[] + { + new ToggleMenuItem("Toggle"), + } + }); + } + } +} diff --git a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs index efa0b3d69c..591ed3df83 100644 --- a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs @@ -16,10 +16,10 @@ namespace osu.Game.Graphics.UserInterface { public class DrawableOsuMenuItem : Menu.DrawableMenuItem { - private const int margin_horizontal = 17; + public const int MARGIN_HORIZONTAL = 17; + public const int MARGIN_VERTICAL = 4; private const int text_size = 17; private const int transition_length = 80; - public const int MARGIN_VERTICAL = 4; private SampleChannel sampleClick; private SampleChannel sampleHover; @@ -115,7 +115,7 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: text_size), - Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, + Margin = new MarginPadding { Horizontal = MARGIN_HORIZONTAL, Vertical = MARGIN_VERTICAL }, }, BoldText = new OsuSpriteText { @@ -124,7 +124,7 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold), - Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, + Margin = new MarginPadding { Horizontal = MARGIN_HORIZONTAL, Vertical = MARGIN_VERTICAL }, } }; } diff --git a/osu.Game/Graphics/UserInterface/DrawableToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableToggleMenuItem.cs new file mode 100644 index 0000000000..cf0f154486 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/DrawableToggleMenuItem.cs @@ -0,0 +1,60 @@ +// 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.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Graphics.UserInterface +{ + public class DrawableToggleMenuItem : DrawableOsuMenuItem + { + protected new ToggleMenuItem Item => (ToggleMenuItem)base.Item; + + public DrawableToggleMenuItem(ToggleMenuItem item) + : base(item) + { + } + + protected override TextContainer CreateTextContainer() => new ToggleTextContainer + { + State = { BindTarget = Item.State } + }; + + private class ToggleTextContainer : TextContainer + { + public readonly Bindable State = new Bindable(); + + private readonly SpriteIcon checkmark; + + public ToggleTextContainer() + { + Add(checkmark = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.Check, + Size = new Vector2(10), + Margin = new MarginPadding { Horizontal = MARGIN_HORIZONTAL }, + AlwaysPresent = true, + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + State.BindValueChanged(state => checkmark.Alpha = state.NewValue ? 1 : 0, true); + } + + protected override void Update() + { + base.Update(); + + // Todo: This is bad. This can maybe be done better with a refactor of DrawableOsuMenuItem. + checkmark.X = BoldText.DrawWidth + 10; + } + } + } +} diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index be642e6afb..da32a2c861 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -39,7 +39,16 @@ namespace osu.Game.Graphics.UserInterface } } - protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item); + protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) + { + switch (item) + { + case ToggleMenuItem toggle: + return new DrawableToggleMenuItem(toggle); + } + + return new DrawableOsuMenuItem(item); + } protected override ScrollContainer CreateScrollContainer(Direction direction) => new OsuScrollContainer(direction); diff --git a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs new file mode 100644 index 0000000000..7b2bb32f47 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs @@ -0,0 +1,25 @@ +// 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 osu.Framework.Bindables; + +namespace osu.Game.Graphics.UserInterface +{ + public class ToggleMenuItem : OsuMenuItem + { + public readonly BindableBool State = new BindableBool(); + + public ToggleMenuItem(string text, MenuItemType type = MenuItemType.Standard) + : this(text, type, null) + { + } + + public ToggleMenuItem(string text, MenuItemType type, Action action) + : base(text, type) + { + Action.Value = () => State.Toggle(); + State.BindValueChanged(state => action?.Invoke(state.NewValue)); + } + } +} From 5235d2b3191948818b2e744083b3683a51ab9975 Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 7 Nov 2019 14:38:06 -0800 Subject: [PATCH 05/73] Fix home button not closing login and now playing overlays --- osu.Game/OsuGame.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1f823e6eba..3980390611 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -601,14 +601,14 @@ namespace osu.Game loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true); loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true); - loadComponentSingleFile(new LoginOverlay + var login = loadComponentSingleFile(new LoginOverlay { GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, rightFloatingOverlayContent.Add, true); - loadComponentSingleFile(new NowPlayingOverlay + var nowPlaying = loadComponentSingleFile(new NowPlayingOverlay { GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, @@ -671,6 +671,8 @@ namespace osu.Game }; } + overlays.AddRange(new OverlayContainer[] { login, nowPlaying }); + OverlayActivationMode.ValueChanged += mode => { if (mode.NewValue != OverlayActivation.All) CloseAllOverlays(); From 4fe69dbc896d77fd1efea4c469254fdbb3563fe0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 11:13:53 +0900 Subject: [PATCH 06/73] Fix context menu sub-menu display --- osu.Game/Graphics/UserInterface/OsuContextMenu.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs index cea8427296..4b629080e1 100644 --- a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterface { @@ -35,5 +36,7 @@ namespace osu.Game.Graphics.UserInterface protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint); protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint); + + protected override Menu CreateSubMenu() => new OsuContextMenu(); } } From ce08d664a52fef8633accc8f11b53ecb7d758906 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 11:15:03 +0900 Subject: [PATCH 07/73] Abstract statefulness of new menu item type --- .../TestSceneStatefulMenuItem.cs | 90 +++++++++++++++++++ .../UserInterface/TestSceneToggleMenuItem.cs | 33 ------- ...enuItem.cs => DrawableStatefulMenuItem.cs} | 44 +++++---- osu.Game/Graphics/UserInterface/OsuMenu.cs | 4 +- .../UserInterface/StatefulMenuItem.cs | 56 ++++++++++++ .../Graphics/UserInterface/ToggleMenuItem.cs | 11 ++- 6 files changed, 181 insertions(+), 57 deletions(-) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs rename osu.Game/Graphics/UserInterface/{DrawableToggleMenuItem.cs => DrawableStatefulMenuItem.cs} (51%) create mode 100644 osu.Game/Graphics/UserInterface/StatefulMenuItem.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs new file mode 100644 index 0000000000..fbb35ba09f --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs @@ -0,0 +1,90 @@ +// 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 osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneStatefulMenuItem : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(OsuMenu), + typeof(ToggleMenuItem), + typeof(DrawableStatefulMenuItem) + }; + + public TestSceneStatefulMenuItem() + { + Add(new OsuMenu(Direction.Vertical, true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Items = new[] + { + new TestMenuItem("First", MenuItemType.Standard, getNextState), + new TestMenuItem("Second", MenuItemType.Standard, getNextState) { State = { Value = TestStates.State2 } }, + new TestMenuItem("Third", MenuItemType.Standard, getNextState) { State = { Value = TestStates.State3 } }, + } + }); + } + + private TestStates getNextState(TestStates state) + { + switch (state) + { + case TestStates.State1: + return TestStates.State2; + + case TestStates.State2: + return TestStates.State3; + + case TestStates.State3: + return TestStates.State1; + } + + return TestStates.State1; + } + + private class TestMenuItem : StatefulMenuItem + { + public TestMenuItem(string text, MenuItemType type = MenuItemType.Standard) + : base(text, type) + { + } + + public TestMenuItem(string text, MenuItemType type, Func changeStateFunc) + : base(text, type, changeStateFunc) + { + } + + public override IconUsage? GetIconForState(TestStates state) + { + switch (state) + { + case TestStates.State1: + return FontAwesome.Solid.DiceOne; + + case TestStates.State2: + return FontAwesome.Solid.DiceTwo; + + case TestStates.State3: + return FontAwesome.Solid.DiceThree; + } + + return null; + } + } + + private enum TestStates + { + State1, + State2, + State3 + } + } +} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs deleted file mode 100644 index 97257b5226..0000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs +++ /dev/null @@ -1,33 +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; -using System.Collections.Generic; -using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public class TestSceneToggleMenuItem : OsuTestScene - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(OsuMenu), - typeof(ToggleMenuItem), - typeof(DrawableToggleMenuItem) - }; - - public TestSceneToggleMenuItem() - { - Add(new OsuMenu(Direction.Vertical, true) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Items = new[] - { - new ToggleMenuItem("Toggle"), - } - }); - } - } -} diff --git a/osu.Game/Graphics/UserInterface/DrawableToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs similarity index 51% rename from osu.Game/Graphics/UserInterface/DrawableToggleMenuItem.cs rename to osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs index cf0f154486..3dc99f2dbe 100644 --- a/osu.Game/Graphics/UserInterface/DrawableToggleMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs @@ -8,33 +8,33 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class DrawableToggleMenuItem : DrawableOsuMenuItem + public class DrawableStatefulMenuItem : DrawableOsuMenuItem { - protected new ToggleMenuItem Item => (ToggleMenuItem)base.Item; + protected new StatefulMenuItem Item => (StatefulMenuItem)base.Item; - public DrawableToggleMenuItem(ToggleMenuItem item) + public DrawableStatefulMenuItem(StatefulMenuItem item) : base(item) { } - protected override TextContainer CreateTextContainer() => new ToggleTextContainer - { - State = { BindTarget = Item.State } - }; + protected override TextContainer CreateTextContainer() => new ToggleTextContainer(Item); private class ToggleTextContainer : TextContainer { - public readonly Bindable State = new Bindable(); + private readonly StatefulMenuItem menuItem; + private readonly Bindable state; + private readonly SpriteIcon stateIcon; - private readonly SpriteIcon checkmark; - - public ToggleTextContainer() + public ToggleTextContainer(StatefulMenuItem menuItem) { - Add(checkmark = new SpriteIcon + this.menuItem = menuItem; + + state = menuItem.State.GetBoundCopy(); + + Add(stateIcon = new SpriteIcon { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Icon = FontAwesome.Solid.Check, Size = new Vector2(10), Margin = new MarginPadding { Horizontal = MARGIN_HORIZONTAL }, AlwaysPresent = true, @@ -44,8 +44,7 @@ namespace osu.Game.Graphics.UserInterface protected override void LoadComplete() { base.LoadComplete(); - - State.BindValueChanged(state => checkmark.Alpha = state.NewValue ? 1 : 0, true); + state.BindValueChanged(updateState, true); } protected override void Update() @@ -53,7 +52,20 @@ namespace osu.Game.Graphics.UserInterface base.Update(); // Todo: This is bad. This can maybe be done better with a refactor of DrawableOsuMenuItem. - checkmark.X = BoldText.DrawWidth + 10; + stateIcon.X = BoldText.DrawWidth + 10; + } + + private void updateState(ValueChangedEvent state) + { + var icon = menuItem.GetIconForState(state.NewValue); + + if (icon == null) + stateIcon.Alpha = 0; + else + { + stateIcon.Alpha = 1; + stateIcon.Icon = icon.Value; + } } } } diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index da32a2c861..e7bf4f66ee 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -43,8 +43,8 @@ namespace osu.Game.Graphics.UserInterface { switch (item) { - case ToggleMenuItem toggle: - return new DrawableToggleMenuItem(toggle); + case StatefulMenuItem stateful: + return new DrawableStatefulMenuItem(stateful); } return new DrawableOsuMenuItem(item); diff --git a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs new file mode 100644 index 0000000000..ede2c9df48 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs @@ -0,0 +1,56 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Sprites; + +namespace osu.Game.Graphics.UserInterface +{ + public abstract class StatefulMenuItem : OsuMenuItem + { + public readonly Bindable State = new Bindable(); + + protected StatefulMenuItem(string text, MenuItemType type = MenuItemType.Standard) + : this(text, type, null) + { + } + + protected StatefulMenuItem(string text, MenuItemType type, Func changeStateFunc) + : base(text, type) + { + Action.Value = () => State.Value = changeStateFunc?.Invoke(State.Value) ?? State.Value; + } + + public abstract IconUsage? GetIconForState(object state); + } + + public abstract class StatefulMenuItem : StatefulMenuItem + where T : struct + { + public new readonly Bindable State = new Bindable(); + + protected StatefulMenuItem(string text, MenuItemType type = MenuItemType.Standard) + : this(text, type, null) + { + } + + protected StatefulMenuItem(string text, MenuItemType type, Func changeStateFunc) + : base(text, type, o => changeStateFunc?.Invoke((T)o) ?? o) + { + base.State.BindValueChanged(state => + { + if (state.NewValue == null) + base.State.Value = default(T); + + State.Value = (T)base.State.Value; + }, true); + + State.BindValueChanged(state => base.State.Value = state.NewValue); + } + + public sealed override IconUsage? GetIconForState(object state) => GetIconForState((T)state); + + public abstract IconUsage? GetIconForState(T state); + } +} diff --git a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs index 7b2bb32f47..a0ed745c5a 100644 --- a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs @@ -2,24 +2,23 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Bindables; +using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public class ToggleMenuItem : OsuMenuItem + public class ToggleMenuItem : StatefulMenuItem { - public readonly BindableBool State = new BindableBool(); - public ToggleMenuItem(string text, MenuItemType type = MenuItemType.Standard) : this(text, type, null) { } public ToggleMenuItem(string text, MenuItemType type, Action action) - : base(text, type) + : base(text, type, value => !value) { - Action.Value = () => State.Toggle(); State.BindValueChanged(state => action?.Invoke(state.NewValue)); } + + public override IconUsage? GetIconForState(bool state) => state ? (IconUsage?)FontAwesome.Solid.Check : null; } } From 30f877c4ab7751066bd6a0ca2dc45178de355b69 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 12:47:42 +0900 Subject: [PATCH 08/73] Implement a three-state menu item --- .../TestSceneThreeStateMenuItem.cs | 35 ++++++++++++ .../UserInterface/ThreeStateMenuItem.cs | 53 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs create mode 100644 osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs new file mode 100644 index 0000000000..caa07e7b60 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs @@ -0,0 +1,35 @@ +// 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 osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneThreeStateMenuItem : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(OsuMenu), + typeof(ThreeStateMenuItem), + typeof(DrawableStatefulMenuItem) + }; + + public TestSceneThreeStateMenuItem() + { + Add(new OsuMenu(Direction.Vertical, true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Items = new[] + { + new ThreeStateMenuItem("First"), + new ThreeStateMenuItem("Second") { State = { Value = ThreeStates.Indeterminate } }, + new ThreeStateMenuItem("Third") { State = { Value = ThreeStates.Enabled } }, + } + }); + } + } +} diff --git a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs new file mode 100644 index 0000000000..107bfe208b --- /dev/null +++ b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs @@ -0,0 +1,53 @@ +// 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.Sprites; + +namespace osu.Game.Graphics.UserInterface +{ + public class ThreeStateMenuItem : StatefulMenuItem + { + public ThreeStateMenuItem(string text, MenuItemType type = MenuItemType.Standard) + : base(text, type, getNextState) + { + } + + public override IconUsage? GetIconForState(ThreeStates state) + { + switch (state) + { + case ThreeStates.Indeterminate: + return FontAwesome.Regular.Circle; + + case ThreeStates.Enabled: + return FontAwesome.Solid.Check; + } + + return null; + } + + private static ThreeStates getNextState(ThreeStates state) + { + switch (state) + { + case ThreeStates.Disabled: + return ThreeStates.Enabled; + + case ThreeStates.Indeterminate: + return ThreeStates.Enabled; + + case ThreeStates.Enabled: + return ThreeStates.Disabled; + } + + return ThreeStates.Disabled; + } + } + + public enum ThreeStates + { + Disabled, + Indeterminate, + Enabled + } +} From 0a15a13fabd66d5676dfd12e1117772a31ae605a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 12:55:22 +0900 Subject: [PATCH 09/73] Reorder parameters --- .../TestSceneStatefulMenuItem.cs | 4 ++-- .../UserInterface/StatefulMenuItem.cs | 20 +++++++++++-------- .../UserInterface/ThreeStateMenuItem.cs | 8 +++++++- .../Graphics/UserInterface/ToggleMenuItem.cs | 3 +-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs index fbb35ba09f..00678a6ab4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs @@ -53,12 +53,12 @@ namespace osu.Game.Tests.Visual.UserInterface private class TestMenuItem : StatefulMenuItem { public TestMenuItem(string text, MenuItemType type = MenuItemType.Standard) - : base(text, type) + : this(text, type, null) { } public TestMenuItem(string text, MenuItemType type, Func changeStateFunc) - : base(text, type, changeStateFunc) + : base(text, changeStateFunc, type) { } diff --git a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs index ede2c9df48..b5f9a3d635 100644 --- a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs @@ -11,15 +11,19 @@ namespace osu.Game.Graphics.UserInterface { public readonly Bindable State = new Bindable(); - protected StatefulMenuItem(string text, MenuItemType type = MenuItemType.Standard) - : this(text, type, null) + protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) + : this(text, changeStateFunc, type, null) { } - protected StatefulMenuItem(string text, MenuItemType type, Func changeStateFunc) + protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) : base(text, type) { - Action.Value = () => State.Value = changeStateFunc?.Invoke(State.Value) ?? State.Value; + Action.Value = () => + { + State.Value = changeStateFunc?.Invoke(State.Value) ?? State.Value; + action?.Invoke(State.Value); + }; } public abstract IconUsage? GetIconForState(object state); @@ -30,13 +34,13 @@ namespace osu.Game.Graphics.UserInterface { public new readonly Bindable State = new Bindable(); - protected StatefulMenuItem(string text, MenuItemType type = MenuItemType.Standard) - : this(text, type, null) + protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) + : this(text, changeStateFunc, type, null) { } - protected StatefulMenuItem(string text, MenuItemType type, Func changeStateFunc) - : base(text, type, o => changeStateFunc?.Invoke((T)o) ?? o) + protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) + : base(text, o => changeStateFunc?.Invoke((T)o) ?? o, type, o => action?.Invoke((T)o)) { base.State.BindValueChanged(state => { diff --git a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs index 107bfe208b..d41a95daa1 100644 --- a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface @@ -8,7 +9,12 @@ namespace osu.Game.Graphics.UserInterface public class ThreeStateMenuItem : StatefulMenuItem { public ThreeStateMenuItem(string text, MenuItemType type = MenuItemType.Standard) - : base(text, type, getNextState) + : this(text, type, null) + { + } + + public ThreeStateMenuItem(string text, MenuItemType type, Action action) + : base(text, getNextState, type, action) { } diff --git a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs index a0ed745c5a..f5a442b317 100644 --- a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs @@ -14,9 +14,8 @@ namespace osu.Game.Graphics.UserInterface } public ToggleMenuItem(string text, MenuItemType type, Action action) - : base(text, type, value => !value) + : base(text, value => !value, type, action) { - State.BindValueChanged(state => action?.Invoke(state.NewValue)); } public override IconUsage? GetIconForState(bool state) => state ? (IconUsage?)FontAwesome.Solid.Check : null; From 011bf095166d88d560087bbf83d07567309c585f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 13:14:23 +0900 Subject: [PATCH 10/73] Add xmldocs and cleanup --- .../TestSceneStatefulMenuItem.cs | 5 ++- .../UserInterface/StatefulMenuItem.cs | 45 +++++++++++++++++++ .../UserInterface/ThreeStateMenuItem.cs | 45 +++++++++++++++++-- .../Graphics/UserInterface/ToggleMenuItem.cs | 14 ++++++ 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs index 00678a6ab4..d010abc862 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs @@ -74,9 +74,10 @@ namespace osu.Game.Tests.Visual.UserInterface case TestStates.State3: return FontAwesome.Solid.DiceThree; - } - return null; + default: + throw new ArgumentOutOfRangeException(nameof(state), state, null); + } } } diff --git a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs index b5f9a3d635..0d7b36e51b 100644 --- a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs @@ -7,15 +7,34 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { + /// + /// An which contains and displays a state. + /// public abstract class StatefulMenuItem : OsuMenuItem { + /// + /// The current state that should be displayed. + /// public readonly Bindable State = new Bindable(); + /// + /// Creates a new . + /// + /// The text to display. + /// A function that mutates a state to another state after this is pressed. + /// The type of action which this performs. protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) : this(text, changeStateFunc, type, null) { } + /// + /// Creates a new . + /// + /// The text to display. + /// A function that mutates a state to another state after this is pressed. + /// The type of action which this performs. + /// A delegate to be invoked when this is pressed. protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) : base(text, type) { @@ -26,19 +45,40 @@ namespace osu.Game.Graphics.UserInterface }; } + /// + /// Retrieves the icon to be displayed for a state. + /// + /// The state to retrieve the relevant icon for. + /// The icon to be displayed for . public abstract IconUsage? GetIconForState(object state); } public abstract class StatefulMenuItem : StatefulMenuItem where T : struct { + /// + /// The current state that should be displayed. + /// public new readonly Bindable State = new Bindable(); + /// + /// Creates a new . + /// + /// The text to display. + /// A function that mutates a state to another state after this is pressed. + /// The type of action which this performs. protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) : this(text, changeStateFunc, type, null) { } + /// + /// Creates a new . + /// + /// The text to display. + /// A function that mutates a state to another state after this is pressed. + /// The type of action which this performs. + /// A delegate to be invoked when this is pressed. protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) : base(text, o => changeStateFunc?.Invoke((T)o) ?? o, type, o => action?.Invoke((T)o)) { @@ -55,6 +95,11 @@ namespace osu.Game.Graphics.UserInterface public sealed override IconUsage? GetIconForState(object state) => GetIconForState((T)state); + /// + /// Retrieves the icon to be displayed for a state. + /// + /// The state to retrieve the relevant icon for. + /// The icon to be displayed for . public abstract IconUsage? GetIconForState(T state); } } diff --git a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs index d41a95daa1..e33c68bebd 100644 --- a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs @@ -6,15 +6,41 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { + /// + /// An with three possible states. + /// public class ThreeStateMenuItem : StatefulMenuItem { + /// + /// Creates a new . + /// + /// The text to display. + /// The type of action which this performs. public ThreeStateMenuItem(string text, MenuItemType type = MenuItemType.Standard) : this(text, type, null) { } + /// + /// Creates a new . + /// + /// The text to display. + /// The type of action which this performs. + /// A delegate to be invoked when this is pressed. public ThreeStateMenuItem(string text, MenuItemType type, Action action) - : base(text, getNextState, type, action) + : this(text, getNextState, type, action) + { + } + + /// + /// Creates a new . + /// + /// The text to display. + /// A function that mutates a state to another state after this is pressed. + /// The type of action which this performs. + /// A delegate to be invoked when this is pressed. + protected ThreeStateMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) + : base(text, changeStateFunc, type, action) { } @@ -44,16 +70,29 @@ namespace osu.Game.Graphics.UserInterface case ThreeStates.Enabled: return ThreeStates.Disabled; - } - return ThreeStates.Disabled; + default: + throw new ArgumentOutOfRangeException(nameof(state), state, null); + } } } public enum ThreeStates { + /// + /// The current state is disabled. + /// Disabled, + + /// + /// The current state is a combination of and . + /// The state becomes if the is pressed. + /// Indeterminate, + + /// + /// The current state is enabled. + /// Enabled } } diff --git a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs index f5a442b317..f9ff9859dd 100644 --- a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs @@ -6,13 +6,27 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { + /// + /// An which displays an enabled or disabled state. + /// public class ToggleMenuItem : StatefulMenuItem { + /// + /// Creates a new . + /// + /// The text to display. + /// The type of action which this performs. public ToggleMenuItem(string text, MenuItemType type = MenuItemType.Standard) : this(text, type, null) { } + /// + /// Creates a new . + /// + /// The text to display. + /// The type of action which this performs. + /// A delegate to be invoked when this is pressed. public ToggleMenuItem(string text, MenuItemType type, Action action) : base(text, value => !value, type, action) { From a2c265c1478f1b33937d8da76343eabd688046ad Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 13:16:09 +0900 Subject: [PATCH 11/73] Separate ThreeStates into its own file --- .../UserInterface/ThreeStateMenuItem.cs | 19 ------------- .../Graphics/UserInterface/ThreeStates.cs | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+), 19 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/ThreeStates.cs diff --git a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs index e33c68bebd..ebb6436196 100644 --- a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs @@ -76,23 +76,4 @@ namespace osu.Game.Graphics.UserInterface } } } - - public enum ThreeStates - { - /// - /// The current state is disabled. - /// - Disabled, - - /// - /// The current state is a combination of and . - /// The state becomes if the is pressed. - /// - Indeterminate, - - /// - /// The current state is enabled. - /// - Enabled - } } diff --git a/osu.Game/Graphics/UserInterface/ThreeStates.cs b/osu.Game/Graphics/UserInterface/ThreeStates.cs new file mode 100644 index 0000000000..f099250937 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/ThreeStates.cs @@ -0,0 +1,27 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Graphics.UserInterface +{ + /// + /// An on/off state with an extra indeterminate state. + /// + public enum ThreeStates + { + /// + /// The current state is disabled. + /// + Disabled, + + /// + /// The current state is a combination of and . + /// The state becomes if the is pressed. + /// + Indeterminate, + + /// + /// The current state is enabled. + /// + Enabled + } +} From e574aa0e94ee16366a7c4086f2eb80042edb494f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 13:33:15 +0900 Subject: [PATCH 12/73] Add toggle menu item test --- .../UserInterface/TestSceneToggleMenuItem.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs new file mode 100644 index 0000000000..2abda56a28 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs @@ -0,0 +1,34 @@ +// 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 osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneToggleMenuItem : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(OsuMenu), + typeof(ToggleMenuItem), + typeof(DrawableStatefulMenuItem) + }; + + public TestSceneToggleMenuItem() + { + Add(new OsuMenu(Direction.Vertical, true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Items = new[] + { + new ToggleMenuItem("First"), + new ToggleMenuItem("Second") { State = { Value = true } } + } + }); + } + } +} From 92d8526370e8cdc166460b30c58e0d47c4cc2654 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 13:34:27 +0900 Subject: [PATCH 13/73] Adjust test namespaces --- .../{ => MenuItems}/TestSceneStatefulMenuItem.cs | 4 ++-- .../{ => MenuItems}/TestSceneThreeStateMenuItem.cs | 2 +- .../UserInterface/{ => MenuItems}/TestSceneToggleMenuItem.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename osu.Game.Tests/Visual/UserInterface/{ => MenuItems}/TestSceneStatefulMenuItem.cs (96%) rename osu.Game.Tests/Visual/UserInterface/{ => MenuItems}/TestSceneThreeStateMenuItem.cs (95%) rename osu.Game.Tests/Visual/UserInterface/{ => MenuItems}/TestSceneToggleMenuItem.cs (94%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneStatefulMenuItem.cs similarity index 96% rename from osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs rename to osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneStatefulMenuItem.cs index d010abc862..95e9aea97f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneStatefulMenuItem.cs @@ -7,14 +7,14 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Tests.Visual.UserInterface +namespace osu.Game.Tests.Visual.UserInterface.MenuItems { public class TestSceneStatefulMenuItem : OsuTestScene { public override IReadOnlyList RequiredTypes => new[] { typeof(OsuMenu), - typeof(ToggleMenuItem), + typeof(StatefulMenuItem), typeof(DrawableStatefulMenuItem) }; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneThreeStateMenuItem.cs similarity index 95% rename from osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs rename to osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneThreeStateMenuItem.cs index caa07e7b60..e035e43630 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneThreeStateMenuItem.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Tests.Visual.UserInterface +namespace osu.Game.Tests.Visual.UserInterface.MenuItems { public class TestSceneThreeStateMenuItem : OsuTestScene { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneToggleMenuItem.cs similarity index 94% rename from osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs rename to osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneToggleMenuItem.cs index 2abda56a28..92875740cf 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneToggleMenuItem.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Tests.Visual.UserInterface +namespace osu.Game.Tests.Visual.UserInterface.MenuItems { public class TestSceneToggleMenuItem : OsuTestScene { From abb3a6ca5bf610f50ff8519a4847bf1b650a2c67 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Nov 2019 22:51:49 +0900 Subject: [PATCH 14/73] Initial right click context menu implementation --- .../Compose/Components/BlueprintContainer.cs | 22 +++ .../Compose/Components/SelectionHandler.cs | 67 +++++++- osu.Game/Screens/Edit/Editor.cs | 143 +++++++++--------- 3 files changed, 162 insertions(+), 70 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 8fa022f129..af0ac22a70 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -17,6 +17,7 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osuTK; +using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components { @@ -95,12 +96,18 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override bool OnMouseDown(MouseDownEvent e) { + if (e.Button == MouseButton.Right) + return false; + beginClickSelection(e); return true; } protected override bool OnClick(ClickEvent e) { + if (e.Button == MouseButton.Right) + return false; + // Deselection should only occur if no selected blueprints are hovered // A special case for when a blueprint was selected via this click is added since OnClick() may occur outside the hitobject and should not trigger deselection if (endClickSelection() || selectionHandler.SelectedBlueprints.Any(b => b.IsHovered)) @@ -112,6 +119,9 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override bool OnDoubleClick(DoubleClickEvent e) { + if (e.Button == MouseButton.Right) + return false; + SelectionBlueprint clickedBlueprint = selectionHandler.SelectedBlueprints.FirstOrDefault(b => b.IsHovered); if (clickedBlueprint == null) @@ -123,6 +133,9 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override bool OnMouseUp(MouseUpEvent e) { + if (e.Button == MouseButton.Right) + return false; + // Special case for when a drag happened instead of a click Schedule(() => endClickSelection()); return true; @@ -141,6 +154,9 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override bool OnDragStart(DragStartEvent e) { + if (e.Button == MouseButton.Right) + return false; + if (!beginSelectionMovement()) { dragBox.UpdateDrag(e); @@ -152,6 +168,9 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override bool OnDrag(DragEvent e) { + if (e.Button == MouseButton.Right) + return false; + if (!moveCurrentSelection(e)) dragBox.UpdateDrag(e); @@ -160,6 +179,9 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override bool OnDragEnd(DragEndEvent e) { + if (e.Button == MouseButton.Right) + return false; + if (!finishSelectionMovement()) { dragBox.FadeOut(250, Easing.OutQuint); diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 44bf22cfe1..779cd86318 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -7,11 +7,16 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Input.States; +using osu.Game.Audio; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -22,7 +27,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// A component which outlines s and handles movement of selections. /// - public class SelectionHandler : CompositeDrawable, IKeyBindingHandler + public class SelectionHandler : CompositeDrawable, IKeyBindingHandler, IHasContextMenu { public const float BORDER_RADIUS = 2; @@ -142,6 +147,8 @@ namespace osu.Game.Screens.Edit.Compose.Components #endregion + #region Outline Display + /// /// Updates whether this is visible. /// @@ -176,5 +183,63 @@ namespace osu.Game.Screens.Edit.Compose.Components outline.Size = bottomRight - topLeft; outline.Position = topLeft; } + + #endregion + + #region Context Menu + + public virtual MenuItem[] ContextMenuItems + { + get + { + if (!SelectedBlueprints.Any()) + return Array.Empty(); + + return new MenuItem[] + { + new OsuMenuItem("hit sound") + { + Items = new[] + { + createHitSampleMenuItem(HitSampleInfo.HIT_WHISTLE), + createHitSampleMenuItem(HitSampleInfo.HIT_CLAP), + createHitSampleMenuItem(HitSampleInfo.HIT_FINISH) + } + } + }; + } + } + + private MenuItem createHitSampleMenuItem(string sampleName) + { + return new ToggleMenuItem(sampleName, MenuItemType.Standard, setHitSampleState) + { + State = { Value = getHitSampleState() } + }; + + void setHitSampleState(bool enabled) + { + if (enabled) + { + foreach (var h in SelectedHitObjects) + { + // Make sure there isn't already an existing sample + if (h.Samples.Any(s => s.Name == sampleName)) + continue; + + h.Samples.Add(new HitSampleInfo { Name = sampleName }); + } + } + else + { + foreach (var h in SelectedHitObjects) + h.Samples.RemoveAll(s => s.Name == sampleName); + } + } + + bool getHitSampleState() => SelectedHitObjects.All(h => h.Samples.Any(s => s.Name == sampleName)); + } + + #endregion } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 35408e4003..1ae3fd71ab 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -24,6 +24,7 @@ using osuTK.Input; using System.Collections.Generic; using osu.Framework; using osu.Framework.Input.Bindings; +using osu.Game.Graphics.Cursor; using osu.Game.Input.Bindings; using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Setup; @@ -85,87 +86,91 @@ namespace osu.Game.Screens.Edit fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit)); - InternalChildren = new[] + InternalChild = new OsuContextMenuContainer { - new Container + RelativeSizeAxes = Axes.Both, + Children = new[] { - Name = "Screen container", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 40, Bottom = 60 }, - Child = screenContainer = new Container + new Container { + Name = "Screen container", RelativeSizeAxes = Axes.Both, - Masking = true - } - }, - new Container - { - Name = "Top bar", - RelativeSizeAxes = Axes.X, - Height = 40, - Child = menuBar = new EditorMenuBar - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Both, - Items = new[] - { - new MenuItem("File") - { - Items = fileMenuItems - } - } - } - }, - new Container - { - Name = "Bottom bar", - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Height = 60, - Children = new Drawable[] - { - bottomBackground = new Box { RelativeSizeAxes = Axes.Both }, - new Container + Padding = new MarginPadding { Top = 40, Bottom = 60 }, + Child = screenContainer = new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Vertical = 5, Horizontal = 10 }, - Child = new GridContainer + Masking = true + } + }, + new Container + { + Name = "Top bar", + RelativeSizeAxes = Axes.X, + Height = 40, + Child = menuBar = new EditorMenuBar + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + Items = new[] + { + new MenuItem("File") + { + Items = fileMenuItems + } + } + } + }, + new Container + { + Name = "Bottom bar", + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = 60, + Children = new Drawable[] + { + bottomBackground = new Box { RelativeSizeAxes = Axes.Both }, + new Container { RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] + Padding = new MarginPadding { Vertical = 5, Horizontal = 10 }, + Child = new GridContainer { - new Dimension(GridSizeMode.Absolute, 220), - new Dimension(), - new Dimension(GridSizeMode.Absolute, 220) - }, - Content = new[] - { - new Drawable[] + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = 10 }, - Child = new TimeInfoContainer { RelativeSizeAxes = Axes.Both }, - }, - new SummaryTimeline - { - RelativeSizeAxes = Axes.Both, - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = 10 }, - Child = new PlaybackControl { RelativeSizeAxes = Axes.Both }, - } + new Dimension(GridSizeMode.Absolute, 220), + new Dimension(), + new Dimension(GridSizeMode.Absolute, 220) }, - } - }, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 10 }, + Child = new TimeInfoContainer { RelativeSizeAxes = Axes.Both }, + }, + new SummaryTimeline + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 10 }, + Child = new PlaybackControl { RelativeSizeAxes = Axes.Both }, + } + }, + } + }, + } } - } - }, + }, + } }; menuBar.Mode.ValueChanged += onModeChanged; From 573d11503e27e7a99202a94ee08b2912e65bcb1f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 11:13:24 +0900 Subject: [PATCH 15/73] Remove unused using --- osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 779cd86318..43dbeb35f7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Audio; using osu.Game.Graphics; From 046f0b0fe5947f57ae312ee80c88e6e3d42b2529 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 13:40:47 +0900 Subject: [PATCH 16/73] Allow right-clicks to trigger selection --- .../Edit/Compose/Components/BlueprintContainer.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index af0ac22a70..e7877f962e 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -96,11 +96,8 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override bool OnMouseDown(MouseDownEvent e) { - if (e.Button == MouseButton.Right) - return false; - beginClickSelection(e); - return true; + return e.Button == MouseButton.Left; } protected override bool OnClick(ClickEvent e) @@ -133,12 +130,9 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override bool OnMouseUp(MouseUpEvent e) { - if (e.Button == MouseButton.Right) - return false; - // Special case for when a drag happened instead of a click Schedule(() => endClickSelection()); - return true; + return e.Button == MouseButton.Left; } protected override bool OnMouseMove(MouseMoveEvent e) From 864b8db638b6b3a70eb3f6189d2a9761127b3e1d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 13:52:36 +0900 Subject: [PATCH 17/73] Use three states for the hitsound menu items --- .../Compose/Components/SelectionHandler.cs | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 43dbeb35f7..dc147a92cd 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -196,47 +196,61 @@ namespace osu.Game.Screens.Edit.Compose.Components return new MenuItem[] { - new OsuMenuItem("hit sound") + new OsuMenuItem("Sound") { Items = new[] { - createHitSampleMenuItem(HitSampleInfo.HIT_WHISTLE), - createHitSampleMenuItem(HitSampleInfo.HIT_CLAP), - createHitSampleMenuItem(HitSampleInfo.HIT_FINISH) + createHitSampleMenuItem("Whistle", HitSampleInfo.HIT_WHISTLE), + createHitSampleMenuItem("Clap", HitSampleInfo.HIT_CLAP), + createHitSampleMenuItem("Finish", HitSampleInfo.HIT_FINISH) } } }; } } - private MenuItem createHitSampleMenuItem(string sampleName) + private MenuItem createHitSampleMenuItem(string name, string sampleName) { - return new ToggleMenuItem(sampleName, MenuItemType.Standard, setHitSampleState) + return new ThreeStateMenuItem(name, MenuItemType.Standard, setHitSampleState) { State = { Value = getHitSampleState() } }; - void setHitSampleState(bool enabled) + void setHitSampleState(ThreeStates state) { - if (enabled) + switch (state) { - foreach (var h in SelectedHitObjects) - { - // Make sure there isn't already an existing sample - if (h.Samples.Any(s => s.Name == sampleName)) - continue; + case ThreeStates.Disabled: + foreach (var h in SelectedHitObjects) + h.Samples.RemoveAll(s => s.Name == sampleName); + break; - h.Samples.Add(new HitSampleInfo { Name = sampleName }); - } - } - else - { - foreach (var h in SelectedHitObjects) - h.Samples.RemoveAll(s => s.Name == sampleName); + case ThreeStates.Enabled: + foreach (var h in SelectedHitObjects) + { + // Make sure there isn't already an existing sample + if (h.Samples.Any(s => s.Name == sampleName)) + continue; + + h.Samples.Add(new HitSampleInfo { Name = sampleName }); + } + + break; } } - bool getHitSampleState() => SelectedHitObjects.All(h => h.Samples.Any(s => s.Name == sampleName)); + ThreeStates getHitSampleState() + { + int countExisting = SelectedHitObjects.Count(h => h.Samples.Any(s => s.Name == sampleName)); + + if (countExisting == 0) + return ThreeStates.Disabled; + + if (countExisting < SelectedHitObjects.Count()) + return ThreeStates.Indeterminate; + + return ThreeStates.Enabled; + } } #endregion From 6fc1be64c2c4adbb7335288d765c77e3343a5e73 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 14:04:57 +0900 Subject: [PATCH 18/73] Make hitobject samples a bindable list --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 2 +- .../Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Legacy/DistanceObjectPatternGenerator.cs | 2 +- osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs | 6 +++--- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 +++--- .../Beatmaps/TaikoBeatmapConverter.cs | 6 +++--- osu.Game/Rulesets/Objects/HitObject.cs | 12 ++++++++---- .../Objects/Legacy/Catch/ConvertHitObjectParser.cs | 2 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 4 ++-- osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs | 2 +- .../Objects/Legacy/Mania/ConvertHitObjectParser.cs | 2 +- .../Objects/Legacy/Osu/ConvertHitObjectParser.cs | 2 +- .../Objects/Legacy/Taiko/ConvertHitObjectParser.cs | 2 +- osu.Game/Rulesets/Objects/Types/IHasRepeats.cs | 2 +- .../Edit/Compose/Components/SelectionHandler.cs | 3 ++- 15 files changed, 30 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 0952e8981a..80a3af0aa0 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Catch.Objects public double Distance => Path.Distance; - public List> NodeSamples { get; set; } = new List>(); + public List> NodeSamples { get; set; } = new List>(); public double? LegacyLastTickOffset { get; set; } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index e10602312e..6c5bb304bf 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -255,7 +255,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// /// The time to retrieve the sample info list from. /// - private List sampleInfoListAt(double time) + private IList sampleInfoListAt(double time) { var curveData = HitObject as IHasCurve; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index ea418eedb4..6297a68e08 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -472,7 +472,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// /// The time to retrieve the sample info list from. /// - private List sampleInfoListAt(double time) + private IList sampleInfoListAt(double time) { var curveData = HitObject as IHasCurve; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs index a955911bd5..46a2a36ac7 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs @@ -275,7 +275,7 @@ namespace osu.Game.Rulesets.Osu.Tests private Drawable createCatmull(int repeats = 0) { - var repeatSamples = new List>(); + var repeatSamples = new List>(); for (int i = 0; i < repeats; i++) repeatSamples.Add(new List()); @@ -297,9 +297,9 @@ namespace osu.Game.Rulesets.Osu.Tests return createDrawable(slider, 3, 1); } - private List> createEmptySamples(int repeats) + private List> createEmptySamples(int repeats) { - var repeatSamples = new List>(); + var repeatSamples = new List>(); for (int i = 0; i < repeats; i++) repeatSamples.Add(new List()); return repeatSamples; diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index f60b7e67b2..c41026d954 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Osu.Objects /// internal float LazyTravelDistance; - public List> NodeSamples { get; set; } = new List>(); + public List> NodeSamples { get; set; } = new List>(); private int repeatCount; @@ -128,7 +128,7 @@ namespace osu.Game.Rulesets.Osu.Objects foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset)) { - var firstSample = Samples.Find(s => s.Name == HitSampleInfo.HIT_NORMAL) + var firstSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) var sampleList = new List(); @@ -203,7 +203,7 @@ namespace osu.Game.Rulesets.Osu.Objects TailCircle.Position = EndPosition; } - private List getNodeSamples(int nodeIndex) => + private IList getNodeSamples(int nodeIndex) => nodeIndex < NodeSamples.Count ? NodeSamples[nodeIndex] : Samples; public override Judgement CreateJudgement() => new OsuJudgement(); diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index f0cf8d9c7d..180e0d8309 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps var curveData = obj as IHasCurve; // Old osu! used hit sounding to determine various hit type information - List samples = obj.Samples; + IList samples = obj.Samples; bool strong = samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH); @@ -117,13 +117,13 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) { - List> allSamples = curveData != null ? curveData.NodeSamples : new List>(new[] { samples }); + List> allSamples = curveData != null ? curveData.NodeSamples : new List>(new[] { samples }); int i = 0; for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing) { - List currentSamples = allSamples[i]; + 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); diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 6211fe50e6..ee0705ec5a 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Objects set => StartTimeBindable.Value = value; } - private List samples; + public readonly BindableList SamplesBindable = new BindableList(); /// /// The samples to be played when this hit object is hit. @@ -54,10 +54,14 @@ namespace osu.Game.Rulesets.Objects /// and can be treated as the default samples for the hit object. /// /// - public List Samples + public IList Samples { - get => samples ?? (samples = new List()); - set => samples = value; + get => SamplesBindable; + set + { + SamplesBindable.Clear(); + SamplesBindable.AddRange(value); + } } [JsonIgnore] diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index 71e321f205..545cfe07f8 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch } protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, - List> nodeSamples) + List> nodeSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index e990938291..bbf46a0c8f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } // Generate the final per-node samples - var nodeSamples = new List>(nodes); + var nodeSamples = new List>(nodes); for (int i = 0; i < nodes; i++) nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i])); @@ -279,7 +279,7 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The samples to be played when the slider nodes are hit. This includes the head and tail of the slider. /// The hit object. protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, - List> nodeSamples); + List> nodeSamples); /// /// Creates a legacy Spinner-type hit object. diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index ff6b9be8b5..8d523022d6 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Legacy public double Distance => Path.Distance; - public List> NodeSamples { get; set; } + public List> NodeSamples { get; set; } public int RepeatCount { get; set; } public double EndTime => StartTime + this.SpanCount() * Distance / Velocity; diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 94aba95e90..8012b4230f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania } protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, - List> nodeSamples) + List> nodeSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index 65102f1e89..99872e630d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu } protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, - List> nodeSamples) + List> nodeSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index eb598f1368..9dc0c01932 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko } protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, - List> nodeSamples) + List> nodeSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs index 697adeda98..b22752e902 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Objects.Types /// n-1: The last repeat.
/// n: The last node. ///
- List> NodeSamples { get; } + List> NodeSamples { get; } } public static class HasRepeatsExtensions diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index dc147a92cd..5f0bfb6d70 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -222,7 +222,8 @@ namespace osu.Game.Screens.Edit.Compose.Components { case ThreeStates.Disabled: foreach (var h in SelectedHitObjects) - h.Samples.RemoveAll(s => s.Name == sampleName); + h.SamplesBindable.RemoveAll(s => s.Name == sampleName); + break; case ThreeStates.Enabled: From 53e6186b6d4421bdb4abb9feca0674ea827603fe Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 14:59:47 +0900 Subject: [PATCH 19/73] Fix drawable hitobject samples not updating --- .../Objects/Drawables/DrawableHitObject.cs | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 1d9b66f88d..592cddeff6 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -78,6 +78,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public JudgementResult Result { get; private set; } + private BindableList samplesBindable; private Bindable startTimeBindable; private Bindable comboIndexBindable; @@ -108,20 +109,7 @@ namespace osu.Game.Rulesets.Objects.Drawables throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); } - var samples = GetSamples().ToArray(); - - if (samples.Length > 0) - { - if (HitObject.SampleControlPoint == null) - throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." - + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); - - samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray(); - foreach (var s in samples) - s.Namespace = SampleNamespace; - - AddInternal(Samples = new SkinnableSound(samples)); - } + loadSamples(); } protected override void LoadComplete() @@ -139,10 +127,34 @@ namespace osu.Game.Rulesets.Objects.Drawables comboIndexBindable.BindValueChanged(_ => updateAccentColour(), true); } + samplesBindable = HitObject.SamplesBindable.GetBoundCopy(); + samplesBindable.ItemsAdded += _ => scheduleLoadSamples(); + samplesBindable.ItemsRemoved += _ => scheduleLoadSamples(); + updateState(ArmedState.Idle, true); onDefaultsApplied(); } + private void scheduleLoadSamples() => Scheduler.AddOnce(loadSamples); + + private void loadSamples() + { + var samples = GetSamples().ToArray(); + + if (samples.Length <= 0) + return; + + if (HitObject.SampleControlPoint == null) + throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." + + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); + + samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray(); + foreach (var s in samples) + s.Namespace = SampleNamespace; + + AddInternal(Samples = new SkinnableSound(samples)); + } + private void onDefaultsApplied() => apply(HitObject); private void apply(HitObject hitObject) From df31acb2940ca5333e019e0340c2fdd67ff5f9e9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 15:39:07 +0900 Subject: [PATCH 20/73] Fix slider nested hitobject samples not getting updated --- .../TestSceneSlider.cs | 75 +++++++++++++++---- osu.Game.Rulesets.Osu/Objects/Slider.cs | 47 ++++++++---- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs index 46a2a36ac7..5c656bf594 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs @@ -126,6 +126,67 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("body positioned correctly", () => slider.Position == slider.HitObject.StackedPosition); } + [Test] + public void TestChangeSamplesWithNoNodeSamples() + { + DrawableSlider slider = null; + + AddStep("create slider", () => + { + slider = (DrawableSlider)createSlider(repeats: 1); + Add(slider); + }); + + AddStep("change samples", () => slider.HitObject.Samples = new[] + { + new HitSampleInfo { Name = HitSampleInfo.HIT_CLAP }, + new HitSampleInfo { Name = HitSampleInfo.HIT_WHISTLE }, + }); + + AddAssert("head samples updated", () => assertSamples(((Slider)slider.HitObject).HeadCircle)); + AddAssert("tick samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType().All(assertTickSamples)); + AddAssert("repeat samples updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType().All(assertSamples)); + AddAssert("tail has no samples", () => ((Slider)slider.HitObject).TailCircle.Samples.Count == 0); + + bool assertTickSamples(SliderTick tick) => tick.Samples.Single().Name == "slidertick"; + + bool assertSamples(HitObject hitObject) + { + return hitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP) + && hitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_WHISTLE); + } + } + + [Test] + public void TestChangeSamplesWithNodeSamples() + { + DrawableSlider slider = null; + + AddStep("create slider", () => + { + slider = (DrawableSlider)createSlider(repeats: 1); + + for (int i = 0; i < 2; i++) + ((Slider)slider.HitObject).NodeSamples.Add(new List { new HitSampleInfo { Name = HitSampleInfo.HIT_FINISH } }); + + Add(slider); + }); + + AddStep("change samples", () => slider.HitObject.Samples = new[] + { + new HitSampleInfo { Name = HitSampleInfo.HIT_CLAP }, + new HitSampleInfo { Name = HitSampleInfo.HIT_WHISTLE }, + }); + + AddAssert("head samples not updated", () => assertSamples(((Slider)slider.HitObject).HeadCircle)); + AddAssert("tick samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType().All(assertTickSamples)); + AddAssert("repeat samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType().All(assertSamples)); + AddAssert("tail has no samples", () => ((Slider)slider.HitObject).TailCircle.Samples.Count == 0); + + bool assertTickSamples(SliderTick tick) => tick.Samples.Single().Name == "slidertick"; + bool assertSamples(HitObject hitObject) => hitObject.Samples.All(s => s.Name != HitSampleInfo.HIT_CLAP && s.Name != HitSampleInfo.HIT_WHISTLE); + } + private Drawable testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats); private Drawable testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10); @@ -143,7 +204,6 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(52, -34) }, 700), RepeatCount = repeats, - NodeSamples = createEmptySamples(repeats), StackHeight = 10 }; @@ -174,7 +234,6 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(distance, 0), }, distance), RepeatCount = repeats, - NodeSamples = createEmptySamples(repeats), StackHeight = stackHeight }; @@ -194,7 +253,6 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(400, 0) }, 600), RepeatCount = repeats, - NodeSamples = createEmptySamples(repeats) }; return createDrawable(slider, 2, 3); @@ -218,7 +276,6 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(430, 0) }), RepeatCount = repeats, - NodeSamples = createEmptySamples(repeats) }; return createDrawable(slider, 2, 3); @@ -241,7 +298,6 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(430, 0) }), RepeatCount = repeats, - NodeSamples = createEmptySamples(repeats) }; return createDrawable(slider, 2, 3); @@ -265,7 +321,6 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(0, -200) }), RepeatCount = repeats, - NodeSamples = createEmptySamples(repeats) }; return createDrawable(slider, 2, 3); @@ -297,14 +352,6 @@ namespace osu.Game.Rulesets.Osu.Tests return createDrawable(slider, 3, 1); } - private List> createEmptySamples(int repeats) - { - var repeatSamples = new List>(); - for (int i = 0; i < repeats; i++) - repeatSamples.Add(new List()); - return repeatSamples; - } - private Drawable createDrawable(Slider slider, float circleSize, double speedMultiplier) { var cpi = new ControlPointInfo(); diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index c41026d954..f3399af2de 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -108,6 +108,12 @@ namespace osu.Game.Rulesets.Osu.Objects public HitCircle HeadCircle; public SliderTailCircle TailCircle; + public Slider() + { + SamplesBindable.ItemsAdded += _ => updateNestedSamples(); + SamplesBindable.ItemsRemoved += _ => updateNestedSamples(); + } + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); @@ -128,18 +134,6 @@ namespace osu.Game.Rulesets.Osu.Objects foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset)) { - var firstSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) - ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) - var sampleList = new List(); - - if (firstSample != null) - sampleList.Add(new HitSampleInfo - { - Bank = firstSample.Bank, - Volume = firstSample.Volume, - Name = @"slidertick", - }); - switch (e.Type) { case SliderEventType.Tick: @@ -151,7 +145,6 @@ namespace osu.Game.Rulesets.Osu.Objects Position = Position + Path.PositionAt(e.PathProgress), StackHeight = StackHeight, Scale = Scale, - Samples = sampleList }); break; @@ -161,7 +154,6 @@ namespace osu.Game.Rulesets.Osu.Objects StartTime = e.Time, Position = Position, StackHeight = StackHeight, - Samples = getNodeSamples(0), SampleControlPoint = SampleControlPoint, }); break; @@ -187,11 +179,12 @@ namespace osu.Game.Rulesets.Osu.Objects Position = Position + Path.PositionAt(e.PathProgress), StackHeight = StackHeight, Scale = Scale, - Samples = getNodeSamples(e.SpanIndex + 1) }); break; } } + + updateNestedSamples(); } private void updateNestedPositions() @@ -203,6 +196,30 @@ namespace osu.Game.Rulesets.Osu.Objects TailCircle.Position = EndPosition; } + private void updateNestedSamples() + { + var firstSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) + ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) + var sampleList = new List(); + + if (firstSample != null) + sampleList.Add(new HitSampleInfo + { + Bank = firstSample.Bank, + Volume = firstSample.Volume, + Name = @"slidertick", + }); + + foreach (var tick in NestedHitObjects.OfType()) + tick.Samples = sampleList; + + foreach (var repeat in NestedHitObjects.OfType()) + repeat.Samples = getNodeSamples(repeat.RepeatIndex + 1); + + if (HeadCircle != null) + HeadCircle.Samples = getNodeSamples(0); + } + private IList getNodeSamples(int nodeIndex) => nodeIndex < NodeSamples.Count ? NodeSamples[nodeIndex] : Samples; From a9b4106075614da8a60eae0afa3f30b85f7bf53d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 16:19:43 +0900 Subject: [PATCH 21/73] Remove unnecessary (for now) scheduling --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 592cddeff6..9c72a1a220 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -128,15 +128,13 @@ namespace osu.Game.Rulesets.Objects.Drawables } samplesBindable = HitObject.SamplesBindable.GetBoundCopy(); - samplesBindable.ItemsAdded += _ => scheduleLoadSamples(); - samplesBindable.ItemsRemoved += _ => scheduleLoadSamples(); + samplesBindable.ItemsAdded += _ => loadSamples(); + samplesBindable.ItemsRemoved += _ => loadSamples(); updateState(ArmedState.Idle, true); onDefaultsApplied(); } - private void scheduleLoadSamples() => Scheduler.AddOnce(loadSamples); - private void loadSamples() { var samples = GetSamples().ToArray(); From b4cb4c124366097b79239f267033eed6e7c3dffb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 16:19:55 +0900 Subject: [PATCH 22/73] Remove previous samples on change --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 9c72a1a220..818571bb23 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Objects.Drawables // Todo: Rulesets should be overriding the resources instead, but we need to figure out where/when to apply overrides first protected virtual string SampleNamespace => null; - protected SkinnableSound Samples; + protected SkinnableSound Samples { get; private set; } protected virtual IEnumerable GetSamples() => HitObject.Samples; @@ -137,6 +137,12 @@ namespace osu.Game.Rulesets.Objects.Drawables private void loadSamples() { + if (Samples != null) + { + RemoveInternal(Samples); + Samples = null; + } + var samples = GetSamples().ToArray(); if (samples.Length <= 0) From df08a95734e8184847a55210f2da9eed9a6c30f6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 16:46:58 +0900 Subject: [PATCH 23/73] Separate addition/removal into separate methods --- .../Compose/Components/SelectionHandler.cs | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 5f0bfb6d70..7b61640c89 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -185,6 +185,36 @@ namespace osu.Game.Screens.Edit.Compose.Components #endregion + #region Sample Changes + + /// + /// Adds a hit sample to all selected s. + /// + /// The name of the hit sample. + public void AddHitSample(string sampleName) + { + foreach (var h in SelectedHitObjects) + { + // Make sure there isn't already an existing sample + if (h.Samples.Any(s => s.Name == sampleName)) + continue; + + h.Samples.Add(new HitSampleInfo { Name = sampleName }); + } + } + + /// + /// Removes a hit sample from all selected s. + /// + /// The name of the hit sample. + public void RemoveHitSample(string sampleName) + { + foreach (var h in SelectedHitObjects) + h.SamplesBindable.RemoveAll(s => s.Name == sampleName); + } + + #endregion + #region Context Menu public virtual MenuItem[] ContextMenuItems @@ -221,21 +251,11 @@ namespace osu.Game.Screens.Edit.Compose.Components switch (state) { case ThreeStates.Disabled: - foreach (var h in SelectedHitObjects) - h.SamplesBindable.RemoveAll(s => s.Name == sampleName); - + RemoveHitSample(sampleName); break; case ThreeStates.Enabled: - foreach (var h in SelectedHitObjects) - { - // Make sure there isn't already an existing sample - if (h.Samples.Any(s => s.Name == sampleName)) - continue; - - h.Samples.Add(new HitSampleInfo { Name = sampleName }); - } - + AddHitSample(sampleName); break; } } From 8ef9ccc39edf317f14a79b5bcb5a6fcc2ca091ea Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 8 Nov 2019 13:19:06 +0300 Subject: [PATCH 24/73] Schedule new track assignment after stopping current track --- osu.Game/Audio/PreviewTrackManager.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index fad2b5a5e8..08a69fa265 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -46,12 +46,18 @@ namespace osu.Game.Audio { var track = CreatePreviewTrack(beatmapSetInfo, trackStore); - track.Started += () => Schedule(() => + track.Started += () => { + // Stopping track should not be within the below schedule since its stop event schedules a null assign to current. + // Due to that, assigning the new track to current must be scheduled after the null assign to avoid current track loss. current?.Stop(); - current = track; - audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable); - }); + + Schedule(() => + { + current = track; + audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable); + }); + }; track.Stopped += () => Schedule(() => { From 901a8d597b81617c7032e9a16cbd57c5b0181511 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Fri, 8 Nov 2019 13:20:02 +0300 Subject: [PATCH 25/73] Add test steps ensuring correct behaviour --- .../Visual/Components/TestScenePreviewTrackManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs index f3f6444149..7d46958496 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs @@ -59,6 +59,9 @@ namespace osu.Game.Tests.Visual.Components AddStep("start track 2", () => track2.Start()); AddAssert("track 1 stopped", () => !track1.IsRunning); AddAssert("track 2 started", () => track2.IsRunning); + AddStep("start track 1", () => track1.Start()); + AddAssert("track 2 stopped", () => !track2.IsRunning); + AddAssert("track 1 started", () => track1.IsRunning); } [Test] From 97ea07db0e6ec5406f8b73cdc05618b8aad35793 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Nov 2019 19:44:47 +0900 Subject: [PATCH 26/73] Add delete option to the right-click menu --- .../Edit/Compose/Components/SelectionHandler.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 7b61640c89..9b7082dec5 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -80,8 +80,7 @@ namespace osu.Game.Screens.Edit.Compose.Components switch (action.ActionMethod) { case PlatformActionMethod.Delete: - foreach (var h in selectedBlueprints.ToList()) - placementHandler.Delete(h.DrawableObject.HitObject); + deleteSelected(); return true; } @@ -144,6 +143,12 @@ namespace osu.Game.Screens.Edit.Compose.Components UpdateVisibility(); } + private void deleteSelected() + { + foreach (var h in selectedBlueprints.ToList()) + placementHandler.Delete(h.DrawableObject.HitObject); + } + #endregion #region Outline Display @@ -234,7 +239,8 @@ namespace osu.Game.Screens.Edit.Compose.Components createHitSampleMenuItem("Clap", HitSampleInfo.HIT_CLAP), createHitSampleMenuItem("Finish", HitSampleInfo.HIT_FINISH) } - } + }, + new OsuMenuItem("Delete", MenuItemType.Destructive, deleteSelected), }; } } From ff225c3691312bbb9d79bbc733c5ed760d5c9b25 Mon Sep 17 00:00:00 2001 From: Joehu Date: Fri, 8 Nov 2019 06:04:18 -0800 Subject: [PATCH 27/73] Remove toolbarElements --- osu.Game/OsuGame.cs | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 3980390611..145b7de9f2 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -102,8 +102,6 @@ namespace osu.Game private readonly List overlays = new List(); - private readonly List toolbarElements = new List(); - private readonly List visibleBlockingOverlays = new List(); public OsuGame(string[] args = null) @@ -134,17 +132,13 @@ namespace osu.Game /// /// Close all game-wide overlays. /// - /// Whether the toolbar (and accompanying controls) should also be hidden. - public void CloseAllOverlays(bool hideToolbarElements = true) + /// Whether the toolbar should also be hidden. + public void CloseAllOverlays(bool hideToolbar = true) { foreach (var overlay in overlays) overlay.Hide(); - if (hideToolbarElements) - { - foreach (var overlay in toolbarElements) - overlay.Hide(); - } + if (hideToolbar) Toolbar.Hide(); } private DependencyContainer dependencies; @@ -570,11 +564,7 @@ namespace osu.Game CloseAllOverlays(false); menuScreen?.MakeCurrent(); }, - }, d => - { - topMostOverlayContent.Add(d); - toolbarElements.Add(d); - }); + }, topMostOverlayContent.Add); loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add, true); @@ -613,11 +603,7 @@ namespace osu.Game GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - }, d => - { - rightFloatingOverlayContent.Add(d); - toolbarElements.Add(d); - }, true); + }, rightFloatingOverlayContent.Add, true); loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true); loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true); From 20ed6c4d520444955e7fa690a9e06b6d1391ef9e Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 10 Nov 2019 23:07:51 +0300 Subject: [PATCH 28/73] Use track check solution for this --- osu.Game/Audio/PreviewTrackManager.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 08a69fa265..f104dc8f9f 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -46,21 +46,20 @@ namespace osu.Game.Audio { var track = CreatePreviewTrack(beatmapSetInfo, trackStore); - track.Started += () => + track.Started += () => Schedule(() => { - // Stopping track should not be within the below schedule since its stop event schedules a null assign to current. - // Due to that, assigning the new track to current must be scheduled after the null assign to avoid current track loss. - current?.Stop(); + var last = current; + current = track; + last?.Stop(); - Schedule(() => - { - current = track; - audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable); - }); - }; + audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable); + }); track.Stopped += () => Schedule(() => { + if (current != track) + return; + current = null; audio.Tracks.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); }); From 9d61d73cedf9088af374f18f1018f7e32f64b3cd Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 10 Nov 2019 23:09:04 +0300 Subject: [PATCH 29/73] Change Track and TrackManagerPreviewTrack accessibilities --- osu.Game/Audio/PreviewTrack.cs | 25 +++++++++++++------------ osu.Game/Audio/PreviewTrackManager.cs | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 1234554e79..b39d2bc8f8 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -24,36 +24,37 @@ namespace osu.Game.Audio /// public event Action Started; - private Track track; + protected Track Track; + private bool hasStarted; [BackgroundDependencyLoader] private void load() { - track = GetTrack(); - if (track != null) - track.Completed += Stop; + Track = GetTrack(); + if (Track != null) + Track.Completed += Stop; } /// /// Length of the track. /// - public double Length => track?.Length ?? 0; + public double Length => Track?.Length ?? 0; /// /// The current track time. /// - public double CurrentTime => track?.CurrentTime ?? 0; + public double CurrentTime => Track?.CurrentTime ?? 0; /// /// Whether the track is loaded. /// - public bool TrackLoaded => track?.IsLoaded ?? false; + public bool TrackLoaded => Track?.IsLoaded ?? false; /// /// Whether the track is playing. /// - public bool IsRunning => track?.IsRunning ?? false; + public bool IsRunning => Track?.IsRunning ?? false; private ScheduledDelegate startDelegate; @@ -63,7 +64,7 @@ namespace osu.Game.Audio /// Whether the track is started or already playing. public bool Start() { - if (track == null) + if (Track == null) return false; startDelegate = Schedule(() => @@ -73,7 +74,7 @@ namespace osu.Game.Audio hasStarted = true; - track.Restart(); + Track.Restart(); Started?.Invoke(); }); @@ -87,7 +88,7 @@ namespace osu.Game.Audio { startDelegate?.Cancel(); - if (track == null) + if (Track == null) return; if (!hasStarted) @@ -95,7 +96,7 @@ namespace osu.Game.Audio hasStarted = false; - track.Stop(); + Track.Stop(); Stopped?.Invoke(); } diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index f104dc8f9f..1c1b4c3059 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -90,7 +90,7 @@ namespace osu.Game.Audio /// protected virtual TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TrackManagerPreviewTrack(beatmapSetInfo, trackStore); - protected class TrackManagerPreviewTrack : PreviewTrack + public class TrackManagerPreviewTrack : PreviewTrack { public IPreviewTrackOwner Owner { get; private set; } From 9a00898c0d3dae94f922782fc3eebc871959d04b Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 10 Nov 2019 23:21:46 +0300 Subject: [PATCH 30/73] Add test for non-present preview tracks To avoid reverting what #6738 solved --- .../TestScenePreviewTrackManager.cs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs index 7d46958496..3a9fce90cd 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs @@ -7,6 +7,7 @@ using osu.Framework.Audio.Track; using osu.Framework.Graphics.Containers; using osu.Game.Audio; using osu.Game.Beatmaps; +using static osu.Game.Tests.Visual.Components.TestScenePreviewTrackManager.TestPreviewTrackManager; namespace osu.Game.Tests.Visual.Components { @@ -91,9 +92,25 @@ namespace osu.Game.Tests.Visual.Components AddAssert("stopped", () => !track.IsRunning); } - private PreviewTrack getTrack() => trackManager.Get(null); + [Test] + public void TestNonPresentTrack() + { + TestPreviewTrack track = null; - private PreviewTrack getOwnedTrack() + AddStep("get non-present track", () => + { + Add(new TestTrackOwner(track = getTrack())); + track.Alpha = 0; + }); + AddUntilStep("wait loaded", () => track.IsLoaded); + AddStep("start", () => track.Start()); + AddStep("seek to end", () => track.Track.Seek(track.Track.Length)); + AddAssert("track stopped", () => !track.IsRunning); + } + + private TestPreviewTrack getTrack() => (TestPreviewTrack)trackManager.Get(null); + + private TestPreviewTrack getOwnedTrack() { var track = getTrack(); @@ -125,14 +142,16 @@ namespace osu.Game.Tests.Visual.Components } } - private class TestPreviewTrackManager : PreviewTrackManager + public class TestPreviewTrackManager : PreviewTrackManager { protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore); - protected class TestPreviewTrack : TrackManagerPreviewTrack + public class TestPreviewTrack : TrackManagerPreviewTrack { private readonly ITrackStore trackManager; + public new Track Track => base.Track; + public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackManager) : base(beatmapSetInfo, trackManager) { From 8f4916ad2d7fee51b0c28acad32a89fdf6c8f3ec Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 10 Nov 2019 23:53:31 +0300 Subject: [PATCH 31/73] Add inline comment --- osu.Game/Audio/PreviewTrackManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 1c1b4c3059..8f723194e3 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -48,6 +48,7 @@ namespace osu.Game.Audio track.Started += () => Schedule(() => { + // Assign the new track to current before stopping last track to avoid assigning null to current. var last = current; current = track; last?.Stop(); From 3b13ad480af5afa7f0fe15c300a5e02bcf0fb4d7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Nov 2019 13:06:41 +0900 Subject: [PATCH 32/73] Increase fade-out time of hitobjects in the editor --- .../Edit/DrawableOsuEditRuleset.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs index cc08d356f9..e262fa3c60 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs @@ -2,8 +2,12 @@ // 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.Game.Beatmaps; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; using osuTK; @@ -17,6 +21,25 @@ namespace osu.Game.Rulesets.Osu.Edit { } + public override DrawableHitObject CreateDrawableRepresentation(OsuHitObject h) + => base.CreateDrawableRepresentation(h)?.With(d => d.ApplyCustomUpdateState += updateState); + + private void updateState(DrawableHitObject hitObject, ArmedState state) + { + switch (state) + { + case ArmedState.Miss: + // Get the existing fade out transform + var existing = hitObject.Transforms.LastOrDefault(t => t.TargetMember == nameof(Alpha)); + if (existing == null) + return; + + using (hitObject.BeginAbsoluteSequence(existing.StartTime)) + hitObject.FadeOut(500).Expire(); + break; + } + } + protected override Playfield CreatePlayfield() => new OsuPlayfieldNoCursor(); public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new OsuPlayfieldAdjustmentContainer { Size = Vector2.One }; From f3dc38e3427f9c52364bcc11a8ea36d065b0934c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Nov 2019 13:41:10 +0900 Subject: [PATCH 33/73] Add Ctrl+A to select all (esc to deselect all) --- .../Compose/Components/BlueprintContainer.cs | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 8fa022f129..7528ac8aa6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Input; +using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; @@ -17,10 +18,11 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osuTK; +using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components { - public class BlueprintContainer : CompositeDrawable + public class BlueprintContainer : CompositeDrawable, IKeyBindingHandler { public event Action> SelectionChanged; @@ -169,6 +171,37 @@ namespace osu.Game.Screens.Edit.Compose.Components return true; } + protected override bool OnKeyDown(KeyDownEvent e) + { + switch (e.Key) + { + case Key.Escape: + if (!selectionHandler.SelectedBlueprints.Any()) + return false; + + deselectAll(); + return true; + } + + return false; + } + + protected override bool OnKeyUp(KeyUpEvent e) => false; + + public bool OnPressed(PlatformAction action) + { + switch (action.ActionType) + { + case PlatformActionType.SelectAll: + selectAll(); + return true; + } + + return false; + } + + public bool OnReleased(PlatformAction action) => false; + protected override void Update() { base.Update(); @@ -314,6 +347,15 @@ namespace osu.Game.Screens.Edit.Compose.Components } } + /// + /// Selects all s. + /// + private void selectAll() + { + selectionBlueprints.ToList().ForEach(m => m.Select()); + selectionHandler.UpdateVisibility(); + } + /// /// Deselects all selected s. /// From dc88bd3d611a1a5c31c3768eb637725b6a6bf02d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 13:49:12 +0900 Subject: [PATCH 34/73] Add local preserving container to OsuTestScene to ensure correct test dimensions --- osu.Game/Tests/Visual/OsuTestScene.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 96b39b303e..daa1a56221 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -10,12 +10,16 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Database; +using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -93,6 +97,10 @@ namespace osu.Game.Tests.Visual return Dependencies; } + protected override Container Content => content ?? base.Content; + + private readonly Container content; + protected OsuTestScene() { localStorage = new Lazy(() => new NativeStorage($"{GetType().Name}-{Guid.NewGuid()}")); @@ -104,6 +112,8 @@ namespace osu.Game.Tests.Visual usage.Migrate(); return factory; }); + + base.Content.Add(content = new DrawSizePreservingFillContainer()); } [Resolved] From 8ac708ada5f44773ed593f02f5badd144d9a93f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 13:58:35 +0900 Subject: [PATCH 35/73] Move scaling container to OsuGame so OsuGameBase doesn't apply UI scale --- osu.Game/OsuGame.cs | 2 ++ osu.Game/OsuGameBase.cs | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1f823e6eba..c375ccda81 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -393,6 +393,8 @@ namespace osu.Game protected virtual Loader CreateLoader() => new Loader(); + protected override Container CreateScalingContainer() => new ScalingContainer(ScalingMode.Everything); + #region Beatmap progression private void beatmapChanged(ValueChangedEvent beatmap) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 194a439b06..947df75783 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -26,7 +26,6 @@ using osu.Framework.Input; using osu.Framework.Logging; using osu.Game.Audio; using osu.Game.Database; -using osu.Game.Graphics.Containers; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.IO; @@ -228,7 +227,7 @@ namespace osu.Game Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both } }; - base.Content.Add(new ScalingContainer(ScalingMode.Everything) { Child = MenuCursorContainer }); + base.Content.Add(CreateScalingContainer().WithChild(MenuCursorContainer)); KeyBindingStore.Register(globalBinding); dependencies.Cache(globalBinding); @@ -238,6 +237,8 @@ namespace osu.Game Add(previewTrackManager); } + protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer(); + protected override void LoadComplete() { base.LoadComplete(); From 13fd95d513da835f427e59095b606ced479ff29b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 14:03:29 +0900 Subject: [PATCH 36/73] Remove misplaced usings --- osu.Game/Tests/Visual/OsuTestScene.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index daa1a56221..345fff90aa 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -17,9 +17,7 @@ using osu.Framework.Platform; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Database; -using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; From fced262c41859aa3fc01f3ffcb3eeded6610245e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 17:03:40 +0900 Subject: [PATCH 37/73] Add labelled dropdown component --- .../UserInterfaceV2/LabelledDropdown.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs new file mode 100644 index 0000000000..7e50fa7bc6 --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + public class LabelledDropdown : LabelledComponent, T> + { + public LabelledDropdown() + : base(true) + { + } + + public IEnumerable Items + { + get => Component.Items; + set => Component.Items = value; + } + + protected override OsuDropdown CreateComponent() => new OsuDropdown + { + RelativeSizeAxes = Axes.X, + Width = 0.5f, + }; + } +} From 702a1c496bd6e2a146dd5a7b2a82d42752f90e42 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 17:03:50 +0900 Subject: [PATCH 38/73] Add ruleset selection to tournament client --- osu.Game.Tournament/Models/LadderInfo.cs | 3 +++ osu.Game.Tournament/Screens/SetupScreen.cs | 13 ++++++++++++- osu.Game.Tournament/TournamentGameBase.cs | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Models/LadderInfo.cs b/osu.Game.Tournament/Models/LadderInfo.cs index 547c4eab08..5db0b01547 100644 --- a/osu.Game.Tournament/Models/LadderInfo.cs +++ b/osu.Game.Tournament/Models/LadderInfo.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using Newtonsoft.Json; using osu.Framework.Bindables; +using osu.Game.Rulesets; namespace osu.Game.Tournament.Models { @@ -14,6 +15,8 @@ namespace osu.Game.Tournament.Models [Serializable] public class LadderInfo { + public Bindable Ruleset = new Bindable(); + public BindableList Matches = new BindableList(); public BindableList Rounds = new BindableList(); public BindableList Teams = new BindableList(); diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index a67daa2756..b511d572da 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -10,6 +10,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Overlays; +using osu.Game.Rulesets; using osu.Game.Tournament.IPC; using osuTK; using osuTK.Graphics; @@ -28,6 +29,9 @@ namespace osu.Game.Tournament.Screens [Resolved] private IAPIProvider api { get; set; } + [Resolved] + private RulesetStore rulesets { get; set; } + [BackgroundDependencyLoader] private void load() { @@ -85,7 +89,14 @@ namespace osu.Game.Tournament.Screens Value = api?.LocalUser.Value.Username, Failing = api?.IsLoggedIn != true, Description = "In order to access the API and display metadata, a login is required." - } + }, + new LabelledDropdown + { + Label = "Ruleset", + Description = "Decides what stats are displayed and which ranks are retrieved for players", + Items = rulesets.AvailableRulesets, + Current = LadderInfo.Ruleset, + }, }; } diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 3b7718c61d..59edd18341 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -126,6 +126,8 @@ namespace osu.Game.Tournament ladder = new LadderInfo(); } + Ruleset.BindTo(ladder.Ruleset); + dependencies.Cache(ladder); bool addedInfo = false; From 5d96e6d90a30b85d27866d70ce9ff5f693247e0f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 17:39:48 +0900 Subject: [PATCH 39/73] Populate users centrally, using the correct ruleset --- .../Screens/Editors/TeamEditorScreen.cs | 26 +++------------ osu.Game.Tournament/TournamentGameBase.cs | 32 ++++++++++++++++--- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index e1f6d16623..11c2732d62 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Overlays.Settings; using osu.Game.Tournament.Components; using osu.Game.Tournament.Models; @@ -24,7 +23,7 @@ namespace osu.Game.Tournament.Screens.Editors public class TeamEditorScreen : TournamentEditorScreen { [Resolved] - private Framework.Game game { get; set; } + private TournamentGameBase game { get; set; } protected override BindableList Storage => LadderInfo.Teams; @@ -198,6 +197,9 @@ namespace osu.Game.Tournament.Screens.Editors [Resolved] protected IAPIProvider API { get; private set; } + [Resolved] + private TournamentGameBase game { get; set; } + private readonly Bindable userId = new Bindable(); private readonly Container drawableContainer; @@ -280,25 +282,7 @@ namespace osu.Game.Tournament.Screens.Editors return; } - var req = new GetUserRequest(user.Id); - - req.Success += res => - { - // TODO: this should be done in a better way. - user.Username = res.Username; - user.Country = res.Country; - user.Cover = res.Cover; - - updatePanel(); - }; - - req.Failure += _ => - { - user.Id = 1; - updatePanel(); - }; - - API.Queue(req); + game.PopulateUser(user, updatePanel, updatePanel); }, true); } diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 59edd18341..b0ca099a86 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Drawing; using System.IO; using System.Linq; @@ -21,11 +22,13 @@ using osu.Game.Graphics; using osu.Game.Online.API.Requests; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; +using osu.Game.Users; using osuTK.Graphics; using osuTK.Input; namespace osu.Game.Tournament { + [Cached(typeof(TournamentGameBase))] public abstract class TournamentGameBase : OsuGameBase { private const string bracket_filename = "bracket.json"; @@ -197,10 +200,7 @@ namespace osu.Game.Tournament foreach (var p in t.Players) if (string.IsNullOrEmpty(p.Username)) { - var req = new GetUserRequest(p.Id); - req.Perform(API); - p.Username = req.Result.Username; - + PopulateUser(p); addedInfo = true; } @@ -228,6 +228,30 @@ namespace osu.Game.Tournament return addedInfo; } + public void PopulateUser(User user, Action success = null, Action failure = null) + { + var req = new GetUserRequest(user.Id, Ruleset.Value); + + req.Success += res => + { + user.Username = res.Username; + user.Statistics = res.Statistics; + user.Username = res.Username; + user.Country = res.Country; + user.Cover = res.Cover; + + success?.Invoke(); + }; + + req.Failure += _ => + { + user.Id = 1; + failure?.Invoke(); + }; + + API.Queue(req); + } + protected override void LoadComplete() { MenuCursorContainer.Cursor.AlwaysPresent = true; // required for tooltip display From 6d3d7c5d95823d9915e197116e7f327dad54592b Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 11 Nov 2019 11:57:14 +0300 Subject: [PATCH 40/73] Remove unnecessary use of local --- osu.Game/Audio/PreviewTrackManager.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 8f723194e3..72b33c4073 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -48,11 +48,8 @@ namespace osu.Game.Audio track.Started += () => Schedule(() => { - // Assign the new track to current before stopping last track to avoid assigning null to current. - var last = current; + current?.Stop(); current = track; - last?.Stop(); - audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable); }); From ce4843be22ff62e95362da8a2f24530c1fb9b91c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 18:42:32 +0900 Subject: [PATCH 41/73] Move tests to parent namespace for now --- .../UserInterface/{MenuItems => }/TestSceneStatefulMenuItem.cs | 2 +- .../{MenuItems => }/TestSceneThreeStateMenuItem.cs | 2 +- .../UserInterface/{MenuItems => }/TestSceneToggleMenuItem.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename osu.Game.Tests/Visual/UserInterface/{MenuItems => }/TestSceneStatefulMenuItem.cs (98%) rename osu.Game.Tests/Visual/UserInterface/{MenuItems => }/TestSceneThreeStateMenuItem.cs (95%) rename osu.Game.Tests/Visual/UserInterface/{MenuItems => }/TestSceneToggleMenuItem.cs (94%) diff --git a/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs similarity index 98% rename from osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneStatefulMenuItem.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs index 95e9aea97f..fd30da39e6 100644 --- a/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneStatefulMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Tests.Visual.UserInterface.MenuItems +namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneStatefulMenuItem : OsuTestScene { diff --git a/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneThreeStateMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs similarity index 95% rename from osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneThreeStateMenuItem.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs index e035e43630..caa07e7b60 100644 --- a/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneThreeStateMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Tests.Visual.UserInterface.MenuItems +namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneThreeStateMenuItem : OsuTestScene { diff --git a/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneToggleMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs similarity index 94% rename from osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneToggleMenuItem.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs index 92875740cf..2abda56a28 100644 --- a/osu.Game.Tests/Visual/UserInterface/MenuItems/TestSceneToggleMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Tests.Visual.UserInterface.MenuItems +namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneToggleMenuItem : OsuTestScene { From bed62e0d2f2b62d19a76bfb051c04263900706c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 18:56:18 +0900 Subject: [PATCH 42/73] Rename ThreeState -> TernaryState and add basic tests --- .../UserInterface/TestSceneTernaryMenuItem.cs | 65 +++++++++++++++++++ .../TestSceneThreeStateMenuItem.cs | 35 ---------- .../{ThreeStates.cs => TernaryState.cs} | 14 ++-- .../UserInterface/ThreeStateMenuItem.cs | 28 ++++---- 4 files changed, 86 insertions(+), 56 deletions(-) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneTernaryMenuItem.cs delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs rename osu.Game/Graphics/UserInterface/{ThreeStates.cs => TernaryState.cs} (56%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneTernaryMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneTernaryMenuItem.cs new file mode 100644 index 0000000000..fdb8c330c5 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneTernaryMenuItem.cs @@ -0,0 +1,65 @@ +// 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 osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneTernaryMenuItem : ManualInputManagerTestScene + { + private readonly OsuMenu menu; + + public override IReadOnlyList RequiredTypes => new[] + { + typeof(OsuMenu), + typeof(ThreeStateMenuItem), + typeof(DrawableStatefulMenuItem) + }; + + private readonly Bindable state = new Bindable(TernaryState.Indeterminate); + + public TestSceneTernaryMenuItem() + { + Add(menu = new OsuMenu(Direction.Vertical, true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Items = new[] + { + new ThreeStateMenuItem("First"), + new ThreeStateMenuItem("Second") { State = { BindTarget = state } }, + new ThreeStateMenuItem("Third") { State = { Value = TernaryState.True } }, + } + }); + + checkState(TernaryState.Indeterminate); + + click(); + checkState(TernaryState.True); + + click(); + checkState(TernaryState.False); + + click(); + checkState(TernaryState.True); + + click(); + checkState(TernaryState.False); + } + + private void click() => + AddStep("click", () => + { + InputManager.MoveMouseTo(menu.ScreenSpaceDrawQuad.Centre); + InputManager.Click(MouseButton.Left); + }); + + private void checkState(TernaryState expected) + => AddAssert($"state is {expected}", () => state.Value == expected); + } +} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs deleted file mode 100644 index caa07e7b60..0000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneThreeStateMenuItem.cs +++ /dev/null @@ -1,35 +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; -using System.Collections.Generic; -using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public class TestSceneThreeStateMenuItem : OsuTestScene - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(OsuMenu), - typeof(ThreeStateMenuItem), - typeof(DrawableStatefulMenuItem) - }; - - public TestSceneThreeStateMenuItem() - { - Add(new OsuMenu(Direction.Vertical, true) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Items = new[] - { - new ThreeStateMenuItem("First"), - new ThreeStateMenuItem("Second") { State = { Value = ThreeStates.Indeterminate } }, - new ThreeStateMenuItem("Third") { State = { Value = ThreeStates.Enabled } }, - } - }); - } - } -} diff --git a/osu.Game/Graphics/UserInterface/ThreeStates.cs b/osu.Game/Graphics/UserInterface/TernaryState.cs similarity index 56% rename from osu.Game/Graphics/UserInterface/ThreeStates.cs rename to osu.Game/Graphics/UserInterface/TernaryState.cs index f099250937..784122e35c 100644 --- a/osu.Game/Graphics/UserInterface/ThreeStates.cs +++ b/osu.Game/Graphics/UserInterface/TernaryState.cs @@ -6,22 +6,22 @@ namespace osu.Game.Graphics.UserInterface /// /// An on/off state with an extra indeterminate state. /// - public enum ThreeStates + public enum TernaryState { /// - /// The current state is disabled. + /// The current state is false. /// - Disabled, + False, /// - /// The current state is a combination of and . - /// The state becomes if the is pressed. + /// The current state is a combination of and . + /// The state becomes if the is pressed. /// Indeterminate, /// - /// The current state is enabled. + /// The current state is true. /// - Enabled + True } } diff --git a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs index ebb6436196..c5b9edf3c4 100644 --- a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs @@ -9,7 +9,7 @@ namespace osu.Game.Graphics.UserInterface /// /// An with three possible states. /// - public class ThreeStateMenuItem : StatefulMenuItem + public class ThreeStateMenuItem : StatefulMenuItem { /// /// Creates a new . @@ -27,7 +27,7 @@ namespace osu.Game.Graphics.UserInterface /// The text to display. /// The type of action which this performs. /// A delegate to be invoked when this is pressed. - public ThreeStateMenuItem(string text, MenuItemType type, Action action) + public ThreeStateMenuItem(string text, MenuItemType type, Action action) : this(text, getNextState, type, action) { } @@ -39,37 +39,37 @@ namespace osu.Game.Graphics.UserInterface /// A function that mutates a state to another state after this is pressed. /// The type of action which this performs. /// A delegate to be invoked when this is pressed. - protected ThreeStateMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) + protected ThreeStateMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) : base(text, changeStateFunc, type, action) { } - public override IconUsage? GetIconForState(ThreeStates state) + public override IconUsage? GetIconForState(TernaryState state) { switch (state) { - case ThreeStates.Indeterminate: - return FontAwesome.Regular.Circle; + case TernaryState.Indeterminate: + return FontAwesome.Solid.DotCircle; - case ThreeStates.Enabled: + case TernaryState.True: return FontAwesome.Solid.Check; } return null; } - private static ThreeStates getNextState(ThreeStates state) + private static TernaryState getNextState(TernaryState state) { switch (state) { - case ThreeStates.Disabled: - return ThreeStates.Enabled; + case TernaryState.False: + return TernaryState.True; - case ThreeStates.Indeterminate: - return ThreeStates.Enabled; + case TernaryState.Indeterminate: + return TernaryState.True; - case ThreeStates.Enabled: - return ThreeStates.Disabled; + case TernaryState.True: + return TernaryState.False; default: throw new ArgumentOutOfRangeException(nameof(state), state, null); From 82cc6aa0c5b2b251a229808b0a6494ba684a7cbb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 19:00:14 +0900 Subject: [PATCH 43/73] Remove unused constructor --- .../Visual/UserInterface/TestSceneStatefulMenuItem.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs index fd30da39e6..bd7f73c6d8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs @@ -52,11 +52,6 @@ namespace osu.Game.Tests.Visual.UserInterface private class TestMenuItem : StatefulMenuItem { - public TestMenuItem(string text, MenuItemType type = MenuItemType.Standard) - : this(text, type, null) - { - } - public TestMenuItem(string text, MenuItemType type, Func changeStateFunc) : base(text, changeStateFunc, type) { From 54da8e4035cd3b033eee59839e5c7428a297d25d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 11 Nov 2019 19:09:38 +0900 Subject: [PATCH 44/73] Combine similar tests --- .../TestSceneStatefulMenuItem.cs | 81 ++++++++++++++++--- .../UserInterface/TestSceneTernaryMenuItem.cs | 65 --------------- 2 files changed, 70 insertions(+), 76 deletions(-) delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneTernaryMenuItem.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs index bd7f73c6d8..1eff30d15e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs @@ -3,33 +3,92 @@ using System; using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneStatefulMenuItem : OsuTestScene + public class TestSceneStatefulMenuItem : ManualInputManagerTestScene { public override IReadOnlyList RequiredTypes => new[] { typeof(OsuMenu), typeof(StatefulMenuItem), - typeof(DrawableStatefulMenuItem) + typeof(ThreeStateMenuItem), + typeof(DrawableStatefulMenuItem), }; - public TestSceneStatefulMenuItem() + [Test] + public void TestTernaryMenuItem() { - Add(new OsuMenu(Direction.Vertical, true) + OsuMenu menu = null; + + Bindable state = new Bindable(TernaryState.Indeterminate); + + AddStep("create menu", () => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Items = new[] + state.Value = TernaryState.Indeterminate; + + Child = menu = new OsuMenu(Direction.Vertical, true) { - new TestMenuItem("First", MenuItemType.Standard, getNextState), - new TestMenuItem("Second", MenuItemType.Standard, getNextState) { State = { Value = TestStates.State2 } }, - new TestMenuItem("Third", MenuItemType.Standard, getNextState) { State = { Value = TestStates.State3 } }, - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Items = new[] + { + new ThreeStateMenuItem("First"), + new ThreeStateMenuItem("Second") { State = { BindTarget = state } }, + new ThreeStateMenuItem("Third") { State = { Value = TernaryState.True } }, + } + }; + }); + + checkState(TernaryState.Indeterminate); + + click(); + checkState(TernaryState.True); + + click(); + checkState(TernaryState.False); + + click(); + checkState(TernaryState.True); + + click(); + checkState(TernaryState.False); + + AddStep("change state via bindable", () => state.Value = TernaryState.True); + + void click() => + AddStep("click", () => + { + InputManager.MoveMouseTo(menu.ScreenSpaceDrawQuad.Centre); + InputManager.Click(MouseButton.Left); + }); + + void checkState(TernaryState expected) + => AddAssert($"state is {expected}", () => state.Value == expected); + } + + [Test] + public void TestCustomState() + { + AddStep("create menu", () => + { + Child = new OsuMenu(Direction.Vertical, true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Items = new[] + { + new TestMenuItem("First", MenuItemType.Standard, getNextState), + new TestMenuItem("Second", MenuItemType.Standard, getNextState) { State = { Value = TestStates.State2 } }, + new TestMenuItem("Third", MenuItemType.Standard, getNextState) { State = { Value = TestStates.State3 } }, + } + }; }); } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneTernaryMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneTernaryMenuItem.cs deleted file mode 100644 index fdb8c330c5..0000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneTernaryMenuItem.cs +++ /dev/null @@ -1,65 +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; -using System.Collections.Generic; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public class TestSceneTernaryMenuItem : ManualInputManagerTestScene - { - private readonly OsuMenu menu; - - public override IReadOnlyList RequiredTypes => new[] - { - typeof(OsuMenu), - typeof(ThreeStateMenuItem), - typeof(DrawableStatefulMenuItem) - }; - - private readonly Bindable state = new Bindable(TernaryState.Indeterminate); - - public TestSceneTernaryMenuItem() - { - Add(menu = new OsuMenu(Direction.Vertical, true) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Items = new[] - { - new ThreeStateMenuItem("First"), - new ThreeStateMenuItem("Second") { State = { BindTarget = state } }, - new ThreeStateMenuItem("Third") { State = { Value = TernaryState.True } }, - } - }); - - checkState(TernaryState.Indeterminate); - - click(); - checkState(TernaryState.True); - - click(); - checkState(TernaryState.False); - - click(); - checkState(TernaryState.True); - - click(); - checkState(TernaryState.False); - } - - private void click() => - AddStep("click", () => - { - InputManager.MoveMouseTo(menu.ScreenSpaceDrawQuad.Centre); - InputManager.Click(MouseButton.Left); - }); - - private void checkState(TernaryState expected) - => AddAssert($"state is {expected}", () => state.Value == expected); - } -} From 3d1c31f2ae57d010e1845d4a77dcd4b4b395ab74 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 11 Nov 2019 19:45:52 +0800 Subject: [PATCH 45/73] Copy configs from framework repo. --- .editorconfig | 167 ++++++++- osu.sln.DotSettings | 846 +++++++++++++++++++++++--------------------- 2 files changed, 594 insertions(+), 419 deletions(-) diff --git a/.editorconfig b/.editorconfig index 0dd7ef8ed1..8f9d0ca9b0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,16 +12,171 @@ trim_trailing_whitespace = true #PascalCase for public and protected members dotnet_naming_style.pascalcase.capitalization = pascal_case -dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal -dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event,delegate -dotnet_naming_rule.public_members_pascalcase.severity = suggestion +dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal,private_protected +dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event +dotnet_naming_rule.public_members_pascalcase.severity = error dotnet_naming_rule.public_members_pascalcase.symbols = public_members dotnet_naming_rule.public_members_pascalcase.style = pascalcase #camelCase for private members dotnet_naming_style.camelcase.capitalization = camel_case + dotnet_naming_symbols.private_members.applicable_accessibilities = private -dotnet_naming_symbols.private_members.applicable_kinds = property,method,field,event,delegate -dotnet_naming_rule.private_members_camelcase.severity = suggestion +dotnet_naming_symbols.private_members.applicable_kinds = property,method,field,event +dotnet_naming_rule.private_members_camelcase.severity = warning dotnet_naming_rule.private_members_camelcase.symbols = private_members -dotnet_naming_rule.private_members_camelcase.style = camelcase \ No newline at end of file +dotnet_naming_rule.private_members_camelcase.style = camelcase + +dotnet_naming_symbols.local_function.applicable_kinds = local_function +dotnet_naming_rule.local_function_camelcase.severity = warning +dotnet_naming_rule.local_function_camelcase.symbols = local_function +dotnet_naming_rule.local_function_camelcase.style = camelcase + +#all_lower for private and local constants/static readonlys +dotnet_naming_style.all_lower.capitalization = all_lower +dotnet_naming_style.all_lower.word_separator = _ + +dotnet_naming_symbols.private_constants.applicable_accessibilities = private +dotnet_naming_symbols.private_constants.required_modifiers = const +dotnet_naming_symbols.private_constants.applicable_kinds = field +dotnet_naming_rule.private_const_all_lower.severity = warning +dotnet_naming_rule.private_const_all_lower.symbols = private_constants +dotnet_naming_rule.private_const_all_lower.style = all_lower + +dotnet_naming_symbols.private_static_readonly.applicable_accessibilities = private +dotnet_naming_symbols.private_static_readonly.required_modifiers = static,readonly +dotnet_naming_symbols.private_static_readonly.applicable_kinds = field +dotnet_naming_rule.private_static_readonly_all_lower.severity = warning +dotnet_naming_rule.private_static_readonly_all_lower.symbols = private_static_readonly +dotnet_naming_rule.private_static_readonly_all_lower.style = all_lower + +dotnet_naming_symbols.local_constants.applicable_kinds = local +dotnet_naming_symbols.local_constants.required_modifiers = const +dotnet_naming_rule.local_const_all_lower.severity = warning +dotnet_naming_rule.local_const_all_lower.symbols = local_constants +dotnet_naming_rule.local_const_all_lower.style = all_lower + +#ALL_UPPER for non private constants/static readonlys +dotnet_naming_style.all_upper.capitalization = all_upper +dotnet_naming_style.all_upper.word_separator = _ + +dotnet_naming_symbols.public_constants.applicable_accessibilities = public,internal,protected,protected_internal,private_protected +dotnet_naming_symbols.public_constants.required_modifiers = const +dotnet_naming_symbols.public_constants.applicable_kinds = field +dotnet_naming_rule.public_const_all_upper.severity = warning +dotnet_naming_rule.public_const_all_upper.symbols = public_constants +dotnet_naming_rule.public_const_all_upper.style = all_upper + +dotnet_naming_symbols.public_static_readonly.applicable_accessibilities = public,internal,protected,protected_internal,private_protected +dotnet_naming_symbols.public_static_readonly.required_modifiers = static,readonly +dotnet_naming_symbols.public_static_readonly.applicable_kinds = field +dotnet_naming_rule.public_static_readonly_all_upper.severity = warning +dotnet_naming_rule.public_static_readonly_all_upper.symbols = public_static_readonly +dotnet_naming_rule.public_static_readonly_all_upper.style = all_upper + +#Roslyn formating options + +#Formatting - indentation options +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = false +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +#Formatting - new line options +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_open_brace = all +#csharp_new_line_before_members_in_anonymous_types = true +#csharp_new_line_before_members_in_object_initializers = true # Currently no effect in VS/dotnet format (16.4), and makes Rider confusing +csharp_new_line_between_query_expression_clauses = true + +#Formatting - organize using options +dotnet_sort_system_directives_first = true + +#Formatting - spacing options +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false + +#Formatting - wrapping options +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#Roslyn language styles + +#Style - type names +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +csharp_style_var_when_type_is_apparent = true:none +csharp_style_var_for_built_in_types = true:none +csharp_style_var_elsewhere = true:silent + +#Style - modifiers +dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning +csharp_preferred_modifier_order = public,private,protected,internal,new,abstract,virtual,sealed,override,static,readonly,extern,unsafe,volatile,async:warning + +#Style - parentheses +# Skipped because roslyn cannot separate +-*/ with << >> + +#Style - expression bodies +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_methods = true:silent +csharp_style_expression_bodied_operators = true:silent +csharp_style_expression_bodied_properties = true:silent + +#Style - expression preferences +dotnet_style_object_initializer = true:warning +dotnet_style_collection_initializer = true:warning +dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_prefer_compound_assignment = true:warning + +#Style - null/type checks +dotnet_style_coalesce_expression = true:warning +dotnet_style_null_propagation = true:warning +csharp_style_pattern_matching_over_is_with_cast_check = true:silent +csharp_style_pattern_matching_over_as_with_null_check = true:silent +csharp_style_throw_expression = true:silent +csharp_style_conditional_delegate_call = true:suggestion + +#Style - unused +dotnet_code_quality_unused_parameters = non_public:silent +csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_style_unused_value_assignment_preference = discard_variable:suggestion + +#Style - variable declaration +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = true:silent + +#Style - other C# 7.x features +csharp_style_expression_bodied_local_functions = true:silent +dotnet_style_prefer_inferred_tuple_names = true:warning +csharp_prefer_simple_default_expression = true:warning +csharp_style_pattern_local_over_anonymous_function = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent + +#Supressing roslyn built-in analyzers +# Suppress: EC112 + +#Field can be readonly +dotnet_diagnostic.IDE0044.severity = silent +#Private method is unused +dotnet_diagnostic.IDE0051.severity = silent +#Private member is unused +dotnet_diagnostic.IDE0052.severity = silent + +#Rules for disposable +dotnet_diagnostic.IDE0067.severity = none +dotnet_diagnostic.IDE0068.severity = none +dotnet_diagnostic.IDE0069.severity = none \ No newline at end of file diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index eb9e3ffafb..44c5c05bc0 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -12,7 +12,7 @@ HINT HINT WARNING - + WARNING True WARNING WARNING @@ -70,11 +70,20 @@ WARNING WARNING DO_NOT_SHOW + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING HINT WARNING DO_NOT_SHOW WARNING HINT + DO_NOT_SHOW HINT HINT ERROR @@ -125,6 +134,7 @@ WARNING WARNING WARNING + WARNING WARNING WARNING ERROR @@ -171,7 +181,7 @@ WARNING WARNING WARNING - HINT + WARNING WARNING WARNING WARNING @@ -201,6 +211,7 @@ HINT HINT + HINT WARNING WARNING WARNING @@ -218,9 +229,14 @@ WARNING <?xml version="1.0" encoding="utf-16"?><Profile name="Code Cleanup (peppy)"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSUseVar><BehavourStyle>CAN_CHANGE_TO_EXPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_EXPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSUpdateFileHeader>True</CSUpdateFileHeader><CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="False" ArrangeBraces="False" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSArrangeQualifiers>True</CSArrangeQualifiers></Profile> Code Cleanup (peppy) - Required - Required - Required + RequiredForMultiline + RequiredForMultiline + RequiredForMultiline + RequiredForMultiline + RequiredForMultiline + RequiredForMultiline + RequiredForMultiline + RequiredForMultiline Explicit ExpressionBody ExpressionBody @@ -239,6 +255,10 @@ 1 NEXT_LINE MULTILINE + True + True + True + True NEXT_LINE 1 1 @@ -289,397 +309,397 @@ SHA SRGB TK - SS - PP - GMT - QAT - BNG + SS + PP + GMT + QAT + BNG UI False HINT <?xml version="1.0" encoding="utf-16"?> <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> - <TypePattern DisplayName="COM interfaces or structs"> - <TypePattern.Match> - <Or> - <And> - <Kind Is="Interface" /> - <Or> - <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /> - <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> - </Or> - </And> - <Kind Is="Struct" /> - </Or> - </TypePattern.Match> - </TypePattern> - <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"> - <TypePattern.Match> - <And> - <Kind Is="Class" /> - <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" /> - </And> - </TypePattern.Match> - <Entry DisplayName="Setup/Teardown Methods"> - <Entry.Match> - <And> - <Kind Is="Method" /> - <Or> - <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" /> - <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" /> - <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" /> - <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" /> - </Or> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="All other members" /> - <Entry Priority="100" DisplayName="Test Methods"> - <Entry.Match> - <And> - <Kind Is="Method" /> - <HasAttribute Name="NUnit.Framework.TestAttribute" /> - </And> - </Entry.Match> - <Entry.SortBy> - <Name /> - </Entry.SortBy> - </Entry> - </TypePattern> - <TypePattern DisplayName="Default Pattern"> - <Group DisplayName="Fields/Properties"> - <Group DisplayName="Public Fields"> - <Entry DisplayName="Constant Fields"> - <Entry.Match> - <And> - <Access Is="Public" /> - <Or> - <Kind Is="Constant" /> - <Readonly /> - <And> - <Static /> - <Readonly /> - </And> - </Or> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Static Fields"> - <Entry.Match> - <And> - <Access Is="Public" /> - <Static /> - <Not> - <Readonly /> - </Not> - <Kind Is="Field" /> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Normal Fields"> - <Entry.Match> - <And> - <Access Is="Public" /> - <Not> - <Or> - <Static /> - <Readonly /> - </Or> - </Not> - <Kind Is="Field" /> - </And> - </Entry.Match> - </Entry> - </Group> - <Entry DisplayName="Public Properties"> - <Entry.Match> - <And> - <Access Is="Public" /> - <Kind Is="Property" /> - </And> - </Entry.Match> - </Entry> - <Group DisplayName="Internal Fields"> - <Entry DisplayName="Constant Fields"> - <Entry.Match> - <And> - <Access Is="Internal" /> - <Or> - <Kind Is="Constant" /> - <Readonly /> - <And> - <Static /> - <Readonly /> - </And> - </Or> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Static Fields"> - <Entry.Match> - <And> - <Access Is="Internal" /> - <Static /> - <Not> - <Readonly /> - </Not> - <Kind Is="Field" /> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Normal Fields"> - <Entry.Match> - <And> - <Access Is="Internal" /> - <Not> - <Or> - <Static /> - <Readonly /> - </Or> - </Not> - <Kind Is="Field" /> - </And> - </Entry.Match> - </Entry> - </Group> - <Entry DisplayName="Internal Properties"> - <Entry.Match> - <And> - <Access Is="Internal" /> - <Kind Is="Property" /> - </And> - </Entry.Match> - </Entry> - <Group DisplayName="Protected Fields"> - <Entry DisplayName="Constant Fields"> - <Entry.Match> - <And> - <Access Is="Protected" /> - <Or> - <Kind Is="Constant" /> - <Readonly /> - <And> - <Static /> - <Readonly /> - </And> - </Or> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Static Fields"> - <Entry.Match> - <And> - <Access Is="Protected" /> - <Static /> - <Not> - <Readonly /> - </Not> - <Kind Is="Field" /> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Normal Fields"> - <Entry.Match> - <And> - <Access Is="Protected" /> - <Not> - <Or> - <Static /> - <Readonly /> - </Or> - </Not> - <Kind Is="Field" /> - </And> - </Entry.Match> - </Entry> - </Group> - <Entry DisplayName="Protected Properties"> - <Entry.Match> - <And> - <Access Is="Protected" /> - <Kind Is="Property" /> - </And> - </Entry.Match> - </Entry> - <Group DisplayName="Private Fields"> - <Entry DisplayName="Constant Fields"> - <Entry.Match> - <And> - <Access Is="Private" /> - <Or> - <Kind Is="Constant" /> - <Readonly /> - <And> - <Static /> - <Readonly /> - </And> - </Or> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Static Fields"> - <Entry.Match> - <And> - <Access Is="Private" /> - <Static /> - <Not> - <Readonly /> - </Not> - <Kind Is="Field" /> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Normal Fields"> - <Entry.Match> - <And> - <Access Is="Private" /> - <Not> - <Or> - <Static /> - <Readonly /> - </Or> - </Not> - <Kind Is="Field" /> - </And> - </Entry.Match> - </Entry> - </Group> - <Entry DisplayName="Private Properties"> - <Entry.Match> - <And> - <Access Is="Private" /> - <Kind Is="Property" /> - </And> - </Entry.Match> - </Entry> - </Group> - <Group DisplayName="Constructor/Destructor"> - <Entry DisplayName="Ctor"> - <Entry.Match> - <Kind Is="Constructor" /> - </Entry.Match> - </Entry> - <Region Name="Disposal"> - <Entry DisplayName="Dtor"> - <Entry.Match> - <Kind Is="Destructor" /> - </Entry.Match> - </Entry> - <Entry DisplayName="Dispose()"> - <Entry.Match> - <And> - <Access Is="Public" /> - <Kind Is="Method" /> - <Name Is="Dispose" /> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Dispose(true)"> - <Entry.Match> - <And> - <Access Is="Protected" /> - <Or> - <Virtual /> - <Override /> - </Or> - <Kind Is="Method" /> - <Name Is="Dispose" /> - </And> - </Entry.Match> - </Entry> - </Region> - </Group> - <Group DisplayName="Methods"> - <Group DisplayName="Public"> - <Entry DisplayName="Static Methods"> - <Entry.Match> - <And> - <Access Is="Public" /> - <Static /> - <Kind Is="Method" /> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Methods"> - <Entry.Match> - <And> - <Access Is="Public" /> - <Not> - <Static /> - </Not> - <Kind Is="Method" /> - </And> - </Entry.Match> - </Entry> - </Group> - <Group DisplayName="Internal"> - <Entry DisplayName="Static Methods"> - <Entry.Match> - <And> - <Access Is="Internal" /> - <Static /> - <Kind Is="Method" /> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Methods"> - <Entry.Match> - <And> - <Access Is="Internal" /> - <Not> - <Static /> - </Not> - <Kind Is="Method" /> - </And> - </Entry.Match> - </Entry> - </Group> - <Group DisplayName="Protected"> - <Entry DisplayName="Static Methods"> - <Entry.Match> - <And> - <Access Is="Protected" /> - <Static /> - <Kind Is="Method" /> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Methods"> - <Entry.Match> - <And> - <Access Is="Protected" /> - <Not> - <Static /> - </Not> - <Kind Is="Method" /> - </And> - </Entry.Match> - </Entry> - </Group> - <Group DisplayName="Private"> - <Entry DisplayName="Static Methods"> - <Entry.Match> - <And> - <Access Is="Private" /> - <Static /> - <Kind Is="Method" /> - </And> - </Entry.Match> - </Entry> - <Entry DisplayName="Methods"> - <Entry.Match> - <And> - <Access Is="Private" /> - <Not> - <Static /> - </Not> - <Kind Is="Method" /> - </And> - </Entry.Match> - </Entry> - </Group> - </Group> - </TypePattern> + <TypePattern DisplayName="COM interfaces or structs"> + <TypePattern.Match> + <Or> + <And> + <Kind Is="Interface" /> + <Or> + <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /> + <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> + </Or> + </And> + <Kind Is="Struct" /> + </Or> + </TypePattern.Match> + </TypePattern> + <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"> + <TypePattern.Match> + <And> + <Kind Is="Class" /> + <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" /> + </And> + </TypePattern.Match> + <Entry DisplayName="Setup/Teardown Methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <Or> + <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" /> + </Or> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="All other members" /> + <Entry Priority="100" DisplayName="Test Methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <HasAttribute Name="NUnit.Framework.TestAttribute" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> + <TypePattern DisplayName="Default Pattern"> + <Group DisplayName="Fields/Properties"> + <Group DisplayName="Public Fields"> + <Entry DisplayName="Constant Fields"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Or> + <Kind Is="Constant" /> + <Readonly /> + <And> + <Static /> + <Readonly /> + </And> + </Or> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Static Fields"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Static /> + <Not> + <Readonly /> + </Not> + <Kind Is="Field" /> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Normal Fields"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Not> + <Or> + <Static /> + <Readonly /> + </Or> + </Not> + <Kind Is="Field" /> + </And> + </Entry.Match> + </Entry> + </Group> + <Entry DisplayName="Public Properties"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Kind Is="Property" /> + </And> + </Entry.Match> + </Entry> + <Group DisplayName="Internal Fields"> + <Entry DisplayName="Constant Fields"> + <Entry.Match> + <And> + <Access Is="Internal" /> + <Or> + <Kind Is="Constant" /> + <Readonly /> + <And> + <Static /> + <Readonly /> + </And> + </Or> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Static Fields"> + <Entry.Match> + <And> + <Access Is="Internal" /> + <Static /> + <Not> + <Readonly /> + </Not> + <Kind Is="Field" /> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Normal Fields"> + <Entry.Match> + <And> + <Access Is="Internal" /> + <Not> + <Or> + <Static /> + <Readonly /> + </Or> + </Not> + <Kind Is="Field" /> + </And> + </Entry.Match> + </Entry> + </Group> + <Entry DisplayName="Internal Properties"> + <Entry.Match> + <And> + <Access Is="Internal" /> + <Kind Is="Property" /> + </And> + </Entry.Match> + </Entry> + <Group DisplayName="Protected Fields"> + <Entry DisplayName="Constant Fields"> + <Entry.Match> + <And> + <Access Is="Protected" /> + <Or> + <Kind Is="Constant" /> + <Readonly /> + <And> + <Static /> + <Readonly /> + </And> + </Or> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Static Fields"> + <Entry.Match> + <And> + <Access Is="Protected" /> + <Static /> + <Not> + <Readonly /> + </Not> + <Kind Is="Field" /> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Normal Fields"> + <Entry.Match> + <And> + <Access Is="Protected" /> + <Not> + <Or> + <Static /> + <Readonly /> + </Or> + </Not> + <Kind Is="Field" /> + </And> + </Entry.Match> + </Entry> + </Group> + <Entry DisplayName="Protected Properties"> + <Entry.Match> + <And> + <Access Is="Protected" /> + <Kind Is="Property" /> + </And> + </Entry.Match> + </Entry> + <Group DisplayName="Private Fields"> + <Entry DisplayName="Constant Fields"> + <Entry.Match> + <And> + <Access Is="Private" /> + <Or> + <Kind Is="Constant" /> + <Readonly /> + <And> + <Static /> + <Readonly /> + </And> + </Or> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Static Fields"> + <Entry.Match> + <And> + <Access Is="Private" /> + <Static /> + <Not> + <Readonly /> + </Not> + <Kind Is="Field" /> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Normal Fields"> + <Entry.Match> + <And> + <Access Is="Private" /> + <Not> + <Or> + <Static /> + <Readonly /> + </Or> + </Not> + <Kind Is="Field" /> + </And> + </Entry.Match> + </Entry> + </Group> + <Entry DisplayName="Private Properties"> + <Entry.Match> + <And> + <Access Is="Private" /> + <Kind Is="Property" /> + </And> + </Entry.Match> + </Entry> + </Group> + <Group DisplayName="Constructor/Destructor"> + <Entry DisplayName="Ctor"> + <Entry.Match> + <Kind Is="Constructor" /> + </Entry.Match> + </Entry> + <Region Name="Disposal"> + <Entry DisplayName="Dtor"> + <Entry.Match> + <Kind Is="Destructor" /> + </Entry.Match> + </Entry> + <Entry DisplayName="Dispose()"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Kind Is="Method" /> + <Name Is="Dispose" /> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Dispose(true)"> + <Entry.Match> + <And> + <Access Is="Protected" /> + <Or> + <Virtual /> + <Override /> + </Or> + <Kind Is="Method" /> + <Name Is="Dispose" /> + </And> + </Entry.Match> + </Entry> + </Region> + </Group> + <Group DisplayName="Methods"> + <Group DisplayName="Public"> + <Entry DisplayName="Static Methods"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Static /> + <Kind Is="Method" /> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Methods"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Not> + <Static /> + </Not> + <Kind Is="Method" /> + </And> + </Entry.Match> + </Entry> + </Group> + <Group DisplayName="Internal"> + <Entry DisplayName="Static Methods"> + <Entry.Match> + <And> + <Access Is="Internal" /> + <Static /> + <Kind Is="Method" /> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Methods"> + <Entry.Match> + <And> + <Access Is="Internal" /> + <Not> + <Static /> + </Not> + <Kind Is="Method" /> + </And> + </Entry.Match> + </Entry> + </Group> + <Group DisplayName="Protected"> + <Entry DisplayName="Static Methods"> + <Entry.Match> + <And> + <Access Is="Protected" /> + <Static /> + <Kind Is="Method" /> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Methods"> + <Entry.Match> + <And> + <Access Is="Protected" /> + <Not> + <Static /> + </Not> + <Kind Is="Method" /> + </And> + </Entry.Match> + </Entry> + </Group> + <Group DisplayName="Private"> + <Entry DisplayName="Static Methods"> + <Entry.Match> + <And> + <Access Is="Private" /> + <Static /> + <Kind Is="Method" /> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="Methods"> + <Entry.Match> + <And> + <Access Is="Private" /> + <Not> + <Static /> + </Not> + <Kind Is="Method" /> + </And> + </Entry.Match> + </Entry> + </Group> + </Group> + </TypePattern> </Patterns> Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. See the LICENCE file in the repository root for full licence text. @@ -774,7 +794,7 @@ Origin = Anchor.$anchor$, True InternalChildren = new Drawable[] { - $END$ + $END$ }; True True @@ -787,12 +807,12 @@ Origin = Anchor.$anchor$, True new GridContainer { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] { $END$ }, - new Drawable[] { } - } + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] { $END$ }, + new Drawable[] { } + } }; True True @@ -805,12 +825,12 @@ Origin = Anchor.$anchor$, True new FillFlowContainer { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - $END$ - } + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + $END$ + } }, True True @@ -823,11 +843,11 @@ Origin = Anchor.$anchor$, True new Container { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - $END$ - } + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + $END$ + } }, True True @@ -841,7 +861,7 @@ Origin = Anchor.$anchor$, [BackgroundDependencyLoader] private void load() { - $END$ + $END$ } True True @@ -854,8 +874,8 @@ private void load() True new Box { - Colour = Color4.Black, - RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, }, True True @@ -868,7 +888,7 @@ private void load() True Children = new Drawable[] { - $END$ + $END$ }; True True From ccc8aa6fa4296bf6061527544269caf55c5baff6 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 11 Nov 2019 19:53:22 +0800 Subject: [PATCH 46/73] Apply brace style. --- .../TestSceneHyperDash.cs | 2 + .../Beatmaps/CatchBeatmapProcessor.cs | 4 ++ .../Objects/BananaShower.cs | 2 + .../Legacy/HitObjectPatternGenerator.cs | 4 ++ .../TestSceneDrawableJudgement.cs | 2 + .../TestSceneHitCircleLongCombo.cs | 2 + osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 4 ++ osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 + .../NonVisual/FramedReplayInputHandlerTest.cs | 2 + osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 2 + .../Online/TestSceneStandAloneChatDisplay.cs | 4 ++ .../SongSelect/TestSceneBeatmapCarousel.cs | 2 + .../SongSelect/TestScenePlaySongSelect.cs | 2 + osu.Game.Tests/Visual/TestSceneOsuGame.cs | 4 ++ .../TestSceneTournamentMatchChatDisplay.cs | 28 +++++------ .../Components/TournamentBeatmapPanel.cs | 2 + .../Components/TourneyVideo.cs | 2 + osu.Game.Tournament/IPC/FileBasedIPC.cs | 2 + .../Screens/Editors/RoundEditorScreen.cs | 2 + .../Screens/Ladder/LadderScreen.cs | 6 ++- .../Screens/TeamIntro/TeamIntroScreen.cs | 2 + osu.Game.Tournament/TournamentGameBase.cs | 48 +++++++++++-------- .../Formats/LegacyStoryboardDecoder.cs | 24 +++++----- osu.Game/Beatmaps/WorkingBeatmap.cs | 6 ++- osu.Game/Database/ArchiveModelManager.cs | 8 ++++ .../Graphics/Containers/ShakeContainer.cs | 2 + .../Graphics/UserInterface/OsuTabControl.cs | 2 + .../Graphics/UserInterface/ScoreCounter.cs | 2 + osu.Game/Input/KeyBindingStore.cs | 2 + osu.Game/Online/Leaderboards/Leaderboard.cs | 6 +++ osu.Game/OsuGame.cs | 2 + osu.Game/OsuGameBase.cs | 2 + osu.Game/Overlays/Changelog/ChangelogBuild.cs | 6 +++ .../Changelog/ChangelogSingleBuild.cs | 2 + .../Overlays/Comments/CommentsContainer.cs | 2 + osu.Game/Overlays/Direct/DirectPanel.cs | 2 + osu.Game/Overlays/Mods/ModButton.cs | 2 + osu.Game/Overlays/Mods/ModSection.cs | 2 + .../Difficulty/Utils/LimitedCapacityStack.cs | 2 + .../Objects/Drawables/DrawableHitObject.cs | 2 + .../Objects/Legacy/ConvertHitObjectParser.cs | 2 + osu.Game/Rulesets/Objects/SliderPath.cs | 2 + osu.Game/Rulesets/RulesetStore.cs | 2 + osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 + osu.Game/Rulesets/UI/Playfield.cs | 4 ++ .../Screens/Multi/Components/BeatmapTitle.cs | 2 + .../Screens/Play/HUD/HoldForMenuButton.cs | 2 + osu.Game/Screens/Play/SkipOverlay.cs | 3 ++ .../Select/Carousel/CarouselBeatmap.cs | 4 ++ osu.Game/Screens/Select/SongSelect.cs | 4 ++ osu.Game/Skinning/LegacySkin.cs | 2 + osu.Game/Skinning/LegacySkinExtensions.cs | 6 ++- osu.Game/Skinning/SkinnableSound.cs | 8 ++++ osu.Game/Storyboards/CommandTimelineGroup.cs | 2 + osu.Game/Storyboards/StoryboardSprite.cs | 3 ++ .../Tests/Beatmaps/BeatmapConversionTest.cs | 4 ++ osu.Game/Tests/Visual/OsuGridTestScene.cs | 6 ++- osu.Game/Users/UserCoverBackground.cs | 2 + 58 files changed, 214 insertions(+), 52 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs index 7b8c699f2c..da36673930 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs @@ -40,8 +40,10 @@ namespace osu.Game.Rulesets.Catch.Tests beatmap.HitObjects.Add(new Fruit { StartTime = 1008, X = 56 / 512f, }); for (int i = 0; i < 512; i++) + { if (i % 5 < 3) beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = 2000 + i * 100, NewCombo = i % 8 == 0 }); + } return beatmap; } diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 5ab47c1611..5d0c6116d7 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -196,9 +196,13 @@ namespace osu.Game.Rulesets.Catch.Beatmaps if (currentObject is Fruit) objectWithDroplets.Add(currentObject); if (currentObject is JuiceStream) + { foreach (var currentJuiceElement in currentObject.NestedHitObjects) + { if (!(currentJuiceElement is TinyDroplet)) objectWithDroplets.Add((CatchHitObject)currentJuiceElement); + } + } } objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs index 6d44e4660e..267e6d12c7 100644 --- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs @@ -27,11 +27,13 @@ namespace osu.Game.Rulesets.Catch.Objects return; for (double i = StartTime; i <= EndTime; i += spacing) + { AddNested(new Banana { Samples = Samples, StartTime = i }); + } } public double EndTime => StartTime + Duration; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index decd159ee9..ada960a78d 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -109,8 +109,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { // Generate a new pattern by copying the last hit objects in reverse-column order for (int i = RandomStart; i < TotalColumns; i++) + { if (PreviousPattern.ColumnHasObject(i)) addToPattern(pattern, RandomStart + TotalColumns - i - 1); + } return pattern; } @@ -132,8 +134,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { // Generate a new pattern by placing on the already filled columns for (int i = RandomStart; i < TotalColumns; i++) + { if (PreviousPattern.ColumnHasObject(i)) addToPattern(pattern, i); + } return pattern; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs index 433ec6bd25..ac627aa23e 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs @@ -24,12 +24,14 @@ namespace osu.Game.Rulesets.Osu.Tests public TestSceneDrawableJudgement() { foreach (HitResult result in Enum.GetValues(typeof(HitResult)).OfType().Skip(1)) + { AddStep("Show " + result.GetDescription(), () => SetContents(() => new DrawableOsuJudgement(new JudgementResult(new HitObject(), new Judgement()) { Type = result }, null) { Anchor = Anchor.Centre, Origin = Anchor.Centre, })); + } } } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs index 95c2810e94..b99cd523ff 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs @@ -29,8 +29,10 @@ namespace osu.Game.Rulesets.Osu.Tests }; for (int i = 0; i < 512; i++) + { if (i % 32 < 20) beatmap.HitObjects.Add(new HitCircle { Position = new Vector2(256, 192), StartTime = i * 100 }); + } return beatmap; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index 17fcd03dd5..1664a37a66 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -55,8 +55,10 @@ namespace osu.Game.Rulesets.Osu.Mods } for (int i = 0; i < amountWiggles; i++) + { using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * wiggle_duration, true)) wiggle(); + } // Keep wiggling sliders and spinners for their duration if (!(osuObject is IHasEndTime endTime)) @@ -65,8 +67,10 @@ namespace osu.Game.Rulesets.Osu.Mods amountWiggles = (int)(endTime.Duration / wiggle_duration); for (int i = 0; i < amountWiggles; i++) + { using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * wiggle_duration, true)) wiggle(); + } } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index f60b7e67b2..3e23d09741 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -133,12 +133,14 @@ namespace osu.Game.Rulesets.Osu.Objects var sampleList = new List(); if (firstSample != null) + { sampleList.Add(new HitSampleInfo { Bank = firstSample.Bank, Volume = firstSample.Volume, Name = @"slidertick", }); + } switch (e.Type) { diff --git a/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs index 18cbd4e7c5..7df7df22ea 100644 --- a/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs +++ b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs @@ -225,8 +225,10 @@ namespace osu.Game.Tests.NonVisual private void fastForwardToPoint(double destination) { for (int i = 0; i < 1000; i++) + { if (handler.SetFrameFromTime(destination) == null) return; + } throw new TimeoutException("Seek was never fulfilled"); } diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 0d96dd08da..ea9d51a9b8 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -26,6 +26,7 @@ namespace osu.Game.Tests.Skins List expectedColors; if (hasColours) + { expectedColors = new List { new Color4(142, 199, 255, 255), @@ -33,6 +34,7 @@ namespace osu.Game.Tests.Skins new Color4(128, 255, 255, 255), new Color4(100, 100, 100, 100), }; + } else expectedColors = new DefaultSkin().Configuration.ComboColours; diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index 01400bf1d9..28b5693ef4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -130,12 +130,14 @@ namespace osu.Game.Tests.Visual.Online AddRepeatStep("add many messages", () => { for (int i = 0; i < messages_per_call; i++) + { testChannel.AddNewMessages(new Message(sequence++) { Sender = longUsernameUser, Content = "Many messages! " + Guid.NewGuid(), Timestamp = DateTimeOffset.Now }); + } }, Channel.MAX_HISTORY / messages_per_call + 5); AddAssert("Ensure no adjacent day separators", () => @@ -143,8 +145,10 @@ namespace osu.Game.Tests.Visual.Online var indices = chatDisplay.FillFlow.OfType().Select(ds => chatDisplay.FillFlow.IndexOf(ds)); foreach (var i in indices) + { if (i < chatDisplay.FillFlow.Count && chatDisplay.FillFlow[i + 1] is DrawableChannel.DaySeparator) return false; + } return true; }); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 8b82567a8d..aa63bc1cf6 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -467,8 +467,10 @@ namespace osu.Game.Tests.Visual.SongSelect private void advanceSelection(bool diff, int direction = 1, int count = 1) { if (count == 1) + { AddStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => carousel.SelectNext(direction, !diff)); + } else { AddRepeatStep($"select {(direction > 0 ? "next" : "prev")} {(diff ? "diff" : "set")}", () => diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index efe7fee5e4..794d135b06 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -132,11 +132,13 @@ namespace osu.Game.Tests.Visual.SongSelect changeRuleset(1); if (rulesetsInSameBeatmap) + { AddStep("import multi-ruleset map", () => { var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); manager.Import(createTestBeatmapSet(0, usableRulesets)).Wait(); }); + } else { addRulesetImportStep(1); diff --git a/osu.Game.Tests/Visual/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/TestSceneOsuGame.cs index fcc3a3596f..36cd49d839 100644 --- a/osu.Game.Tests/Visual/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/TestSceneOsuGame.cs @@ -109,16 +109,20 @@ namespace osu.Game.Tests.Visual AddAssert("check OsuGame DI members", () => { foreach (var type in requiredGameDependencies) + { if (game.Dependencies.Get(type) == null) throw new Exception($"{type} has not been cached"); + } return true; }); AddAssert("check OsuGameBase DI members", () => { foreach (var type in requiredGameBaseDependencies) + { if (gameBase.Dependencies.Get(type) == null) throw new Exception($"{type} has not been cached"); + } return true; }); diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs index 41d32d9448..d77a0b75a5 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs @@ -103,20 +103,20 @@ namespace osu.Game.Tournament.Tests.Components })); AddStep("multiple messages", () => testChannel.AddNewMessages(new Message(nextMessageId()) - { - Sender = admin, - Content = "I spam you!" - }, - new Message(nextMessageId()) - { - Sender = admin, - Content = "I spam you!!!1" - }, - new Message(nextMessageId()) - { - Sender = admin, - Content = "I spam you!1!1" - })); + { + Sender = admin, + Content = "I spam you!" + }, + new Message(nextMessageId()) + { + Sender = admin, + Content = "I spam you!!!1" + }, + new Message(nextMessageId()) + { + Sender = admin, + Content = "I spam you!1!1" + })); AddStep("change channel to 2", () => chatDisplay.Channel.Value = testChannel2); diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs index f6c1be0e36..0908814537 100644 --- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs +++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs @@ -131,6 +131,7 @@ namespace osu.Game.Tournament.Components }); if (!string.IsNullOrEmpty(mods)) + { AddInternal(new Sprite { Texture = textures.Get($"mods/{mods}"), @@ -139,6 +140,7 @@ namespace osu.Game.Tournament.Components Margin = new MarginPadding(20), Scale = new Vector2(0.5f) }); + } } private void matchChanged(ValueChangedEvent match) diff --git a/osu.Game.Tournament/Components/TourneyVideo.cs b/osu.Game.Tournament/Components/TourneyVideo.cs index 8582b1634c..206689ca1a 100644 --- a/osu.Game.Tournament/Components/TourneyVideo.cs +++ b/osu.Game.Tournament/Components/TourneyVideo.cs @@ -29,12 +29,14 @@ namespace osu.Game.Tournament.Components }; } else + { InternalChild = video = new VideoSprite(stream) { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, Clock = new FramedClock(manualClock = new ManualClock()) }; + } } public bool Loop diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs index e05d96e098..47f2bed77a 100644 --- a/osu.Game.Tournament/IPC/FileBasedIPC.cs +++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs @@ -60,6 +60,7 @@ namespace osu.Game.Tournament.IPC const string file_ipc_channel_filename = "ipc-channel.txt"; if (Storage.Exists(file_ipc_filename)) + { scheduled = Scheduler.AddDelayed(delegate { try @@ -134,6 +135,7 @@ namespace osu.Game.Tournament.IPC // file might be in use. } }, 250, true); + } } catch (Exception e) { diff --git a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs index b036350879..2c515edda7 100644 --- a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs @@ -266,12 +266,14 @@ namespace osu.Game.Tournament.Screens.Editors drawableContainer.Clear(); if (Model.BeatmapInfo != null) + { drawableContainer.Child = new TournamentBeatmapPanel(Model.BeatmapInfo, Model.Mods) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Width = 300 }; + } } } } diff --git a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs index 83a41a662f..66e68a0f37 100644 --- a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs +++ b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs @@ -81,8 +81,10 @@ namespace osu.Game.Tournament.Screens.Ladder LadderInfo.Matches.ItemsRemoved += matches => { foreach (var p in matches) - foreach (var d in MatchesContainer.Where(d => d.Match == p)) - d.Expire(); + { + foreach (var d in MatchesContainer.Where(d => d.Match == p)) + d.Expire(); + } layout.Invalidate(); }; diff --git a/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs index c901a5c7ef..47c923ff30 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs @@ -164,6 +164,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro if (team != null) { foreach (var p in team.Players) + { players.Add(new OsuSpriteText { Text = p.Username, @@ -172,6 +173,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro Anchor = left ? Anchor.CentreRight : Anchor.CentreLeft, Origin = left ? Anchor.CentreRight : Anchor.CentreLeft, }); + } } } diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 3b7718c61d..d34ea9648d 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -164,15 +164,17 @@ namespace osu.Game.Tournament // link matches to rounds foreach (var round in ladder.Rounds) - foreach (var id in round.Matches) { - var found = ladder.Matches.FirstOrDefault(p => p.ID == id); - - if (found != null) + foreach (var id in round.Matches) { - found.Round.Value = round; - if (round.StartDate.Value > found.Date.Value) - found.Date.Value = round.StartDate.Value; + var found = ladder.Matches.FirstOrDefault(p => p.ID == id); + + if (found != null) + { + found.Round.Value = round; + if (round.StartDate.Value > found.Date.Value) + found.Date.Value = round.StartDate.Value; + } } } @@ -192,15 +194,19 @@ namespace osu.Game.Tournament bool addedInfo = false; foreach (var t in ladder.Teams) - foreach (var p in t.Players) - if (string.IsNullOrEmpty(p.Username)) + { + foreach (var p in t.Players) { - var req = new GetUserRequest(p.Id); - req.Perform(API); - p.Username = req.Result.Username; + if (string.IsNullOrEmpty(p.Username)) + { + var req = new GetUserRequest(p.Id); + req.Perform(API); + p.Username = req.Result.Username; - addedInfo = true; + addedInfo = true; + } } + } return addedInfo; } @@ -213,15 +219,19 @@ namespace osu.Game.Tournament bool addedInfo = false; foreach (var r in ladder.Rounds) - foreach (var b in r.Beatmaps) - if (b.BeatmapInfo == null && b.ID > 0) + { + foreach (var b in r.Beatmaps) { - var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID }); - req.Perform(API); - b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore); + if (b.BeatmapInfo == null && b.ID > 0) + { + var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID }); + req.Perform(API); + b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore); - addedInfo = true; + addedInfo = true; + } } + } return addedInfo; } diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 5dbd67d304..a86fa43f3c 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -144,16 +144,16 @@ namespace osu.Game.Beatmaps.Formats var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue; var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0; timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber); - } break; + } case "L": { var startTime = double.Parse(split[1], CultureInfo.InvariantCulture); var loopCount = int.Parse(split[2]); timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount); - } break; + } default: { @@ -172,7 +172,7 @@ namespace osu.Game.Beatmaps.Formats var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue); } - break; + break; case "S": { @@ -180,7 +180,7 @@ namespace osu.Game.Beatmaps.Formats var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue)); } - break; + break; case "V": { @@ -190,7 +190,7 @@ namespace osu.Game.Beatmaps.Formats var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY)); } - break; + break; case "R": { @@ -198,7 +198,7 @@ namespace osu.Game.Beatmaps.Formats var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue)); } - break; + break; case "M": { @@ -209,7 +209,7 @@ namespace osu.Game.Beatmaps.Formats timelineGroup?.X.Add(easing, startTime, endTime, startX, endX); timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY); } - break; + break; case "MX": { @@ -217,7 +217,7 @@ namespace osu.Game.Beatmaps.Formats var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue); } - break; + break; case "MY": { @@ -225,7 +225,7 @@ namespace osu.Game.Beatmaps.Formats var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue); } - break; + break; case "C": { @@ -239,7 +239,7 @@ namespace osu.Game.Beatmaps.Formats new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1), new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1)); } - break; + break; case "P": { @@ -260,13 +260,13 @@ namespace osu.Game.Beatmaps.Formats break; } } - break; + break; default: throw new InvalidDataException($@"Unknown command type: {commandType}"); } } - break; + break; } } } diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 3fc33e9f52..7c69a992dd 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -133,8 +133,10 @@ namespace osu.Game.Beatmaps obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty); foreach (var mod in mods.OfType()) - foreach (var obj in converted.HitObjects) - mod.ApplyToHitObject(obj); + { + foreach (var obj in converted.HitObjects) + mod.ApplyToHitObject(obj); + } processor?.PostProcess(); diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 9fed8e03ac..a262b76125 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -265,8 +265,10 @@ namespace osu.Game.Database // for now, concatenate all .osu files in the set to create a unique hash. MemoryStream hashable = new MemoryStream(); foreach (string file in reader.Filenames.Where(f => HashableFileTypes.Any(f.EndsWith))) + { using (Stream s = reader.GetStream(file)) s.CopyTo(hashable); + } return hashable.Length > 0 ? hashable.ComputeSHA2Hash() : null; } @@ -485,12 +487,16 @@ namespace osu.Game.Database // import files to manager foreach (string file in reader.Filenames) + { using (Stream s = reader.GetStream(file)) + { fileInfos.Add(new TFileModel { Filename = FileSafety.PathStandardise(file.Substring(prefix.Length)), FileInfo = files.Add(s) }); + } + } return fileInfos; } @@ -651,8 +657,10 @@ namespace osu.Game.Database private void handleEvent(Action a) { if (delayingEvents) + { lock (queuedEvents) queuedEvents.Add(a); + } else a.Invoke(); } diff --git a/osu.Game/Graphics/Containers/ShakeContainer.cs b/osu.Game/Graphics/Containers/ShakeContainer.cs index e5a6bcc28e..dca9df1e98 100644 --- a/osu.Game/Graphics/Containers/ShakeContainer.cs +++ b/osu.Game/Graphics/Containers/ShakeContainer.cs @@ -43,9 +43,11 @@ namespace osu.Game.Graphics.Containers // if we don't have enough time for the second shake, skip it. if (!maximumLength.HasValue || maximumLength >= ShakeDuration * 4) + { sequence = sequence .MoveToX(shake_amount, ShakeDuration, Easing.InOutSine).Then() .MoveToX(-shake_amount, ShakeDuration, Easing.InOutSine).Then(); + } sequence.MoveToX(0, ShakeDuration / 2, Easing.InSine); } diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index c55d14456b..5d1bdc62e9 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -51,8 +51,10 @@ namespace osu.Game.Graphics.UserInterface }); if (isEnumType && AddEnumEntriesAutomatically) + { foreach (var val in (T[])Enum.GetValues(typeof(T))) AddItem(val); + } } [BackgroundDependencyLoader] diff --git a/osu.Game/Graphics/UserInterface/ScoreCounter.cs b/osu.Game/Graphics/UserInterface/ScoreCounter.cs index 63062cdc9d..ee96b78844 100644 --- a/osu.Game/Graphics/UserInterface/ScoreCounter.cs +++ b/osu.Game/Graphics/UserInterface/ScoreCounter.cs @@ -44,8 +44,10 @@ namespace osu.Game.Graphics.UserInterface { string format = new string('0', (int)LeadingZeroes); if (UseCommaSeparator) + { for (int i = format.Length - 3; i > 0; i -= 3) format = format.Insert(i, @","); + } return ((long)count).ToString(format); } diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index caddb1ae0d..b1c794a856 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -47,6 +47,7 @@ namespace osu.Game.Input foreach (var insertable in group.Skip(count).Take(aimCount - count)) // insert any defaults which are missing. + { usage.Context.DatabasedKeyBinding.Add(new DatabasedKeyBinding { KeyCombination = insertable.KeyCombination, @@ -54,6 +55,7 @@ namespace osu.Game.Input RulesetID = rulesetId, Variant = variant }); + } } } } diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 83de0635fb..d214743b30 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -75,8 +75,10 @@ namespace osu.Game.Online.Leaderboards int i = 0; foreach (var s in scrollFlow.Children) + { using (s.BeginDelayedSequence(i++ * 50, true)) s.Show(); + } scrollContainer.ScrollTo(0f, false); }, (showScoresCancellationSource = new CancellationTokenSource()).Token)); @@ -342,13 +344,17 @@ namespace osu.Game.Online.Leaderboards else { if (bottomY - fadeBottom > 0 && FadeBottom) + { c.Colour = ColourInfo.GradientVertical( Color4.White.Opacity(Math.Min(1 - (topY - fadeBottom) / LeaderboardScore.HEIGHT, 1)), Color4.White.Opacity(Math.Min(1 - (bottomY - fadeBottom) / LeaderboardScore.HEIGHT, 1))); + } else if (FadeTop) + { c.Colour = ColourInfo.GradientVertical( Color4.White.Opacity(Math.Min(1 - (fadeTop - topY) / LeaderboardScore.HEIGHT, 1)), Color4.White.Opacity(Math.Min(1 - (fadeTop - bottomY) / LeaderboardScore.HEIGHT, 1))); + } } } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1f823e6eba..7735030bbb 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -402,8 +402,10 @@ namespace osu.Game nextBeatmap.Track.Completed += currentTrackCompleted; using (var oldBeatmap = beatmap.OldValue) + { if (oldBeatmap?.Track != null) oldBeatmap.Track.Completed -= currentTrackCompleted; + } nextBeatmap?.LoadBeatmapAsync(); } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 194a439b06..87321030a9 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -292,8 +292,10 @@ namespace osu.Game var extension = Path.GetExtension(paths.First())?.ToLowerInvariant(); foreach (var importer in fileImporters) + { if (importer.HandledExtensions.Contains(extension)) await importer.Import(paths); + } } public string[] HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions).ToArray(); diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs index d8488b21ab..5a3ce6291e 100644 --- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs @@ -130,6 +130,7 @@ namespace osu.Game.Overlays.Changelog }); if (entry.GithubUser.UserId != null) + { title.AddUserLink(new User { Username = entry.GithubUser.OsuUsername, @@ -139,18 +140,23 @@ namespace osu.Game.Overlays.Changelog t.Font = fontMedium; t.Colour = entryColour; }); + } else if (entry.GithubUser.GithubUrl != null) + { title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t => { t.Font = fontMedium; t.Colour = entryColour; }); + } else + { title.AddText(entry.GithubUser.DisplayName, t => { t.Font = fontSmall; t.Colour = entryColour; }); + } ChangelogEntries.Add(titleContainer); diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index adcd33fb48..3297b00322 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -68,11 +68,13 @@ namespace osu.Game.Overlays.Changelog } if (build != null) + { Children = new Drawable[] { new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, new Comments(build) }; + } } public class ChangelogBuildWithNavigation : ChangelogBuild diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index abc1b7233d..560123eb55 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -162,10 +162,12 @@ namespace osu.Game.Overlays.Comments foreach (var c in response.Comments) { if (c.IsTopLevel) + { page.Add(new DrawableComment(c) { ShowDeleted = { BindTarget = ShowDeleted } }); + } } LoadComponentAsync(page, loaded => diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 3ffc3f332b..c1c5113c5e 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -149,8 +149,10 @@ namespace osu.Game.Overlays.Direct icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is DirectListPanel ? Color4.White : colours.Gray5)); } else + { foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty)) icons.Add(new DifficultyIcon(b)); + } return icons; } diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 58892cd0dd..8252020e9b 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -194,8 +194,10 @@ namespace osu.Game.Overlays.Mods start = Mods.Length - 1; for (int i = start; i < Mods.Length && i >= 0; i += direction) + { if (SelectAt(i)) return; + } Deselect(); } diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index dedd397fa5..5c2ab8e18c 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -112,6 +112,7 @@ namespace osu.Game.Overlays.Mods if (selected == null) continue; foreach (var type in modTypes) + { if (type.IsInstanceOfType(selected)) { if (immediate) @@ -119,6 +120,7 @@ namespace osu.Game.Overlays.Mods else Scheduler.AddDelayed(button.Deselect, delay += 50); } + } } } diff --git a/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs b/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs index 95b7d9b19d..d47caf409b 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityStack.cs @@ -81,8 +81,10 @@ namespace osu.Game.Rulesets.Difficulty.Utils yield return array[i]; if (Count == capacity) + { for (int i = 0; i < marker; ++i) yield return array[i]; + } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 1d9b66f88d..af1a2fb63a 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -113,8 +113,10 @@ namespace osu.Game.Rulesets.Objects.Drawables if (samples.Length > 0) { if (HitObject.SampleControlPoint == null) + { throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); + } samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray(); foreach (var s in samples) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index e990938291..64f01952b1 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -75,8 +75,10 @@ namespace osu.Game.Rulesets.Objects.Legacy int pointCount = 1; foreach (var t in pointSplit) + { if (t.Length > 1) pointCount++; + } var points = new Vector2[pointCount]; diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index bc9571c85d..7763b0eaaf 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -185,8 +185,10 @@ namespace osu.Game.Rulesets.Objects ReadOnlySpan cpSpan = ControlPoints.Slice(start, end - start); foreach (Vector2 t in calculateSubpath(cpSpan)) + { if (calculatedPath.Count == 0 || calculatedPath.Last() != t) calculatedPath.Add(t); + } start = end; } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 23988ff0ff..7d13afe9e5 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -69,8 +69,10 @@ namespace osu.Game.Rulesets //add any other modes foreach (var r in instances.Where(r => r.LegacyID == null)) + { if (context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == r.RulesetInfo.InstantiationInfo) == null) context.RulesetInfo.Add(r.RulesetInfo); + } context.SaveChanges(); diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index e005eea831..d1749d33c0 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -436,8 +436,10 @@ namespace osu.Game.Rulesets.UI return h.HitWindows; foreach (var n in h.NestedHitObjects) + { if (h.HitWindows.WindowFor(HitResult.Miss) > 0) return n.HitWindows; + } } return null; diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index f2e7f51b52..ca4983e3d7 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -130,9 +130,13 @@ namespace osu.Game.Rulesets.UI base.Update(); if (beatmap != null) + { foreach (var mod in mods) + { if (mod is IUpdatableByPlayfield updatable) updatable.Update(this); + } + } } /// diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs index f79cac7649..b41b2d073e 100644 --- a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs @@ -57,11 +57,13 @@ namespace osu.Game.Screens.Multi.Components var beatmap = CurrentItem.Value?.Beatmap; if (beatmap == null) + { textFlow.AddText("No beatmap selected", s => { s.Font = s.Font.With(size: TextSize); s.Colour = colours.PinkLight; }); + } else { textFlow.AddLink(new[] diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index a05937801c..968b83e68c 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -100,9 +100,11 @@ namespace osu.Game.Screens.Play.HUD if (text.Alpha > 0 || button.Progress.Value > 0 || button.IsHovered) Alpha = 1; else + { Alpha = Interpolation.ValueAt( MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 200), Alpha, MathHelper.Clamp(1 - positionalAdjust, 0.04f, 1), 0, 200, Easing.OutQuint); + } } private class Button : HoldToConfirmContainer, IKeyBindingHandler diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 31cdff5fb9..835867fe62 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -181,8 +181,11 @@ namespace osu.Game.Screens.Play this.FadeIn(500, Easing.OutExpo); if (!IsHovered && !IsDragged) + { using (BeginDelayedSequence(1000)) scheduledHide = Schedule(Hide); + } + break; case Visibility.Hidden: diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 6c3c9d20f3..afd6211dec 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -44,10 +44,14 @@ namespace osu.Game.Screens.Select.Carousel criteria.Artist.Matches(Beatmap.Metadata.ArtistUnicode); if (match) + { foreach (var criteriaTerm in criteria.SearchTerms) + { match &= Beatmap.Metadata.SearchableTerms.Any(term => term.IndexOf(criteriaTerm, StringComparison.InvariantCultureIgnoreCase) >= 0) || Beatmap.Version.IndexOf(criteriaTerm, StringComparison.InvariantCultureIgnoreCase) >= 0; + } + } Filtered.Value = !match; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 409ea4bbbe..78ff150f08 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -251,11 +251,13 @@ namespace osu.Game.Screens.Select { // if we have no beatmaps but osu-stable is found, let's prompt the user to import. if (!beatmaps.GetAllUsableBeatmapSetsEnumerable().Any() && beatmaps.StableInstallationAvailable) + { dialogOverlay.Push(new ImportFromStablePopup(() => { Task.Run(beatmaps.ImportFromStableAsync).ContinueWith(_ => scores.ImportFromStableAsync(), TaskContinuationOptions.OnlyOnRanToCompletion); Task.Run(skins.ImportFromStableAsync); })); + } }); } } @@ -333,11 +335,13 @@ namespace osu.Game.Screens.Select if (this.IsCurrentScreen() && !Carousel.SelectBeatmap(e.NewValue?.BeatmapInfo, false)) // If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch + { if (e.NewValue?.BeatmapInfo?.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) { Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset; Carousel.SelectBeatmap(e.NewValue.BeatmapInfo); } + } } // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index fea15458e4..593b80c012 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -36,8 +36,10 @@ namespace osu.Game.Skinning { Stream stream = storage?.GetStream(filename); if (stream != null) + { using (LineBufferedReader reader = new LineBufferedReader(stream)) Configuration = new LegacySkinDecoder().Decode(reader); + } else Configuration = new DefaultSkinConfiguration(); diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index c5582af836..c758b699ed 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -22,17 +22,19 @@ namespace osu.Game.Skinning if (animatable) { - for (int i = 0;; i++) + for (int i = 0; true; i++) { if ((texture = getFrameTexture(i)) == null) break; if (animation == null) + { animation = new TextureAnimation { DefaultFrameLength = default_frame_time, Repeat = looping }; + } animation.AddFrame(texture); } @@ -42,10 +44,12 @@ namespace osu.Game.Skinning return animation; if ((texture = source.GetTexture(componentName)) != null) + { return new Sprite { Texture = texture }; + } return null; } diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index bdf8be773b..6d23f22515 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -81,9 +81,13 @@ namespace osu.Game.Skinning var ch = skin.GetSample(s); if (ch == null && allowFallback) + { foreach (var lookup in s.LookupNames) + { if ((ch = samples.Get($"Gameplay/{lookup}")) != null) break; + } + } if (ch != null) { @@ -91,8 +95,10 @@ namespace osu.Game.Skinning ch.Volume.Value = s.Volume / 100.0; if (adjustments != null) + { foreach (var adjustment in adjustments) ch.AddAdjustment(adjustment.property, adjustment.bindable); + } } return ch; @@ -104,8 +110,10 @@ namespace osu.Game.Skinning base.Dispose(isDisposing); if (channels != null) + { foreach (var c in channels) c.Dispose(); + } } } } diff --git a/osu.Game/Storyboards/CommandTimelineGroup.cs b/osu.Game/Storyboards/CommandTimelineGroup.cs index 461ee762e9..364c971874 100644 --- a/osu.Game/Storyboards/CommandTimelineGroup.cs +++ b/osu.Game/Storyboards/CommandTimelineGroup.cs @@ -65,6 +65,7 @@ namespace osu.Game.Storyboards public virtual IEnumerable.TypedCommand> GetCommands(CommandTimelineSelector timelineSelector, double offset = 0) { if (offset != 0) + { return timelineSelector(this).Commands.Select(command => new CommandTimeline.TypedCommand { @@ -74,6 +75,7 @@ namespace osu.Game.Storyboards StartValue = command.StartValue, EndValue = command.EndValue, }); + } return timelineSelector(this).Commands; } diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index 37c3ff495f..96c7ceea8d 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -106,8 +106,11 @@ namespace osu.Game.Storyboards foreach (var loop in loops) commands = commands.Concat(loop.GetCommands(timelineSelector)); if (triggeredGroups != null) + { foreach (var pair in triggeredGroups) commands = commands.Concat(pair.Item1.GetCommands(timelineSelector, pair.Item2)); + } + return commands; } diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index e99b5fc5fb..b144de35c5 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -72,11 +72,15 @@ namespace osu.Game.Tests.Beatmaps break; if (objectCounter >= ourMapping.Objects.Count) + { Assert.Fail($"The conversion did not generate a hitobject, but should have, for hitobject at time: {expectedMapping.StartTime}:\n" + $"Expected: {JsonConvert.SerializeObject(expectedMapping.Objects[objectCounter])}\n"); + } else if (objectCounter >= expectedMapping.Objects.Count) + { Assert.Fail($"The conversion generated a hitobject, but should not have, for hitobject at time: {ourMapping.StartTime}:\n" + $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n"); + } else if (!expectedMapping.Objects[objectCounter].Equals(ourMapping.Objects[objectCounter])) { Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}:\n" diff --git a/osu.Game/Tests/Visual/OsuGridTestScene.cs b/osu.Game/Tests/Visual/OsuGridTestScene.cs index c09f4d6218..33ede9453e 100644 --- a/osu.Game/Tests/Visual/OsuGridTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGridTestScene.cs @@ -38,8 +38,10 @@ namespace osu.Game.Tests.Visual cells = new Drawable[rows, cols]; for (int r = 0; r < rows; r++) - for (int c = 0; c < cols; c++) - cells[r, c] = new Container { RelativeSizeAxes = Axes.Both }; + { + for (int c = 0; c < cols; c++) + cells[r, c] = new Container { RelativeSizeAxes = Axes.Both }; + } testContainer.Content = cells.ToJagged(); } diff --git a/osu.Game/Users/UserCoverBackground.cs b/osu.Game/Users/UserCoverBackground.cs index e583acac9f..a45fd85901 100644 --- a/osu.Game/Users/UserCoverBackground.cs +++ b/osu.Game/Users/UserCoverBackground.cs @@ -46,6 +46,7 @@ namespace osu.Game.Users }; } else + { InternalChild = new Sprite { RelativeSizeAxes = Axes.Both, @@ -54,6 +55,7 @@ namespace osu.Game.Users Anchor = Anchor.Centre, Origin = Anchor.Centre }; + } } protected override void LoadComplete() From d8482448dc91ecf93e63789075fc287e0b2c7258 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 11 Nov 2019 19:53:41 +0800 Subject: [PATCH 47/73] Save iOS projects with BOM to avoid VS continuously changing them. --- .../osu.Game.Rulesets.Catch.Tests.iOS.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.iOS.csproj | 2 +- .../osu.Game.Rulesets.Osu.Tests.iOS.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.iOS.csproj | 2 +- osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj | 2 +- osu.iOS/osu.iOS.csproj | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj index 708779986c..be6044bbd0 100644 --- a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj @@ -1,4 +1,4 @@ - + Debug diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj index 52e558931b..88ad484bc1 100644 --- a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj @@ -1,4 +1,4 @@ - + Debug diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj index cacd035078..545abcec6c 100644 --- a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj @@ -1,4 +1,4 @@ - + Debug diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj index c20bd4fe02..8ee640cd99 100644 --- a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj @@ -1,4 +1,4 @@ - + Debug diff --git a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj index 583d188295..ca68369ebb 100644 --- a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj +++ b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj @@ -1,4 +1,4 @@ - + Debug diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj index 378ac231c2..d60a3475e7 100644 --- a/osu.iOS/osu.iOS.csproj +++ b/osu.iOS/osu.iOS.csproj @@ -1,4 +1,4 @@ - + Debug From e9b8cbb5165a65db0c779cc8ef4b97a580d8d3cc Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 11 Nov 2019 20:05:36 +0800 Subject: [PATCH 48/73] Apply other styles. --- .../Beatmaps/CatchBeatmapProcessor.cs | 1 + osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 1 + .../TestSceneTournamentMatchChatDisplay.cs | 31 ++++++++++--------- .../Formats/LegacyStoryboardDecoder.cs | 22 +++++++------ osu.Game/Database/ArchiveModelManager.cs | 1 + .../Graphics/UserInterface/ScoreCounter.cs | 1 + osu.Game/Input/KeyBindingStore.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 2 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 1 + osu.Game/Screens/Select/SongSelect.cs | 2 +- osu.Game/Skinning/LegacySkin.cs | 1 + osu.Game/Storyboards/StoryboardSprite.cs | 1 + osu.Game/Tests/Visual/OsuGridTestScene.cs | 1 + osu.iOS/AppDelegate.cs | 1 - 14 files changed, 39 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 5d0c6116d7..58bf811fac 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -195,6 +195,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps { if (currentObject is Fruit) objectWithDroplets.Add(currentObject); + if (currentObject is JuiceStream) { foreach (var currentJuiceElement in currentObject.NestedHitObjects) diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index ea9d51a9b8..085f502517 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -25,6 +25,7 @@ namespace osu.Game.Tests.Skins var comboColors = decoder.Decode(stream).ComboColours; List expectedColors; + if (hasColours) { expectedColors = new List diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs index d77a0b75a5..9905e17824 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs @@ -102,21 +102,22 @@ namespace osu.Game.Tournament.Tests.Components Content = "Okay okay, calm down guys. Let's do this!" })); - AddStep("multiple messages", () => testChannel.AddNewMessages(new Message(nextMessageId()) - { - Sender = admin, - Content = "I spam you!" - }, - new Message(nextMessageId()) - { - Sender = admin, - Content = "I spam you!!!1" - }, - new Message(nextMessageId()) - { - Sender = admin, - Content = "I spam you!1!1" - })); + AddStep("multiple messages", () => testChannel.AddNewMessages( + new Message(nextMessageId()) + { + Sender = admin, + Content = "I spam you!" + }, + new Message(nextMessageId()) + { + Sender = admin, + Content = "I spam you!!!1" + }, + new Message(nextMessageId()) + { + Sender = admin, + Content = "I spam you!1!1" + })); AddStep("change channel to 2", () => chatDisplay.Channel.Value = testChannel2); diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index a86fa43f3c..e3320f62ac 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -171,16 +171,16 @@ namespace osu.Game.Beatmaps.Formats var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue); + break; } - break; case "S": { var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue)); + break; } - break; case "V": { @@ -189,16 +189,16 @@ namespace osu.Game.Beatmaps.Formats var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY)); + break; } - break; case "R": { var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue)); + break; } - break; case "M": { @@ -208,24 +208,24 @@ namespace osu.Game.Beatmaps.Formats var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; timelineGroup?.X.Add(easing, startTime, endTime, startX, endX); timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY); + break; } - break; case "MX": { var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue); + break; } - break; case "MY": { var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue); + break; } - break; case "C": { @@ -238,8 +238,8 @@ namespace osu.Game.Beatmaps.Formats timelineGroup?.Colour.Add(easing, startTime, endTime, new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1), new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1)); + break; } - break; case "P": { @@ -259,14 +259,16 @@ namespace osu.Game.Beatmaps.Formats timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime); break; } + + break; } - break; default: throw new InvalidDataException($@"Unknown command type: {commandType}"); } + + break; } - break; } } } diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index a262b76125..8fa4eaf267 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -264,6 +264,7 @@ namespace osu.Game.Database { // for now, concatenate all .osu files in the set to create a unique hash. MemoryStream hashable = new MemoryStream(); + foreach (string file in reader.Filenames.Where(f => HashableFileTypes.Any(f.EndsWith))) { using (Stream s = reader.GetStream(file)) diff --git a/osu.Game/Graphics/UserInterface/ScoreCounter.cs b/osu.Game/Graphics/UserInterface/ScoreCounter.cs index ee96b78844..e291401670 100644 --- a/osu.Game/Graphics/UserInterface/ScoreCounter.cs +++ b/osu.Game/Graphics/UserInterface/ScoreCounter.cs @@ -43,6 +43,7 @@ namespace osu.Game.Graphics.UserInterface protected override string FormatCount(double count) { string format = new string('0', (int)LeadingZeroes); + if (UseCommaSeparator) { for (int i = format.Length - 3; i > 0; i -= 3) diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index b1c794a856..74b3134964 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -46,8 +46,8 @@ namespace osu.Game.Input continue; foreach (var insertable in group.Skip(count).Take(aimCount - count)) - // insert any defaults which are missing. { + // insert any defaults which are missing. usage.Context.DatabasedKeyBinding.Add(new DatabasedKeyBinding { KeyCombination = insertable.KeyCombination, diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 4f6066cab1..1d8c5609d9 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -220,7 +220,7 @@ namespace osu.Game.Online.Chat break; } - var channel = availableChannels.Where(c => c.Name == content || c.Name == $"#{content}").FirstOrDefault(); + var channel = availableChannels.FirstOrDefault(c => c.Name == content || c.Name == $"#{content}"); if (channel == null) { diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 64f01952b1..4049e40013 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -74,6 +74,7 @@ namespace osu.Game.Rulesets.Objects.Legacy string[] pointSplit = split[5].Split('|'); int pointCount = 1; + foreach (var t in pointSplit) { if (t.Length > 1) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 78ff150f08..375b994169 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -334,8 +334,8 @@ namespace osu.Game.Screens.Select if (e.NewValue is DummyWorkingBeatmap) return; if (this.IsCurrentScreen() && !Carousel.SelectBeatmap(e.NewValue?.BeatmapInfo, false)) - // If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch { + // If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch if (e.NewValue?.BeatmapInfo?.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) { Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset; diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 593b80c012..67a83f19e2 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -35,6 +35,7 @@ namespace osu.Game.Skinning : base(skin) { Stream stream = storage?.GetStream(filename); + if (stream != null) { using (LineBufferedReader reader = new LineBufferedReader(stream)) diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index 96c7ceea8d..d5e69fd103 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -105,6 +105,7 @@ namespace osu.Game.Storyboards var commands = TimelineGroup.GetCommands(timelineSelector); foreach (var loop in loops) commands = commands.Concat(loop.GetCommands(timelineSelector)); + if (triggeredGroups != null) { foreach (var pair in triggeredGroups) diff --git a/osu.Game/Tests/Visual/OsuGridTestScene.cs b/osu.Game/Tests/Visual/OsuGridTestScene.cs index 33ede9453e..48f85be6ba 100644 --- a/osu.Game/Tests/Visual/OsuGridTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGridTestScene.cs @@ -37,6 +37,7 @@ namespace osu.Game.Tests.Visual Add(testContainer = new GridContainer { RelativeSizeAxes = Axes.Both }); cells = new Drawable[rows, cols]; + for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) diff --git a/osu.iOS/AppDelegate.cs b/osu.iOS/AppDelegate.cs index 164a182ebe..14e3627752 100644 --- a/osu.iOS/AppDelegate.cs +++ b/osu.iOS/AppDelegate.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Foundation; using osu.Framework.iOS; -using osu.Framework.Threading; using UIKit; namespace osu.iOS From d3858622676274c0c30d731099311a9bca1401d2 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 11 Nov 2019 20:32:32 +0800 Subject: [PATCH 49/73] Add dotnet format check. --- .config/dotnet-tools.json | 6 ++++++ build/build.cake | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 1b70c949eb..6ba6ae82c8 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -7,6 +7,12 @@ "commands": [ "dotnet-cake" ] + }, + "dotnet-format": { + "version": "3.1.37601", + "commands": [ + "dotnet-format" + ] } } } \ No newline at end of file diff --git a/build/build.cake b/build/build.cake index 389ff4829d..274e57ef4e 100644 --- a/build/build.cake +++ b/build/build.cake @@ -11,6 +11,7 @@ var target = Argument("target", "Build"); var configuration = Argument("configuration", "Release"); var rootDirectory = new DirectoryPath(".."); +var sln = rootDirectory.CombineWithFilePath("osu.sln"); var desktopBuilds = rootDirectory.CombineWithFilePath("build/Desktop.proj"); var desktopSlnf = rootDirectory.CombineWithFilePath("osu.Desktop.slnf"); @@ -60,8 +61,12 @@ Task("CodeFileSanity") }); }); +Task("DotnetFormat") + .Does(() => DotNetCoreTool(sln.FullPath, "format", "--dry-run --check")); + Task("Build") .IsDependentOn("CodeFileSanity") + .IsDependentOn("DotnetFormat") .IsDependentOn("InspectCode") .IsDependentOn("Test"); From 1ef645a7105977268c17c5fe438341be1f59ab5a Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 11 Nov 2019 21:02:48 +0800 Subject: [PATCH 50/73] Turn off some more not applied styles. --- .editorconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.editorconfig b/.editorconfig index 8f9d0ca9b0..2c000d3881 100644 --- a/.editorconfig +++ b/.editorconfig @@ -140,7 +140,7 @@ dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning dotnet_style_prefer_auto_properties = true:silent dotnet_style_prefer_conditional_expression_over_assignment = true:silent dotnet_style_prefer_conditional_expression_over_return = true:silent -dotnet_style_prefer_compound_assignment = true:warning +dotnet_style_prefer_compound_assignment = true:silent #Style - null/type checks dotnet_style_coalesce_expression = true:warning @@ -153,17 +153,17 @@ csharp_style_conditional_delegate_call = true:suggestion #Style - unused dotnet_code_quality_unused_parameters = non_public:silent csharp_style_unused_value_expression_statement_preference = discard_variable:silent -csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:silent #Style - variable declaration -csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:silent csharp_style_deconstructed_variable_declaration = true:silent #Style - other C# 7.x features csharp_style_expression_bodied_local_functions = true:silent dotnet_style_prefer_inferred_tuple_names = true:warning csharp_prefer_simple_default_expression = true:warning -csharp_style_pattern_local_over_anonymous_function = true:warning +csharp_style_pattern_local_over_anonymous_function = true:silent dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent #Supressing roslyn built-in analyzers From e690a8a301d6c9e451b6723d215be23d9fdc4d14 Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Mon, 11 Nov 2019 22:15:19 +0700 Subject: [PATCH 51/73] Fix capitalisation in README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 67eb3254e1..bc5beeb83d 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ Detailed changelogs are published on the [official osu! site](https://osu.ppy.sh ## Requirements - A desktop platform with the [.NET Core SDK 3.0](https://www.microsoft.com/net/learn/get-started) or higher installed. -- When running on linux, please have a system-wide ffmpeg installation available to support video decoding. +- When running on Linux, please have a system-wide ffmpeg installation available to support video decoding. - When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore2x)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs. -- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [Jetbrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/). +- When working with the codebase, we recommend using an IDE with IntelliSense and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [Jetbrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/). ## Running osu! From 851b414e9874fc5c6bb1e024b8eda2db3ddf94db Mon Sep 17 00:00:00 2001 From: recapitalverb <41869184+recapitalverb@users.noreply.github.com> Date: Mon, 11 Nov 2019 22:37:15 +0700 Subject: [PATCH 52/73] Update README.md Co-Authored-By: Joseph Madamba --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc5beeb83d..0ee1bedae4 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Detailed changelogs are published on the [official osu! site](https://osu.ppy.sh - A desktop platform with the [.NET Core SDK 3.0](https://www.microsoft.com/net/learn/get-started) or higher installed. - When running on Linux, please have a system-wide ffmpeg installation available to support video decoding. - When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore2x)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs. -- When working with the codebase, we recommend using an IDE with IntelliSense and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [Jetbrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/). +- When working with the codebase, we recommend using an IDE with IntelliSense and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/). ## Running osu! From 810cfab870dc042ec48e21361cc11dec7097cd1e Mon Sep 17 00:00:00 2001 From: recapitalverb Date: Mon, 11 Nov 2019 22:53:16 +0700 Subject: [PATCH 53/73] Fix capitalisation and grammar in README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0ee1bedae4..b8c6451c75 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ Detailed changelogs are published on the [official osu! site](https://osu.ppy.sh ## Requirements - A desktop platform with the [.NET Core SDK 3.0](https://www.microsoft.com/net/learn/get-started) or higher installed. -- When running on Linux, please have a system-wide ffmpeg installation available to support video decoding. +- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding. - When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore2x)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs. -- When working with the codebase, we recommend using an IDE with IntelliSense and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/). +- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/). ## Running osu! @@ -68,7 +68,7 @@ dotnet run --project osu.Desktop If you are not interested in debugging osu!, you can add `-c Release` to gain performance. In this case, you must replace `Debug` with `Release` in any commands mentioned in this document. -If the build fails, try to restore nuget packages with `dotnet restore`. +If the build fails, try to restore NuGet packages with `dotnet restore`. ### Testing with resource/framework modifications @@ -76,11 +76,11 @@ Sometimes it may be necessary to cross-test changes in [osu-resources](https://g ### Code analysis -Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternatively, you can install resharper or use rider to get inline support in your IDE of choice. +Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is currently only supported under Windows due to [ReSharper CLI shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternatively, you can install ReSharper or use Rider to get inline support in your IDE of choice. ## Contributing -We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted. +We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention of having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted. If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) label). From 9efcc6addde56b5080ea2ab6b34c8c7aa6b1e647 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 11 Nov 2019 08:53:05 -0800 Subject: [PATCH 54/73] Fix remaining proper nouns --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b8c6451c75..a078265d6c 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Before starting, please make sure you are familiar with the [development and tes Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. We welcome all feedback so we can make contributing to this project as pain-free as possible. -For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via paypal or osu! supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project. +For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via PayPal or osu!supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project. ## Licence From 8402fb1490c32a920a2b3ae9a0df122a563560de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 10:02:42 +0900 Subject: [PATCH 55/73] Move to const and add some xmldoc for future visitors --- osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs index e262fa3c60..3437af8c1e 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs @@ -16,6 +16,12 @@ namespace osu.Game.Rulesets.Osu.Edit { public class DrawableOsuEditRuleset : DrawableOsuRuleset { + /// + /// Hit objects are intentionally made to fade out at a constant slower rate than in gameplay. + /// This allows a mapper to gain better historical context and use recent hitobjects as reference / snap points. + /// + private const double editor_hit_object_fade_out_extension = 500; + public DrawableOsuEditRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) { @@ -35,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Edit return; using (hitObject.BeginAbsoluteSequence(existing.StartTime)) - hitObject.FadeOut(500).Expire(); + hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire(); break; } } From 5bb65d0716ad1f0520b152e3ab14701b1f998fd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 10:18:25 +0900 Subject: [PATCH 56/73] Rename button class --- .../TestSceneStatefulMenuItem.cs | 8 +++--- .../Graphics/UserInterface/TernaryState.cs | 2 +- ...ateMenuItem.cs => TernaryStateMenuItem.cs} | 26 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) rename osu.Game/Graphics/UserInterface/{ThreeStateMenuItem.cs => TernaryStateMenuItem.cs} (69%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs index 1eff30d15e..2ada5b927b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.UserInterface { typeof(OsuMenu), typeof(StatefulMenuItem), - typeof(ThreeStateMenuItem), + typeof(TernaryStateMenuItem), typeof(DrawableStatefulMenuItem), }; @@ -39,9 +39,9 @@ namespace osu.Game.Tests.Visual.UserInterface Origin = Anchor.Centre, Items = new[] { - new ThreeStateMenuItem("First"), - new ThreeStateMenuItem("Second") { State = { BindTarget = state } }, - new ThreeStateMenuItem("Third") { State = { Value = TernaryState.True } }, + new TernaryStateMenuItem("First"), + new TernaryStateMenuItem("Second") { State = { BindTarget = state } }, + new TernaryStateMenuItem("Third") { State = { Value = TernaryState.True } }, } }; }); diff --git a/osu.Game/Graphics/UserInterface/TernaryState.cs b/osu.Game/Graphics/UserInterface/TernaryState.cs index 784122e35c..d4de28044f 100644 --- a/osu.Game/Graphics/UserInterface/TernaryState.cs +++ b/osu.Game/Graphics/UserInterface/TernaryState.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface /// /// The current state is a combination of and . - /// The state becomes if the is pressed. + /// The state becomes if the is pressed. /// Indeterminate, diff --git a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs b/osu.Game/Graphics/UserInterface/TernaryStateMenuItem.cs similarity index 69% rename from osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs rename to osu.Game/Graphics/UserInterface/TernaryStateMenuItem.cs index c5b9edf3c4..2d9e2106d4 100644 --- a/osu.Game/Graphics/UserInterface/ThreeStateMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/TernaryStateMenuItem.cs @@ -9,37 +9,37 @@ namespace osu.Game.Graphics.UserInterface /// /// An with three possible states. /// - public class ThreeStateMenuItem : StatefulMenuItem + public class TernaryStateMenuItem : StatefulMenuItem { /// - /// Creates a new . + /// Creates a new . /// /// The text to display. - /// The type of action which this performs. - public ThreeStateMenuItem(string text, MenuItemType type = MenuItemType.Standard) + /// The type of action which this performs. + public TernaryStateMenuItem(string text, MenuItemType type = MenuItemType.Standard) : this(text, type, null) { } /// - /// Creates a new . + /// Creates a new . /// /// The text to display. - /// The type of action which this performs. - /// A delegate to be invoked when this is pressed. - public ThreeStateMenuItem(string text, MenuItemType type, Action action) + /// The type of action which this performs. + /// A delegate to be invoked when this is pressed. + public TernaryStateMenuItem(string text, MenuItemType type, Action action) : this(text, getNextState, type, action) { } /// - /// Creates a new . + /// Creates a new . /// /// The text to display. - /// A function that mutates a state to another state after this is pressed. - /// The type of action which this performs. - /// A delegate to be invoked when this is pressed. - protected ThreeStateMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) + /// A function that mutates a state to another state after this is pressed. + /// The type of action which this performs. + /// A delegate to be invoked when this is pressed. + protected TernaryStateMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) : base(text, changeStateFunc, type, action) { } From a43b0ee01bc9b92db30ff4084c11c09b3547dd26 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 10:45:46 +0900 Subject: [PATCH 57/73] Apply naming and styling changes --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 ++ .../Edit/Compose/Components/SelectionHandler.cs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index f3399af2de..c6f5a075e0 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -203,12 +203,14 @@ namespace osu.Game.Rulesets.Osu.Objects var sampleList = new List(); if (firstSample != null) + { sampleList.Add(new HitSampleInfo { Bank = firstSample.Bank, Volume = firstSample.Volume, Name = @"slidertick", }); + } foreach (var tick in NestedHitObjects.OfType()) tick.Samples = sampleList; diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 7b61640c89..942643d116 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -241,36 +241,36 @@ namespace osu.Game.Screens.Edit.Compose.Components private MenuItem createHitSampleMenuItem(string name, string sampleName) { - return new ThreeStateMenuItem(name, MenuItemType.Standard, setHitSampleState) + return new TernaryStateMenuItem(name, MenuItemType.Standard, setHitSampleState) { State = { Value = getHitSampleState() } }; - void setHitSampleState(ThreeStates state) + void setHitSampleState(TernaryState state) { switch (state) { - case ThreeStates.Disabled: + case TernaryState.False: RemoveHitSample(sampleName); break; - case ThreeStates.Enabled: + case TernaryState.True: AddHitSample(sampleName); break; } } - ThreeStates getHitSampleState() + TernaryState getHitSampleState() { int countExisting = SelectedHitObjects.Count(h => h.Samples.Any(s => s.Name == sampleName)); if (countExisting == 0) - return ThreeStates.Disabled; + return TernaryState.False; if (countExisting < SelectedHitObjects.Count()) - return ThreeStates.Indeterminate; + return TernaryState.Indeterminate; - return ThreeStates.Enabled; + return TernaryState.True; } } From 2f8768a4b10af5290f94c80cba54184b2957b5d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 11:04:49 +0900 Subject: [PATCH 58/73] Move LabelledDropdown local to usage --- osu.Game.Tournament/Screens/SetupScreen.cs | 21 ++++++++++++++ .../UserInterfaceV2/LabelledDropdown.cs | 29 ------------------- 2 files changed, 21 insertions(+), 29 deletions(-) delete mode 100644 osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index b511d572da..8e1481d87c 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -100,6 +101,26 @@ namespace osu.Game.Tournament.Screens }; } + public class LabelledDropdown : LabelledComponent, T> + { + public LabelledDropdown() + : base(true) + { + } + + public IEnumerable Items + { + get => Component.Items; + set => Component.Items = value; + } + + protected override OsuDropdown CreateComponent() => new OsuDropdown + { + RelativeSizeAxes = Axes.X, + Width = 0.5f, + }; + } + private class ActionableInfo : LabelledDrawable { private OsuButton button; diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs deleted file mode 100644 index 7e50fa7bc6..0000000000 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs +++ /dev/null @@ -1,29 +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 osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Graphics.UserInterfaceV2 -{ - public class LabelledDropdown : LabelledComponent, T> - { - public LabelledDropdown() - : base(true) - { - } - - public IEnumerable Items - { - get => Component.Items; - set => Component.Items = value; - } - - protected override OsuDropdown CreateComponent() => new OsuDropdown - { - RelativeSizeAxes = Axes.X, - Width = 0.5f, - }; - } -} From 9f1d490ac9876457e7299ed758da3858f893b105 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Nov 2019 12:18:24 +0900 Subject: [PATCH 59/73] Only handle selection input on blueprints --- osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 942643d116..258304d775 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -90,6 +90,8 @@ namespace osu.Game.Screens.Edit.Compose.Components public bool OnReleased(PlatformAction action) => action.ActionMethod == PlatformActionMethod.Delete; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => selectedBlueprints.Any(b => b.IsHovered); + #endregion #region Selection Handling From 3f8928ca253660e6ae7a686e5c6f0d3faad60075 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Nov 2019 13:41:54 +0900 Subject: [PATCH 60/73] Suppress warnings --- osu.Game/Rulesets/Configuration/IRulesetConfigManager.cs | 3 ++- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 ++ osu.Game/Rulesets/RulesetConfigCache.cs | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Configuration/IRulesetConfigManager.cs b/osu.Game/Rulesets/Configuration/IRulesetConfigManager.cs index 179cd5e2dc..5a3ad5e786 100644 --- a/osu.Game/Rulesets/Configuration/IRulesetConfigManager.cs +++ b/osu.Game/Rulesets/Configuration/IRulesetConfigManager.cs @@ -1,11 +1,12 @@ // 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 osu.Framework.Configuration.Tracking; namespace osu.Game.Rulesets.Configuration { - public interface IRulesetConfigManager : ITrackableConfigManager + public interface IRulesetConfigManager : ITrackableConfigManager, IDisposable { } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 818571bb23..35228e9ad1 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -149,8 +149,10 @@ namespace osu.Game.Rulesets.Objects.Drawables return; if (HitObject.SampleControlPoint == null) + { throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); + } samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray(); foreach (var s in samples) diff --git a/osu.Game/Rulesets/RulesetConfigCache.cs b/osu.Game/Rulesets/RulesetConfigCache.cs index cdcd2666cf..d42428638c 100644 --- a/osu.Game/Rulesets/RulesetConfigCache.cs +++ b/osu.Game/Rulesets/RulesetConfigCache.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets // ensures any potential database operations are finalised before game destruction. foreach (var c in configCache.Values) - (c as IDisposable)?.Dispose(); + c?.Dispose(); } } } From b4525c1f6e95d61a56ca33b5a09cbeba38d60ab5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 14:42:30 +0900 Subject: [PATCH 61/73] Fix right clicking to select not showing context menu --- osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 258304d775..3a7c85d36c 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -90,8 +90,6 @@ namespace osu.Game.Screens.Edit.Compose.Components public bool OnReleased(PlatformAction action) => action.ActionMethod == PlatformActionMethod.Delete; - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => selectedBlueprints.Any(b => b.IsHovered); - #endregion #region Selection Handling @@ -223,7 +221,7 @@ namespace osu.Game.Screens.Edit.Compose.Components { get { - if (!SelectedBlueprints.Any()) + if (!selectedBlueprints.Any(b => b.IsHovered)) return Array.Empty(); return new MenuItem[] From 461f76926f6e23015eaec30ae5344f3ea9085861 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Nov 2019 13:32:31 +0900 Subject: [PATCH 62/73] Add right-click menu to support control point addition --- .../Sliders/SliderSelectionBlueprint.cs | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 25362820a3..a77350714f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -1,8 +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 System; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -10,10 +15,11 @@ using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osuTK; +using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderSelectionBlueprint : OsuSelectionBlueprint + public class SliderSelectionBlueprint : OsuSelectionBlueprint, IHasContextMenu { protected readonly SliderBodyPiece BodyPiece; protected readonly SliderCircleSelectionBlueprint HeadBlueprint; @@ -44,6 +50,48 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders BodyPiece.UpdateFrom(HitObject); } + private Vector2 rightClickPosition; + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (e.Button == MouseButton.Right) + rightClickPosition = e.MouseDownPosition; + + return false; + } + + private void addControlPoint() + { + Vector2 position = rightClickPosition - HitObject.Position; + + var controlPoints = new Vector2[HitObject.Path.ControlPoints.Length + 1]; + HitObject.Path.ControlPoints.CopyTo(controlPoints); + + // Find the index at which the point will be inserted, by increasing x-coordinates + int insertionIndex = Array.FindIndex(controlPoints, 0, controlPoints.Length - 1, c => c.X >= position.X); + + // If no index was found, it should be inserted at the end + if (insertionIndex == -1) + insertionIndex = controlPoints.Length - 1; + + // Move the control points from the insertion index onwards to make room for the insertion + Array.Copy(controlPoints, insertionIndex, controlPoints, insertionIndex + 1, controlPoints.Length - insertionIndex - 1); + + if (insertionIndex == 0) + { + // Special case for a new first control point being added - the entire slider moves + HitObject.Position += position; + + // The first control point is always at (0, 0), but all other control points need to be re-referenced + for (int i = 1; i < controlPoints.Length; i++) + controlPoints[i] -= position; + } + else + controlPoints[insertionIndex] = position; + + onNewControlPoints(controlPoints); + } + private void onNewControlPoints(Vector2[] controlPoints) { var unsnappedPath = new SliderPath(controlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, controlPoints); @@ -54,6 +102,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders UpdateHitObject(); } + public MenuItem[] ContextMenuItems => new MenuItem[] + { + new OsuMenuItem("Add control point", MenuItemType.Standard, addControlPoint), + }; + public override Vector2 SelectionPoint => HeadBlueprint.SelectionPoint; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos); From 10fd5ef5a7137a66f037e0c49fdf19173986e0e8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Nov 2019 13:38:42 +0900 Subject: [PATCH 63/73] Merge context menus --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 5 ++--- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 6 ++++++ .../Screens/Edit/Compose/Components/SelectionHandler.cs | 7 ++++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index a77350714f..e87145fdc3 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -4,7 +4,6 @@ using System; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics.UserInterface; @@ -19,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderSelectionBlueprint : OsuSelectionBlueprint, IHasContextMenu + public class SliderSelectionBlueprint : OsuSelectionBlueprint { protected readonly SliderBodyPiece BodyPiece; protected readonly SliderCircleSelectionBlueprint HeadBlueprint; @@ -102,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders UpdateHitObject(); } - public MenuItem[] ContextMenuItems => new MenuItem[] + public override MenuItem[] ContextMenuItems => new MenuItem[] { new OsuMenuItem("Add control point", MenuItemType.Standard, addControlPoint), }; diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 2923411ce1..bf99f83e0b 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -104,6 +105,11 @@ namespace osu.Game.Rulesets.Edit public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.ReceivePositionalInputAt(screenSpacePos); + /// + /// The s to be displayed in the context menu for this . + /// + public virtual MenuItem[] ContextMenuItems => Array.Empty(); + /// /// The screen-space point that causes this to be selected. /// diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 3a7c85d36c..d5bbeeb907 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -224,7 +224,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (!selectedBlueprints.Any(b => b.IsHovered)) return Array.Empty(); - return new MenuItem[] + var items = new List { new OsuMenuItem("Sound") { @@ -236,6 +236,11 @@ namespace osu.Game.Screens.Edit.Compose.Components } } }; + + if (selectedBlueprints.Count == 1) + items.AddRange(selectedBlueprints[0].ContextMenuItems); + + return items.ToArray(); } } From 13b11996e0f625cec223e18ebecf8a83a2898bd0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Nov 2019 14:37:07 +0900 Subject: [PATCH 64/73] Improve closest segment algorithm --- .../Sliders/SliderSelectionBlueprint.cs | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index e87145fdc3..9da684025f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -66,27 +66,33 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders var controlPoints = new Vector2[HitObject.Path.ControlPoints.Length + 1]; HitObject.Path.ControlPoints.CopyTo(controlPoints); - // Find the index at which the point will be inserted, by increasing x-coordinates - int insertionIndex = Array.FindIndex(controlPoints, 0, controlPoints.Length - 1, c => c.X >= position.X); + int insertionIndex = 0; + float minDistance = float.MaxValue; - // If no index was found, it should be inserted at the end - if (insertionIndex == -1) - insertionIndex = controlPoints.Length - 1; + for (int i = 0; i < controlPoints.Length - 2; i++) + { + Vector2 p1 = controlPoints[i]; + Vector2 p2 = controlPoints[i + 1]; + + if (p1 == p2) + continue; + + Vector2 dir = p2 - p1; + float projLength = MathHelper.Clamp(Vector2.Dot(position - p1, dir) / dir.LengthSquared, 0, 1); + Vector2 proj = p1 + projLength * dir; + + float dist = Vector2.Distance(position, proj); + + if (dist < minDistance) + { + insertionIndex = i + 1; + minDistance = dist; + } + } // Move the control points from the insertion index onwards to make room for the insertion Array.Copy(controlPoints, insertionIndex, controlPoints, insertionIndex + 1, controlPoints.Length - insertionIndex - 1); - - if (insertionIndex == 0) - { - // Special case for a new first control point being added - the entire slider moves - HitObject.Position += position; - - // The first control point is always at (0, 0), but all other control points need to be re-referenced - for (int i = 1; i < controlPoints.Length; i++) - controlPoints[i] -= position; - } - else - controlPoints[insertionIndex] = position; + controlPoints[insertionIndex] = position; onNewControlPoints(controlPoints); } From 316dcae6145594ec2cc83ab2aed1b3c7fb1ba6c7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Nov 2019 14:41:10 +0900 Subject: [PATCH 65/73] Use squared distance --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 9da684025f..0f058dc088 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -78,10 +78,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders continue; Vector2 dir = p2 - p1; + float projLength = MathHelper.Clamp(Vector2.Dot(position - p1, dir) / dir.LengthSquared, 0, 1); Vector2 proj = p1 + projLength * dir; - float dist = Vector2.Distance(position, proj); + float dist = Vector2.DistanceSquared(position, proj); if (dist < minDistance) { From 407ca41ba454f1bd644ecb3fc1f5eabf9f1fe564 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Nov 2019 14:44:11 +0900 Subject: [PATCH 66/73] Simplify using existing tools --- .../Blueprints/Sliders/SliderSelectionBlueprint.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 0f058dc088..34dc7ddc24 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics.UserInterface; @@ -71,18 +72,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders for (int i = 0; i < controlPoints.Length - 2; i++) { - Vector2 p1 = controlPoints[i]; - Vector2 p2 = controlPoints[i + 1]; - - if (p1 == p2) - continue; - - Vector2 dir = p2 - p1; - - float projLength = MathHelper.Clamp(Vector2.Dot(position - p1, dir) / dir.LengthSquared, 0, 1); - Vector2 proj = p1 + projLength * dir; - - float dist = Vector2.DistanceSquared(position, proj); + float dist = new Line(controlPoints[i], controlPoints[i + 1]).DistanceToPoint(position); if (dist < minDistance) { From 93d8cd38ca4652f5082fdfbd3d87120e144bbc37 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Nov 2019 15:00:57 +0900 Subject: [PATCH 67/73] Implement addition via ctrl+click --- .../Sliders/SliderSelectionBlueprint.cs | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 34dc7ddc24..226afd68b1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; @@ -54,15 +55,47 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders protected override bool OnMouseDown(MouseDownEvent e) { - if (e.Button == MouseButton.Right) - rightClickPosition = e.MouseDownPosition; + switch (e.Button) + { + case MouseButton.Right: + rightClickPosition = e.MouseDownPosition; + return false; // Allow right click to be handled by context menu + + case MouseButton.Left when e.ControlPressed: + placementControlPointIndex = addControlPoint(e.MousePosition); + return true; // Stop input from being handled and modifying the selection + } return false; } - private void addControlPoint() + private int? placementControlPointIndex; + + protected override bool OnDragStart(DragStartEvent e) => placementControlPointIndex != null; + + protected override bool OnDrag(DragEvent e) { - Vector2 position = rightClickPosition - HitObject.Position; + Debug.Assert(placementControlPointIndex != null); + + Vector2 position = e.MousePosition - HitObject.Position; + + var controlPoints = HitObject.Path.ControlPoints.ToArray(); + controlPoints[placementControlPointIndex.Value] = position; + + onNewControlPoints(controlPoints); + + return true; + } + + protected override bool OnDragEnd(DragEndEvent e) + { + placementControlPointIndex = null; + return true; + } + + private int addControlPoint(Vector2 position) + { + position -= HitObject.Position; var controlPoints = new Vector2[HitObject.Path.ControlPoints.Length + 1]; HitObject.Path.ControlPoints.CopyTo(controlPoints); @@ -86,6 +119,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders controlPoints[insertionIndex] = position; onNewControlPoints(controlPoints); + + return insertionIndex; } private void onNewControlPoints(Vector2[] controlPoints) @@ -100,7 +135,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders public override MenuItem[] ContextMenuItems => new MenuItem[] { - new OsuMenuItem("Add control point", MenuItemType.Standard, addControlPoint), + new OsuMenuItem("Add control point", MenuItemType.Standard, () => addControlPoint(rightClickPosition)), }; public override Vector2 SelectionPoint => HeadBlueprint.SelectionPoint; From 25eb9642904dfe8e640e85c2430c290de04e6462 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 15:03:58 +0900 Subject: [PATCH 68/73] Simplify overlay adding logic --- osu.Game/OsuGame.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index fa97044c95..e2ece8422c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -593,14 +593,14 @@ namespace osu.Game loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true); loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true); - var login = loadComponentSingleFile(new LoginOverlay + loadComponentSingleFile(new LoginOverlay { GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, rightFloatingOverlayContent.Add, true); - var nowPlaying = loadComponentSingleFile(new NowPlayingOverlay + loadComponentSingleFile(new NowPlayingOverlay { GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, @@ -615,10 +615,10 @@ namespace osu.Game Add(externalLinkOpener = new ExternalLinkOpener()); + // side overlays which cancel each other. var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications }; - overlays.AddRange(singleDisplaySideOverlays); - foreach (var overlay in singleDisplaySideOverlays) + foreach (var overlay in new OverlayContainer[] { Settings, notifications }) { overlay.State.ValueChanged += state => { @@ -630,7 +630,6 @@ namespace osu.Game // eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time. var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile }; - overlays.AddRange(informationalOverlays); foreach (var overlay in informationalOverlays) { @@ -644,7 +643,6 @@ namespace osu.Game // ensure only one of these overlays are open at once. var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, social, direct, changelogOverlay }; - overlays.AddRange(singleDisplayOverlays); foreach (var overlay in singleDisplayOverlays) { @@ -659,8 +657,6 @@ namespace osu.Game }; } - overlays.AddRange(new OverlayContainer[] { login, nowPlaying }); - OverlayActivationMode.ValueChanged += mode => { if (mode.NewValue != OverlayActivation.All) CloseAllOverlays(); @@ -747,6 +743,9 @@ namespace osu.Game if (cache) dependencies.Cache(d); + if (d is OverlayContainer overlay) + overlays.Add(overlay); + // schedule is here to ensure that all component loads are done after LoadComplete is run (and thus all dependencies are cached). // with some better organisation of LoadComplete to do construction and dependency caching in one step, followed by calls to loadComponentSingleFile, // we could avoid the need for scheduling altogether. From 35351d7f7c34cb8f0395aa0992f245b7dfc52ddb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 15:04:51 +0900 Subject: [PATCH 69/73] Use variable instead of duplicated list --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e2ece8422c..f6b8d5cfbb 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -618,7 +618,7 @@ namespace osu.Game // side overlays which cancel each other. var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications }; - foreach (var overlay in new OverlayContainer[] { Settings, notifications }) + foreach (var overlay in singleDisplaySideOverlays) { overlay.State.ValueChanged += state => { From a0884fe9d42a0815f642eb7203246b6bf608d838 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Nov 2019 15:07:54 +0900 Subject: [PATCH 70/73] Fix being able to add while not selected --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 226afd68b1..820d6c92d7 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders rightClickPosition = e.MouseDownPosition; return false; // Allow right click to be handled by context menu - case MouseButton.Left when e.ControlPressed: + case MouseButton.Left when e.ControlPressed && IsSelected: placementControlPointIndex = addControlPoint(e.MousePosition); return true; // Stop input from being handled and modifying the selection } From 47be20fa3773c1fed6ba2e521d9a71b4c93a3582 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 15:13:47 +0900 Subject: [PATCH 71/73] Private set on track for safety --- osu.Game/Audio/PreviewTrack.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index b39d2bc8f8..5df656e1e0 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -24,7 +24,7 @@ namespace osu.Game.Audio /// public event Action Started; - protected Track Track; + protected Track Track { get; private set; } private bool hasStarted; From 46d02d9077e75619b535975778118175fa704601 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 17:37:01 +0900 Subject: [PATCH 72/73] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 6c40dc4812..6fab2e7868 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -53,6 +53,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index baa1c14071..af60da3e70 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -21,7 +21,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 0184e45c15..8124357312 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -73,6 +73,6 @@ - + From 70a02d27a99e86f4308f62aac12dbe10f75fa5bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Nov 2019 22:53:01 +0900 Subject: [PATCH 73/73] Update solution paths --- fastlane/Fastfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 7adf42a1eb..28a83fbbae 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -49,12 +49,12 @@ desc 'Deploy to play store' desc 'Compile the project' lane :build do |options| nuget_restore( - project_path: 'osu.Android.sln' + project_path: 'osu.sln' ) souyuz( build_configuration: 'Release', - solution_path: 'osu.Android.sln', + solution_path: 'osu.sln', platform: "android", output_path: "osu.Android/bin/Release/", keystore_path: options[:keystore_path], @@ -70,7 +70,7 @@ desc 'Deploy to play store' android_build = split.join('') app_version( - solution_path: 'osu.Android.sln', + solution_path: 'osu.sln', version: options[:version], build: android_build, ) @@ -106,7 +106,7 @@ platform :ios do desc 'Compile the project' lane :build do nuget_restore( - project_path: 'osu.iOS.sln' + project_path: 'osu.sln' ) souyuz(