diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaTouchInput.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaTouchInput.cs new file mode 100644 index 0000000000..dc95cd9ca0 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaTouchInput.cs @@ -0,0 +1,68 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Input; +using osu.Framework.Testing; +using osu.Game.Rulesets.Mania.UI; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests +{ + public partial class TestSceneManiaTouchInput : PlayerTestScene + { + protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); + + [Test] + public void TestTouchInput() + { + for (int i = 0; i < 4; i++) + { + int index = i; + + AddStep($"touch column {index}", () => InputManager.BeginTouch(new Touch(TouchSource.Touch1, getColumn(index).ScreenSpaceDrawQuad.Centre))); + + AddAssert("action sent", + () => this.ChildrenOfType().SelectMany(m => m.KeyBindingContainer.PressedActions), + () => Does.Contain(getColumn(index).Action.Value)); + + AddStep($"release column {index}", () => InputManager.EndTouch(new Touch(TouchSource.Touch1, getColumn(index).ScreenSpaceDrawQuad.Centre))); + + AddAssert("action released", + () => this.ChildrenOfType().SelectMany(m => m.KeyBindingContainer.PressedActions), + () => Does.Not.Contain(getColumn(index).Action.Value)); + } + } + + [Test] + public void TestOneColumnMultipleTouches() + { + AddStep("touch column 0", () => InputManager.BeginTouch(new Touch(TouchSource.Touch1, getColumn(0).ScreenSpaceDrawQuad.Centre))); + + AddAssert("action sent", + () => this.ChildrenOfType().SelectMany(m => m.KeyBindingContainer.PressedActions), + () => Does.Contain(getColumn(0).Action.Value)); + + AddStep("touch another finger", () => InputManager.BeginTouch(new Touch(TouchSource.Touch2, getColumn(0).ScreenSpaceDrawQuad.Centre))); + + AddAssert("action still pressed", + () => this.ChildrenOfType().SelectMany(m => m.KeyBindingContainer.PressedActions), + () => Does.Contain(getColumn(0).Action.Value)); + + AddStep("release first finger", () => InputManager.EndTouch(new Touch(TouchSource.Touch1, getColumn(0).ScreenSpaceDrawQuad.Centre))); + + AddAssert("action still pressed", + () => this.ChildrenOfType().SelectMany(m => m.KeyBindingContainer.PressedActions), + () => Does.Contain(getColumn(0).Action.Value)); + + AddStep("release second finger", () => InputManager.EndTouch(new Touch(TouchSource.Touch2, getColumn(0).ScreenSpaceDrawQuad.Centre))); + + AddAssert("action released", + () => this.ChildrenOfType().SelectMany(m => m.KeyBindingContainer.PressedActions), + () => Does.Not.Contain(getColumn(0).Action.Value)); + } + + private Column getColumn(int index) => this.ChildrenOfType().ElementAt(index); + } +} diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaTouchInputArea.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaTouchInputArea.cs deleted file mode 100644 index 30c0113bff..0000000000 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaTouchInputArea.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using NUnit.Framework; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input; -using osu.Framework.Testing; -using osu.Game.Rulesets.Mania.UI; -using osu.Game.Tests.Visual; - -namespace osu.Game.Rulesets.Mania.Tests -{ - public partial class TestSceneManiaTouchInputArea : PlayerTestScene - { - protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); - - [Test] - public void TestTouchAreaNotInitiallyVisible() - { - AddAssert("touch area not visible", () => getTouchOverlay()?.State.Value == Visibility.Hidden); - } - - [Test] - public void TestPressReceptors() - { - AddAssert("touch area not visible", () => getTouchOverlay()?.State.Value == Visibility.Hidden); - - for (int i = 0; i < 4; i++) - { - int index = i; - - AddStep($"touch receptor {index}", () => InputManager.BeginTouch(new Touch(TouchSource.Touch1, getReceptor(index).ScreenSpaceDrawQuad.Centre))); - - AddAssert("action sent", - () => this.ChildrenOfType().SelectMany(m => m.KeyBindingContainer.PressedActions), - () => Does.Contain(getReceptor(index).Action.Value)); - - AddStep($"release receptor {index}", () => InputManager.EndTouch(new Touch(TouchSource.Touch1, getReceptor(index).ScreenSpaceDrawQuad.Centre))); - - AddAssert("touch area visible", () => getTouchOverlay()?.State.Value == Visibility.Visible); - } - } - - private ManiaTouchInputArea? getTouchOverlay() => this.ChildrenOfType().SingleOrDefault(); - - private ManiaTouchInputArea.ColumnInputReceptor getReceptor(int index) => this.ChildrenOfType().ElementAt(index); - } -} diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index c05a8f2a29..99d952ef1f 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -180,5 +180,29 @@ namespace osu.Game.Rulesets.Mania.UI public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) // This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border => DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos)); + + #region Touch Input + + [Resolved(canBeNull: true)] + private ManiaInputManager maniaInputManager { get; set; } + + private int touchActivationCount; + + protected override bool OnTouchDown(TouchDownEvent e) + { + maniaInputManager.KeyBindingContainer.TriggerPressed(Action.Value); + touchActivationCount++; + return true; + } + + protected override void OnTouchUp(TouchUpEvent e) + { + touchActivationCount--; + + if (touchActivationCount == 0) + maniaInputManager.KeyBindingContainer.TriggerReleased(Action.Value); + } + + #endregion } } diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index 136b172a59..65841af5de 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -112,8 +112,6 @@ namespace osu.Game.Rulesets.Mania.UI configScrollSpeed.BindValueChanged(speed => TargetTimeRange = ComputeScrollTime(speed.NewValue)); TimeRange.Value = TargetTimeRange = currentTimeRange = ComputeScrollTime(configScrollSpeed.Value); - - KeyBindingInputManager.Add(new ManiaTouchInputArea()); } protected override void AdjustScrollSpeed(int amount) => configScrollSpeed.Value += amount; diff --git a/osu.Game.Rulesets.Mania/UI/ManiaTouchInputArea.cs b/osu.Game.Rulesets.Mania/UI/ManiaTouchInputArea.cs deleted file mode 100644 index 8c4a71cf24..0000000000 --- a/osu.Game.Rulesets.Mania/UI/ManiaTouchInputArea.cs +++ /dev/null @@ -1,199 +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.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; -using osu.Game.Configuration; -using osuTK; - -namespace osu.Game.Rulesets.Mania.UI -{ - /// - /// An overlay that captures and displays osu!mania mouse and touch input. - /// - public partial class ManiaTouchInputArea : VisibilityContainer - { - // visibility state affects our child. we always want to handle input. - public override bool PropagatePositionalInputSubTree => true; - public override bool PropagateNonPositionalInputSubTree => true; - - [SettingSource("Spacing", "The spacing between receptors.")] - public BindableFloat Spacing { get; } = new BindableFloat(10) - { - Precision = 1, - MinValue = 0, - MaxValue = 100, - }; - - [SettingSource("Opacity", "The receptor opacity.")] - public BindableFloat Opacity { get; } = new BindableFloat(1) - { - Precision = 0.1f, - MinValue = 0, - MaxValue = 1 - }; - - [Resolved] - private DrawableManiaRuleset drawableRuleset { get; set; } = null!; - - private GridContainer gridContainer = null!; - - public ManiaTouchInputArea() - { - Anchor = Anchor.BottomCentre; - Origin = Anchor.BottomCentre; - - RelativeSizeAxes = Axes.Both; - Height = 0.5f; - } - - [BackgroundDependencyLoader] - private void load() - { - List receptorGridContent = new List(); - List receptorGridDimensions = new List(); - - bool first = true; - - foreach (var stage in drawableRuleset.Playfield.Stages) - { - foreach (var column in stage.Columns) - { - if (!first) - { - receptorGridContent.Add(new Gutter { Spacing = { BindTarget = Spacing } }); - receptorGridDimensions.Add(new Dimension(GridSizeMode.AutoSize)); - } - - receptorGridContent.Add(new ColumnInputReceptor { Action = { BindTarget = column.Action } }); - receptorGridDimensions.Add(new Dimension()); - - first = false; - } - } - - InternalChild = gridContainer = new GridContainer - { - RelativeSizeAxes = Axes.Both, - AlwaysPresent = true, - Content = new[] { receptorGridContent.ToArray() }, - ColumnDimensions = receptorGridDimensions.ToArray() - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - Opacity.BindValueChanged(o => Alpha = o.NewValue, true); - } - - protected override bool OnKeyDown(KeyDownEvent e) - { - // Hide whenever the keyboard is used. - Hide(); - return false; - } - - protected override bool OnTouchDown(TouchDownEvent e) - { - Show(); - return true; - } - - protected override void PopIn() - { - gridContainer.FadeIn(500, Easing.OutQuint); - } - - protected override void PopOut() - { - gridContainer.FadeOut(300); - } - - public partial class ColumnInputReceptor : CompositeDrawable - { - public readonly IBindable Action = new Bindable(); - - private readonly Box highlightOverlay; - - [Resolved] - private ManiaInputManager? inputManager { get; set; } - - private bool isPressed; - - public ColumnInputReceptor() - { - RelativeSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 10, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.15f, - }, - highlightOverlay = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Blending = BlendingParameters.Additive, - } - } - } - }; - } - - protected override bool OnTouchDown(TouchDownEvent e) - { - updateButton(true); - return false; // handled by parent container to show overlay. - } - - protected override void OnTouchUp(TouchUpEvent e) - { - updateButton(false); - } - - private void updateButton(bool press) - { - if (press == isPressed) - return; - - isPressed = press; - - if (press) - { - inputManager?.KeyBindingContainer.TriggerPressed(Action.Value); - highlightOverlay.FadeTo(0.1f, 80, Easing.OutQuint); - } - else - { - inputManager?.KeyBindingContainer.TriggerReleased(Action.Value); - highlightOverlay.FadeTo(0, 400, Easing.OutQuint); - } - } - } - - private partial class Gutter : Drawable - { - public readonly IBindable Spacing = new Bindable(); - - public Gutter() - { - Spacing.BindValueChanged(s => Size = new Vector2(s.NewValue)); - } - } - } -}