From ce7be940e2dd4f220583318bdf623a63d0f6e4f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 14:34:33 +0900 Subject: [PATCH] Setup basics for control and test --- .../Editing/TestSceneTapTimingControl.cs | 94 +++++++++ .../UserInterfaceV2/LabelledDrawable.cs | 3 +- .../Screens/Edit/Timing/TapTimingControl.cs | 189 ++++++++++++++++++ osu.Game/Screens/Edit/Timing/TimingSection.cs | 2 + 4 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs create mode 100644 osu.Game/Screens/Edit/Timing/TapTimingControl.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs new file mode 100644 index 0000000000..c2889b2549 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs @@ -0,0 +1,94 @@ +// 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.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Timing; +using osuTK; + +namespace osu.Game.Tests.Visual.Editing +{ + [TestFixture] + public class TestSceneTapTimingControl : EditorClockTestScene + { + [Cached(typeof(EditorBeatmap))] + [Cached(typeof(IBeatSnapProvider))] + private readonly EditorBeatmap editorBeatmap; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [Cached] + private Bindable selectedGroup = new Bindable(); + + private TapTimingControl control; + + public TestSceneTapTimingControl() + { + editorBeatmap = new EditorBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)); + selectedGroup.Value = editorBeatmap.ControlPointInfo.Groups.First(); + } + + [Test] + public void TestTapThenReset() + { + AddStep("click tap button", () => + { + control.ChildrenOfType() + .First(b => b.Text == "Tap to beat") + .TriggerClick(); + }); + + AddUntilStep("wait for track playing", () => Clock.IsRunning); + + AddStep("click reset button", () => + { + control.ChildrenOfType() + .First(b => b.Text == "Reset") + .TriggerClick(); + }); + + AddUntilStep("wait for track stopped", () => !Clock.IsRunning); + } + + [Test] + public void TestBasic() + { + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); + Beatmap.Disabled = true; + + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, + Width = 400, + Scale = new Vector2(1.5f), + Child = control = new TapTimingControl(), + }; + } + + protected override void Dispose(bool isDisposing) + { + Beatmap.Disabled = false; + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs index 1e6032c1d0..066e1a7978 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs @@ -41,7 +41,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected const float CONTENT_PADDING_VERTICAL = 10; protected const float CONTENT_PADDING_HORIZONTAL = 15; - protected const float CORNER_RADIUS = 15; + + public const float CORNER_RADIUS = 15; /// /// The component that is being displayed. diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs new file mode 100644 index 0000000000..3867a4bcec --- /dev/null +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -0,0 +1,189 @@ +// 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.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Screens.Edit.Timing +{ + public class TapTimingControl : CompositeDrawable + { + [Resolved] + private EditorClock editorClock { get; set; } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider, OsuColour colours) + { + Height = 200; + RelativeSizeAxes = Axes.X; + + CornerRadius = LabelledDrawable.CORNER_RADIUS; + Masking = true; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = colourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 60), + }, + Content = new[] + { + new Drawable[] + { + new Metronome() + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(10), + Children = new Drawable[] + { + new RoundedButton + { + Text = "Reset", + BackgroundColour = colours.Pink, + RelativeSizeAxes = Axes.X, + Width = 0.3f, + Action = reset, + }, + new RoundedButton + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Text = "Tap to beat", + RelativeSizeAxes = Axes.X, + BackgroundColour = colourProvider.Background1, + Width = 0.68f, + Action = tap, + } + } + }, + } + } + }, + }; + } + + private void tap() + { + if (!editorClock.IsRunning) + { + editorClock.Seek(0); + editorClock.Start(); + } + } + + private void reset() + { + editorClock.Stop(); + } + + private class Metronome : BeatSyncedContainer + { + private Container swing; + private Box weight; + private OsuSpriteText bpm; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider overlayColourProvider) + { + Margin = new MarginPadding(10); + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Triangle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(80, 120), + Colour = overlayColourProvider.Background1, + }, + new Circle + { + Y = -25, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + Colour = overlayColourProvider.Content2, + Size = new Vector2(10) + }, + bpm = new OsuSpriteText + { + Colour = overlayColourProvider.Content1, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + swing = new Container + { + RelativeSizeAxes = Axes.Both, + Y = -25, + Height = 0.8f, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Children = new Drawable[] + { + new Box + { + Colour = overlayColourProvider.Content2, + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Width = 4, + }, + weight = new Box + { + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Colour = overlayColourProvider.Content2, + Size = new Vector2(15), + RelativePositionAxes = Axes.Y, + Y = -0.4f, + }, + } + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + swing + .RotateTo(20, 500, Easing.InOutQuad) + .Then() + .RotateTo(-20, 500, Easing.InOutQuad) + .Loop(); + } + + protected override void Update() + { + base.Update(); + + if (CurrentTimingPoint == null) + return; + + weight.Y = Math.Clamp((float)CurrentTimingPoint.BPM / 480, 0, 0.95f); + bpm.Text = $"{CurrentTimingPoint.BPM:F0}"; + } + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/TimingSection.cs b/osu.Game/Screens/Edit/Timing/TimingSection.cs index 13af04cd4b..be719d0cb6 100644 --- a/osu.Game/Screens/Edit/Timing/TimingSection.cs +++ b/osu.Game/Screens/Edit/Timing/TimingSection.cs @@ -19,6 +19,7 @@ namespace osu.Game.Screens.Edit.Timing { Flow.AddRange(new Drawable[] { + new TapTimingControl(), bpmTextEntry = new BPMTextBox(), timeSignature = new LabelledTimeSignature { @@ -96,5 +97,6 @@ namespace osu.Game.Screens.Edit.Timing } private static double beatLengthToBpm(double beatLength) => 60000 / beatLength; + } }